Index: ChangeLog ================================================================== --- ChangeLog +++ ChangeLog @@ -1,5 +1,4738 @@ +2007-06-06 Daniel Steffen + + * unix/configure.in (Darwin): add plist for tclsh; link the + * unix/Makefile.in (Darwin): Tcl and tclsh plists into their + * macosx/Tclsh-Info.plist.in (new): binaries in all cases. + + * unix/tcl.m4 (Darwin): fix CF checks in fat 32&64bit builds. + * unix/configure: autoconf-2.13 + +2007-06-05 Don Porter + + * tests/result.test (result-6.2): Add test for Bug 1649062 so + that 8.4 and 8.5 both test the same outcome and we verify compatibility. + +2007-05-30 Don Porter + + * README: Bump version number to 8.4.16 + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/configure.in: + * unix/tcl.spec: + * win/README.binary: + * win/configure.in: + + * unix/configure: autoconf-2.13 + * win/configure: + +2007-05-29 Jeff Hobbs + + * unix/tclUnixThrd.c (Tcl_JoinThread): fix for 64-bit handling of + pthread_join exit return code storage. [Bug 1712723] + +2007-05-24 Don Porter + + *** 8.4.15 TAGGED FOR RELEASE *** + + * generic/tclIO.c: Backport memleak fix in TclFinalizeIOSubsystem. + +2007-05-17 Don Porter + + * tests/fCmd.test: Backport the notNetworkFilesystem constraint. + +2007-05-15 Don Porter + + * generic/tclNamesp.c: Plugged memory leak related to + [namespace delete ::]. [Bug 1716782] + + * changes: updates for 8.4.15 release. + + * win/tclWinReg.c: Bump to registry 1.1.5 to account + * library/reg/pkgIndex.tcl: for [1682211] bug fix. + +2007-05-10 Don Porter + + * generic/tclInt.h: TclFinalizeThreadAlloc() is always defined, + so make sure it is also always declared. + + [Tcl Bug 1706140] + + * generic/tclCmdMZ.c (Trace*Proc): Update Tcl_VarTraceProcs so + * generic/tclLink.c (LinkTraceProc): that they call + * generic/tclUtil.c (TclPrecTraceProc): Tcl_InterpDeleted() for + themselves, and do not rely on (frequently buggy) setting of the + TCL_INTERP_DESTROYED flag by the trace core. + + * generic/tclVar.c: Update callers of CallVarTraces to not + pass in the TCL_INTERP_DESTROYED flag. Also apply filters so that + public routines only pass documented flag values down to lower level + routines. + + * generic/tclVar.c (CallVarTraces): The setting of the + TCL_INTERP_DESTROYED flag is now done entirely within the + CallVarTraces routine, the only place it can be done right. + +2007-04-30 Daniel Steffen + + * unix/Makefile.in: add 'tclsh' dependency to install targets that rely + on tclsh, fixes parallel 'make install' from empty build dir. + +2007-04-29 Daniel Steffen + + * unix/tclUnixFCmd.c: add workaround for crashing bug in fts_open() + * unix/tclUnixInit.c: without FTS_NOSTAT on 64bit Darwin 8 or earlier. + + * unix/tclLoadDyld.c (TclpLoadMemory): fix (void*) arithmetic. + + * macosx/tclMacOSXNotify.c: fix warnings. + + * macosx/README: sync whitespace/formatting with HEAD. + * macosx/tclMacOSXBundle.c: + * macosx/tclMacOSXNotify.c: + * unix/tclLoadDyld.c: + + * macosx/Makefile: fix/add copyright and license refs. + * macosx/tclMacOSXBundle.c: + * macosx/Tcl-Info.plist.in: + + * unix/Makefile.in (dist): copy license.terms to dist macosx dir. + * unix/configure.in: install license.terms into Tcl.framework. + * unix/configure: autoconf-2.13 + +2007-04-21 Kevin B. Kenny + + * generic/tclClock.c: Restored Cygwin buildability [Bug 1387154] + * generic/tclInt.decls: Yet another round of attempting + * generic/tclInt.h: to get the correct type signature + * unix/tclUnixPort.h: for TclpLocaltime and TclpGmtime. + * unix/tclUnixTime.c: CONST TclpTime_t is a 'time_t *CONST' + * win/tclWinTime.c: and not a 'CONST time_t*' [Bug 1677275] + * generic/tclIntDecls.h: + * generic/tclIntPlatDecls.h: Regenerated. + +2007-03-24 Zoran Vasiljevic + + * win/tclWinThrd.c: Thread exit handler marks the current + thread as un-initialized. This allows exit handlers that + are registered later to re-initialize this subsystem in + case they need to use some sync primitives (cond variables) + from this file again. + +2007-03-19 Don Porter + + * generic/tclEvent.c (Tcl_CreateThread): Replaced some calls to + * generic/tclPkg.c (CheckVersion): Tcl_Alloc() with calls to + * unix/tclUnixTime.c (SetTZIfNecessary): ckalloc(), which better + * win/tclAppInit.c (setargv): supports memory debugging. + +2007-03-17 Kevin Kenny + + * win/tclWinReg.c (GetKeyNames): Size the buffer for enumerating + key names correctly, so that Unicode names exceeding 127 chars + can be retrieved without crashing. [Bug 1682211] + * tests/registry.test (registry-4.9): Added test case for the + above bug. + +2007-03-13 Don Porter + + * generic/tclExecute.c (INST_FOREACH_STEP4): Re-fetch pointers for + * tests/foreach.test (foreach-10.1): the value list each iteration + of the loop as defense against shimmers. [Bug 1671087] + + * generic/tclVar.c (TclArraySet): Re-fetch pointers for the list + * tests/var.test (var-17.1): argument of [array set] each time + through the loop as defense against possible shimmer issues. + [Bug 1669489]. + +2007-03-10 Donal K. Fellows + + * generic/tclCmdIL.c (Tcl_LsortObjCmd): Handle tricky case with loss + * tests/cmdIL.test (cmdIL-1.29):of list rep during sorting due + to shimmering. [Bug 1675116] + +2007-03-07 Daniel Steffen + + * macosx/tclMacOSXNotify.c: add spinlock debugging and sanity checks. + + * unix/tcl.m4 (Darwin): s/CFLAGS/CPPFLAGS/ in macosx-version-min check. + * unix/configure: autoconf-2.13 + +2007-03-01 Donal K. Fellows + + * generic/tclCompCmds.c (TclCompileForeachCmd): Prevent an unexpected + * tests/foreach.test (foreach-9.1): infinite loop when the + variable list is empty and the foreach is compiled. [Bug 1671138] + +2007-02-22 Andreas Kupries + + * tests/pkg.test: Added tests for the case of an alpha package + satisfying a require for the regular package, demonstrating a + corner case specified in TIP#280. More notes in the comments to + the test. + +2007-02-20 Don Porter + + * doc/tcltest.n: Typo fix. [Bug 1663539] + +2007-02-19 Jeff Hobbs + + * generic/tclIOUtil.c (Tcl_FSEvalFile): safe incr of objPtr ref. + + * unix/tcl.m4: use SHLIB_SUFFIX=".so" on HP-UX ia64 arch. + * unix/configure: autoconf-2.13 + +2007-02-12 Andreas Kupries + + * generic/tclEncoding.c (EscapeFromUtfProc): Applied patch + supplied by Mo DeJong to fix [Bug 1516109]. Backport from Tcl + 8.5. Mo's description: Clear the TCL_ENCODING_END flag when end + bytes are written. This fix keep this method from writing escape + bytes for an encoding like iso2022-jp multiple times when the + escape byte overlap with the end of the IO buffer. + * tests/io.test: Add test case for escape byte overlap case. + +2007-02-04 Daniel Steffen + + * unix/configure.in: add caching to -pipe check. + * unix/configure: autoconf-2.13 + +2007-01-30 Jeff Hobbs + + * win/Makefile.in (install-private-headers): added target + +2007-01-29 Don Porter + + * doc/fcopy.n: Typo fix. [Bug 1630627] + +2007-01-25 Daniel Steffen + + * unix/tcl.m4: integrate CPPFLAGS into CFLAGS as late as possible + * unix/configure.in: and move (rather than duplicate) -isysroot flags + from CFLAGS to CPPFLAGS to avoid errors about multiple -isysroot flags + from some older gcc builds. + + * unix/configure: autoconf-2.13 + +2007-01-22 Andreas Kupries + + * compat/memcmp.c (memcmp): Fixed the VOID / CONST typo introduced + by the last checkin. + +2007-01-22 Donal K. Fellows + + * compat/memcmp.c (memcmp): Reworked so that arithmetic is never + performed upon void pointers, since that is illegal. [Bug 1631017] + +2006-01-19 Daniel Steffen + + * macosx/tclMacOSXNotify.c: accommodate changes to prototypes of + OSSpinLock(Un)Lock API. + + * tests/env.test: add extra system env vars that need to be preserved + on some Mac OS X versions for testsuite to work. + + * unix/tcl.m4: ensure CPPFLAGS env var is used when set. [Bug 1586861] + (Darwin): add -isysroot and -mmacosx-version-min flags to CPPFLAGS when + present in CFLAGS to avoid discrepancies between what headers configure + sees during preprocessing tests and compiling tests. + + * unix/configure: autoconf-2.13 + +2006-12-19 Daniel Steffen + + * unix/tclUnixThrd.c (TclpInetNtoa): fix for 64 bit. + + * unix/tcl.m4 (Darwin): --enable-64bit: verify linking with 64bit -arch + flag succeeds before enabling 64bit build. + * unix/configure: autoconf-2.13 + +2006-12-14 Donal K. Fellows + + * doc/string.n: Fix example. [Bug 1615277] + +2006-12-05 Andreas Kupries + + * tests/pkg.test: Backport to 8.4 (Don Porter's work): + * generic/tclPkg.c: When no requirements are supplied to a [package + require $pkg] and [package unknown] is invoked to find a satisfying + package, pass the requirement argument "0-" (which means all versions + are acceptable). This permits a registered [package unknown] command + to call [package vsatisfies $testVersion {*}$args] without any special + handling of the empty $args case. This fixes/avoids a bug in + [::tcl::tm::UnknownHandler] that was causing old TM versions to be + provided in preference to newer TM versions. Thanks to Julian Noble + for discovering the issue. + +2006-12-04 Donal K. Fellows + + * doc/file.n: Fix confusing wording for [file pathtype]. [Bug 1606454] + +2006-11-28 Andreas Kupries + + * generic/tclBasic.c: TIP #280 implementation, conditional on the + * generic/tclCmdAH.c: define TCL_TIP280. + * generic/tclCmdIL.c: + * generic/tclCmdMZ.c: + * generic/tclCompCmds.c: + * generic/tclCompExpr.c: + * generic/tclCompile.c: + * generic/tclCompile.h: + * generic/tclExecute.c: + * generic/tclIOUtil.c: + * generic/tclInt.h: + * generic/tclInterp.c: + * generic/tclNamesp.c: + * generic/tclObj.c: + * generic/tclProc.c: + * tests/compile.test: + * tests/info.test: + * tests/platform.test: + * tests/safe.test: + +2006-11-27 Kevin Kenny + + * unix/tclUnixChan.c (TclUnixWaitForFile): + * tests/event.test (event-14.*): Corrected a bug where + TclUnixWaitForFile would present select() with the wrong mask on an + LP64 machine if a fd number exceeds 32. Thanks to Jean-Luc Fontaine + for reporting and diagnosing [Bug 1602208] + +2006-11-26 Daniel Steffen + + * unix/tcl.m4 (Linux): --enable-64bit support. [Patch 1597389] + * unix/configure: autoconf-2.13 [Bug 1230558] + +2006-11-07 Andreas Kupries + + * unix/tclUnixFCmd.c (CopyFile): Added code to fall back to a + hardwired default block size should the filesystem report a bogus + value. [Bug 1586470] + +2006-11-03 Miguel Sofer + + * generic/tclBasic.c (TEOVI): fix for possible leak of a Command in + the presence of execution traces that delete it. + + * generic/tclBasic.c (TEOVI): + * tests/trace.test (trace-21.11): fix for [Bug 1590232], execution + traces may cause a second command resolution in the wrong + namespace. + +2006-11-01 Daniel Steffen + + * generic/tclEnv.c (Darwin): mark _environ symbol as unexported. + +2006-10-31 Pat Thoyts + + * rules.vc: Fix [Bug 1582769] build with VC2003 and correct i386 arch + +2006-10-23 Don Porter + + * README: Bump version number to 8.4.15 + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/configure.in: + * unix/tcl.spec: + * win/README.binary: + * win/configure.in: + + * unix/configure: autoconf-2.13 + * win/configure: + +2006-10-18 Pat Thoyts + + *** 8.4.14 TAGGED FOR RELEASE *** + + * win/nmakehlp.c: Ensure builds with VC6 without Platform SDK. + * win/rules.vc: Pickup MACHINE from environment. + +2006-10-17 Don Porter + + * generic/tclIOUtil.c: Cleaned up some code flagged by a + * generic/tclInt.h: `make checkexports` test. + * win/tclWin32Dll.c: + * win/tclWinFile.c: + +2006-10-16 Daniel Steffen + + * changes: updates for 8.4.14 release. + + * macosx/Makefile: don't redo prebinding of non-prebound binaires. + +2006-10-11 Andreas Kupries + + * generic/tclPkg.c (Tcl_PkgRequireEx): Corrected crash when argument + version==NULL passed in. Backport of the fix for the same problem in + 8.5. + +2006-10-10 Don Porter + + * changes: changes updated for 8.4.14 release. + +2006-10-06 Jeff Hobbs + + * tests/http.test: update tests to handle strictness change. + +2006-10-06 Pat Thoyts + + * win/rules.vc: avoid /RTCc flag with MSVC8. [Bug 1571954] + +2006-10-05 Jeff Hobbs + + * library/http/http.tcl (http::geturl): only do geturl url rfc 3986 + validity checking if $::http::strict is true (default false for 8.4). + [Bug 1560506] + + * generic/tcl.h: note limitation on changing Tcl_UniChar size + * generic/tclEncoding.c (UtfToUnicodeProc, UnicodeToUtfProc): + * tests/encoding.test (encoding-16.1): fix alignment issues in + unicode <> utf conversion procs. [Bug 1122671] + +2006-10-05 Miguel Sofer + + * generic/tclVar.c (Tcl_LappendObjCmd): + * tests/append.test(4.21-22): fix for longstanding [Bug 1570718], + lappending nothing to non-list. Reported by lvirden + +2006-10-02 Don Porter + + * generic/tclFileName.c (TclGlob): Prevent doubling of directory + separators by [glob]. [Bug 1569042] + +2006-10-01 Pat Thoyts + + * win/tclWinFile.c: Handle possible missing define. + * win/tclWinFile.c: Backported fix for [Bug 1420432] (cannot set + * tests/cmdAH.test: mtime for directories on windows). + +2006-09-30 Miguel Sofer + + * generic/tclUtil.c (Tcl_SplitList): optimisation, [Patch 1344747] + by dgp. + +2006-09-26 Pat Thoyts + + * win/makefile.vc: Updated MSVC build to properly deal with + * win/nmakehlp.c: MSVC8 and AMD64 target. Backport from 8.5 + * win/rules.vc: + * generic/tcl.h: Fixed stat definition for MSVC8 AMD64. + * win/tclWinSock.c: Casting type police. + * win/tclWinTime.c: + +2006-09-26 Don Porter + + * generic/tcl.h: As 2006-09-22 commit from Donal K. Fellows + demonstrates, "#define NULL 0" is just wrong, and as a quotable chat + figure observed, "If NULL isn't defined, we're not using a C compiler." + Improper fallback definition of NULL removed. + +2006-09-25 Andreas Kupries + + * generic/tclIO.c (Tcl_StackChannel): Fixed [SF Tcl Bug 1564642], aka + coverity #51. Extended loop condition, added checking for NULL to + prevent seg.fault. + +2006-09-25 Andreas Kupries + + * generic/tclBasic.c: Reverted exposure of patchlevel in registered + core version when TIP#268 features are activated. Better compatibility + with existing packages. Like Tk. + +2006-09-24 Miguel Sofer + + * generic/tclParse.c (Tcl_ParseCommand): also return an error if + start==NULL and numBytes<0. This is coverity's bug #20 + + * generic/tclStringObj.c (STRING_SIZE): fix allocation for 0-length + strings. This is coverity's bugs #54-5 + +2006-09-22 Andreas Kupries + + * generic/tclInt.h: Moved TIP#268's field 'packagePrefer' to the end + of the structure, for better backward compatibility. + +2006-09-22 Andreas Kupries + + * generic/tclPkg.c (Tcl_PkgRequireEx): Changes handling of the return + information from 'Tcl_PkgRequireProc'. Keep the interpreter result + empty. Backport of fix for problem found while testing #268 under 8.5. + More details in the comments. + +2006-09-22 Donal K. Fellows + + * generic/tclThreadTest.c (TclCreateThread): Use NULL instead of 0 as + end-of-strings marker to Tcl_AppendResult; the difference matters on + 64-bit machines. [Bug 1562528] + +2006-09-21 Andreas Kupries + + * generic/tcl.decls: Implemented TIP #268, conditionally. + * generic/tclBasic.c: Define TCL_TIP268 to activate the new + * generic/tclDecls.h: features. + * generic/tclInt.h: + * generic/tclPkg.c: + * generic/tclStubInit.c: + * generic/tclTest.c: + * library/init.tcl + * library/package.tcl: + * tests/pkg.test: + * tests/platform.test: + * tests/safe.test: + * doc/PkgRequire.3: + +2006-09-15 Jeff Hobbs + + * library/http/http.tcl: Change " " -> "+" url encoding mapping + * library/http/pkgIndex.tcl: to " " -> "%20" as per RFC 3986. + * tests/http.test (http-5.1): bump http to 2.5.3 for 8.4.14 + +2006-09-12 Andreas Kupries + + * unix/configure.in (HAVE_MTSAFE_GETHOST*): Modified to recognize + HP-UX 11.00 and beyond as having mt-safe implementations of the + gethost functions. + * unix/configure: Regenerated, using autoconf 2.13 + + * unix/tclUnixCompat.c (PadBuffer): Fixed bug in calculation of the + increment needed to align the pointer, and added documentation + explaining why the macro is implemented as it is. + +2006-09-11 Andreas Kupries + + * tests/msgcat.test: Bumped version in auxiliary files as well. + * doc/msgcat.n: + +2006-09-11 Daniel Steffen + + * unix/tclUnixCompat.c: make compatLock static and only declare it + when it will actually be used; #ifdef parts of TSD that are not always + needed; adjust #ifdefs to cover all possible cases; fix whitespace. + +2006-09-10 Don Porter + + * library/msgcat/msgcat.tcl: Bump to version msgcat 1.3.4 to account + * library/msgcat/pkgIndex.tcl: for modifications. + +2006-09-10 Daniel Steffen + + * library/msgcat/msgcat.tcl (msgcat::Init): on Darwin, add fallback of + * tests/msgcat.test: default msgcat locale to + * unix/tclUnixInit.c (TclpSetVariables): current CFLocale + identifier if available (via private ::tcl::mac::locale global, set at + interp init when on Mac OS X 10.3 or later with CoreFoundation). + + * unix/tcl.m4: add caching to new SC_TCL_* macros for MT-safe wrappers + * unix/configure: autoconf-2.13 + +2006-09-08 Andreas Kupries + + * unix/tclUnixCompat.c: Fixed conditions for CopyArray/CopyString, and + CopyHostent. Also fixed bad var names in TclpGetHostByName. + +2006-09-08 Zoran Vasiljevic + + * unix/tclUnixCompat.c: Added fallback to gethostbyname() and + gethostbyaddr() if the implementation is known to be MT-safe + (currently for Darwin 6 or later only). + + * unix/configure.in: Assume gethostbyname() and gethostbyaddr() are + MT-safe starting with Darwin 6 (Mac OSX 10.2). + + * unix/configure: Regenerated with autoconf V2.13 + +2006-09-07 Zoran Vasiljevic + + * unix/tclUnixFCmd.c: Removed some false tests added (and left by + mistake) by fixing [Bug 999544] + + * unix/tclUnixCompat.c: Added fallback to MT-unsafe library calls if + TCL_THREADS is not defined. Fixed alignment of arrays copied by + CopyArrayi() to be on the sizeof(char *) boundary. + +2006-09-07 Andreas Kupries + + * unix/configure: Regenerated using autoconf 2.13. + +2006-09-07 Zoran Vasiljevic + + * unix/tclUnixChan.c Rewritten MT-safe wrappers to + * unix/tclUnixCompat.c return ptrs to TSD storage + * unix/tclUnixFCmd.c making them all look like their + * unix/tclUnixPort.h MT-unsafe pendants API-wise. + * unix/tclUnixSock.c + +2006-09-06 Zoran Vasiljevic + + * unix/tclUnixChan.c: Added TCL_THREADS ifdef'ed usage + * unix/tclUnixFCmd.c: of MT-safe calls like: + * unix/tclUnixSock.c: getpwuid, getpwnam, getgrgid, getgrnam, + * unix/tclUnixPort.h: gethostbyname and gethostbyaddr. + * unix/Makefile.in: See Tcl Bug: 999544 + * unix/configure.in: + * unix/tcl.m4: + * unix/configure: Regenerated. + + * unix/tclUnixCompat.c: New file containing MT-safe implementation of + some library calls. + +2006-09-04 Don Porter + + * tests/main.text (Tcl_Main-4.4): Test corrected to not be + timing sensitive to the Bug 1481986 fix. [Bug 1550858] + +2006-09-04 Jeff Hobbs + + * doc/package.n: correct package example + +2006-08-30 Jeff Hobbs + + * win/tclWinChan.c: [Bug 819667] Improve logic for identifying COM + ports. + + * win/tclWinFCmd.c: [Bug 1548263] Added test for NULL return + * generic/tclIOUtil.c: from Tcl_FSGetNormalizedPath which was + causing segv's + + * generic/tclFileName.c (TclDoGlob): match incr with existing decr. + + * unix/Makefile.in: add valgrindshell target and update default + VALGRINDARGS. User can override, or add to it with VALGRIND_OPTS env + var. + + * generic/tclBasic.c (Tcl_CreateInterp): init iPtr->threadId + + * generic/tclIOGT.c (ExecuteCallback): + * generic/tclPkg.c (Tcl_PkgRequireEx): replace Tcl_GlobalEval(Obj) + with more efficient Tcl_Eval(Obj)Ex + +2006-08-22 Andreas Kupries + + * unix/tclUnixNotfy.c (Tcl_WaitForEvent): Fixed broken if syntax + committed 2006-08-21 by Daniel. The broken syntax is visible to all + unix platforms, but not on OSX for machines which HAVE_COREFOUNDATION. + +2006-08-21 Don Porter + + * generic/tclIOUtil.c: Revisions to complete the thread finalization + of the cwdPathPtr. [Bug 1536142] + +2006-08-21 Daniel Steffen + + * macosx/tclMacOSXNotify.c (Tcl_WaitForEvent): if the run loop is + already running (e.g. if Tcl_WaitForEvent was called recursively), + re-run it in a custom run loop mode containing only the source for the + notifier thread, otherwise wakeups from other sources added to the + common run loop modes might get lost; sync panic msg changes from + HEAD. + + * unix/tclUnixNotfy.c (Tcl_WaitForEvent): 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 on that platform. [Bug 1457797] + + * unix/tclUnixPort.h (Darwin): override potentially faulty configure + detection of termios availability in all cases, since termios is known + to be present on all Mac OS X releases since 10.0. [Bug 497147] + +2006-08-18 Daniel Steffen + + * unix/tcl.m4 (Darwin): add support for --enable-64bit on x86_64, for + universal builds including x86_64, for 64-bit CoreFoundation on + Leopard and for use of -mmacosx-version-min instead of + MACOSX_DEPLOYMENT_TARGET. + * unix/configure: autoconf-2.13 + + * generic/tcl.h: add fixes for building on Leopard and support + * unix/tclUnixPort.h: for 64-bit CoreFoundation on Leopard. + + * unix/tclUnixPort.h: on Darwin x86_64, disable use of vfork as it + causes execve to fail intermittently. (rdar://4685553) + + * macosx/README: updates for x86_64 support and Xcode 2.4. + + * unix/tclUnixChan.c (TclUnixWaitForFile): with timeout < 0, if + select() returns early (e.g. due to a signal), call it again instead + of returning a timeout result. Fixes intermittent event-13.8 failures. + +2006-08-09 Don Porter + + * generic/tclEncoding.c: Replace buffer copy in for loop with + call to memcpy(). Thanks to afredd. [Patch 1530262] + +2006-08-03 Daniel Steffen + + * unix/tclUnixPipe.c (TclpCreateProcess): for USE_VFORK: ensure + standard channels are initialized before vfork() so that the child + doesn't potentially corrupt global state in the parent's address + space. + +2006-07-30 Kevin Kenny + + * tests/clock.test: Allowed UTC as a synonym for GMT in two tests that + indirectly invoke 'strftime' with the result of 'gmtime' to fix a + bogus test failure on FreeBSD systems. [Bug 1513489] + +2006-07-30 Joe English + + * doc/AppInit.3: Fix typo [Bug 1496886] + +2006-07-20 Daniel Steffen + + * macosx/tclMacOSXNotify.c (Tcl_InitNotifier, Tcl_WaitForEvent): + create notifier thread lazily upon first call to Tcl_WaitForEvent() + rather than in Tcl_InitNotifier(). Allows calling exeve() in processes + where the event loop has not yet been run (Darwin's execve() fails in + processes with more than one thread), in particular allows embedders + to call fork() followed by execve(), previously the pthread_atfork() + child handler's call to Tcl_InitNotifier() would immediately recreate + the notifier thread in the child after a fork. + + * macosx/tclMacOSXNotify.c (Tcl_InitNotifier): add support for + * unix/tclUnixFCmd.c (DoRenameFile, CopyFileAtts): weakly importing + * unix/tclUnixInit.c (TclpSetInitialEncodings): symbols not + available on OSX 10.2 or 10.3, enables binaires built on later OSX + versions to run on earlier ones. + * macosx/README: document how to enable weak-linking; cleanup. + * unix/tclUnixPort.h: add support for weak-linking; conditionalize + AvailabilityMacros.h inclusion; only disable realpath on 10.2 or + earlier when threads are enabled. + * unix/tclLoadDyld.c (TclpLoadMemoryGetBuffer): change runtime Darwin + * unix/tclUnixInit.c (TclpInitPlatform): release check to use + global initialized once + * unix/tclUnixFCmd.c (DoRenameFile, TclpObjNormalizePath): add runtime + Darwin release check to determine if realpath is threadsafe. + * unix/configure.in: add check on Darwin for compiler support of weak + * unix/tcl.m4: import and for AvailabilityMacros.h header; move + Darwin specific checks & defines that are only relevant to the tcl + build out of tcl.m4; restrict framework option to Darwin; cleanup + quoting. + * unix/configure: autoconf-2.13 + + * unix/tclLoadDyld.c (TclpLoadMemory): + * unix/tclUnixPipe.c (TclpCreateProcess): fix signed-with-unsigned + comparison and other warnings from gcc4 -Wextra. + +2006-07-13 Andreas Kupries + + * unix/tclUnixPort.h: Added the inclusion of . + The missing header caused the upcoming #if conditions to wrongly + exclude realpath, causing file normalize to ignore symbolic links in + the path. + +2006-07-11 Zoran Vasiljevic + + * generic/tclAsync.c: Made Tcl_AsyncDelete() more tolerant when called + after all thread TSD has been garbage-collected. + +2006-07-10 Jeff Hobbs + + * generic/tclIO.c (Tcl_CreateChannel): allow Tcl std channel + inheritance to be #defined out (default remains in). + +2006-06-15 Don Porter + + * changes: changes to start prep for an 8.4.14 release. + +2006-06-14 Daniel Steffen + + * unix/tclUnixPort.h (Darwin): support for MAC_OS_X_VERSION_MAX_ALLOWED + define from AvailabilityMacros.h: override configure detection and only + use API available in the indicated OS version or earlier. + +2006-06-14 Pat Thoyts + + * generic/regerror.c: Enable building Tcl with Microsoft's latest + * generic/tcl.h: compiler offering (VS2005). We have to handle + * generic/tclDate.c: a number of oddities as they have deprecated + * tests/env.test: most of the standard C library and now + * win/makefile.vc: generate manifest files to be linked into the + * win/nmakehlp.c: binaries. [Bug 1424909] + * win/rules.vc: + * win/tclWinTime.c: + +2006-06-13 Donal K. Fellows + + * unix/tclLoadDl.c (TclpDlopen): Workaround for a compiler bug in Sun + Forte 6. [Bug 1503729] + +2006-06-06 Don Porter + + * doc/GetStdChan.3: Added recommendation that each call to + Tcl_SetStdChannel() be accompanied by a call to Tcl_RegisterChannel(). + +2006-05-31 Jeff Hobbs + + * generic/tclNamesp.c (NamespaceInscopeCmd): revert [Bug 1400572] + fix of 2006-01-09 for [namespace inscope] as it seems to mess with + itcl scope decoding. Leaving namespace-29.6 test failure until final + cause it determined. + +2006-05-29 Jeff Hobbs + + * generic/tcl.h (Tcl_DecrRefCount): use if/else construct to allow + placement in unbraced outer if/else conditions. (jcw) + +2006-05-27 Daniel Steffen + + * macosx/tclMacOSXNotify.c: implemented pthread_atfork() handler that + * unix/tcl.m4 (Darwin): recreates CoreFoundation state and notifier + thread in the child after a fork(). Note that pthread_atfork() is + available starting with Tiger only. Because vfork() is used by the core + on Darwin, [exec]/[open] are not affected by this fix, only extensions + or embedders that call fork() directly (such as TclX). However, this + only makes fork() safe from corefoundation tcl with --disable-threads; + as on all platforms, forked children may deadlock in threaded tcl due + to the potential for stale locked mutexes in the child. [Patch 923072] + * unix/configure: autoconf-2.59 + +2006-05-24 Donal K. Fellows + + * unix/tcl.m4 (SC_CONFIG_SYSTEM): Fixed quoting of command script to + awk; it was a rarely used branch, but it was wrong. [Bug 1494160] + +2006-05-13 Don Porter + + * generic/tclFileName.c (TclDoGlob): Disabled the partial + normalization done by the recursive glob routine, since changing the + precise string of the pathname broke [glob] on some Tcl_Filesystems. + [Bug 943995] + + * generic/tclProc.c (ProcCompileProc): When a bump of the compile + epoch forces the re-compile of a proc body, take care not to + overwrite any Proc struct that may be referred to on the active + call stack. This fixes [Bug 1482718]. Note that the fix will not be + effective for code that calls the private routine TclProcCompileProc() + directly. + +2006-05-05 Don Porter + + * generic/tclMain.c (Tcl_Main): Corrected flaw that required + * tests/main.test: (Tcl_Main-4.5): processing of one interactive + command before passing control to the loop routine registered with + Tcl_SetMainLoop() [Bug 1481986] + +2006-05-04 Don Porter + + * README: Bump version number to 8.4.14 + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/configure.in: + * unix/tcl.spec: + * win/README.binary: + * win/configure.in: + + * unix/configure: autoconf-2.13 + * win/configure: + + * generic/tclExecute.c (ExprSrandFunc): Restore acceptance of wide + * tests/expr-old.test: integer values by srand() [Bug 1480509] + +2006-04-12 Don Porter + + *** 8.4.13 TAGGED FOR RELEASE *** + + * changes: updates for another RC. + +2006-04-11 Don Porter + + * generic/tclCmdMZ.c: Stop some interference between enter traces + * tests/trace.test: and enterstep traces. [Bug 1458266] + +2006-04-10 Don Porter + + * changes: updates for another RC. + +2006-04-06 Jeff Hobbs + + * generic/tclRegexp.c (FinalizeRegexp): full reset data to indicate + readiness for reinitialization. + +2006-04-06 Don Porter + + * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct): It seems there + * tests/indexObj.test: are extensions that rely on the prior behavior + * doc/GetIndex.3: that the empty string cannot succeed as a + unique prefix matcher, so I'm restoring Donal Fellows's solution. + Added mention of this detail to the documentation. [Bug 1464039] + +2006-04-06 Daniel Steffen + + * unix/tcl.m4: removed TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING + define on Darwin. [Bug 1457515] + * unix/configure: autoconf-2.13 + +2006-04-05 Don Porter + + * library/reg/pkgIndex.tcl: Long overlooked bump to registry + * win/tclWinReg.c: package version 1.1.4 (should have + been done for the Tcl 8.4.8 release!) + + * library/dde/pkgIndex.tcl: Long overlooked bump to dde package + * win/tclWinDde.c: version 1.2.4 (should have been done + for the Tcl 8.4.8 release!) + +2006-04-05 Donal K. Fellows + + * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct): Allow empty + strings to be matched by the Tcl_GetIndexFromObj machinery, in the + same manner as any other key. [Bug 1464039] + +2006-04-04 Don Porter + + * generic/tclPkg.c: Revised Bug 1162286 fix from 2005-11-08 to be + * tests/pkg.test: even more forgiving of package version + mismatch errors in [package ifneeded] commands, not even logging any + warning messages. This further reduces the + ***POTENTIAL INCOMPATIBILITY*** noted for that change. + +2006-04-03 Andreas Kupries + + * generic/tclIO.c (ReadChars): Added check, panic and commentary to a + piece of code which relies on BUFFER_PADDING to create enough space at + the beginning of each buffer for the insertion of partial multibyte + data at the beginning of a buffer. Commentary explains why this code + is OK, and the panic is as a precaution if someone twiddled the + BUFFER_PADDING into uselessness. + + * generic/tclIO.c (ReadChars): Temporarily suppress the use of + TCL_ENCODING_END set when EOF was reached while the buffer we are + converting is not truly the last buffer in the queue. Together with + the Utf bug below it was possible to completely wreck the buffer data + structures, eventually crashing Tcl. [Bug 1462248] + + * generic/tclEncoding.c (UtfToUtfProc): Stop accessing memory beyond + the end of the input buffer when TCL_ENCODING_END is set and the last + bytes of the buffer start a multi-byte sequence. This bug contributed + to [Bug 1462248]. + +2006-03-28 Jeff Hobbs + + * win/configure, win/tcl.m4: define MACHINE for gcc builds as well. + Needed by Tk for manifest generation. + + * win/tclWinConsole.c: revert 2005-11-03 [Patch 1256872] change to add + win32 unicode console support as it broke the ability to modify the + encoding to the console. + +2006-03-28 Daniel Steffen + + * unix/tclUnixFCmd.c (TclpObjNormalizePath): deal with *BSD/Darwin + realpath() converting relative paths into absolute paths. [Bug 1064247] + +2006-03-28 Vince Darley + + * generic/tclIOUtil.c: fix to nativeFilesystemRecord comparisons + (lesser part of [Bug 1064247]) + +2006-03-27 Pat Thoyts + + * win/tclWinTest.c: Fixes for [Bug 1456373] (mingw-gcc issue) + +2006-03-23 Don Porter + + * tests/expr.test: Nan self-inquality test silenced. [Bug 761471] + +2006-03-22 Don Porter + + * changes: updates for another RC. + +2006-03-18 Vince Darley + + * generic/tclTest.c: + * win/tclWinFile.c: + * win/tclWinTest.c: + * tests/fCmd.test: + * tests/winFCmd.test: + * tests/tcltest.test: Backport of [file writable] fixes for Windows + from HEAD. [Bug 1193497] + +2006-03-16 Andreas Kupries + + * doc/open.n: Documented the changed behaviour of 'a'ppend mode. + + * tests/io.test (io-43.1 io-44.[1234]): Rewritten to be + self-contained with regard to setup and cleanup. [Bug 681793] + + * generic/tclIOUtil.c (TclGetOpenMode): Added the flag O_APPEND to the + list of POSIX modes used when opening a file for 'a'ppend. This + enables the proper automatic seek-to-end-on-write by the OS. See [Bug + 680143] for longer discussion. + + * tests/ioCmd.test (iocmd-13.7.*): Extended the testsuite to check the + new handling of 'a'. + +2006-03-15 Andreas Kupries + + * tests/socket.test: Extended the timeout in socket-11.11 from 10 to + 40 seconds to allow for really slow machines. Also extended + actual/expected results with value of variable 'done' to make it + clearer when a test fails due to a timeout. [Bug 792159] + +2006-03-14 Andreas Kupries + + * generic/tclPipe.c (TclCreatePipeline): Modified the processing of + pipebars to fail if the last bar is followed only by redirections. + [Bug 768659] + +2006-03-14 Andreas Kupries + + * doc/fconfigure.n: Clarified that -translation is binary is reported + as lf when queried, because it is identical to lf, except for the + special additional behaviour when setting it. [Bug 666770] + +2006-03-14 Andreas Kupries + + * win/tclWinPipe.c (Tcl_WaitPid): Backport of fix made to the head by + David Gravereaux in 2004. See ChangeLog entry 2004-01-19. [Bug 1381436] + + Fixed a thread-safety problem with the process list. The delayed cut + operation after the wait was going stale by being outside the list + lock. It now cuts within the lock and does a locked splice for when it + needs to instead. [Bug 859820] + +2006-03-13 Don Porter + + * generic/tclEncoding.c: Report error when an escape encoding + is missing one of its sub-encodings [Bug 506653] + + * unix/configure.in: Revert change from 2005-07-26 that sometimes + * unix/configure: added $prefix/share to the tcl_pkgPath. + See [Patch 1231015]. autoconf-2.13. + +2006-03-10 Zoran Vasiljevic + + -- Summary of changes fixing [Bug 1437595] -- + + * generic/tclEvent.c: Cosmetic touches and identation + * generic/tclInt.h: Added TclpFinalizeSockets() call. + + * generic/tclIO.c: Calls TclpFinalizeSockets() as part of the + TclFinalizeIOSubsystem(). + + * unix/tclUnixSock: Added no-op TclpFinalizeSockets(). + + * mac/tclMacSock.c: + * win/tclWinPipe.c + * win/tclWinSock.c: Finalization of the sockets/pipes is now solely + done in TclpFinalizeSockets() and TclpFinalizePipes() and not over the + thread-exit handler, because the order of actions the Tcl generic core + will impose may result in cores/hangs if the thread exit handler tears + down corresponding subsystem(s) too early. + +2006-03-10 Vince Darley + + * win/tclWin32Dll.c: + * win/tclWinInt.h: + * win/tclWinFile.c: backported some fixes from HEAD relating to 'file + readable' and 'file writable', but main 'file writable' bug still + outstanding. + +2006-03-07 Don Porter + + * README: Bump version number to 8.4.13 and update + * changes: changes to start prep for an 8.4.13 release. + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/configure{.in}: + * unix/tcl.spec: + * win/README.binary: + * win/configure{.in}: + + * tests/parse.test: Missing constraint + +2006-03-06 Don Porter + + * generic/tclBasic.c: Revised handling of TCL_EVAL_* flags to + * tests/parse.test: simplify TclEvalObjvInternal and to correct + the auto-loading of alias targets (parse-8.12). [Bug 1444291] + +2006-03-02 Jeff Hobbs + + * win/Makefile.in: convert _NATIVE paths to use / to avoid ".\" + path-as-escape issue. + + * unix/tcl.m4, win/tcl.m4: []-quote ac_defun functions. + +2006-03-02 Pat Thoyts + + * unix/tcl.m4: Fix for [Tk Bug 1334613] to sort out shared library + * unix/configure: issues on NetBSD. Regenerated configure script. + +2006-02-28 Don Porter + + * generic/tclBasic.c: Corrections to be sure that TCL_EVAL_GLOBAL + * tests/parse.test: evaluations act the same as [uplevel #0] + * tests/trace.test: evaluations, even when execution traces or + invocations of [::unknown] are present. [Bug 1439836] + +2006-02-16 Don Porter + + * generic/tclIndexObj.c: Disallow the "ambiguous" error message + * tests/indexObj.test: when TCL_EXACT matching is requested. + +2006-02-15 Don Porter + + * generic/tclIO.c: Made several routines tolerant of + * generic/tclIOUtil.c: interp == NULL arguments. [Bug 1380662] + +2006-02-09 Don Porter + + * tests/main.test (Tcl_Main-6.7): Improved robustness of command + auto-completion test. [Bug 1422736] + +2006-01-25 Donal K. Fellows + + * unix/tclUnixInit.c (TclpInitPlatform): Improved conditions on when + to update the FP rounding mode on FreeBSD, taken from FreeBSD port. + +2006-01-23 Miguel Sofer + + * generic/tclStringObj.c (Tcl_GetRange): + * tests/stringTest (string-12.21):fixed incorrect handling of internal + rep in Tcl_GetRange. Thanks to twylite and Peter Spjuth. [Bug 1410553] + +2006-01-16 Reinhard Max + + * generic/tclPipe.c (FileForRedirect): Prevent nameString from being + freed without having been initialized. + * tests/exec.test: Added a test for the above. + +2006-01-12 Zoran Vasiljevic + + * generic/tclIOUtil.c (Tcl_FSGetInternalRep): fixed potential + overwriting of already freed memory which caused all kinds of (rare + but reproducible) coredumps all over the place. + +2006-01-11 Don Porter + + * tests/error.test (error-7.0): Test the timing of write traces on + ::errorInfo. [Bug 1397843] + +2006-01-10 Daniel Steffen + + * unix/configure: add caching, use AC_CACHE_CHECK instead of + * unix/configure.in: AC_CACHE_VAL where possible, consistent message + * unix/tcl.m4: quoting, sync relevant tclconfig/tcl.m4 and HEAD + changes and gratuitous formatting differences, fix SC_CONFIG_MANPAGES + with default argument, Darwin improvements to SC_LOAD_*CONFIG. + +2006-01-09 Don Porter + + * generic/tclNamesp.c (NamespaceInscopeCmd): [namespace inscope] + * tests/namespace.test: commands were not reported by [info level]. + [Bug 1400572] + +2005-12-20 Donal K. Fellows + + * generic/tclThreadAlloc.c (Tcl_GetMemoryInfo): Format values as longs + and not ints, so they are less likely to wrap on 64-bit machines. + +2005-12-19 Donal K. Fellows + + * doc/Tcl.n: Clarify what is going on in variable substitution + following thread on comp.lang.tcl. + +2005-12-14 Daniel Steffen + + * generic/tclIOUtil.c: workaround gcc warning "comparison is always + * generic/tclTest.c: false due to limited range of data type". + + * unix/configure.in: run check for fts API on all platforms, since + Linux glibc2 and *BSDs also have this and using fts is more efficient + than recursive opendir/readdir (sync with HEAD). + * unix/configure: regen. + +2005-12-12 Jeff Hobbs + + * unix/tcl.m4, unix/configure: Fix sh quoting error reported in + bash-3.1+ [Bug 1377619] (schafer) + +2005-12-12 Reinhard Max + + * generic/tclExecute.c (ExprAbsFunc): fixed the abs(MIN_INT) case so + that it doesn't break on compilers that don't assume integers to wrap + around (e.g. gcc-4.1.0). + +2005-12-09 Donal K. Fellows + + * tests/lsearch.test (lsearch-10.8..10): If the -start is off the end, + * generic/tclCmdIL.c (Tcl_LsearchObjCmd): searching should find + nothing at all. [Bug 1374778] + +2005-12-05 Daniel Steffen + + *** 8.4.12 TAGGED FOR RELEASE *** + + * unix/tclUnixPort.h (Darwin): fix incorrect __DARWIN_UNIX03 configure + overrides that were originally copied from Darwin CVS (rdar://3693001). + +2005-12-05 Don Porter + + * unix/configure.in: Revised fix for [Bug 1034337] from Daniel + * unix/tclUnixFCmd.c: Steffen. Uses fts_*() routines. + * unix/configure: autoconf-2.13 + * changes: Update changes for 8.4.12 release + +2005-12-04 Daniel Steffen + + * README: refer to macosx/README instead of mac/README. + * mac/README: add note that mac classic port is no longer supported. + +2005-12-03 Jeff Hobbs + + * README: correct 2 urls + +2005-12-01 Don Porter + + * changes: Update changes for 8.4.12 release + +2005-12-01 Daniel Steffen + + * unix/tcl.m4 (Darwin): fixed error when MACOSX_DEPLOYMENT_TARGET unset + * unix/configure: regen. + +2005-11-29 Jeff Hobbs + + * win/tcl.m4: Add build support for Windows-x64 builds. + * win/configure: --enable-64bit now accepts =amd64|ia64 for + * win/Makefile.in: Windows 64-bit build variants (default: amd64) + * win/makefile.vc: [Bug 1369597] + +2005-11-29 Donal K. Fellows + + * generic/tclObj.c (Tcl_GetWideIntFromObj): Add more efficient + conversion to wides from normal ints. [Bug 1310081] + + * generic/tclCmdIL.c (Tcl_LsearchObjCmd): Allow [lsearch -regexp] to + process REs that contain backreferences. This expensive mode of + operation is only used if the RE would otherwise cause a compilation + failure. [Bug 1366683] + +2005-11-28 Donal K. Fellows + + * win/tclWinSock.c (CreateSocket): Applied [Patch 1353853] to prevent + reads of uninitialized variables during cleanup. + +2005-11-27 Daniel Steffen + + * unix/tcl.m4 (Darwin): add 64bit support, check for Tiger copyfile(), + add CFLAGS to SHLIB_LD to support passing -isysroot in env(CFLAGS) to + configure (flag can't be present twice, so can't be in both CFLAGS and + LDFLAGS during configure), don't use -prebind when deploying on 10.4, + define TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING (rdar://3171542). + (SC_ENABLE_LANGINFO, SC_TIME_HANDLER): add/fix caching, fix obsolete + autoconf macros. Sync with tk/unix/tcl.m4, sync whitespace with HEAD. + + * unix/configure.in: fix obsolete autoconf macros, sync gratuitous + formatting/ordering differences with tk/unix/configure.in. + + * unix/Makefile.in: add CFLAGS to tclsh/tcltest link to make + executable linking the same as during configure (needed to avoid + loosing any linker relevant flags in CFLAGS, in particular flags that + can't be in LDFLAGS). Avoid concurrent linking of tclsh and compiling + of tclTestInit.o or xtTestInit.o during parallel make. + (checkstubs, checkdoc, checkexports): dependency and Darwin fixes + + * unix/tclLoadDyld.c (TclpDlopen): [Bug 1204237] use + NSADDIMAGE_OPTION_WITH_SEARCHING on second NSAddImage only. + (TclGuessPackageName): should not be MODULE_SCOPE. + (TclpLoadMemory): ppc64 and endian (i386) fixes, add support for + loading universal (fat) bundles from memory. + + * unix/tclUnixPort.h: + * unix/tclUnixFCmd.c: add support for new Tiger copyfile() API to + enable copying of xattrs & ACLs by [file copy]. + + * generic/tcl.h: add Darwin specifc configure overrides for TCL_WIDE + defines to support fat compiles of ppc and ppc64 at the same time, + (replaces Darwin CVS fix by emoy, rdar://3693001). + add/correct location of version numbers in macosx files. + + * generic/tclInt.h: clarify fat compile comment. + + * unix/tclUnixPort.h: add Darwin specifc configure overrides to + support fat compiles, where configure runs only once for multiple + architectures (replaces Darwin CVS fix by emoy, rdar://3693001). + + * macosx/tclMacOSXBundle.c: + * macosx/tclMacOSXNotify.c: + * unix/tclUnixNotfy.c: fix #include order to support compile time + * unix/tclUnixPort.h: override of HAVE_COREFOUNDATION in + tclUnixPort.h when building for ppc64 + + * macosx/Tcl.pbproj/default.pbxuser (new file): + * macosx/Tcl.pbproj/jingham.pbxuser: + * macosx/Tcl.pbproj/project.pbxproj: sync with HEAD. + + * macosx/README: clarification/cleanup, sync with HEAD, document + universal (fat) builds via CFLAGS (i.e. all of ppc ppc64 i386 at once). + + * macosx/Makefile: add support for reusing configure cache, build + target fixes, remove GENERIC_FLAGS override now handled by tcl.m4. + + * generic/tclIOUtil.c: + * generic/tclRegexp.c: + * generic/tclVar.c: declare globals used only in own file as static + (sync with HEAD). + + * generic/rege_dfa.c (getvacant): + * generic/regexec.c (cfind): + * generic/tclCompExpr.c (CompileSubExpr): + * unix/tclUnixChan.c (TclUnixWaitForFile): initialise variables to + silence gcc 4 warnings. + + * generic/regguts.h: only #define NDEBUG if not already #defined. + + * macosx/tclMacOSXNotify.c: sync whitespace & comments with HEAD + + * unix/configure: regen. + +2005-11-20 Joe English + + * generic/tclStubLib.c: Don't set tclStubsPtr to 0 when + Tcl_PkgRequireEx() fails [Fix for [Bug 1091431] "Tcl_InitStubs failure + crashes wish"] + +2005-11-18 Miguel Sofer + + * tests/trace.test (trace-34.5): [Bug 1047286], added a second test + illustrating the role of "ns in callStack" in the ns's visibility + during deletion traces. + + * generic/tclBasic.c (Tcl_DeleteCommandFromToken): + * generic/tclCmdMZ.c (TraceCommandProc): + * generic/tclInt.h (NS_KILLED): + * generic/tclNamesp.c (Tcl_DeleteNamespace + * tests/namespace.test (namespace-7.3-6): + * tests/trace.test (trace-20.13-16): fix [Bugs 1355942/1355342]. + +2005-11-18 Jeff Hobbs + + * generic/tclIO.c (TclFinalizeIOSubsystem): preserve statePtr until we + netrieve next statePtr from it. + +2005-11-18 Don Porter + + * generic/tclPkg.c: Revised Bug 1162286 fix from 2005-11-08 to be + * tests/pkg.test: more forgiving of package version mismatch + errors in [package ifneeded] commands. This reduces the + ***POTENTIAL INCOMPATIBILITY*** noted for that change. + +2005-11-18 Andreas Kupries + + * generic/tclIO.c (TclFinalizeIOSubsystem): Applied Pat Thoyts' patch + for [Bug 1359094]. This moves the retrieval of the next channel state + to the end of the loop, as the called closeproc may close other + channels, i.e., modify the list we are iterating, invalidating any + pointer retrieved earlier. + +2005-11-18 Donal K. Fellows + + * library/http/http.tcl (http::geturl): Improved syntactic validation + of URLs, and better error messages in some cases. [Bug 1358369] + +2005-11-16 Don Porter + + * README: Bump version number to 8.4.12 + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/configure.in: + * unix/tcl.spec: + * win/README.binary: + * win/configure.in: + + * unix/configure: autoconf-2.13 + * win/configure: + +2005-11-15 Don Porter + + * changes: Update changes for 8.4.12 release + +2005-11-15 Kevin B. Kenny + + * tests/cmdAH.test: Backported the fix for [Bug 926016] because of + * win/tclWinFile.c: a repeated bug report in 8.4 [Bug 1353840]. + Windows [file mtime] will now return seconds from the Posix epoch + correctly (except for FAT32 file systems after a DST change without a + reboot - for which there is no help). A side effect is that file times + will appear different in Tcl from the way they do in Windows Explorer + or a 'dir' listing, because the Microsoft tools get the DST state + wrong in the listings. + +2005-11-09 Kevin B. Kenny + + * generic/tclTimer.c: Changed [after] so that it behaves correctly + * tests/timer.test: with negative arguments. [Bug 1350293] + +2005-11-08 Jeff Hobbs + + * unix/tclUnixFCmd.c (MAX_READDIR_UNLINK_THRESHOLD): reduce to 130 + based on errors seen on OS X 10.3 with lots of links in a dir. [Bug + 1034337 followup] + +2005-11-08 Don Porter + + * tests/expr.test: Portable tests expr-46.13-18 [Bug 1341368] + + * generic/tclPkg.c: Corrected inconsistencies in the value returned + * tests/pkg.test: by Tcl_PkgRequire(Ex) so that the returned + values will always agree with what is stored in the package database. + This way repeated calls to Tcl_PkgRequire(Ex) have the same results. + Thanks to Hemang Lavana. [Bug 1162286] + ***POTENTIAL INCOMPATIBILITY***: Incompatible with those existing + packages that are accustomed to the [package] command forgiving + their bugs. + + * tests/namespace.test (25.7,8): Backport test of knownBug. + +2005-11-08 Donal K. Fellows + + * generic/tclCmdMZ.c (TclTraceVariableObjCmd, TraceVarProc): Applied + Miguel's fix for [Bug 1348775]. It is not quite as elegant as the one + applied to the HEAD, but it is easier to use it rather than fully + backporting. + +2005-11-07 Miguel Sofer + + * tests/trace.test (trace-13.2-4): added tests to detect leak, see + [Bug 1348775]. + +2005-11-04 Don Porter + + * unix/tcl.m4: Added code to enable [load] on LynxOS. Thanks to + heidibr@users.sf.net for the patch. [Bug 1163896] + + * unix/configure: autoconf-2.13. + +2005-11-04 Pat Thoyts + + * win/tclWinPipe.c: Applied [Patch 1267871] by Matt Newman which + * win/tclWinPort.h: provides extended error code support. + * tests/exec.test: Wrote some tests for this feature. + +2005-11-04 Kevin Kenny + + * generic/tclGetDate.y: Added abbreviations for the Korean timezone. + * generic/tclDate.c: Regenerated. + + * compat/strftime.c: Fixed a problem where the name of the time zone + was double-converted from system encoding to UTF-8. Thanks to the + anonymous submitter of [Bug 1317477] for the report and the patch. + +2005-11-04 Miguel Sofer + + * generic/tclInt.h: + * generic/tclNamesp.c: + * generic/tclVar.c: fix for [Bugs 1338280/1337229]. Thanks Don. + + * tests/trace.test: fix duplicate test numbers + +2005-11-03 Don Porter + + * generic/tclUnixInit.c (TclpSetInitialEncodings): Modified so + that multiple calls can continue to atttempt to properly set the + system encoding. Needed for Tclkit to properly support non-default + encodings. Thanks to Yaroslav Schekin. [Bug 1201171] + +2005-11-03 Pat Thoyts + + * win/tclWin32Dll.c: Backported Anton Kovalenko's [Patch 1256872] + * win/tclWinConsole.c: to give unicode console support on + * win/tclWinInt.h: suitable systems (eg: NT/XP) + +2005-11-01 Don Porter + + * generic/tclCmdMZ.c (TclCheckExecutionTraces): Corrected mistaken + assumption that all command traces are set at the script level. + Report/fix from Jacques H. de Villiers. [Bug 1337941] + + * tests/expr-old.test (expr-32.52): Use int(.) to restrict result + of left shift to the C long range. + +2005-10-29 Mo DeJong + + * tests/expr.test: Fix problems in new round() tests that lead to + correct result only on 32 bit long systems. [Bug 1341368] + +2005-10-29 Miguel Sofer + + * generic/tclCmdMZ.c (TraceVarProc): [Bug 1337229], partial fix. + Ensure that a second call with TCL_TRACE_DESTROYED does not lead to a + second call to Tcl_EventuallyFree(). It is still true that that second + call should not happen, so the bug is not completely fixed. + * tests/trace.test (test-18.3-4): added tests for [Bugs 1337229 and + 1338280]. + +2005-10-27 Mo DeJong + + * generic/tclExecute.c (ExprRoundFunc): Fix typo where number before + rounding is compared with smallest integer instead of number after + rounding. This fix does not change the results of any tests. + * tests/expr.test: Add round() tests for cases near the min and max + int values. + * tests/util.test: Remove pointless warning code about testobj command + +2005-10-23 Miguel Sofer + + * generic/tclBasic.c: + * generic/tclBinary.c: + * generic/tclCmdAH.c: + * generic/tclCmdIL.c: + * generic/tclCmdMZ.c: + * generic/tclExecute.c: + * generic/tclLink.c: + * generic/tclMain.c: + * generic/tclProc.c: + * generic/tclScan.c: + * generic/tclTest.c: + * generic/tclVar.c: + * mac/tclMacInit.c: + * unix/tclUnixInit.c: + * win/tclWinInit.c: Ensure that the core never calls TclPtrSetVar, + Tcl_SetVar2Ex, Tcl_ObjSetVar2 or Tcl_SetObjErrorCode with a 0-ref new + value. It is not possible to handle error returns correctly in that + case [Bug 1334947], one has the choice of leaking the object in some + cases, or else risk crashing in some others. + +2005-10-22 Miguel Sofer + + * generic/tclExecute.c (INST_CONCAT): disable the optimisation for + wide integers. [Bug 1251791] + +2005-10-14 Zoran Vasiljevic + + * generic/tclIO.c (Tcl_ClearChannelHandlers): removed change dated + 2005-10-04 below. Look into [Bug 1323992] for detailed discussion. + +2005-10-13 Donal K. Fellows + + * generic/tclCmdAH.c (Tcl_FormatObjCmd): Stop [format] from seeing + the difference between ints and wides. [Bug 1284178] + +2005-10-13 Zoran Vasiljevic + + * generic/tclIO.c (Tcl_ClearChannelHandlers): temporary + ifdef TCL_THREADS changes done to de-activate pending + event processing when channel is being closed/cutted. + +2005-10-10 Jeff Hobbs + + * generic/tclInt.h: ensure MODULE_SCOPE decl + +2005-10-07 Jeff Hobbs + + * unix/tclUnixFCmd.c (TraverseUnixTree): Adjust 2004-11-11 change to + * tests/fCmd.test (fCmd-20.2): account for NFS special + files with a readdir rewind threshold. [Bug 1034337] + +2005-10-05 Andreas Kupries + + * generic/tclPipe.c (TclCreatePipeline): Fixed [Bug 1109294]. Applied + the patch provided by David Gravereaux. + + * doc/CrtChannel.3: Fixed [Bug 1104682], by application of David + Welton's patch for it, and added a note about wideSeekProc. + +2005-10-05 Jeff Hobbs + + * tests/env.test (env-6.1): + * win/tclWinPort.h: define USE_PUTENV_FOR_UNSET 1 + * generic/tclEnv.c (TclSetEnv, TclUnsetEnv): add + USE_PUTENV_FOR_UNSET to existing USE_PUTENV define to account for + various systems that have putenv(), but can't unset env vars with it. + Note difference between Windows and Linux for actually unsetting the + env var (use of '='). + Correct the resizing of the environ array. We assume that we are in + full ownership, but that's not correct. [Bug 979640] + +2005-10-04 Jeff Hobbs + + * win/tclWinSerial.c (SerialSetOptionProc): free argv [Bug 1067708] + + * tests/http.test: Do not URI encode -._~ according to + * library/http/http.tcl (init): RFC3986. [Bug 1182373] (aho) + + * generic/tclIOUtil.c (TclFSNormalizeAbsolutePath): make static + * generic/tclEncoding.c (TclFindEncodings): make static + + * unix/tclLoadShl.c (TclpDlopen): use DYNAMIC_PATH on second + shl_load only. [Bug 1204237] + +2005-10-04 Zoran Vasiljevic + + * generic/tclIO.c (Tcl_ClearChannelHandlers): now deletes any + outstanding timer for the channel. Also, prevents events still + in the event queue from triggering on the current channel. + + * generic/tclTimer.c (Tcl_DeleteTimerHandler): bail out early + if passed NULL argument. + +2005-09-30 Don Porter + + * generic/tclMain.c: Separate encoding conversion of command line + arguments from list formatting. [Bug 1306162] + +2005-09-27 Donal K. Fellows + + * generic/tclBinary.c (FormatNumber): Factorize out copying of double + values to a helper to work around ugly broken compiler problems. [Bug + 1116542] + +2005-09-15 Miguel Sofer + + * doc/ParseCmd.3: copy/paste fix [Bug 1292427] + +2005-09-15 Donal K. Fellows + + * unix/tcl.m4 (SC_TCL_EARLY_FLAGS): Added extra hack to allow Tcl to + transparently open large files on RHEL 3. [Bug 1287638] + + * unix/configure: autoconf-2.13 + +2005-09-07 Don Porter + + * generic/tclUtf.c (Tcl_UniCharToUtf): Corrected handling of negative + * tests/utf.test (utf-1.5): Tcl_UniChar input value. Incorrect + handling was producing byte sequences outside of Tcl's legal internal + encoding. [Bug 1283976] + +2005-08-29 Kevin Kenny + + * generic/tclBasic.c (ExprMathFunc): Restored "round away from zero" + * tests/expr.test (expr-46.*): behaviour to the "round" + function. Added test cases for the behavior, including the awkward + case of a number whose fractional part is 1/2-1/2ulp. [Bug 1275043] + +2005-08-25 Donal K. Fellows + + * generic/tclListObj.c (UpdateStringOfList): Stop uncontrolled and + unsafe crashes from happening when working with very large string + representations. [Bug 1267380] + +2005-08-17 Jeff Hobbs + + * generic/tclFCmd.c (TclFileMakeDirsCmd): fix to race condition in + file mkdir (backport from head 2005-06-13) [Bug 1217375] + +2005-08-16 Kevin Kenny + + * generic/tclEvent.c (Tcl_Finalize): Pushed Tcl_FinalizeLoad and + Tcl_ResetFilesystem down after Tcl_FinalizeThreadAlloc because + unloading DLLs can't happen while they still own TSD keys. + (This is a backport of changes made in the HEAD on 2005-08-10.) + +2005-08-05 Donal K. Fellows + + * unix/tclUnixInit.c (localeTable): Solaris uses a non-standard name + for the cp1251 charset. Thanks to Victor Wagner for reporting this. + [Bug 1252475] + +2005-08-05 Kevin Kenny + + * generic/tclExecute.c (TclExecuteByteCode): Fixed a corner case + * tests/expr.test (expr-38.1): where applying abs to + MIN_INT failed to promote the result to a wide integer. [Bug 1241572] + +2005-08-04 Don Porter + + * generic/tclObj.c: Simplified routines that manage the typeTable. + +2005-08-03 Don Porter + + * generic/tclCompExpr.c: Untangled some dependencies in the + * generic/tclEvent.c: order of finalization routines. + * generic/tclInt.h: [Bug 1251399] + * generic/tclObj.c: + +2005-07-30 Daniel Steffen + + * unix/configure, unix/tcl.m4: revert 2005-07-28 change. + + * unix/tclLoadDyld.c (TclpDlopen, TclpLoadMemory): workarounds for + bugs/changes in behaviour in Mac OS X 10.4 Tiger, sync formatting + changes from HEAD. + +2005-07-29 Donal K. Fellows + + * generic/tclCmdIL.c (InfoGlobalsCmd): Even in high-speed mode, still + have to take care with non-existant variables. [Bug 1247135] + +2005-07-28 Mo DeJong + + * win/README: Update link to msys_mingw8.zip. Remove old Cygwin + + Mingw info, people should just build with the msys + mingw + configuration. + +2005-07-28 Jeff Hobbs + + * unix/configure, unix/tcl.m4: defined TCL_LOAD_FROM_MEMORY on Darwin + only for SHARED_BUILD + +2005-07-28 Donal K. Fellows + + * generic/tclPipe.c (TclCreatePipeline): Arrange for POSIX systems to + * unix/tclUnixPipe.c (TclpOpenFile): use the O_APPEND flag for + * tests/exec.test (exec-19.1): files opened in a pipeline + like ">>this". Note that Windows cannot support such access; there is + no equivalent flag on the handle that can be set at the kernel-call + level. The test is unix-specific in every way. [Bug 1245953] + +2005-07-26 Mo DeJong + + * unix/configure: Regen. + * unix/configure.in: Check for a $prefix/share directory and add it + the the package if found. This will check for Tcl packages in + /usr/local/share when Tcl is configured with the default dist install. + [Patch 1231015] + +2005-07-26 Don Porter + + * doc/tclvars.n: Improved $errorCode documentation. [RFE 776921] + + * generic/tclBasic.c (Tcl_CallWhenDeleted): Converted to use + per-thread counter, rather than a process global one that required + mutex protection. [RFE 1077194] + + * generic/tclNamesp.c (TclTeardownNamespace): Re-ordering so that + * tests/trace.test (trace-34.4): command delete traces fire + while the command still exists. [Bug 1047286] + +2005-07-24 Mo DeJong + + * unix/tcl.m4 (SC_PROG_TCLSH, SC_BUILD_TCLSH): + * win/tcl.m4 (SC_PROG_TCLSH, SC_BUILD_TCLSH): + Split confused search for tclsh on PATH and build and install + locations into two macros. SC_PROG_TCLSH searches just the PATH. + SC_BUILD_TCLSH determines the name of the tclsh executable in the Tcl + build directory. [Bug 1160114], [Patch 1244153] + +2005-07-22 Don Porter + + * library/auto.tcl: Updates to the Tcl script library to make + * library/history.tcl: use of Tcl 8.4 feautures. Thanks to + * library/init.tcl: Patrick Fradin for prompting on this. + * library/package.tcl: [Patch 1237755] + * library/safe.tcl: + * library/word.tcl: + +2005-07-07 Jeff Hobbs + + * unix/tcl.m4, unix/configure: Backported [Bug 1095909], removing + * unix/tclUnixPort.h: any use of readdir_r as it is not + * unix/tclUnixThrd.c: necessary and just confuses things. + +2005-07-05 Don Porter + + * generic/tclCmdAH.c: New "encoding" Tcl_ObjType (not registered) + * generic/tclEncoding.c: that permits longer lifetimes of the + * generic/tclInt.h: Tcl_Encoding values kept as intreps of + Tcl_Obj's. Reduces the need for repeated reading of encoding + definition files from the filesystem. [Bug 1077262] + + * generic/tclNamesp.c: Allow for [namespace import] of a command + * tests/namespace.test: over a previous [namespace import] of itself + without throwing an error. [RFE 1230597] + +2005-07-01 Zoran Vasiljevic + + * unix/tclUnixNotfy.c: protect against spurious wake-ups while waiting + on the condition variable when tearing down the notifier thread. [Bug + 1222872] + +2005-06-27 Don Porter + + *** 8.4.11 TAGGED FOR RELEASE *** + + * library/auto.tcl: Reverted to Revision 1.12.2.3 (Tcl 8.4.9). + Restores the (buggy) behavior of [auto_reset] that fails to clear + away auto-loaded commands from non-global namespaces. Fixing this + bug exposed an unknown number of buggy files out there (including at + least portions of the Tk script library) that cannot tolerate double + [source]-ing. The burden of fixing these exposed bugs will not be + forced on package/extension/application authors until Tcl 8.5. + +2005-06-24 Kevin Kenny + + * generic/tclEvent.c (Tcl_Finalize): + * generic/tclInt.h: + * generic/tclPreserve.c (TclFinalizePreserve): Changed the + finalization logic so that Tcl_Preserve finalizes after exit + handlers run; a lot of code called from Tk's exit handlers + presumes tha Tcl_Preserve will still work even from an exit + handler. Also, made the assertion check that no exit handlers + are created in Tcl_Finalize conditional on TCL_MEM_DEBUG to + avoid spurious panics in the "stable" release. + +2005-06-24 Don Porter + + * library/auto.tcl: Make file safe to re-[source] without + destroying registered auto_mkindex_parser hooks. + +2005-06-23 Daniel Steffen + + * tools/tcltk-man2html.tcl: fixed useversion glob pattern to accept + multi-digit patchlevels. + +2005-06-23 Kevin Kenny + + * win/tclWinChan.c: More rewriting of __asm__ blocks that + * win/tclWinFCmd.c: implement SEH in GCC, because mingw's + gcc 3.4.2 is not as forgiving of violations committed by + the old code and caused panics. [Bug 1225957] + +2005-06-23 Daniel Steffen + + * unix/Makefile.in (install-private-headers): rewrite tclPort.h when + installing private headers to remove ../unix relative #include path to + tclUnixPort.h (which is incorrect at the installed location). + +2005-06-22 Kevin Kenny + + * generic/tclInt.h: Changed the finalization + * generic/tclEvent.c (Tcl_Finalize): logic to defer the + * generic/tclIO.c (TclFinalizeIOSubsystem): shutdown of the pipe + * unix/tclUnixPipe.c (TclFinalizePipes): management until after + * win/tclWinPipe.c (TclFinalizePipes): all channels have been + closed, in order to avoid a situation where the Windows + PipeCloseProc2 would re-establish the exit handler after exit + handlers had already run, corrupting the heap. [Bug 1225727] + Corrected a read of uninitialized memory in PipeCloseProc2, which (at + least on certain configurations) caused a great number of tests to + either fail or hang. [Bug 1225044] + +2005-06-22 Andreas Kupries + + * generic/tclInt.h: Followup to change made on 2005-06-18 by Daniel + Steffen. There are compilers (*) who error out on the redefinition of + WORDS_BIGENDIAN. We have to undef the previous definition (on the + command line) first to make this acceptable. (*): AIX native. + +2005-06-22 Don Porter + + * win/tclWinFile.c: Potential buffer overflow. [Bug 1225571] + Thanks to Pat Thoyts for discovery and fix. + + * tests/safe.test: Backport performance improvement from + reduced $::auto_path. + +2005-06-21 Pat Thoyts + + * tests/winDde.test: Added some waits to the dde server script to + let event processing run after we create the dde server and before + we exit the server process. This avoids 'server did not respond' + errors. + +2005-06-21 Kevin Kenny + + * generic/tclFileName.c: Corrected a problem where a directory name + containing a colon can crash the process on Windows [Bug 1194458] + * tests/fileName.test: Added test for [file split] and [file join] + with a name containing a colon. + * win/tclWinPipe.c: Reverted davygrvy's changes of 2005-04-19; + they cause multiple failures in io.test. [Bug 1225044, still open] + +2005-06-21 Don Porter + + * generic/tclBasic.c: Made the walk of the active trace list aware + * generic/tclCmdMZ.c: of the direction of trace scanning, so the + * generic/tclInt.h: proper correction can be made. [Bug 1224585] + * tests/trace.test (trace-34.2,3): + + * generic/tclBasic.c (Tcl_DeleteTrace): Added missing walk of the + * tests/trace.test (trace-34.1): list of active traces to + cleanup references to traces being deleted. [Bug 1201035] + +2005-06-20 Don Porter + + * doc/FileSystem.3: added missing Tcl_GlobTypeData documentation [Bug + 935853] + +2005-06-18 Daniel Steffen + + * generic/tclInt.h: ensure WORDS_BIGENDIAN is defined correctly with + fat compiles on Darwin (i.e. ppc and i386 at the same time), the + configure AC_C_BIGENDIAN check is not sufficient in this case because + a single run of the compiler builds for two architectures with + different endianness. + + * unix/tcl.m4 (Darwin): add -headerpad_max_install_names to LDFLAGS to + ensure we can always relocate binaries with install_name_tool. + + * unix/configure: autoconf-2.13 + +2005-06-18 Don Porter + + * changes: Update changes for 8.4.11 release + + * README: Bump version number to 8.4.11 + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/configure.in: + * unix/tcl.spec: + * win/README.binary: + * win/configure.in: + + * unix/configure: autoconf + * win/configure: + +2005-06-18 Donal K. Fellows + + * generic/tclCmdAH.c (Tcl_FormatObjCmd): Fix for [Bug 1154163]; only + * tests/format.test: insert 'l' modifier when it is needed. + +2005-06-07 Donal K. Fellows + + * unix/tclUnixNotfy.c (Tcl_FinalizeNotifier): Add dummy variable + so threaded build compiles. + +2005-06-06 Kevin B. Kenny + + * win/tclWin32Dll.c: Corrected another buglet in the assembly code for + stack probing on Win32/gcc. [Bug 1213678] + +2005-06-03 Daniel Steffen + + *** 8.4.10 TAGGED FOR RELEASE *** + + * unix/tclLoadDyld.c: fixed header conflict when building this file + with USE_TCL_STUBS. + + * macosx/Makefile: fixed 'embedded' target. + +2005-06-02 Jeff Hobbs + + * unix/Makefile.in (html): add BUILD_HTML_FLAGS optional var + * tools/tcltk-man2html.tcl: add a --useversion to prevent + confusion when multiple Tcl source dirs exist. + + * changes: updated for 8.4.10 release (porter) + +2005-05-31 Zoran Vasiljevic + + * unix/tclUnixNotfy.c: the notifier thread is now created as + joinable thread and it is properly joined in Tcl_FinalizeNotifier. + This is an attempt to fix [Bug 1082283] + +2005-05-29 Jeff Hobbs + + * win/tclWinThrd.c (TclpFinalizeThreadData): move tlsKey defn + to top of file and clarify name (was 'key'). [Bug 1204064] + +2005-05-27 Jeff Hobbs + + * README: Bumped patchlevel to 8.4.10 + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/tcl.spec, unix/configure, unix/configure.in: + * win/configure, win/configure.in: + +2005-05-26 Daniel Steffen + + * macosx/Makefile: moved & corrected EMBEDDED_BUILD check. + + * unix/configure.in: corrected framework finalization to softlink + stub library to Versions/8.x subdir instead of Versions/Current. + * unix/configure: autoconf-2.13 + +2005-05-25 Jeff Hobbs + + * generic/tclCmdMZ.c (Tcl_TimeObjCmd): add necessary cast + + * unix/configure, unix/configure.in: ensure false Tcl.framework is + only created with --enable-framework + +2005-05-24 Daniel Steffen + + * tests/env.test: added DYLD_FRAMEWORK_PATH to the list of env vars + that need to be handled specially. + + * macosx/Makefile: + * macosx/README: + * macosx/Tcl-Info.plist.in (new file): + * unix/Makefile.in: + * unix/configure.in: + * unix/tcl.m4: + * unix/tclUnixInit.c: moved all Darwin framework build support from + macosx/Makefile into the standard unix configure/make buildsystem, the + macosx/Makefile is no longer required to build Tcl.framework (but its + functionality is still available for backwards compatibility). + * unix/configure: autoconf-2.13 + + * generic/tclIOUtil.c (TclLoadFile): + * generic/tclInt.h: + * unix/tcl.m4: + * unix/tclLoadDyld.c: added support for [load]ing .bundle binaries in + addition to .dylib's: .bundle's can be [unload]ed (unlike .dylib's), + and can be [load]ed from memory, e.g. directly from VFS without + needing to be written out to a temporary location first. [Bug 1202209] + * unix/configure: autoconf-2.13 + + * generic/tclCmdMZ.c (Tcl_TimeObjCmd): change [time] called with a + count > 1 to return a string with a float value instead of a rounded + off integer. [Bug 1202178] + +2005-05-20 Zoran Vasiljevic + + * generic/tclParseExpr.c: removed unreferenced stack variable "errMsg" + probably included by fixing [Bug 1201589] (see below). + +2005-05-20 Don Porter + + * generic/tclParseExpr.c: Corrected parser to recognize all + boolean literals accepted by Tcl_GetBoolean, including prefixes like + "y" and "f", and to allow "eq" and "ne" as function names in the + proper context. [Bug 1201589] + +2005-05-19 Daniel Steffen + + * macosx/tclMacOSXNotify.c (Tcl_InitNotifier): fixed crashing + CFRelease of runLoopSource in Tcl_InitNotifier (reported by Zoran): + CFRunLoopAddSource doesn't CFRetain, so can only CFRelease the + runLoopSource in Tcl_FinalizeNotifier. + +2005-05-14 Daniel Steffen + + * macosx/tclMacOSXBundle.c: + * unix/tclUnixInit.c: + * unix/tcl.m4 (Darwin): made use of CoreFoundation API configurable + and added test of CoreFoundation availablility to allow building on + ppc64, replaced HAVE_CFBUNDLE by HAVE_COREFOUNDATION; test for + availability of Tiger or later OSSpinLockLock API. + + * unix/tclUnixNotfy.c: + * unix/Makefile.in: + * macosx/tclMacOSXNotify.c (new file): when CoreFoundation is + available, use new CFRunLoop based notifier: allows easy integration + with other event loops on Mac OS X, in particular the TkAqua Carbon + event loop is now integrated via a standard tcl event source (instead + of TkAqua upon loading having to finalize the exsting notifier and + replace it with its custom version). [Patch 1202052] + + * tests/unixNotfy.test: don't run unthreaded tests on Darwin since + notifier may be using threads even in unthreaded core. + + * unix/tclUnixPort.h: + * unix/tcl.m4 (Darwin): test for thread-unsafe realpath durning + configure, as Darwin 7 and later realpath is threadsafe. + + * macosx/tclMacOSXBundle.c: + * unix/tclLoadDyld.c: + * unix/tclUnixInit.c: fixed gcc 4.0 warnings. + + * unix/configure: autoconf-2.13 + +2005-05-10 Jeff Hobbs + + * tests/string.test: string-10.[21-30] + * generic/tclCmdMZ.c (Tcl_StringObjCmd): add extra checks to + prevent possible UMR in unichar cmp function for string map. + +2005-05-06 Jeff Hobbs + + * unix/tcl.m4, unix/configure: correct Solaris 10 (5.10) check and + add support for x86_64 Solaris cc builds. + +2005-04-29 Donal K. Fellows + + * doc/FileSystem.3: Backport of doc fix. [Bug 1172401] + +2005-04-27 Don Porter + + * library/init.tcl: Corrected flaw in interactive command + * tests/main.test: auto-completion. [Bug 1191409] + + * tests/unixInit.test (7.1): Alternative fix for the + 2005-04-22 commit. + +2005-04-25 Daniel Steffen + + * compat/string.h: fixed memchr() protoype for __APPLE__ so that we + build on Mac OS X 10.1 again. + + * generic/tclNotify.c (TclFinalizeNotifier): fixed notifier not being + finalized in unthreaded core (was testing for notifier initialization + in current thread by checking thread id != 0 but thread id is always 0 + in untreaded core). + + * unix/tclUnixNotfy.c (Tcl_WaitForEvent): sync with HEAD: only declare + and use timeout var in unthreaded core. + + * unix/Makefile.in: added @PLAT_SRCS@ to SRCS and split out + NOTIFY_SRCS from UNIX_SRCS for parity with UNIX_OBJS & NOTIFY_OBJS. + + * unix/configure.in: only run check for broken strstr implementation + if AC_REPLACE_FUNCS(strstr) hasn't already determined that strstr is + unavailable, otherwise compat/strstr.o will be used twice (resulting + in duplicate symbol link errors on Mac OS X 10.1) + + * unix/tcl.m4 (Darwin): added configure checks for recently added + linker flags -single_module and -search_paths_first to allow building + with older tools (and on Mac OS X 10.1), use -single_module in + SHLIB_LD and not just T{CL,K}_SHLIB_LD_EXTRAS, added unexporting from + Tk of symbols from libtclstub to avoid duplicate symbol warnings, + added PLAT_SRCS definition for Mac OS X. + (SC_MISSING_POSIX_HEADERS): added caching of dirent.h check. + (SC_TCL_64BIT_FLAGS): fixed 'checking for off64_t' message output. + + * unix/configure: autoconf-2.13 + +2005-04-22 Don Porter + + * generic/tclCmdMZ.c: Corrected intrep-dependence of + * tests/string.test: [string is boolean] [Bug 1187123] + +2005-04-22 Daniel Steffen + + * tests/unixInit.test (7.1): fixed failure when running tests with + -tmpdir arg not set to working dir. + +2005-04-20 Don Porter + + * generic/tclGet.c (Tcl_GetInt): Corrected error that did not + * generic/tclObj.c (Tcl_GetIntFromObj): permit 0x80000000 to be + recognized as an integer on TCL_WIDE_INT_IS_LONG systems [Bug 1090869] + +2005-04-19 Jeff Hobbs + + * tests/winPipe.test (winpipe-6.2): remove -blocking 1 as this one + can truly block. + +2005-04-19 David Gravereaux + + * win/tclWinPipe.c: The pipe channel driver now respects the -blocking + option when closing. The windows pipe driver now has the same behavior + as the UNIX side. This change is to avoid a hung shell when exiting + due to open pipes that refuse to close in a graceful manner. + * doc/open.n: Added a note about -blocking 0 and lack of exit status + as it had never been documented. [Bug 947693] + + ***POTENTIAL INCOMPATIBILITY*** + + Scripts that use async pipes on windows, must (like the UNIX side) set + -blocking to 1 before calling [close] to receive the exit status. + + * tests/winPipe.test (winpipe-6.1/2): added 'fconfigure $f -blocking + 1' so the exit status can be acquired. + +2005-04-13 David Gravereaux + + * generic/tclIO.c (Tcl_SetChannelBufferSize): Lowest size limit + * tests/io.test: changed from ten bytes to one byte. Need for + * tests/iogt.test: this change was proven by Ross Cartlidge + where [read stdin 1] was grabbing 10 bytes followed + by starting a child process that was intended to continue reading from + stdin. Even with -buffersize set to one, nine chars were getting lost + by the buffersize over reading for the native read() caused by [read]. + +2005-04-12 Kevin B. Kenny + + * compat/strstr.c: Added default definition of NULL to accommodate + building on systems with badly broken headers. [Bug 1175161] + +2005-04-09 Daniel Steffen + + * macosx/README: updated requirements for OS & developer tool versions + + other small fixes/cleanup. + + * unix/tcl.m4 (Darwin): added -single_module linker flag to + TCL_SHLIB_LD_EXTRAS and TK_SHLIB_LD_EXTRAS. + * unix/configure: autoconf-2.13 + +2005-04-05 Zoran Vasiljevic + + Set of changes correcting huge memory waste (not a leak) when a thread + exits. This has been introduced in 8.4.7 within an attempt to + correctly cleanup after ourselves when Tcl library is being unloaded + with the Tcl_Finalize() call. + + This fixes the [Bug 1178445]. + + * generic/tclInt.h: added prototypes for TclpFreeAllocCache() and + TclFreeAllocCache() + + * generic/tclThreadAlloc.c: modified TclFinalizeThreadAlloc() to + explicitly call TclpFreeAllocCache with the NULL-ptr as argument + signalling cleanup of private tsd key used only by the threading + allocator. + + * unix/tclUnixThrd.c: fixed TclpFreeAllocCache() to recognize when + being called with NULL argument. This is a signal for it to clean up + the tsd key associated with the threading allocator. + + * win/tclWinThrd.c: renamed TclWinFreeAllocCache to TclpFreeAllocCache + and fixed to recognize when being called with NULL argument. This is a + signal for it to clean up the tsd key associated with the threading + allocator. + +2005-04-05 Don Porter + + * generic/tclExecute.c (ExprSrandFunc): Replaced incursions into the + * generic/tclUtil.c (TclGetIntForIndex): intreps of numeric types with + simpler calls of Tcl_GetIntFromObj and Tcl_GetLongFromObj, now that + those routines are better behaved wrt shimmering. [Patch 1177129] + +2005-03-29 Jeff Hobbs + + * win/tcl.m4, win/configure: do not require cygpath in macros to + allow msys alone as an alternative. + + * win/tclWinTime.c (TclpGetDate): use time_t for 'time' [Bug 1163422] + +2005-03-18 Don Porter + + * generic/tclCompCmds.c (TclCompileIncrCmd): Corrected checks for + immediate operand usage to permit leading space and sign characters. + Restores more efficient bytecode for [incr x -1] that got lost in the + CONST string reforms of Tcl 8.4. [Bug 1165671] + + * generic/tclBasic.c (Tcl_EvalEx,TclEvalTokensStandard): + * generic/tclCmdMZ.c (Tcl_SubstObj): + * tests/basic.test (basic-46.4): Restored recursion limit + * tests/parse.test (parse-19.*): testing in nested command + substitutions within direct script evaluation (Tcl_EvalEx) that got + lost in the parser reforms of Tcl 8.1. Added tests for correct + behavior. [Bug 1115904] + +2005-03-15 Vince Darley + + * generic/tclFileName.c: + * win/tclWinFile.c: + * tests/winFCMd.test: fix to 'file pathtype' and 'file norm' failures + on reserved filenames like 'COM1:', etc. + +2005-03-15 Kevin B. Kenny + + * generic/tclClock.c: + * generic/tclDate.c: + * generic/tclGetDate.y: + * generic/tclInt.decls: + * unix/tclUnixTime.c: + * win/tclWinTime.c: Replaced 'unsigned long' variable holding + times with 'Tcl_WideInt', to cope with systems on which a time_t is + wider than a long (Win64) [Bug 1163422] + * generic/tclIntDecls.h: Regen + +2005-03-15 Pat Thoyts + + * unix/tcl.m4: Make it work on OpenBSD again. Imported patch + from the OpenBSD ports tree. + +2005-03-10 Don Porter + + * generic/tclCmdMZ.c (TclCheckInterpTraces): Corrected mistaken + cast of ClientData to (TraceCommandInfo *) when not warranted. Thanks + to Yuri Victorovich for the report. [Bug 1153871] + +2005-03-08 Jeff Hobbs + + * win/makefile.vc: clarify necessary defined vars that can come + from MSVC or the Platform SDK. + +2005-02-24 Don Porter + + * library/tcltest/tcltest.tcl: Better use of [glob -types] to avoid + * tests/tcltest.test: failed attempts to [source] a directory, and + similar matters. Thanks to "mpettigr". [Bug 1119798] + + * library/tcltest/pkgIndex.tcl: Bump to tcltest 2.2.8 + +2005-02-23 Donal K. Fellows + + * doc/CrtChannel.3 (THREADACTIONPROC): Formatting fix. [Bug 1149605] + +2005-02-17 Jeff Hobbs + + * win/tclWinFCmd.c (TraverseWinTree): use wcslen on wchar, not + Tcl_UniCharLen. + +2005-02-16 Miguel Sofer + + * doc/variable.n: fix for [Bug 1124160], variables are detected by + [info vars] but not by [info locals]. + +2005-02-10 Jeff Hobbs + + * unix/Makefile.in: remove SHLIB_LD_FLAGS (only for AIX, inlined + * unix/tcl.m4: into SHLIB_LD). Combine AIX-* and AIX-5 + * unix/configure: branches in SC_CONFIG_CFLAGS. + Correct gcc builds for AIX-4+ and HP-UX-11. + +2005-02-10 Miguel Sofer + + * generic/tclBasic.c (Tcl_EvalObjEx): + * tests/basic.test (basic-26.2): preserve the arguments passed to TEOV + in the pure-list branch, in case the list shimmers away. Fix for [Bug + 1119369], reported by Peter MacDonald. + +2005-02-10 Donal K. Fellows + + * doc/binary.n: Made the documentation of sign bit masking and + [binary scan] consistent. [Bug 1117017] + +2005-02-01 Don Porter + + * generic/tclExecute.c (TclCompEvalObj): Removed stray statement + left behind in prior code reorganization. + +2005-01-28 Jeff Hobbs + + * unix/configure, unix/tcl.m4: add solaris 64-bit gcc build + support. [Bug 1021871] + +2005-01-27 Jeff Hobbs + + * generic/tclBasic.c (Tcl_ExprBoolean, Tcl_ExprDouble) + (Tcl_ExprLong): Fix to recognize Tcl_WideInt type. [Bug 1109484] + +2005-01-27 Andreas Kupries + + TIP#218 IMPLEMENTATION + + * generic/tclDecls.h: Regenerated from tcl.decls. + * generic/tclStubInit.c: + + * doc/CrtChannel.3: Documentation of extended API, + * generic/tcl.decls: extended testsuite, and + * generic/tcl.h: implementation. Removal of old + * generic/tclIO.c: driver-specific TclpCut/Splice + * generic/tclInt.h: functions. Replaced with generic + * tests/io.test: thread-action calls through the + * unix/tclUnixChan.c: new hooks. Update of all builtin + * unix/tclUnixPipe.c: channel drivers to version 4. + * unix/tclUnixSock.c: Windows drivers extended to + * win/tclWinChan.c: manage thread state in a thread + * win/tclWinConsole.c: action handler. + * win/tclWinPipe.c: + * win/tclWinSerial.c: + * win/tclWinSock.c: + * mac/tclMacChan.c: + +2005-01-25 Don Porter + + * library/auto.tcl: Updated [auto_reset] to clear auto-loaded + procs in namespaces other than :: [Bug 1101670]. + +2005-01-25 Daniel Steffen + + * unix/tcl.m4 (Darwin): fixed bug with static build linking to dynamic + library in /usr/lib etc instead of linking to static library earlier + in search path. [Bug 956908] + Removed obsolete references to Rhapsody. + * unix/configure: autoconf-2.13 + +2005-01-19 Mo DeJong + + * win/tclWinChan.c (FileCloseProc): Invoke TclpCutFileChannel() to + remove a FileInfo from the thread local list before deallocating it. + This should have been done via an earlier call to Tcl_CutChannel, but + I was running into a crash in the next call to Tcl_CutChannel during + the IO finalization stage. + +2005-01-17 Vince Darley + + * tests/winFCmd.test: made test independent of current drive. [Bug + 1066528] + +2005-01-10 Donal K. Fellows + + * unix/tclUnixFCmd.c (CopyFile): Convert u_int to unsigned to make + clashes with types in standard C headers less of a problem. [Bug + 1098829] + +2005-01-06 Donal K. Fellows + + * library/http/http.tcl (http::mapReply): Significant performance + enhancement by using [string map] instead of [regsub]/[subst], and + update version requirement to Tcl8.4. [Bug 1020491] + +2005-01-05 Donal K. Fellows + + * unix/tclUnixInit.c (localeTable): Add encoding mappings for some + Chinese locales. [Bug 1084595] + + * doc/lsearch.n: Convert to other form of emacs mode control + comment to prevent problems with old versions of man. [Bug 1085127] + +2004-12-29 Jeff Hobbs + + * win/tcl.m4, win/configure: update MSVC CFLAGS_OPT to -O2, remove + -Gs (included in -O2) and -GD (outdated). Use "link -lib" instead + of "lib" binary and remove -YX for MSVC7 portability. Add + -fomit-frame-pointer for gcc OPT compiles. [Bug 1092952, 1091967] + +2004-12-13 Kevin B. Kenny + + * doc/clock.n: Clarify that the [clock scan] command does not accept + the full range of ISO8601 point-in-time formats. [Bug 1075433] + +2004-12-09 Donal K. Fellows + + * doc/Async.3: Reword for better grammar, better nroff and get the + flag name right. (Reported by David Welton.) + +2004-12-06 Jeff Hobbs + + *** 8.4.9 TAGGED FOR RELEASE *** + + * unix/tclUnixNotfy.c (NotifierThreadProc): init numFdBits [Bug + 1079286] + +2004-12-02 Jeff Hobbs + + * changes: updated for 8.4.9 release + +2004-12-02 Vince Darley + + * generic/tclIOUtil.c: fix and new tests for [Bug 1074671] to + * tests/fileSystem.test: ensure tilde paths are not returned specially + by 'glob'. + +2004-12-01 Don Porter + + * library/auto.tcl (tcl_findLibrary): Disabled use of [file normalize] + that caused trouble with freewrap. [Bug 1072136] + +2004-11-26 Don Porter + + * tests/reg.test (reg-32.*): Added missing testregexp constraints. + + * library/auto.tcl (tcl_findLibrary): Made sure the uniquifying + operations on the search path does not also normalize. [Bug 1072136] + +2004-11-26 Donal K. Fellows + + * doc/dde.n: Resynchonized the documentation with itself and fixed + some formatting errors. + +2004-11-25 Zoran Vasiljevic + + * doc/Notify.3: + * doc/Thread.3: Added doc fixes and hints from [Bug 1068077]. + +2004-11-25 Reinhard Max + + * tests/tcltest.test: The order in which [glob] returns the file names + * tests/fCmd.test: is undefined, so tests should not depend on it. + +2004-11-24 Don Porter + + * unix/tcl.m4 (SC_ENABLE_THREADS): Corrected failure to determine + the number of arguments for readdir_r on SunOS systems. [Bug 1071701] + + * unix/configure: autoconf-2.13 + +2004-11-24 Jeff Hobbs + + * README: Bumped patchlevel to 8.4.9 + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/tcl.spec, unix/configure, unix/configure.in: + * win/configure, win/configure.in: + +2004-11-24 Kevin B. Kenny + + * unix/tcl.m4 (SC_ENABLE_THREADS): Corrected bad check for 3-argument + readdir_r(). [Bug 1001325] + * unix/configure: Regenerated. + * unix/tclUnixNotfy.c: Corrected all uses of 'select' to manage their + masks using the FD_CLR, FD_ISSET, FD_SET, and FD_ZERO macros rather + than bit-whacking that failed under Solaris-Sparc-64. [Bug 1071807] + +2004-11-23 Don Porter + + * generic/tclCmdIL.c (InfoVarsCmd): Corrected segfault in new + * tests/info.test (info-19.6): trivial matching branch [Bug 1072654] + +2004-11-23 Vince Darley + + * generic/tclPathObj.c: fix and new test for [Bug 1043129] in + * tests/fileSystem.test: the treatment of backslashes in file join on + Windows. + +2004-11-22 Mo DeJong + + * unix/configure: Regen. + * unix/tcl.m4 (SC_TCL_64BIT_FLAGS): Define HAVE_TYPE_OFF64_T only when + off64_t, open64(), and lseek64() are defined. IRIX 5.3 is known to not + include an open64 function. [Bug 1030465] + +2004-11-22 Mo DeJong + + * unix/configure: Regen. + * unix/tcl.m4 (SC_ENABLE_THREADS): Check for a 2 argument version of + readdir_r that is known to exists under IRIX 5.3. + * unix/tclUnixThrd.c (TclpReaddir): Use either 2 arg or 3 arg version + of readdir_r. [Bug 1001325] + +2004-11-19 Reinhard Max + + *** 8.4.8 TAGGED FOR RELEASE *** + + * unix/installManPage: Classic sed doesn't support | in REs. + +2004-11-19 Daniel Steffen + + * macosx/Makefile: + * unix/configure.in: + * unix/tclUnixInit.c (MacOSXGetLibraryPath): changed detection of tcl + framework build when determining tclLibPath from overloaded + TCL_LIBRARY to configuration define TCL_FRAMEWORK. [Bug 1068088] + + * unix/configure: autoconf-2.13 + + * tests/unixInit.test (7.1): fixed failure when running tests + with -tmpdir arg not set to working dir. + +2004-11-18 Don Porter + + * changes: Final updates for Tcl 8.4.8 release. + +2004-11-18 Reinhard Max + + * unix/tcl.m4 (SC_CONFIG_MANPAGES): Applied an improved version of + * unix/configure.in: [Patch 996085], that introduces + * unix/Makefile.in: --enable-man-suffix. + + * unix/installManPage: added + * unix/mkLinks.tcl: removed + * unix/mkLinks: removed + +2004-11-16 Jeff Hobbs + + * unix/tclUnixChan.c (TtySetOptionProc): fixed crash configuring + -ttycontrol on a channel. [Bug 1067708] + +2004-11-16 Andreas Kupries + + * win/makefile.vc: Fixed bug in installation of http 2.5. + * win/makefile.bc: Was installed into directory http2.4. + * win/Makefile.in: This has been corrected. + * unix/Makefile.in: + * tools/tcl.wse.in: + * tools/tclmin.wse: + +2004-11-16 Don Porter + + * library/auto.tcl: Updated [tcl_findLibrary] search path to + include the $::auto_path. [RFE 695441] + +2004-11-16 Donal K. Fellows + + * doc/tclvars.n: Mention global variables set by tclsh and wish so + they are easier to find. [Patch 1065732] + +2004-11-15 Don Porter + + * generic/tclCmdMZ.c (Tcl_TraceObjCmd): Fixed Bug 1065378 which failed + * tests/trace.test (trace-33.1): to permit a variable trace + created with [trace variable] to be destroyed with [trace remove]. + Thanks to Keith Vetter for the report. + +2004-11-12 Don Porter + + * library/init.tcl: Made [unknown] robust in the case that either + of the variables ::errorInfo or ::errorCode gets unset. [Bug 1063707] + +2004-11-12 Jeff Hobbs + + * generic/tclEncoding.c (TableFromUtfProc): correct crash + condition when TCL_UTF_MAX == 6. [Bug 1004065] + +2004-11-12 Daniel Steffen + + * doc/clock.n: + * doc/registry.n: + * doc/upvar.n: fixed *roff errors uncovered by running 'make html'. + + * tools/tcltk-man2html.tcl: added faked support for bullet point + lists, i.e. *nroff ".IP \(bu" syntax. + Synced other changes from HEAD. + +2004-11-11 Daniel Steffen + + * tests/fCmd.test: + * unix/tclUnixFCmd.c (TraverseUnixTree): added option to rewind() the + readdir() loop whenever the source hierarchy has been modified by + traverseProc (e.g. by deleting files); this is required to ensure + complete traversal of the source hierarchy on certain filesystems like + HFS+. Added test for failing recursive delete on Mac OS X that was due + to this. [Bug 1034337] + + * generic/tclListObj.c (Tcl_ListObjReplace): use memmove() instead of + manual copy loop to shift list elements. Decreases time spent in + Tcl_ListObjReplace() from 5.2% to 1.7% of overall runtime of tclbench + on a ppc 7455 (i.e. 200% speed increase). [Patch 1064243] + + * generic/tclHash.c: hoisted some constant pointer dereferences out of + loops to eliminate redundant loads that the gcc optimizer didn't deal + with. Decreases time spend in Tcl_FindHashEntry() by 10% over a full + run of the tcl testuite on a ppc 7455. [Patch 1064243] + + * tests/fileName.test: + * tests/fileSystem.test: + * tests/io.test: + * tests/tcltest.test: fixed bugs causing failures when running tests + with -tmpdir arg not set to working dir. + + * macosx/Makefile: corrected path to html help inside framework. + Prevent parallel make from building several targets at the same time. + +2004-11-09 Donal K. Fellows + + * doc/catch.n: Clarify documentation on return codes. [Bug 1062647] + +2004-11-02 Don Porter + + * changes: Updates for Tcl 8.4.8 release. + +2004-11-02 Don Porter + + * library/tcltest/tcltest.tcl: Corrected some misleading + * tests/tcltest.test (tcltest-26.1,2): displays of ::errorInfo and + ::errorCode information when the -setup, -body, and/or -cleanup scripts + return an unexpected return code. Thanks to Robert Seeger for the + fix. [RFE 1017151] + +2004-11-02 Donal K. Fellows + + * generic/tclExecute.c (TclExecuteByteCode): NaN-equality fix from + Miguel Sofer. [Bug 761471] + + * doc/CrtChannel.3 (Tcl_GetChannelMode): Add synopsis. [Bug 1058446] + +2004-10-31 Donal K. Fellows + + * generic/tclCmdIL.c (InfoGlobalsCmd): + * tests/info.test (info-8.4): Strip leading global-namespace + specifiers from the pattern argument. [Bug 1057461] + +2004-10-30 Miguel Sofer + + * generic/tclCmdAH.c (Tcl_CatchObjCmd): removed erroneous comment [Bug + 1029518] + +2004-10-29 Don Porter + + * library/tcltest/tcltest.tcl: Correct reaction to errors in the + obsolete processCmdLineArgsHook. [Bug 1055673] + * library/tcltest/pkgIndex.tcl: Bump to tcltest 2.2.7 + +2004-10-28 Andreas Kupries + + * generic/tclAlloc.c: Fixed [Bug 1030548], a threaded debug + * generic/tclThreadAlloc.c: build on Windows now works again. Had to + * win/tclWinThrd.c: touch Unix as well. Basic patch by Kevin, + * unix/tclUnixThrd.c: with modifications by myself. + +2004-10-28 Don Porter + + * README: Bumped patch level to 8.4.8 to prepare for + * generic/tcl.h: next patch release. + * tools/tcl.wse.in: + * unix/configure.in: + * unix/tcl.spec: + * win/README.binary: + * win/configure.in: + + * unix/configure: autoconf (2.13) + * win/configure: + +2004-10-28 Kevin B. Kenny + + * generic/tclInt.decls: + * unix/tclUnixTime.c (TclpGmtime, TclpLocaltime): + * win/tclWinTime.c (TclpGmtime, TclpLocaltime): Changed type + signatures of TclpGmtime and TclpLocaltime to accept CONST TclpTime_t + throughout, to avoid any possible confusion in pedantic compilers. + [Bug 1001319] + * generic/tclIntDecls.h: + * generic/tclIntPlatDecls.h: Regenerated. + +2004-10-27 Don Porter + + * generic/tclCmdAH.c (Tcl_FormatObjCmd): Restored missing line + from yesterday's 868489 backport that caused failed alloc's on LP64 + systems. + + * tests/appendComp.test: Backport test suite fixes of errors + * tests/autoMkindex.test: revealed by -singleproc 1 -debug 1 + * tests/exec.test: options to make test. + * tests/execute.test: + * tests/interp.test: + * tests/io.test: + * tests/namespace.test: + * tests/regexpComp.test: + * tests/stringComp.test: + * tests/unixInit.test: + * tests/winPipe.test: + +2004-10-26 Kevin B. Kenny + + * generic/tclCmdAH.c (Tcl_FormatObjCmd): Backport a missing bit of the + [Bug 868489] fix. + * generic/tclObj.c (SetBooleanFromAny): Backport fix for [Bug 1026125] + * tests/format.test (format-19.1): Additional regression test for + [Bug 868489]. + +2004-10-26 Donal K. Fellows + + * doc/*.n: Backporting of documentation updates. + +2004-10-26 Don Porter + + * tests/subst.test (subst-12.3-5): More tests for [Bug 1036649] + + * tests/compile.test (compile-12.4): Backport test for [Bug 1001997] + * tests/timer.test (timer-10.1): Backport test for [Bug 1016167] + * tests/tcltest.test (tcltest-12.3,4): Backport setup corrections. + * tests/error.test (error-6.3,4,7,9): Backport of some tests. + * tests/basic.test (basic-49.*): + * tests/namespace.test (namespace-8.7): + * tests/init.test (init-2.8): Updated to not rely on http package. + + * generic/tclThreadTest.c (ThreadEventProc): Corrected subtle bug + where the returned (char *) from Tcl_GetStringResult(interp) continued + to be used without copying or refcounting, while activity on the + interp continued. + +2004-10-14 Donal K. Fellows + + * generic/tclUtil.c (TclMatchIsTrivial): Detect degenerate cases of + glob matching that let us avoid scanning through hash tables. + * generic/tclCmdIL.c (InfoCommandsCmd, InfoGlobalsCmd, InfoProcsCmd): + (InfoVarsCmd): Use this to speed up some [info] subcommands. + +2004-10-08 Jeff Hobbs + + * win/tclWinFile.c (NativeIsExec): correct result of 'file executable' + to not be case sensitive. [Bug 954263] + +2004-10-05 Don Porter + + * generic/tclNamesp.c (Tcl_PopCallFrame): Removed Bug 1038021 + workaround. That bug is now fixed. + +2004-09-30 Don Porter + + * generic/tclNamespace.c (TclTeardownNamespace): Tcl_Obj-ified the + * tests/namespace.test (namespace-8.5,6): save/restore of + ::errorInfo and ::errorCode during global namespace teardown. Revised + the comment to clarify why this is done, and added tests that will + fail if this is not done. + + * generic/tclResult.c (TclTransferResult): Added safety checks so + that unexpected undefined ::errorInfo or ::errorCode will not lead to + a segfault. + + * generic/tclVar.c (CallVarTraces): Save/restore the flag values + * tests/var.test (var-16.1): that define part of the interpreter + state during variable traces. [Bug 1038021] + +2004-09-30 Miguel Sofer + + * tests/subst.test (12.2): test correction. + +2004-09-29 Miguel Sofer + + * generic/tclBasic.c (Tcl_EvalEx): + * tests/subst.test (12.1-2): fix for buffer overflow in [subst], [Bug + 1036649] + +2004-09-23 Mo DeJong + + * unix/dltest/Makefile.in (clean): Fixup make clean rule so that it + does not delete all files when SHLIB_SUFFIX is set to the empty string + in a static build. [Bug 1016726] + +2004-09-18 Donal K. Fellows + + * generic/tclExecute.c (TEBC-INST_LSHIFT,INST_RSHIFT): Ensure that + large shifts end up shifting correctly. [Bug 868467] + +2004-09-15 Daniel Steffen + + * tests/load.test (load-2.3): adopted fix for failure on darwin from + HEAD. + +2004-09-14 Don Porter + + * generic/tclObj.c (Tcl_GetIntFromObj): Corrected flaw in returning + the int value of a wideInteger. [Bug 1027690] + +2004-09-10 Donal K. Fellows + + * generic/tclObj.c (SetIntOrWideFromAny): Rewritten integral value + parsing code so that values do not flip so easily between numeric + representations. Thanks to KBK for this! [Bug 868489] + + * generic/tclIO.c (Tcl_Seek): Make sure wide seeks do not fail to set + ::errorCode on error. [Bug 1025359] + +2004-09-10 Andreas Kupries + + * generic/tcl.h: Micro formatting fixes. + * generic/tclIOGT.c: Channel version fixed, must be 3, to have + wideseekProc. Thanks to David Graveraux . + +2004-09-11 Don Porter + + * generic/tclNamespace.c (TclGetNamespaceForQualName): Resolved + longstanding inconsistency in the treatment of the TCL_NAMESPACE_ONLY + flag revealed by testing the 2004-09-09 commits against Itcl. + TCL_NAMESPACE_ONLY now acts as specified in the pre-function + comment, forcing resolution in the passed in context namespace. It has + been incorrectly forcing resolution in the interp's current namespace. + +2004-09-10 Miguel Sofer + + * generic/tclExecute.c (INST_CONCAT1): added a peephole optimisation + for concatting an empty string. This enables replacing the idiom 'K $x + [set x {}]' by '$x[set x {}]' for fastest execution. + +2004-09-09 Don Porter + + * generic/tclNamesp.c (Tcl_ForgetImport): Corrected faulty logic that + * tests/namespace.test: relied exclusively on string matching and + failed in the presence of [rename]s. [Bug 560297] + Also corrected faulty prevention of [namespace import] cycles. [Bug + 1017299] + +2004-09-08 Kevin B. Kenny + + * compat/strftime.c (_conv): Corrected a problem where hour 0 would + format as a blank format group with %k. + * tests/clock.test (clock-41.1): Added regression test case for %k at + the zero hour. + +2004-09-07 Kevin B. Kenny + + * generic/tclTimer.c: Removed a premature optimisation that attempted + to store the assoc data in the client data; the optimisation caused a + bug that [after] would overwrite its imports. [Bug 1016167] + +2004-09-02 Donal K. Fellows + + * doc/lsearch.n: Clarified meaning of -dictionary. [Bug 759545] + +2004-09-01 Jeff Hobbs + + * win/tclWinReg.c (BroadcastValue): WIN64 cast corrections + + * win/tclWinDde.c (DdeClientWindowProc): + (DdeServicesOnAck, DdeEnumWindowsCallback): WIN64 corrections + + * win/tclWin32Dll.c (TclWinCPUID): need _asm for WIN64 (Itanium), + until we have it, just return unknown. [Bug 1020445] + +2004-08-30 Donal K. Fellows + + * generic/tclCmdMZ.c (Tcl_StringObjCmd): Stop [string map] from + crashing when its map and input string are the same object. + +2004-08-27 Daniel Steffen + + * tests/env.test: macosx fixes. + +2004-08-19 Donal K. Fellows + + * generic/tclScan.c (Tcl_ScanObjCmd, ValidateFormat): Ensure that the + %ld conversion works correctly on 64-bit platforms. [Bug 1011860] + +2004-08-16 Miguel Sofer + + * doc/SetVar.3: + * generic/tclTest.c (TestseterrorcodeCmd): + * generic/tclVar.c (TclPtrSetVar): + * tests/result.test (result-4.*, result-5.*): [Bug 1008314] + detected and fixed by dgp. + +2004-08-13 Don Porter + + * library/msgcat/msgcat.tcl: Added checks to prevent [mclocale] + * tests/msgcat.test: from registering filesystem paths to possibly + malicious code to be evaluated by a later [mcload]. + * library/msgcat/pkgIndex.tcl: Bump to msgcat 1.3.3 + +2004-08-10 Zoran Vasiljevic + + * unix/tclUnixThrd.c (TclpThreadCreate): changed handling of the + returned thread ID since broken on 64-bit systems (Cray). Thanks to + Rob Ratcliff for reporting the bug. + +2004-07-30 Don Porter + + * generic/tclEvent.c (Tcl_Finalize): Re-organized Tcl_Finalize so + that Tcl_ExitProc's that call Tcl_Finalize recursively do not cause + deadlock. [Patch 999084, fixes Tk Bug 714956] + +2004-07-30 Daniel Steffen + + * unix/configure: + * unix/tcl.m4 (SC_CONFIG_CFLAGS): Darwin: instead of setting PLAT_OBJS + to explict object files in tcl.m4, refer to MAC_OSX_OBJS makefile var. + * unix/Makefile.in: added MAC_OSX_OBJS variable. + +2004-07-28 Don Porter + + * generic/tclMain.c (Tcl_Main, StdinProc): Append newline only to + * tests/basic.test (basic-46.1): incomplete scripts as part + of multi-line script construction. Do not add an extra trailing + newline to the complete script. [Bug 833150] + +2004-07-26 Jeff Hobbs + + *** 8.4.7 TAGGED FOR RELEASE *** + + * tests/io.test (io-61.1): create file in binary mode for x-plat. + +2004-07-25 Pat Thoyts + + * generic/tclThreadAlloc.c: Moved the tclInt.h include to provide + Tcl_Panic which is now required for non-threaded build. + +2004-07-22 Don Porter + + * tests/eofchar.data (removed): Test io-61.1 now generates its own + * tests/io.test: file of test data as needed. + +2004-07-21 Don Porter + * win/tclWinDde.c: Bump to dde 1.2.3 to cover changes + * library/dde/pkgIndex.tcl: committed on 2004-06-14. + + * changes: Updated for Tcl 8.4.7 release. + +2004-07-20 Jeff Hobbs + + * generic/tclEvent.c: Correct threaded obj allocator to + * generic/tclInt.h: fully cleanup on exit and allow for + * generic/tclThreadAlloc.c: reinitialization. [Bug 736426] + * unix/tclUnixThrd.c: (mistachkin, kenny) + * win/tclWinThrd.c: + +2004-07-20 Daniel Steffen + + * unix/tcl.m4: fixed Darwin autoconf breakage caused by recent CFLAGS + reordering. + * unix/configure: regen + + * unix/tclConfig.sh.in: replaced EXTRA_CFLAGS with CFLAGS. + * unix/dltest/Makefile.in: replaced EXTRA_CFLAGS with DEFS. + + * macosx/tclMacOSXBundle.c: dynamically acquire address for + CFBundleOpenBundleResourceMap symbol, since it is only present in + full CoreFoundation on Mac OS X and not in CFLite on pure Darwin. + +2004-07-19 Jeff Hobbs + + * unix/Makefile.in, unix/tcl.m4: move (C|LD)FLAGS after their + * unix/configure.in, unix/configure: _DEFAULT to allow for env setting + to override m4 switches. + Consolidate header checks to limit redundancy in configure. + (CFLAGS_WARNING): Remove -Wconversion, add -fno-strict-aliasing for + gcc builds (need to suppress 3.x type puning warnings). + (SC_ENABLE_THREADS): Set m4 to force threaded build when built against + a threaded Tcl core. + Reorder configure.in for better 64-bit build configuration, replacing + EXTRA_CFLAGS with CFLAGS. [Bug 874058] + +2004-07-19 Zoran Vasiljevic + + * win/tclwinThrd.c: redefined MASTER_LOCK to call TclpMasterLock. + Fixes [Bug 987967] + +2004-07-16 Andreas Kupries + + * generic/tclIOCmd.c (Tcl_FcopyObjCmd): Corrected a typo in the + generation of error messages and simplified by reusing data in a + variable instead of retrieving the string again. Fixes [Bug 835289] + + * doc/OpenFileChnl.3: Added description of the behaviour of + Tcl_ReadChars when its 'charsToRead' argument is set to -1. Fixes [Bug + 934511] + + * doc/CrtCommand.3: Added note that the arguments given to the command + proc of a Tcl_CreateCommand are in utf8 since Tcl 8.1. Closing [Patch + 414778] + + * doc/ChnlStack.3: Removed the declaration that the interp argument to + Tcl_(un)StackChannel can be NULL. This fixes [Bug 881220], reported by + Marco Maggi . + + * tests/socket.test: Accepted two new testcases by Stuart Casoff + checking that -server and -async don't go + together [Bug 796534] + + * unix/tclUnixNotfy.c (NotifierThreadProc): Accepted Joe Mistachkin's + patch for [Bug 990500], properly closing the notifier thread when its + exits. + +2004-07-15 Andreas Kupries + + * unix/tclUnixThrd.c (TclpFinalizeMutex): Accepted Joe Mistachkin's + patch for [Bug 990453], closing leakage of mutexes. They were not + destroyed properly upon finalization. + +2004-07-15 Zoran Vasiljevic + + * generic/tclEvent.c (NewThreadProc): Backout of changes to fix [Bug + 770053]. See SF bugreport for more info. + + * generic/tclNotify.c (TclFinalizeNotifier): Added conditional + notifier finalization based on the fact that an TclInitNotifier has + been called for the current thread. This fixes [Bug 770053] again. + Hopefully this time w/o unwanted side-effects. + +2004-07-14 Andreas Kupries + + * generic/tclIO.h (CHANNEL_INCLOSE): New flag. Set in Tcl_Close + * generic/tclIO.c (Tcl_UnregisterChannel): while the close callbacks + * generic/tclIO.c (Tcl_Close): are run. Checked in + Tcl_Close and Tcl_Unregister to prevent recursive call of [close] in + the close-callbacks. This is a possible error made by implementors of + virtual filesystems based on 'tclvfs', thinking that they have to + close the channel in the close handler for the filesystem. + +2004-07-14 Andreas Kupries + + * generic/tclIO.c: + * generic/tclIO.h: + Not reverting, but #ifdef'ing the changes from May 19, 2004 out of the + core. This removes the ***POTENTIAL INCOMPATIBILITY*** for channel + drivers it introduced. This has become possible due to Expect gaining + a BlockModeProc and now handling blockingg and non-blocking modes + correctly. Thus [Bug 943274] is still fixed if a recent enough version + of Expect is used. + + * doc/CrtChannel.3: Added warning about usage of a channel without a + BlockModeProc. + +2004-07-15 Andreas Kupries + + * generic/tclIOCmd.c (Tcl_PutsObjCmd): Added length check to the old + depreceated newline syntax, to ensure that only "nonewline" is + accepted. [Bug 985869] (mistachkin) + +2004-07-13 Jeff Hobbs + + * README, generic/tcl.h, tools/tcl.wse.in: bumped to + * unix/configure, unix/configure.in, unix/tcl.spec: patchlevel + * win/README.binary, win/configure, win/configure.in: 8.4.7 + +2004-07-13 Zoran Vasiljevic + + * generic/tclEvent.c (NewThreadProc): Fixed broken build on Windows + caused by missing TCL_THREAD_CREATE_RETURN. This is backported from + HEAD. Thnx to Kevin Kenny for spotting this. + +2004-07-03 Miguel Sofer + + * generic/tclExecute.c (ExprRoundFunc): + * tests/expr-old.test (39.1): added support for wide integers to + round(); [Bug 908375], reported by Hemang Lavana. + +2004-07-02 Jeff Hobbs + + * generic/regcomp.c (stid): correct minor pointer size error + + * generic/tclPipe.c (TclCreatePipeline): Add 2>@1 as a special + * tests/exec.test: case redir of stderr to the result output. + +2004-07-02 Vince Darley + + * tests/fileSystem.test: new tests backported + * win/tclWin32Dll.c: compilation fix for VC++5.2 + +2004-06-29 Donal K. Fellows + + * library/safe.tcl: Make sure that the temporary variable is + local to the namespace and not inadvertently global. [Bug 981733] + +2004-06-22 Zoran Vasiljevic + + * generic/tclEvent.c: + * generic/tclInt.h: + * unix/tclUnixNotfy.c: + * unix/tclUnixThrd.c: + * win/tclWinThrd.c: See bug report for more information about what it + does. [Bug 770053] + + * tests/unixNotfy.test: rewritten to use tcltest::threadReap to + gracefully wait for the test thread to exit. Otherwise we got a race + condition with main thread exiting before the test thread. This + exposed the long-standing Tcl lib issue with resource + garbage-collection on application exit. + +2004-06-21 Mo DeJong + + * win/tclWin32Dll.c (DllMain, _except_dllmain_detach_handler) + (TclpCheckStackSpace, _except_checkstackspace_handler, TclWinCPUID) + (_except_TclWinCPUID_detach_handler): + * win/tclWinChan.c (Tcl_MakeFileChannel) + (_except_makefilechannel_handler): + * win/tclWinFCmd.c (DoRenameFile, _except_dorenamefile_handler) + (DoCopyFile, _except_docopyfile_handler): + Rework pushing of exception handler function pointer so that compiling + with gcc -O3 works. Remove empty function call to avoid compiler + warning. Mark the DllMain function as noinline to avoid compiler error + from duplicated asm labels in generated code. + +2004-06-14 Pat Thoyts + + * tests/winDde.test: Fixed -async test + * win/tclWinDde.c: Backported the fix from 8.5 to avoid hanging in the + presence of applications that do not process Window messages. + +2004-06-10 Andreas Kupries + + * generic/tclDecls.h: Regenerated on a unix box. The Win/DOS + * generic/tclIntDecls.h: EOLs from the last regen screwed up + * generic/tclIntPlatDecls.h: compilation with an older gcc. + * generic/tclPlatDecls.h: + * generic/tclStubInit.c: + +2004-06-10 Zoran Vasiljevic + + * generic/tclIOUtil.c: partially corrected [Bug 932314]. Also, + corrected return values of Tcl_FSChdir() to reflect those of the + underlying platform-specific call. Originally, return codes were mixed + with those of Tcl. + +2004-06-08 Miguel Sofer + + * generic/tclCompile.c: handle warning [Bug 969066] + +2004-06-05 Kevin B. Kenny + + * generic/tcl.h: Corrected Tcl_WideInt declarations so that the mingw + build works again. + * generic/tclDecls.h: Changes to the tests for + * generic/tclInt.decls: clock frequency in Tcl_WinTime + * generic/tclIntDecls.h: so that any clock frequency is + * generic/tclIntPlatDecls.h: accepted provided that all + * generic/tclPlatDecls.h: CPU's in the system share a + * generic/tclStubInit.c: common chip, and hence, + * tests/platform.test (platform-1.3): presumably, a common clock. + * win/tclWin32Dll.c (TclWinCPUID): This change necessitated a + * win/tclWinTest.c (TestwincpuidCmd) small burst of assembly code + * win/tclWinTime.c (Tcl_GetTime): to read CPU ID information, + which was added as TclWinCPUID in the internal Stubs. To test this + code in the common case of a single-processor machine, a + 'testwincpuid' command was added to tclWinTest.c, and a test case in + platform.test. Thanks to Jeff Godfrey and Richard Suchenwirth for + reporting this bug. [Bug 976722] + +2004-05-27 Kevin B. Kenny + + * tests/clock.test: Added a single test for the presence of %G in + [clock format], and conditioned out the clock-10.x series if they're + all going to fail because of a broken strftime() call. [Bug 961714] + +2004-05-27 Reinhard Max + + * generic/tclEncoding.c: + * tests/encoding.test: added support and tests for translating + embedded null characters between real nullbytes and the internal + representation on input/output. [Bug 949905] + +2004-05-26 Don Porter + + * library/tcltest/tcltest.tcl: Correction to debug prints and testing + * library/tcltest/pkgIndex.tcl: if TCLTEST_OPTIONS value. Corrected + * tests/tcltest.test: double increment of numTestFiles in + -singleproc 1 configurations. Updated tcltest-19.1 to tcltest 2.1 + behavior. Corrected tcltest-25.3 to not falsely report a failure in + tcltest.test. Bumped to tcltest 2.2.6. [Bugs 960560, 960926] + +2004-05-25 Jeff Hobbs + + * doc/http.n (http::config): add -urlencoding option (default utf-8) + * library/http/http.tcl: that specifies encoding conversion of + * library/http/pkgIndex.tcl: args for http::formatQuery. Previously + * tests/http.test: undefined, RFC 2718 says it should be + utf-8. 'http::config -urlencoding {}' returns previous behavior, + which will throw errors processing non-latin-1 chars. Bumped http + package to 2.5.0. + +2004-05-25 Kevin Kenny + + * tests/winFCmd.test: Correct test for the presence of a CD-ROM so + that it doesn't misdetect some other sort of filesystem with a + write-protected root as being a CD-ROM drive. [Bug 918267] + +2004-05-24 Jeff Hobbs + + * generic/tclExecute.c (VerifyExprObjType): use GET_WIDE_OR_INT to + properly have tclIntType used for smaller values. This corrects TclX + bug 896727 and any other 3rd party extension that created math + functions but was not yet WIDE_INT aware in them. + +2004-05-24 Miguel Sofer + + * doc/set.n: accurate description of name resolution process, + referring to namespace.n for details [Bug 959180] + +2004-05-22 Miguel Sofer + + * generic/tclVar.c (TclObjUnsetVar2): backported fix [Bug 735335] and + new (in tcl8.4) exteriorisations of [Bug 736729] due to the use of + tclNsVarNameType obj types. The consequences of [Bug 736729] should be + the same as in tcl8.3 and previous versions. The use of + tclNsVarNameType objs is still disabled, pending a decision by the + release manager. + +2004-05-19 Donal K. Fellows + + * win/tclWinFile.c (TclpMatchInDirectory): fix for an issue where + there was a sneak path from Tcl_DStringFree to SetErrorCode(0). The + result was that the error code could be reset between a call to + FindFirstFile and the check of its status return, leading to a bizarre + error return of {POSIX unknown {No error}}. (Found in unplanned test - + no incident logged at SourceForge.) + +2004-05-19 Andreas Kupries + + * generic/tclIO.c: Fixed [SF Tcl Bug 943274]. This is the same problem + * generic/tclIO.h: as [SF Tcl Bug 462317], see ChangeLog entry + 2001-09-26. The fix done at that time is incomplete. It is possible to + get around it if the actual read operation is defered and not executed + in the event handler itself. Instead of tracking if we are in an read + caused by a synthesized fileevent we now track if the OS has delivered + a true event = actual data and bypass the driver if a read finds that + there is no actual data waiting. The flag is cleared by a short or + full read. [[this bug amended 2004-07-14]] + +2004-05-18 Kevin B. Kenny + + * compat/strftime.c (_fmt, ISO8601Week): + * doc/clock.n: + * tests/clock.test: Major rework to the handling of ISO8601 week + numbers. Now passes all the %G and %V test cases on Windows, Linux and + Solaris [Bugs 500285, 500389, and 852944] + +2004-05-17 Kevin B. Kenny + + * generic/tclInt.decls: Restored TclpTime_t kludge to all places + * generic/tclIntPlatDecls.h: where it appeared before the changes of + * unix/tclUnixPort.h 14 May, because use of native time_t in + * unix/tclUnixTime.h its place requires the 8.5 header + * win/tclWinTime.h: reforms. [Bug 955146] + +2004-05-17 Donal K. Fellows + + * doc/OpenFileChnl.3: Documented type of 'offset' argument to Tcl_Seek + was wrong. [Bug 953374] + +2004-05-14 Kevin B. Kenny + + * generic/tclInt.decls: Promoted TclpLocaltime and TclpGmtime + * generic/tclIntDecls.h: from Unix-specific stubs to the generic + * generic/tclIntPlatDecls.h: internal Stubs table. Reran 'genstubs' + * generic/tclStubInit.c: + * unix/tclUnixPort.h: + + * generic/tclClock.c: Changed a buggy 'GMT' timezone specification to + the correct 'GMT0'. [Bug 922848] + + * unix/tclUnixThrd.c: Moved TclpGmtime and TclpLocaltime to + unix/tclUnixTime.c where they belong. + + * unix/tclUnixTime.c (TclpGmtime, TclpLocaltime, TclpGetTimeZone, + (ThreadSafeGMTime[removed], ThreadSafeLocalTime[removed], + (SetTZIfNecessary, CleanupMemory): Restructured to make sure that the + same mutex protects all calls to localtime, gmtime, and tzset. Added a + check in front of those calls to make sure that the TZ env var hasn't + changed since the last call to tzset, and repeat tzset if necessary. + [Bug 940278] Removed a buggy test of the Daylight Saving Time + information in 'gettimeofday' in favor of applying 'localtime' to a + known value. [Bug 922848] + + * tests/clock.test (clock-3.14): Added test to make sure that changes + to $env(TZ) take effect immediately. + + * win/tclWinTime.c (TclpLocaltime, TclpGmtime): Added porting layer + for 'localtime' and 'gmtime' calls. + +2004-05-10 David Gravereaux + + * win/tclWinPipe.c (BuildCommandLine): Append a space when the path + got primed. + (TclpCreateProcess): When under NT, with no console, and executing a + DOS application, the path priming does not need an ending space as + BuildCommandLine() will append one for us. + +2004-05-07 Miguel Sofer + + * doc/unset.n: added upvar.n to the "see also" list + +2004-05-05 David Gravereaux + + * generic/tclEvent.c: TclSetLibraryPath's use of caching the stringrep + of the pathPtr object to TclGetLibraryPath called from another thread + was ineffective if the original's stringrep had been invalidated as + what happens when it gets muted to a list. + + * generic/tclEncoding.c: Added FreeEncoding(systemEncoding) in + TclFinalizeEncodingSubsystem because its ref count was incremented in + TclInitEncodingSubsystem. + + * win/tclWin32Dll.c: Structured Exception Handling added around + Tcl_Finalize called from DllMain's DLL_PROCESS_DETACH. We can't be + 100% assured that Tcl is being unloaded by the OS in a stable + condition and we need to protect the exit handlers should the stack be + in a hosed state. AT&T style assembly for SEH under MinGW included, + too. [Patch 858493] + + Also added DisableThreadLibraryCalls() for the DLL_PROCESS_ATTACH + case. We're not interested in knowing about DLL_THREAD_ATTACH, so + disable the notices. + + * generic/tclInt.h: + * generic/tclThread.c: + * generic/tclEvent.c: + * unix/tclUnixThrd.c: + * win/tclWinThrd.c: Provisions made so masterLock, initLock, + allocLock and joinLock mutexes can be recovered during Tcl_Finalize. + + * win/tclWinSock.c: + (SocketThreadExitHandler): Don't call TerminateThread when + WaitForSingleObject returns a timeout. Tcl_Finalize called from + DllMain will pause all threads. Trust that the thread will get the + close notice at a later time if it does ever wake up before being + cleaned up by the system anyway. + (SocketEventProc): connect errors should fire both the readable and + writable handlers because this is how it works on UNIX. [Bug 794839] + + * win/coffbase.txt: Added the tls extension to the list of preferred + load addresses. + +2004-05-05 Don Porter + + * tests/unixInit.test (unixInit-2.10): Test correction for Mac OSX. + Be sure to consistently compare normalized path names. Thanks to + Steven Abner (tauvan). [Bug 948177] + +2004-05-05 Donal K. Fellows + + * doc/CrtObjCmd.3: Remove reference to Tcl_RenameCommand; there is no + such API. [Bug 848440] + +2004-05-04 Jeff Hobbs + + * generic/tclIOUtil.c (Tcl_FSChdir): Work-around crash condition + * tests/winFCmd.test (winFCmd-16.12): triggered when $HOME is + volumerelative (ie 'C:'). + + * tests/fileName.test (filename-12.9): use C:/ instead of the first + item in file volumes - that's usually A:/, which for most will have + nothing in it. + +2004-05-04 Don Porter + + * tests/tcltest.test: Test corrections for Mac OSX. Thanks to Steven + Abner (tauvan). [Bug 947440] + +2004-05-03 Andreas Kupries + + Applied [SF Tcl Patch 868853], fixing a mem leak in TtySetOptionProc. + Report and Patch provided by Stuart Cassoff . + +2004-05-03 Kevin Kenny + + * win/tclWin32Dll.c (TclpCheckStackSpace): + * tests/stack.test (stack-3.1): Fix for undetected stack overflow in + TclReExec on Windows. [Bug 947070] + +2004-05-03 Don Porter + + * library/init.tcl: Corrected unique prefix matching of + interactive command completion in [unknown]. [Bug 946952] + +2004-05-02 Miguel Sofer + + * generic/tclProc.c (TclObjInvokeProc): + * tests/proc.test (proc-3.6): fix for bad quoting of multi-word proc + names in error messages [Bug 942757] + +2004-04-23 Andreas Kupries + + * generic/tclIO.c (Tcl_SetChannelOption): Fixed [Bug 930851]. When + changing the eofchar we have to zap the related flags to prevent them + from prematurely aborting the next read. + +2004-04-07 Jeff Hobbs + + * win/configure: + * win/configure.in: define TCL_LIB_FLAG, TCL_BUILD_LIB_SPEC, + TCL_LIB_SPEC and TCL_PACKAGE_PATH in tclConfig.sh. + +2004-04-06 Don Porter + + * tests/unixInit.test (unixInit-3.1): Default encoding on Darwin + systems is utf-8. Thanks to Steven Abner (tauvan). [Bug 928808] + +2004-04-06 Donal K. Fellows + + * tests/cmdAH.test (cmdAH-18.2): Added constraint because + access(...,X_OK) is defined to be permitted to be meaningless when + running as root, and OSX exhibits this. [Bug 929892] + +2004-04-02 Don Porter + + * tests/tcltest.test: Corrected constraint typos: "nonRoot" -> + "notRoot". Thanks to Steven Abner (tauvan). [Bug 928353] + +2004-03-31 Don Porter + + * doc/msgcat.n: Clarified message catalog file encodings. [Bug 811457] + * library/msgcat/msgcat.tcl ([mcset], [ConvertLocale], [Init]): + Corrected [mcset] to be able to successfully set a translation to + the empty string. [mcset $loc $src {}] was incorrectly set the $loc + translation of $src back to $src. Also changed [ConvertLocale] to + minimally require a non-empty "language" part in the locale value. If + not, an error raised prompts [Init] to keep looking for a valid locale + value, or ultimately fall back on the "C" locale. [Bug 811461] + * library/msgcat/pkgIndex.tcl: Bump to msgcat 1.3.2. + +2004-03-31 Donal K. Fellows + + * generic/tclObj.c (HashObjKey): Make sure this hashes the whole + string rep of the object, instead of missing the last character. + +2004-03-29 Jeff Hobbs + + * generic/tclInt.h: + * generic/tclEncoding.c (TclFindEncodings, Tcl_FindExecutable): + * mac/tclMacInit.c (TclpInitLibraryPath): Correct handling of UTF + * unix/tclUnixInit.c (TclpInitLibraryPath): data that is actually + * win/tclWinFile.c (TclpFindExecutable): "clean", allowing the + * win/tclWinInit.c (TclpInitLibraryPath): loading of Tcl from paths + that contain multi-byte chars on Windows [Bug 920667] + +2004-03-28 Miguel Sofer + + * generic/tclCompile.c (TclCompileScript): corrected possible segfault + when a compilation returns TCL_OUTLINE_COMPILE after having grown the + compile environment. [Bug 925121] + +2004-03-21 Jeff Hobbs + + * win/tclWinInt.h: define VER_PLATFORM_WIN32_CE if not already set. + * win/tclWinInit.c (TclpSetInitialEncodings): recognize WIN32_CE + as a unicode (WCHAR) platform. + +2004-03-15 Miguel Sofer + + * generic/tclCompile.c (TclCompileScript): + * tests/compile.test (compile-3.5): corrected wrong test and behaviour + in the earlier fix for [Bug 705406]; Don Porter reported this as [Bug + 735055], and provided the solution. Fixed in HEAD on 2003-05-09, but + backport to 8-4-branch was wrongly omitted; re-reported as [Bug + 916795] by Roy Terry, diagnosed by dgp. + +2004-03-08 Vince Darley + + * generic/tclFileName.c: Fix to 'glob -path' near the root + * tests/fileName.test: of the filesystem. [Bug 910525] + +2004-03-01 Don Porter + + *** 8.4.6 TAGGED FOR RELEASE *** + + * unix/tcl.m4 (SC_CONFIG_CFLAGS): Allow 64-bit enabling on + IRIX64-6.5* systems. [Bug 218561] + * unix/configure: autoconf-2.13 + + * generic/tclCmdMZ.c (TclCheckInterpTraces): The TIP 62 + * generic/tclTest.c (TestcmdtraceCmd): implementation introduced a + * tests/basic.test (basic-39.10): bug by testing the CallFrame + level instead of the iPtr->numLevels level when deciding what traces + created by Tcl_Create(Obj)Trace to call. Added test to expose the + error, and made fix. [Request 462580] + +2004-02-26 Daniel Steffen + + * macosx/Makefile: fixed copyright year in Tcl.framework Info.plist + +2004-02-25 Don Porter + + * tests/basic.test: Made several tests more robust to the + * tests/cmdMZ.test: list-quoting of path names that might + * tests/exec.test: contain Tcl-special chars like { or [. + * tests/io.test: Should help us sort out Tcl Bug 554068. + * tests/pid.test: + * tests/socket.test: + * tests/source.test: + * tests/unixInit.test: + +2004-02-25 Donal K. Fellows + + * unix/tclUnixChan.c (TcpGetOptionProc): Stop memory leak with very + long hostnames. [Bug 888777] + +2004-02-25 David Gravereaux + + * tests/winPipe.test: + * win/tclWinPipe.c: backport of BuildCommandLine changes to mirror + msvcrt's parse_cmdline() rules of quoting. + +2004-02-19 Mo DeJong + + * win/tclWinInit.c (AppendEnvironment): Use the tail component of the + passed in lib path instead of just blindly using lib+4. That worked + when lib was "lib/..." but fails for other values. Thanks go to + Patrick Samson for pointing this out. + +2004-02-17 Don Porter + + * doc/tcltest.n: + * library/tcltest/tcltest.tcl: Changed -verbose default value to + {body error} so that detailed information on unexpected errors in + tests is provided by default, even after the fix for [Bug 725253] + +2004-02-17 Jeff Hobbs + + (reverted due to test failures on Solaris, but not Win/Lin :/) + * generic/tclIOUtil.c: backport of rewrite of generic file + normalization code to cope with links followed by '..'. [Bug 849514], + and parts of [859251] + + * tests/unixInit.test: unixInit-7.1 + * unix/tclUnixInit.c (TclpInitPlatform): ensure the std fds exist to + prevent crash condition [Bug 772288] + +2004-02-16 Jeff Hobbs + + * generic/tclCmdMZ.c (TclTraceExecutionObjCmd) + (TclTraceCommandObjCmd): fix possible mem leak in trace info. + +2004-02-12 Jeff Hobbs + + * README: update patchlevel to 8.4.6 + * generic/tcl.h: + * tools/tcl.wse.in: + * unix/configure, unix/configure.in, unix/tcl.spec: + * win/README.binary, win/configure, win/configure.in: + + * unix/tcl.m4: update HP-11 build libs setup + +2004-02-06 Don Porter + + * doc/clock.n: Removed reference to non-existent [file ctime]. + +2004-02-04 Don Porter + + * library/tcltest/tcltest.tcl: Corrected references to + non-existent $name variable in [cleanupTests]. [Bug 833637] + +2004-02-03 Don Porter + + * library/tcltest/tcltest.tcl: Corrected parsing of single + command line argument (option with missing value) [Bug 833910] + * library/tcltest/pkgIndex.tcl: Bump to version 2.2.5. + +2004-02-02 David Gravereaux + + * generic/tclIO.c (Tcl_Ungets): fixes improper filling of the channel + buffer. [Bug 405995] + +2004-01-13 Don Porter + + * generic/tclFileName.c (Tcl_GlobObjCmd): Latest changes to + management of the interp result by Tcl_GetIndexFromObj() exposed + improper interp result management in the [glob] command procedure. + Corrected by adopting the Tcl_SetObjResult(Tcl_NewStringObj) pattern. + This stopped a segfault in test filename-11.36. + +2004-01-13 Donal K. Fellows + + * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct, Tcl_WrongNumArgs): + Create fresh objects instead of using the one currently in the + interpreter, which isn't guaranteed to be fresh and unshared. The + cost for the core will be minimal because of the object cache, and + this fixes. [Bug 875395] + +2004-01-09 Vince Darley + + * generic/tclIOUtil.c: fix to infinite loop in TclFinalizeFilesystem. + [Bug 873311] + +2003-12-17 Daniel Steffen + + * generic/tclBinary.c (DeleteScanNumberCache): fixed crashing bug when + numeric scan-value cache contains NULL value. + +2003-12-17 Zoran Vasiljevic + + * generic/tclIOUtil.c: fixed 2 memory (object) leaks. This fixes [Bug + 839519] + +2003-12-12 Vince Darley + + * generic/tclCmdAH.c: fix to normalization of non-existent user name + ('file normalize ~nobody') [Bug 858937] + +2003-12-09 Donal K. Fellows + + * unix/tclUnixPort.h: #ifdef'd out declarations of errno which + * tools/man2tcl.c: are known to cause problems with recent + glibc. [Bug 852369] + +2003-12-03 Don Porter + + * generic/tcl.h: Bumped patch level to 8.4.5.1 to distinguish + * unix/configure.in: CVS snapshots from 8.4.5 release. + * unix/tcl.spec: + * win/configure.in: + + * unix/configure: autoconf (2.13) + * win/configure: + +2003-12-02 Donal K. Fellows + + * generic/tclBinary.c (DeleteScanNumberCache, ScanNumber): Made + the numeric scan-value cache have proper references to the objects + within it so strange patterns of writes won't cause references to + freed objects. Thanks to Paul Obermeier for the report. [Bug 851747] + +2003-12-01 Miguel Sofer + + * doc/lset.n: fix typo [Bug 852224] + +2003-11-21 Don Porter + + *** 8.4.5 TAGGED FOR RELEASE *** + + * tests/windFCmd.test (winFCmd-16.10): Corrected failure to + initialize variable $dd that caused test suite failure. + +2003-11-20 Miguel Sofer + + * generic/tclVar.c: fix flag bit collision between LOOKUP_FOR_UPVAR + and TCL_PARSE_PART1 (deprecated) [Bug 835020] + +2003-11-20 Vince Darley + + * generic/tclIOUtil.c: + * tests/winFCmd.test: fix to [Bug 845778] - Infinite recursion on [cd] + (Windows only bug). + +2003-11-18 Jeff Hobbs + + * changes: updated for 8.4.5 release + +2003-11-17 Don Porter + + * generic/regcomp.c: Backported regexp bug fixes and tests. Thanks + * generic/tclTest.c: to Pavel Goran and Vince Darley. + * tests/reg.test: [Bugs 230589, 504785, 505048, 703709, 840258] + +2003-11-12 Jeff Hobbs + + * tests/cmdMZ.test (cmdMZ-1.4): change to nonPortable as more + systems are using permissions caching, and this isn't really a Tcl + controlled issue. + +2003-11-11 Jeff Hobbs + + * unix/configure: + * unix/tcl.m4: improve AIX --enable-64bit handling + +2003-11-10 Don Porter + + * tests/unixInit.test (unixInit-2.10): re-enabled. + * unix/tclUnixInit.c (TclpInitLibraryPath): Alternative fix + * win/tclWinInit.c (TclpInitLibraryPath): for [Bug 832657] + that should not run afoul of startup constraints. + + * library/dde/pkgIndex.tcl: Added safeguards so that registry + * library/reg/pkgIndex.tcl: and dde packages are not offered + * win/tclWinDde.c: on non-Windows platforms. Bumped to + * win/tclWinReg.c: registry 1.1.3 and dde 1.2.2. + +2003-11-06 Jeff Hobbs + + * tests/unixInit.test (unixInit-2.10): mark as knownBug + * generic/tclEncoding.c (TclFindEncodings): revert patch from + 2003-11-05. It wasn't valid in the sensitive startup init phase + and broke Windows from working at all. + +2003-11-07 Daniel Steffen + + * macosx/Makefile: optimized builds define NDEBUG to turn off + ThreadAlloc range checking. + +2003-11-05 Don Porter + + * generic/tclEncoding.c (TclFindEncodings): Normalize the path + of the executable before passing to TclpInitLibraryPath() to avoid + buggy handling of paths containing "..". [Bug 832657] + * tests/unixInit.test (unixInit-2.10): New test for fixed bug. + +2003-11-04 Daniel Steffen + + * macosx/Makefile: added 'test' target. + +2003-10-31 Vince Darley + + * generic/tclTest.c: fix test suite memory leak (backport error) + * unix/tclUnixFile.c: ensure translated path (required for correct + error messages) is freed in both code paths. + +2003-10-23 Andreas Kupries + + * unix/tclUnixChan.c (Tcl_MakeFileChannel): Applied [Patch 813606] + fixing [Bug 813087]. Detection of sockets was off for Mac OS X which + implements pipes as local sockets. The new code ensures that only IP + sockets are detected as such. + +2003-10-22 Andreas Kupries + + * win/tclWinSock.c (TcpWatchProc): Watch for FD_CLOSE too when asked + for writable events by the generic layer. + (SocketEventProc): Generate a writable event too when a close is + detected. + + Together the changes fix [Bug 599468]. + +2003-10-22 Andreas Kupries + + * generic/tclIOUtil.c (FsListMounts, FsAddMountsToGlobResult): New + functions. See below for context. + (Tcl_FSMatchInDirectory): Modified to call on the new functions + (above) to handle the mountpoints in the glob'bed directory correctly. + Part of the patch by Vincent Darley to solve the [Bug 800106] for the + 8.4.x series. + + * generic/tcl.h (TCL_GLOB_TYPE_MOUNT): New definition. Part of the + patch by Vincent Darley to solve [Bug 800106] for the 8.4.x series. + +2003-10-22 Donal K. Fellows + + * generic/tclCmdAH.c (Tcl_FileObjCmd): Changed FILE_ prefix for option + enumeration to FCMD_ to prevent collision with symbols defined by + Cygwin/Mingw32 on NT. [Bug 822528] + +2003-10-21 Daniel Steffen + + * tools/tcltk-man2html.tcl: fixed incorrect html generated for .IP/.TP + lists, now use
...
...

...
...
instead of + illegal

...
...

...
...
. Added skipping of + directives directly after .TP to avoid them being used as item + descriptions, e.g. .TP\n.VS in clock.n. + +2003-10-21 Andreas Kupries + + * win/tclWinPipe.c (BuildCommandLine): Applied the patch coming with + [Bug 805605] to the code, fixing the incorrect use of ispace noted by + Ronald Dauster . + +2003-10-14 David Gravereaux + + * win/tclAppInit.c (sigHandler): Punt gracefully if exitToken has + already been destroyed. + +2003-10-13 Vince Darley + + * generic/tclCmdMZ.c: + * tests/regexp.test: fix to [Bug 823524] in regsub; added three new + tests. + +2003-10-12 Jeff Hobbs + + * unix/tclUnixTest.c (TestalarmCmd): don't bother checking return + value of alarm. [Bug 664755] (english) + +2003-10-08 Don Porter + + * generic/tclBasic.c: Save and restore the iPtr->flag bits that + control the state of errorCode and errorInfo management when calling + "leave" execution traces, so that all error information of the traced + command is still available whether traced or not. Thanks to Yahalom + Emet. [Bug 760947] + +2003-10-08 Donal K. Fellows + + * generic/tclTest.c (TestNumUtfCharsCmd): Command to allow finer + access to Tcl_NumUtfChars for testing. + * generic/tclUtf.c (Tcl_NumUtfChars): Corrected string length + determining when the length parameter is negative; the terminator is a + zero byte, not (necessarily) a \u0000 character. [Bug 769812] + +2003-10-07 Don Porter + + * tests/exec.test: Corrected temporary file management + * tests/fileSystem.test: issues uncovered by -debug 1 test + * tests/io.test: operations. Also backported some + * tests/ioCmd.test: other fixes from the HEAD. + * tests/pid.test: [Bugs 675605, 675655, 675659] + * tests/socket.test: + * tests/source.test: + + * tests/fCmd.test: Run tests with the [temporaryDirectory] as + the current directory, so that tests can depend on ability to write + files. [Bug 575837] + + * doc/OpenFileChnl.3: Updated Tcl_Tell and Tcl_Seek documentation + to reflect that they now return Tcl_WideInt (TIP 72) [Bug 787537] + + * tests/io.test: Corrected several tests that failed when paths + * tests/ioCmd.test: included regexp-special chars. [Bug 775394] + +2003-10-06 Don Porter + + * tests/regexp.test: Matched [makeFile] with [removeFile]. + * tests/regexpComp.test: [Bug 675652] + + * tests/fCmd.test (fCmd-8.2): Test only that tilde-substitution + happens, not for any particular result. [Bug 685991] + + * unix/tcl.m4 (SC_PATH_TCLCONFIG): Corrected search path so + that alpha and beta releases of Tcl are not favored. [Bug 608698] + + * tests/reg.test: Corrected duplicate test names. + * tests/resource.test: [Bugs 710370, 710358] + + * tests/cmdMZ.test: Updated [package require tcltest] lines to + * tests/fileSystem.test: indiciate that these test files + * tests/notify.test: use features of tcltest 2. [Bug 706114] + * tests/parseExpr.test: + * tests/unixNotfy.test: + +2003-10-06 Vince Darley + + * generic/tclFileName.c: + * generic/tclIOUtil.c: backport of volumerelative file normalization + and 'file join' inconsistency fixes [Bug 767834, 813273]. + +2003-10-04 Chengye Mao + + * win/tclWinPipe.c: fixed a bug in BuildCommandLine. + This bug built a command line with a missing space between + tclpipe.dll and the following arguments. It caused error + in Windows 98 when exec command.com (e.g. dir) [Bug 789040] + +2003-10-03 Don Porter + + * generic/tclBasic.c: Fixed error in ref count management of command + * generic/tclCmdMZ.c: and execution traces that caused access to + freed memory in trace-32.1. [Bug 811483] + +2003-10-03 Vince Darley + + * tests/fileName.test: + * tests/winFCmd.test: + * doc/FileSystem.3: backported various test and documentation changes + from HEAD. Backport of actual code fixes to follow. + +2003-10-02 Don Porter + + * README: Bumped patch level to 8.4.5 to prepare + * generic/tcl.h: for next patch release. + * tools/tcl.wse.in: + * unix/configure.in: + * unix/tcl.spec: + * win/README.binary: + * win/configure.in: + + * unix/configure: autoconf (2.13) + * win/configure: + + * library/http/http.tcl: Bumped to http 2.4.5 + * library/http/pkgIndex.tcl: + +2003-10-01 Daniel Steffen + + * macosx/Makefile: fixed redo prebinding bug when DESTDIR="". + * mac/tclMacResource.c: fixed possible NULL dereference (bdesgraupes). + +2003-09-29 Don Porter + + * generic/tclBasic.c (CallCommandTraces): Added safety bit + * tests/trace.test: masking to prevent any of the bit values + TCL_TRACE_*_EXEC from leaking into the flags field of any Command + struct. This does not fix [Bug 811483] but helps to contain some of + its worst symptoms. Also backported the corrections to test trace-28.4 + from Vince Darley. + +2003-09-29 Donal K. Fellows + + * library/http/http.tcl (geturl): Correctly check the type of + boolean-valued options. [Bug 811170] + + * unix/tcl.m4 (SC_ENABLE_FRAMEWORK): Added note to make it clearer + that this is an OSX feature, not a general Unix feature. [Bug 619440] + +2003-09-28 David Gravereaux + + * win/tclWinPipe.c: The windows port of expect can call + TclWinAddProcess before any of the other pipe functions. Added a + missing PipeInit() call to make sure the initialization happens. + +2003-09-25 Daniel Steffen + + * macosx/Makefile: ensure SYMROOT exists if OBJROOT is overridden on + command line. Replaced explict use of /usr/bin by ${BINDIR}. + +2003-09-23 Don Porter + + * generic/tclCmdMZ.c: Fixed [Bug 807243] where + * tests/trace.test (trace-31,32.*): the introspection results + of both [trace info command] and [trace info execution] were getting + co-mingled. Thanks to Mark Saye for the report. + + * library/init.tcl (auto_load, auto_import): Expanded Eric Melski's + 2000-01-28 fix for [Bug 218871] to all potentially troubled uses of + [info commands] on input data, where glob-special characters could + cause problems. + +2003-09-19 Miguel Sofer + + * generic/tclExecute.c: adding (DE)CACHE_STACK_INFO() pairs to protect + all calls that may cause traces on ::errorInfo or ::errorCode to + corrupt the stack [Bug 804681] + +2003-09-10 Don Porter + + * library/opt/optparse.tcl: Overlooked dependence of opt 0.4.4 + * library/opt/pkgIndex.tcl: on Tcl 8.2. Bumped to opt 0.4.4.1. + +2003-09-01 Zoran Vasiljevic + + * generic/tclIOUtil.c: backported fix from HEAD [Bug 788780] + +2003-08-27 Don Porter + + * generic/tclUtil.c: Corrected [Bug 411825] and other bugs in + TclNeedSpace() where non-breaking space (\u00A0) and backslash-escaped + spaces were handled incorrectly. + * tests/util.test: Added new tests util-8.[2-6]. + +2003-08-06 Jeff Hobbs + + * win/tclWinInit.c: recognize amd64 and ia32_on_win64 cpus and + Windows CE platform. + +2003-08-06 Don Porter + + * library/msgcat/msgcat.tcl: Added escape so that non-Windows + * library/msgcat/pkgIndex.tcl: platforms do not try to use the + registry package. This can save a costly and pointless package + search. Bumped to 1.3.1. Thanks to Dave Bodenstab. [Bug 781609] + +2003-08-05 Miguel Sofer + + * generic/tclExecute.c (INST_INVOKE, INST_EVAL, INST_PUSH_RESULT): + added a Tcl_ResetResult(interp) at each point where the interp's + result is pushed onto the stack, to avoid keeping an extra reference + that may cause costly Tcl_Obj duplication. Detected by Franco Violi, + analyzed by Peter Spjuth and Donal Fellows. [Bug 781585] + +2003-07-24 Reinhard Max + + * library/package.tcl: Fixed a typo that broke pkg_mkIndex -verbose. + + * tests/pkgMkIndex.test: Added a test for [pkg_mkIndex -verbose]. + +2003-07-23 Daniel Steffen + + * unix/Makefile.in: changes to html-tcl & html-tk targets for + compatibility with non-gnu makes. + + * unix/Makefile.in: added macosx/README to dist target. + +2003-07-23 Pat Thoyts + + * win/tclWinReg.c (OpenSubKey): Backported fix for [Bug 775976] which + causes the registry set command to fail when built with VC7. + * library/reg/pkgIndex.tcl: Incremented the version to 1.1.2. + +2003-07-21 Jeff Hobbs + + *** 8.4.4 TAGGED FOR RELEASE *** + + * changes: updated for 8.4.4 release + +2003-07-18 Daniel Steffen + + * macosx/Makefile: added option to allow installing manpages in + addition to default html help. + +2003-07-18 Donal K. Fellows + + * doc/Utf.3: Tightened up documentation of Tcl_UtfNext and Tcl_UtfPrev + to better match the behaviour. [Bug 769895] + +2003-07-18 Jeff Hobbs + + * generic/tclIOUtil.c: correct MT-safety issues with filesystem + records. [Bug 753315] (vasiljevic) + + * library/http/pkgIndex.tcl: merged to v2.4.4 from head + * library/http/http.tcl: add support for user:pass info in URL. + * tests/http.test: [Bug 759888] (shiobara) + +2003-07-18 Don Porter + + * generic/tclBasic.c: Corrected several instances of unsafe + * generic/tclCompile.c: truncation of UTF-8 strings that might break + * generic/tclProc.c: apart a multi-byte character. [Bug 760872] + * library/init.tcl: + * tests/init.test: + + * doc/tcltest.n: Restored the [Eval] proc to replace + * library/tcltest/tcltest.tcl: the [::puts] command when either the + -output or -error option for [test] is in use, in order to capture + data written to the output or error channels for comparison against + what is expected. This is easier to document and agrees better with + most user expectations than the previous attempt to replace [puts] + only in the caller's namespace. Documentation made more precise on the + subject. [Bug 706359] + + * doc/AddErrInfo.3: Improved consistency of documentation by using + * doc/CrtTrace.3: "null" everywhere to refer to the character + * doc/Encoding.3: '\0', and using "NULL" everywhere to refer to + * doc/Eval.3: the value of a pointer that points to nowhere. + * doc/GetIndex.3: Also dropped references to ASCII that are no + * doc/Hash.3: longer true, and standardized on the + * doc/LinkVar.3: hyphenated spelling of "null-terminated". + * doc/Macintosh.3: + * doc/OpenFileChnl.3: + * doc/SetVar.3: + * doc/StringObj.3: + * doc/Utf.3: + + * doc/CrtSlave.3 (Tcl_MakeSafe): Removed warning about possible + deprecation (no TIP on that). + +2003-07-17 Daniel Steffen + + * macosx/Makefile: added var to allow overriding of tclsh used during + html help building (Landon Fuller). + +2003-07-16 Mumit Khan + + * generic/tclIOUtil.c (SetFsPathFromAny): Add Cygwin specific code to + convert POSIX filename to native format. + * generic/tclFileName.c (Tcl_TranslateFileName): And remove from here. + (TclDoGlob): Adjust for cygwin and append / for dirs instead of \ + * win/tclWinFile.c (TclpObjChdir): Use chdir on Cygwin. [Patch 679315] + +2003-07-16 Jeff Hobbs + + * library/safe.tcl (FileInAccessPath): normalize paths before + comparison. [Bug 759607] (myers) + + * unix/tclUnixNotfy.c (NotifierThreadProc): correct size of found and + word vars from int to long. [Bug 767578] (hgo) + +2003-07-16 Donal K. Fellows + + * doc/CrtSlave.3 (Tcl_MakeSafe): Updated documentation to strongly + discourage use. IMHO code outside the core that uses this function is + a bug... [Bug 655300] + +2003-07-16 Jeff Hobbs + + * generic/tcl.h: Add recognition of -DTCL_UTF_MAX=6 on the + * generic/regcustom.h: make line to support UCS-4 mode. No config arg + at this time, as it is not the recommended build mode. + + * generic/tclPreserve.c: In Result and Preserve'd routines, do not + * generic/tclUtil.c: assume that ckfree == free, as that is not + * generic/tclResult.c: always true. [Bug 756791] (fuller) + +2003-07-16 Mo DeJong + + * win/Makefile.in: Don't define TCL_DBGX symbol for every compile. + Instead, define TCL_PIPE_DLL only when compiling tclWinPipe.c. This + will break other build systems, so they will need to remove the + TCL_DBGX define and replace it with a define for TCL_PIPE_DLL. + * win/makefile.vc: Ditto. + * win/tclWinPipe.c (TclpCreateProcess): Remove PREFIX_IDENT and + DEBUG_IDENT from top of file. Use TCL_PIPE_DLL passed in from build + env instead of trying to construct the dll name from already defined + symbols. This approach is more flexible and better in the long run. + +2003-07-16 Don Porter + + * generic/tclFileName.c (Tcl_GlobObjCmd): [Bug 771840] + * generic/tclIOUtil.c (Tcl_FSConvertToPathType):[Bug 771947] + * unix/tclUnixFCmd.c (GetModeFromPermString): [Bug 771949] + Silence compiler warnings about unreached lines. + + * library/tcltest/tcltest.tcl (ProcessFlags): Corrected broken call + * library/tcltest/pkgIndex.tcl: to [lrange]. Bumped to + version 2.2.4. [Bug 772333] + +2003-07-15 Mo DeJong + + * unix/dltest/pkga.c (Pkga_EqObjCmd): Fix typo that was causing a + crash in load.test. + +2003-07-15 Donal K. Fellows + + * doc/array.n: Added some examples from David Welton [Patch 763312] + +2003-07-15 Don Porter + + * doc/http.n: Updated SYNOPSIS to match actual syntax of commands. + [Bug 756112] + + * unix/dltest/pkga.c: Updated to not use Tcl_UtfNcmp and counted + strings instead of strcmp (not defined in any #include'd header) and + presumed NULL-terminated strings. + + * README: Bumped patch level to 8.4.4 in anticipation + * generic/tcl.h: of another patch release. + * tools/tcl.wse.in: + * unix/configure.in: + * unix/tcl.spec: + * win/README.binary: + * win/configure.in: + + * unix/configure: autoconf (2.13) + * win/configure: + + * generic/tclCompCmds.c (TclCompileIfCmd): Prior fix of Bug 711371 + on 2003-04-07 introduced a buffer overflow. Corrected. [Bug 771613] + +2003-07-15 Donal K. Fellows + + * generic/tclCmdIL.c (SortCompare): Cleared up confusing error + message. [Bug 771539] + +2003-07-15 Daniel Steffen + + * macosx/Makefile: Rewrote buildsystem for Mac OS X framework build to + be purely make driven; in order to become independent of Apple's + closed-source IDE and build tool. The changes are intended to be + transparent to the Makefile user, all existing make targets and cmd + line variable overrides should continue to work. Changed build to only + include tcl specific html help in Tcl.framework, the tk specific html + help is now included in Tk.framework. + + * macosx/Tcl.pbproj/project.pbxproj: + * macosx/Tcl.pbproj/jingham.pbxuser: Changed to purely call through to + the make driven buildsystem; Tcl.framework is no longer assembled by + ProjectBuilder. Set default SYMROOT in target options to simplify + setting up PB (manually setting common build folder for tcl & tk no + longer needed). + + * tools/tcltk-man2html.tcl: Added options to allow building only the + tcl or tk html help files; the default behaviour with none of the new + options is to build both, as before. + + * unix/Makefile.in: Added targets for building only the tcl or tk help. + + * macosx/README (new): Tcl specific excerpts of tk/macosx/README. + + * generic/tcl.h: Updated reminder comment about editing + macosx/Tcl.pbproj/project.pbxproj when version number changes. + +2003-07-11 Donal K. Fellows + + * tests/binary.test (binary-46.*): Tests to help enforce the current + behaviour. + * doc/binary.n: Documented that [binary format a] and [binary scan a] + do encoding conversion by dropping high bytes, unlike the rest of + the core. [Bug 735364] + +2003-07-11 Don Porter + + * library/package.tcl: Corrected [pkg_mkIndex] bug reported on + comp.lang.tcl. The indexer was searching for newly indexed packages + instead of newly provided packages. + +2003-07-04 Donal K. Fellows + + * doc/expr.n: Tighten up the wording of some operations. [Bug 758488] + + * tests/cmdAH.test: Made tests of [file mtime] work better on FAT + filesystems. [Patch 760768] Also a little general cleanup. + +2003-06-25 Mo DeJong + + * unix/configure: Regen. + * unix/tcl.m4 (SC_CONFIG_CFLAGS): Add -ieee when compiling with cc and + add -mieee when compiling with gcc under OSF1-V5 "Tru64" systems. [Bug + 748957] + +2003-06-24 Donal K. Fellows + + * doc/encoding.n: Corrected the docs to say that [source] uses the + system encoding, which it always did anyway (since 8.1) [Bug 742100] + +2003-06-23 Vince Darley + + * generic/tclFCmd.c: fix to bad error message when trying to do 'file + copy foo ""'. [Bug 756951] + * tests/fCmd.test: added two new tests for the bug. + + * doc/FileSystem.3: documentation fix [Bug 720634] + +2003-06-18 Miguel Sofer + + * generic/tclNamesp.c (Tcl_Export): removed erroneous comments [Bug + 756744] + +2003-06-17 Vince Darley + + * generic/tclCmdMZ.c: + * tests/regexp.test: fixing of bugs related to regexp and regsub + matching of empty strings. Addition of a number of new tests. + +2003-06-10 Miguel Sofer + + * generic/tclBasic.c: + * generic/tclExecute.c: let TclEvalObjvInternal call TclInterpReady + instead of relying on its callers to do so; fix for the part of [Bug + 495830] that is new in 8.4. + * tests/interp.test: Added tests 18.9 (knownbug) and 18.10 + +2003-06-09 Don Porter + + * tests/string.test (string-4.15): Added test for [string first] bug + reported in Tcl 8.3, where test for all-single-byte-encoded strings + was not reliable. + +2003-06-04 Joe Mistachkin + + * tools/man2help.tcl: Added duplicate help section checking and + * tools/index.tcl: corrected a comment typo for the getTopics proc + in index.tcl. [Bug 748700] + +2003-05-23 Don Porter + + * generic/tclObj.c (tclCmdNameType): Converted internal rep + management of the cmdName Tcl_ObjType the opposite way, to always use + the twoPtrValue instead of always using the otherValuePtr. Previous + fix on 2003-05-12 broke several extensions that wanted to poke around + with the twoPtrValue.ptr2 value of a cmdName Tcl_Obj, like TclBlend + and e4graph. [Bug 726018] Thanks to George Petasis for the bug report + and Jacob Levy for testing assistance. + +2003-05-22 Daniel Steffen + + *** 8.4.3 TAGGED FOR RELEASE *** + + * macosx/tclMacOSXBundle.c: fixed a problem that caused only the first + call to Tcl_MacOSXOpenVersionedBundleResources() for a given bundle + identifier to succeed. This caused the tcl runtime library not to be + found in all interps created after the inital one. + +2003-05-20 Jeff Hobbs + + * changes: updated for 8.4.3 + + * unix/Makefile.in: do not run autoconf during 'make dist' as the + configure is now a CVS-maintained file and should be up-to-date. + +2003-05-19 Daniel Steffen + + * macosx/Tcl.pbproj/project.pbxproj: changed tclConfig.sh location in + versioned framework subdirectories to be identical to location in + framework toplevel; fixed stub library symbolic links to be Tcl + version specific. + +2003-05-16 Daniel Steffen + + * macosx/Tcl.pbproj/project.pbxproj: updated copyright year. + +2003-05-15 Jeff Hobbs + + * win/tclWinFile.c (TclpMatchInDirectory): revert glob code to r1.44 + as 2003-04-14 optimizations broke Windows98 glob'ing. + + * README: bumped version to 8.4.3 + * generic/tcl.h: + * macosx/Tcl.pbproj/project.pbxproj: + * tools/tcl.wse.in: + * unix/configure: + * unix/configure.in: + * unix/tcl.spec: + * win/README.binary: + * win/configure: + * win/configure.in: + + * doc/socket.n: nroff font handling correction. + + * library/encoding/gb2312-raw.enc (new): This is the original + gb2312.enc renamed to allow for it to still be used. This is needed by + Tk (unix) because X fonts with gb2312* charsets really do want the + original gb2312 encoding. [Bug 557030] + +2003-05-14 Donal K. Fellows + + * generic/tclCmdAH.c (Tcl_FormatObjCmd): Values which can't be + anything but wide shouldn't be demoted to long. [consequence of HEAD + fixes for Bug 699060] + +2003-05-14 Jeff Hobbs + + * library/encoding/gb2312.enc: copy euc-cn.enc over original + gb2312.enc. gb2312.enc appeared to not work as expected, and most uses + of gb2312 really mean euc-cn (which may be the cause of the problem). + [Bug 557030] + + * generic/tclEnv.c (TclUnsetEnv): Another putenv() copy behavior + problem repaired when compiling on windows and using microsoft's + runtime. [Bug 736421] (gravereaux) + +2003-05-13 Jeff Hobbs + + * generic/tclIOUtil.c: add decl for FsThrExitProc to suppress warnings + +2003-05-13 Donal K. Fellows + + * generic/tclEvent.c (Tcl_Finalize): Removed unused variable to reduce + compiler warnings. [Bug 664745] + +2003-05-13 Joe Mistachkin + + * generic/tcl.decls: Changed Tcl_JoinThread parameter name from "id" + * generic/tclDecls.h: to "threadId". [Bug 732477] + * unix/tclUnixThrd.c: + * win/tclWinThrd.c: + * mac/tclMacThrd.c: + +2003-05-13 Daniel Steffen + + * generic/tcl.decls: + * macosx/tclMacOSXBundle.c: added extended version of the + Tcl_MacOSXOpenBundleResources() API taking an extra version number + argument: Tcl_MacOSXOpenVersionedBundleResources(). This is needed to + be able to access bundle resources in versioned frameworks such as Tcl + and Tk, otherwise if multiple versions were installed, only the latest + version's resources could be accessed. [Bug 736774] + + * unix/tclUnixInit.c (Tcl_MacOSXGetLibraryPath): use new versioned + bundle resource API to get tcl runtime library for TCL_VERSION. + [Bug 736774] + + * generic/tclPlatDecls.h: + * generic/tclStubInit.c: regen. + + * unix/tclUnixPort.h: worked around the issue of realpath() not being + thread-safe on Mac OS X by defining NO_REALPATH for threaded builds on + Mac OS X. [Bug 711232] + +2003-05-12 Don Porter + + * generic/tclInterp.c: (AliasObjCmd): Added refCounting of the words + * tests/interp.test (interp-33.1): of the target of an interp + alias during its execution. Also added test. [Bug 730244]. + + * generic/tclBasic.c (TclInvokeObjectCommand): objv[argc] is no + longer set to NULL (Tcl_CreateObjCommand docs already say that it + should not be accessed). + + * generic/tclObj.c (tclCmdNameType): Corrected variable use of the + otherValuePtr or the twoPtrValue.ptr1 fields to store a + (ResolvedCmdName *) as the internal rep. [Bug 726018]. + + * doc/Eval.3: Corrected prototype for Tcl_GlobalEvalObj [Bug 727622]. + +2003-05-12 Miguel Sofer + + * generic/tclVar.c (TclObjLookupVar): [Bug 735335] temporary fix, + disabling usage of tclNsVarNameType. + * tests/var.test (var-15.1): test for [Bug 735335] + +2003-05-10 Zoran Vasiljevic + + * unix/tclUnixThrd.c: corrected [Bug 723502] + +2003-05-10 Jeff Hobbs + + * generic/tclIOUtil.c: ensure cd is thread-safe. + [Bug 710642] (vasiljevic) + + * win/tclWinSerial.c (SerialCloseProc): correct mem leak on closing a + Windows serial port [Bug 718002] (schroedter) + + * generic/tclCmdMZ.c (Tcl_StringObjCmd): prevent string repeat crash + when overflow sizes were given (throws error). [Bug 714106] + +2003-05-09 Joe Mistachkin + + * generic/tclThreadAlloc.c (TclFreeAllocCache): Fixed memory leak + caused by treating cachePtr as a TLS index [Bug 731754]. + + * win/tclAppInit.c (Tcl_AppInit): Fixed memory leaks caused by not + freeing the memory allocated by setargv and the async handler created + by Tcl_AppInit. An exit handler has been created that takes care of + both leaks. In addition, Tcl_AppInit now uses ckalloc instead of + Tcl_Alloc to allow for easier leak tracking and to be more consistent + with the rest of the Tcl core [Bugs 733156, 733221]. + + * tools/encoding/txt2enc.c (main): Fixed memory leak caused by failing + to free the memory used by the toUnicode array of strings [Bug 733221] + +2003-05-05 Don Porter + + * library/tcltest/tcltest.tcl: The -returnCodes option to [test] + failed to recognize the symbolic name "ok" for return code 0. + +2003-05-05 Donal K. Fellows + + * generic/tclBasic.c (Tcl_HideCommand): Fixed error message grammar + and spelling. + +2003-04-29 Vince Darley + + * generic/tclFileName.c: fix to bug reported privately by Jeff where, + for example, 'glob -path {[tcl]} *' gets confused by the leading + special character (which is escaped internally), and instead lists + files in '/'. Bug only occurs on Windows where '\' is also a + directory separator. (Bug has been around at least since Tcl 8.3.) + * tests/fileName.test: added test for the above bug. + +2003-04-25 Don Porter + + * generic/tclBasic.c: Tcl_EvalObjv() failed to honor the + TCL_EVAL_GLOBAL flag when resolving command names. Tcl_EvalEx passed a + string rep including leading whitespace and comments to + TclEvalObjvInternal(). + +2003-04-25 Andreas Kupries + + * win/tclWinThrd.c: Applied [Patch 727271]. This patch changes the + code to catch any errors returned by the windows functions handling + TLS ASAP instead of waiting to get some mysterious crash later on due + to bogus pointers. Patch provided by Joe Mistachkin. + + This is a stop-gap measure to deal with the low number of ?TLS slots + provided by some of the variants of Windows (60-80). + +2003-04-21 Don Porter + + * library/tcltest/tcltest.tcl: When the return code of a test does + not meet expectations, report that as the reason for test failure, + and do not attempt to check the test result for correctness. [Bug + 725253] + +2003-04-18 Jeff Hobbs + + * generic/tclExecute.c (ExprCallMathFunc): remove incorrect + extraneous cast from Tcl_WideAsDouble. + +2003-04-18 Donal K. Fellows + + * doc/open.n: Moved serial port options from [fconfigure] + * doc/fconfigure.n: to [open] as it is up to the creator of a + channel to describe the channel's special + config options. [Bug 679010] + +2003-04-16 Don Porter + + * generic/tcl.h Made changes so that the "wideInt" Tcl_ObjType + * generic/tclObj.c is defined on all platforms, even those where + * generic/tclPort.h TCL_WIDE_INT_IS_LONG is defined. Also made + the Tcl_Value struct have a wideValue field on all platforms. This is + a ***POTENTIAL INCOMPATIBILITY*** for TCL_WIDE_INT_IS_LONG platforms + because that struct changes size. This is the same TIP 72 + incompatibility that was seen on other platforms at the 8.4.0 release, + when this change should have happened as well. [Bug 713562] + + * generic/tclInt.h: New internal macros TclGetWide() and + TclGetLongFromWide() to deal with both forms of the "wideInt" + Tcl_ObjType, so that conditional TCL_WIDE_INT_IS_LONG code + is confined to the header file. + + * generic/tclCmdAH.c: Replaced most coding that was conditional + * generic/tclCmdIL.c: on TCL_WIDE_INT_IS_LONG with code that + * generic/tclExecute.c: works across platforms, sometimes using + * generic/tclTest.c: the new macros above to do it. + * generic/tclUtil.c: + * generic/tclVar.c: + +2003-04-17 Donal K. Fellows + + * doc/socket.n: Added a paragraph to remind people to specify + their encodings when using sockets. [Bug 630621] + +2003-04-16 Donal K. Fellows + + * doc/CrtMathFnc.3: Functions also have to deal with wide ints, + but this was not documented. [Bug 709720] + +2003-04-15 Kevin Kenny + + * win/tclWinTime.c: Corrected use of types to make compilation + compatible with VC++5. + +2003-04-14 Kevin Kenny + + * win/tclWinFile.c: added conditionals to restore compilation on + VC++6, which was broken by recent changes. + +2003-04-14 Vince Darley + + Merged various bug fixes from current cvs head: + + * tests/cmdAH.test: better fix to test suite problem if /home is a + symlink [Bug 703264] + + * generic/tclIOUtil.c: fix bad error message with 'cd ""' [Bug 704917] + * win/tclWinFile.c: + * win/tclWin32Dll.c: + * win/tclWinInt.h: allow Tcl to differentiate between reparse points + which are symlinks and mounted volumes, and correctly handle the + latter. This involves some elaborate code to find the actual drive + letter (if possible) corresponding to a mounted volume. [Bug 697862] + * tests/fileSystem.test: add constraints to stop tests running in + ordinary tcl interpreter. [Bug 705675] + * generic/tclIOUtil.c: Some re-arrangement of code to bring it closer + to CVS HEAD. No functional changes. + + * tests/fCmd.test: + * win/tclWinFile.c: added some filesystem optimisation to the + 'glob' implementation, and some new tests. + + * tests/winFile.test: + * tests/ioUtil.test: + * tests/unixFCmd.test: renumbered tests with duplicate numbers. [Bug + 710361] + +2003-04-12 Kevin Kenny + + * tests/clock.test: Renumbered test cases to avoid duplicates [Bug + 710310]. + * tests/winTime.test: + * win/tclWinTest.c (TestwinclockCmd, TestwinsleepCmd): + * win/tclWinTime.c (Tcl_WinTime, UpdateTimeEachSecond, + (ResetCounterSamples, AccumulateSample, SAMPLES, TimeInfo): Made + substantial changes to the phase-locked loop (replaced an IIR filter + with an FIR one) in a quest for improved loop stability (Bug not + logged at SF, but cited in private communication from Jeff Hobbs). + +2003-04-11 Don Porter + + * generic/tclCmdMZ.c (Tcl_StringObjCmd,STR_IS_INT): Corrected + inconsistent results of [string is integer] observed on systems + where sizeof(long) != sizeof(int). [Bug 718878] + * tests/string.test: Added tests for Bug 718878. + * doc/string.n: Clarified that [string is integer] accepts + 32-bit integers. + +2003-04-11 Andreas Kupries + + * generic/tclIO.c (UpdateInterest): When dropping interest in + TCL_READABLE now dropping interest in TCL_EXCEPTION too. This fixes a + bug where Expect detects eof on a file prematurely on Solaris 2.6 and + higher. A much more complete explanation is in the code itself (40 + lines of comments for a one-line change :) + +2003-04-10 Donal K. Fellows + + * doc/binary.n: Fixed typo in [binary format w] desc. [Bug 718543] + +2003-04-08 Donal K. Fellows + + * generic/tclCmdAH.c (Tcl_ErrorObjCmd): Strings are only empty if they + have zero length, not if their first byte is zero, so fix test + guarding Tcl_AddObjErrorInfo to take this into account. [Bug reported + by Don Porter; no bug-id.] + +2003-04-07 Don Porter + + * generic/tclCompCmds.c (TclCompileIfCmd): Corrected string limits of + arguments interpolated in error messages. [Bug 711371] + + * generic/tclCmdMZ.c (TraceExecutionProc): Added missing + Tcl_DiscardResult() call to avoid memory leak. + +2003-04-07 Donal K. Fellows + + * generic/tclObj.c (tclWideIntType, TclInitObjSubsystem): + (SetBooleanFromAny): Make sure that tclWideIntType is defined and + somewhat sensible everywhere. [Bug 713562] + +2003-04-02 Mo DeJong + + * win/configure: Regen. + * win/configure.in: Set stub lib flag based on new LIBFLAGSUFFIX + variable. + * win/tcl.m4 (SC_CONFIG_CFLAGS): Set new LIBFLAGSUFFIX that works like + LIBSUFFIX, it is used when creating library names. The previous + implementation would generate -ltclstub85 instead of -ltclstub85s when + configured with --disable-shared. + +2003-04-01 Don Porter + + * tests/README: Direct [source] of *.test files is no longer + recommended. The tests/*.test files should only be evaluated under the + control of the [runAllTests] command in tests/all.tcl. + +2003-03-27 Miguel Sofer + + * tests/encoding.test: + * tests/proc-old.test: + * tests/set-old.test: Altered test numers to eliminate duplicates, + [Bugs 710313, 710320, 710352] + +2003-03-27 Donal K. Fellows + + * tests/parseOld.test: Altered test numers to eliminate duplicates. + * tests/parse.test: [Bugs 710365, 710369] + * tests/expr-old.test: + * tests/expr.test: + + * tests/utf.test: Altered test numers to eliminate duplicates. + * tests/trace.test: [Bugs 710322, 710327, 710349, 710363] + * tests/lsearch.test: + * tests/list.test: + * tests/info.test: + * tests/incr-old.test: + * tests/if-old.test: + * tests/format.test: + * tests/foreach.test: + +2003-03-26 Don Porter + + * doc/tcltest.n: + * library/tcltest/tcltest.tcl: Added reporting during [configure + -debug 1] operations to warn about multiple uses of the same test + name. [FR 576693] Replaced [regexp] and [regsub] with [string map] + where possible. Thanks to David Welton. [Bugs 667456,667558] + * library/tcltest/pkgIndex.tcl: Bumped to tcltest 2.2.3 + + * tests/msgcat.test (msgcat-2.2.1): changed test name to avoid + duplication. [Bug 710356] + + * unix/dltest/pkg?.c: Changed all Tcl_InitStubs calls to pass argument + exact = 0, so that rebuilds are not required when Tcl bumps to a new + version. [Bug 701926] + +2003-03-24 Miguel Sofer + + * generic/tclVar.c: + * tests/var.test: fixing ObjMakeUpvar's lookup algorithm for the + created local variable, [Bugs 631741] (Chris Darroch) and [696893] + (David Hilker). + +2003-03-22 Kevin Kenny + + * library/dde/pkgIndex.tcl: + * library/reg/pkgIndex.tcl: Fixed a bug where [package require dde] or + [package require registry] attempted to load the release version of + the DLL into a debug build. [Bug 708218] Thanks to Joe Mistachkin for + the patch. + * win/makefile.vc: Added quoting around the script name in the 'test' + target; Joe Mistachkin insists that he has a configuration that fails + to launch tcltest without it, and it appears harmless otherwise. + +2003-03-20 Don Porter + + * generic/tclInt.h (tclOriginalNotifier): + * generic/tclStubInit.c (tclOriginalNotifier): + * mac/tclMacNotify.c (Tcl_SetTimer,Tcl_WaitForEvent): + * unix/tclUnixNotfy.c (Tcl_SetTimer,Tcl_WaitForEvent, + (Tcl_CreateFileHandler,Tcl_DeleteFileHandler): + * win/tclWinNotify.c (Tcl_SetTimer,Tcl_WaitForEvent): Some linkers + apparently use a different representation for a pointer to a function + within the same compilation unit and a pointer to a function in a + different compilation unit. This causes checks like those in the + original notifier procedures to fall into infinite loops. The fix is + to store pointers to the original notifier procedures in a struct + defined in the same compilation unit as the stubs tables, and compare + against those values. [Bug 707174] + + * generic/tclInt.h: Removed definition of ParseValue struct that is no + longer used. + +2003-03-19 Miguel Sofer + + * generic/tclCompile.c: + * tests/compile.test: bad command count on TCL_OUT_LINE_COMPILE + [Bug 705406] (Don Porter). + +2003-03-19 Don Porter + + * doc/Eval.3 (Tcl_EvalObjEx): Corrected CONST and + * doc/ParseCmd.3 (Tcl_EvalTokensStandard): return type errors in + documentation. [Bug 683994] + +2003-03-18 Kevin Kenny + + * tests/registry.test: Changed the conditionals to avoid an abort if + [testlocale] is missing, as when running the test in tclsh rather than + tcltest. [Bug 705677] + +2003-03-18 Daniel Steffen + + * tools/tcltk-man2html.tcl: added support for building 'make html' + from inside distribution directories named with 8.x.x version numbers. + tcltk-man2html now uses the latest tcl8.x.x resp. tk8.x.x directories + found inside its --srcdir argument. + +2003-03-18 Vince Darley + + * tests/cmdAH.test: fix test suite problem if /home is a symlink + * generic/tclIOUtil.c: fix bad error message with 'cd ""' + * win/tclWinFile.c: allow Tcl to differentiate between reparse points + which are symlinks and mounted drives. + + These changes fix [Bugs 703264, 704917, 697862] respectively. + +2003-03-17 Donal K. Fellows + + * doc/lsearch.n: Altered documentation of -ascii options so + * doc/lsort.n: they don't specify that they operate on + ASCII strings, which they never did + anyway. [Bug 703807] + +2003-03-14 Donal K. Fellows + + * generic/tclCmdAH.c (Tcl_FileObjCmd): Remove assumption that file + times and longs are the same size. [Bug 698146] + (Tcl_FormatObjCmd): Stop surprising type conversions from + happening when working with integer and wide values. [Bug 699060] + + * generic/tclCmdAH.c (Tcl_FormatObjCmd): Only add the modifier that + indicates we've got a wide int when we're formatting in an integer + style. Stops some libc's from going mad. [Bug 702622] + Also tidied whitespace. + +2003-03-13 Kevin Kenny + + * win/makefile.vc: Backed the version to 8.4 on the 8.4 branch. (I + just loathe sticky tags). + +2003-03-12 Don Porter + + * generic/tcl.h: Removed TCL_PREFIX_IDENT and TCL_DEBUG_IDENT + * win/tclWinPipe.c: from tcl.h -- they are not part of Tcl's + public interface. Put them in win/tclWinPipe.c where they are used. + + * generic/tclCmdMZ.c (Tcl_SubstObj): Corrected and added test for + * tests/subst.test (subst-2.4): Tcl_SubstObj's incorrect + halting of substitution at the first \x00 byte. [Bug 685106] + + * generic/tclInterp.c (Tcl_InterpObjCmd): Corrected and added + * tests/interp.test (interp-2.13): test for option + parsing beyond objc for [interp create --]. Thanks to Marco Maggi. + [Bug 702383] + +2003-03-11 Kevin Kenny + + * win/makefile.vc: Added two missing uses of $(DBGX) so that + tclpip8x.dll loads without panicking on Win9x. + +2003-03-08 Don Porter + + * doc/tcltest.n: Added missing "-body" to example. Thanks to + Helmut Giese. [Bug 700011] + +2003-03-06 Don Porter + + * generic/TclUtf.c (Tcl_UniCharNcasecmp): Corrected failure to + * tests/utf.test (utf-25.*): properly compare Unicode strings of + different case in a case insensitive manner. [Bug 699042] + 2003-03-03 Jeff Hobbs *** 8.4.2 TAGGED FOR RELEASE *** 2003-03-03 Daniel Steffen @@ -17,12 +4750,12 @@ stat'ing of broken links. 2003-03-03 Kevin Kenny * win/Makefile.vc: corrected bug introduced by 'g' for debug builds. - -2003-03-03 Don Porter + +2003-03-03 Don Porter * library/dde/pkgIndex.tcl: dde bumped to version 1.2.1 for * win/tclWinDde.c: bundled release with Tcl 8.4.2 * library/reg/pkgIndex.tcl: registry bumped to version 1.1.1 for @@ -33,11 +4766,11 @@ 2003-02-28 Jeff Hobbs * win/configure: * win/configure.in: check for 'g' for debug build type, not 'd'. * win/rules.vc (DBGX): correct to use 'g' for nmake win makefile - to match the cygwin makefile for debug builds. [Bug #635107] + to match the cygwin makefile for debug builds. [Bug 635107] 2003-02-28 Vince Darley * doc/file.n: subcommand is 'file volumes' not 'file volume' @@ -49,91 +4782,90 @@ * tests/winTime.test: added note about PCI hardware dependency issues with high performance clock. 2003-02-27 Donal K. Fellows - * tests/lsearch.test (lsearch-10.7): - * generic/tclCmdIL.c (Tcl_LsearchObjCmd): Stopped -start option - from causing an option when used with an empty list. [Bug #694232] + * tests/lsearch.test (lsearch-10.7): + * generic/tclCmdIL.c (Tcl_LsearchObjCmd): Stopped -start option from + causing an option when used with an empty list. [Bug 694232] 2003-02-26 Chengye Mao * win/tclWinInit.c: fixed a bug in TclpSetVariables by initializing dwUserNameLen with the sizeof(szUserName) before calling GetUserName. Don't know if this bug has been recorded: it caused crash in starting Tcl or wish in Windows. -2003-02-26 Jeff Hobbs +2003-02-26 Jeff Hobbs * generic/tclCmdMZ.c (TraceCommandProc): Fix mem leak when - deleting a command that had trace on it. [Bug #693564] (sofer) + deleting a command that had trace on it. [Bug 693564] (sofer) -2003-02-25 Don Porter +2003-02-25 Don Porter * doc/pkgMkIndex.n: Modified [pkg_mkIndex] to use -nocase matching * library/package.tcl: of -load patterns, to better accomodate common user errors due to confusion between [package names] names and [info loaded] names. -2003-02-25 Andreas Kupries +2003-02-25 Andreas Kupries - * tests/pid.test: See below [Bug #678412]. - * tests/io.test: Made more robust against spaces in paths - [Bug #678400]. + * tests/pid.test: See below [Bug 678412]. + * tests/io.test: Made more robust against spaces in paths [Bug 678400] 2003-02-25 Miguel Sofer - * tests/execute.test: cleaning up testobj's at the end, to avoid - leak warning by valgrind. + * tests/execute.test: cleaning up testobj's at the end, to avoid leak + warning by valgrind. 2003-02-22 Zoran Vasiljevic - * generic/tclEvent.c (Tcl_FinalizeThread): Fix [Bug #571002] + * generic/tclEvent.c (Tcl_FinalizeThread): Fix [Bug 571002] 2003-02-21 Donal K. Fellows - * tests/binary.test (binary-44.[34]): + * tests/binary.test (binary-44.[34]): * generic/tclBinary.c (ScanNumber): Fixed problem with unwanted - sign-bit propagation when scanning wide ints. [Bug #690774] + sign-bit propagation when scanning wide ints. [Bug 690774] 2003-02-21 Daniel Steffen * mac/tclMacChan.c (TclpCutFileChannel, TclpSpliceFileChannel): Implemented missing cut and splice procs for file channels. 2003-02-21 Don Porter - * library/package.tcl (tclPkgUnknown): Minor performance tweaks - to reduce the number of [file] invocations. Meant to improve - startup times, at least a little bit. [Patch 687906] + * library/package.tcl (tclPkgUnknown): Minor performance tweaks to + reduce the number of [file] invocations. Meant to improve startup + times, at least a little bit. [Patch 687906] 2003-02-20 Daniel Steffen * unix/tcl.m4: - * unix/tclUnixPipe.c: (macosx) use vfork() instead of fork() to - create new processes, as recommended by Apple (vfork can be up to - 100 times faster thank fork on macosx). + * unix/tclUnixPipe.c: (macosx) use vfork() instead of fork() to create + new processes, as recommended by Apple (vfork can be up to 100 times + faster thank fork on macosx). * unix/configure: regen. 2003-02-20 Jeff Hobbs * generic/tclEncoding.c (LoadTableEncoding): - * library/encoding/cp932.enc: Correct jis round-trip encoding - * library/encoding/euc-jp.enc: by adding 'R' type to .enc files. - * library/encoding/iso2022-jp.enc: [Patch #689341] (koboyasi, taguchi) + * library/encoding/cp932.enc: Correct jis round-trip encoding + * library/encoding/euc-jp.enc: by adding 'R' type to .enc files. + * library/encoding/iso2022-jp.enc: [Patch 689341] (koboyasi, taguchi) * library/encoding/jis0208.enc: * library/encoding/shiftjis.enc: * tests/encoding.test: * unix/tclUnixChan.c (Tcl_MakeTcpClientChannel): add MakeTcpClientChannelMode that takes actual mode flags to avoid hang on OS X (may be OS X bug, but patch works x-plat). - [Bug #689835] (steffen) + [Bug 689835] (steffen) 2003-02-20 Donal K. Fellows - * doc/regsub.n: Typo fix [Bug #688943] + * doc/regsub.n: Typo fix [Bug 688943] 2003-02-19 Jeff Hobbs * unix/tclUnixThrd.c (TclpReaddir): * unix/tclUnixPort.h: update to Bug 689100 patch to ensure that @@ -140,101 +4872,98 @@ there is a defined value of MAXNAMLEN (aka NAME_MAX in POSIX) and that we have some buffer allocated. 2003-02-19 Daniel Steffen - * generic/tclStringObj.c: restored Tcl_SetObjLength() side-effect - of always invalidating unicode rep (if the obj has a string rep). - Added hasUnicode flag to String struct, allows decoupling of - validity of unicode rep from buffer size allocated to it (improves - memory allocation efficiency). [Bugs #686782, #671138, #635200] + * generic/tclStringObj.c: restored Tcl_SetObjLength() side-effect of + always invalidating unicode rep (if the obj has a string rep). Added + hasUnicode flag to String struct, allows decoupling of validity of + unicode rep from buffer size allocated to it (improves memory + allocation efficiency). [Bugs 686782, 671138, 635200] * macosx/Tcl.pbproj/project.pbxproj: * macosx/Makefile: reworked embedded build to no longer require relinking but to use install_name_tool instead to change the - install_names for embedded frameworks. [Bug #644510] - - * macosx/Tcl.pbproj/project.pbxproj: preserve mod dates when - running 'make install' to build framework (avoids bogus rebuilds - of dependent frameworks because tcl headers appear changed). - - * tests/ioCmd.test (iocmd-1.8): fix failure when system encoding - is utf-8: use iso8859-1 encoding explicitly. + install_names for embedded frameworks. [Bug 644510] + + * macosx/Tcl.pbproj/project.pbxproj: preserve mod dates when running + 'make install' to build framework (avoids bogus rebuilds of dependent + frameworks because tcl headers appear changed). + + * tests/ioCmd.test (iocmd-1.8): fix failure when system encoding is + utf-8: use iso8859-1 encoding explicitly. 2003-02-18 Miguel Sofer - * generic/tclCompile.c (TclCompileExprWords): remove unused - variable "range" [Bug 664743] - * generic/tclExecute.c (ExprSrandFunc): remove unused - variable "result" [Bug 664743] + * generic/tclCompile.c (TclCompileExprWords): remove unused variable + "range" [Bug 664743] + * generic/tclExecute.c (ExprSrandFunc): remove unused variable + "result" [Bug 664743] * generic/tclStringObj.c (UpdateStringOfString): remove unused variable "length" [Bug 664751] - * tests/execute.test (execute-7.30): fix for [Bug 664775] + * tests/execute.test (execute-7.30): fix for [Bug 664775] 2003-02-18 Andreas Kupries - * unix/tcl.m4: [Bug #651811] Added definition of _XOPEN_SOURCE and - linkage of 'xnet' library to HP 11 branch. This kills a lot of - socket-related failures in the testsuite when Tcl was compiled - in 64 bit mode (both PA-RISC 2.0W, and IA 64). + * unix/tcl.m4: [Bug 651811] Added definition of _XOPEN_SOURCE and + linkage of 'xnet' library to HP 11 branch. This kills a lot of + socket-related failures in the testsuite when Tcl was compiled in 64 + bit mode (both PA-RISC 2.0W, and IA 64). * unix/configure: Regenerated. 2003-02-18 Jeff Hobbs * generic/tclIO.c (HaveVersion): correctly decl static * unix/tclUnixThrd.c (TclpReaddir): reduce size of name string in - tsd to NAME_MAX instead of PATH_MAX. [Bug #689100] (waters) + tsd to NAME_MAX instead of PATH_MAX. [Bug 689100] (waters) 2003-02-18 Mo DeJong * unix/configure: Regen. - * unix/tcl.m4 (SC_ENABLE_THREADS): Make sure - -lpthread gets passed on the link line when - checking for the pthread_attr_setstacksize symbol. + * unix/tcl.m4 (SC_ENABLE_THREADS): Make sure -lpthread gets passed on + the link line when checking for the pthread_attr_setstacksize symbol. 2003-02-18 Vince Darley - * generic/tclTest.c: cleanup of new 'simplefs' test code, and - better documentation. + * generic/tclTest.c: cleanup of new 'simplefs' test code, and better + documentation. 2003-02-17 Miguel Sofer * generic/tclBasic.c (TclRenameCommand): fixing error in previous - commit. + commit. 2003-02-17 Jeff Hobbs * generic/tclExecute.c (TclExecuteByteCode INST_STR_MATCH): * generic/tclCmdMZ.c (Tcl_StringObjCmd STR_MATCH): * generic/tclUtf.c (TclUniCharMatch): - * generic/tclInt.decls: add private TclUniCharMatch function that + * generic/tclInt.decls: add private TclUniCharMatch function that * generic/tclIntDecls.h: does string match on counted unicode * generic/tclStubInit.c: strings. Tcl_UniCharCaseMatch has the - * tests/string.test: failing that it can't handle strings or - * tests/stringComp.test: patterns with embedded NULLs. Added + * tests/string.test: failing that it can't handle strings or + * tests/stringComp.test: patterns with embedded NULLs. Added tests that actually try strings/pats with NULLs. TclUniCharMatch should be TIPed and made public in the next minor version rev. 2003-02-17 Miguel Sofer - * generic/tclBasic.c (TclRenameCommand): 'oldFullName' object was - not being freed on all function exits, causing a memory leak - [Bug 684756] - + * generic/tclBasic.c (TclRenameCommand): 'oldFullName' object was not + being freed on all function exits, causing a memory leak. [Bug 684756] + 2003-02-17 Mo DeJong - * generic/tclIO.c (Tcl_GetsObj): Minor change - so that eol is only assigned at the top of the - TCL_TRANSLATE_AUTO case block. The other cases - assign eol so this does not change any functionality. + * generic/tclIO.c (Tcl_GetsObj): Minor change so that eol is only + assigned at the top of the TCL_TRANSLATE_AUTO case block. The other + cases assign eol so this does not change any functionality. 2003-02-17 Kevin Kenny * tests/notify.test: Removed Windows line terminators. [Bug 687913]. - + 2003-02-15 Miguel Sofer * generic/tclBasic.c (Tcl_EvalEx): * generic/tclCompExpr.c (CompileSubExpr): * generic/tclCompile.c (TclCompileScript): @@ -248,23 +4977,23 @@ * tests/subst.test (8.6): Don Porter's fix for bad parsing of nested scripts [Bug 681841]. 2003-02-15 Kevin Kenny - * tests/notify.test (new-file): + * tests/notify.test (new-file): * generic/tclTest.c (TclTest_Init, EventtestObjCmd, EventtestProc, - EventTestDeleteProc): + (EventTestDeleteProc): * generic/tclNotify.c (Tcl_DeleteEvents): Fixed Tcl_DeleteEvents not to get a pointer smash when deleting the last event in the queue. Added test code in 'tcltest' and a new file of test cases 'notify.test' to exercise this functionality; several of the new test cases fail for the original code and pass for the corrected code. [Bug 673714] * unix/tclUnixTest.c (TestfilehandlerCmd): Corrected a couple of typos in error messages. [Bug 596027] - + 2003-02-14 Jeff Hobbs * README: Bumped to version 8.4.2. * generic/tcl.h: * tools/tcl.wse.in: @@ -281,93 +5010,89 @@ * unix/tcl.m4: correct HP-UX ia64 --enable-64bit build flags 2003-02-14 Kevin Kenny - * win/tclWinTime.c: Added code to test and compensate for - forward leaps of the performance counter. See the MSDN Knowledge - Base article Q274323 for the hardware problem that makes this - necessary on certain machines. - * tests/winTime.test: Revised winTime-2.1 - it had a tolerance - of thousands of seconds, rather than milliseconds. (What's six - orders of magnitude among friends? + * win/tclWinTime.c: Added code to test and compensate for forward + leaps of the performance counter. See the MSDN Knowledge Base article + Q274323 for the hardware problem that makes this necessary on certain + machines. + * tests/winTime.test: Revised winTime-2.1 - it had a tolerance of + thousands of seconds, rather than milliseconds. (What's six orders of + magnitude among friends? + Both the above changes are triggered by a problem reported at http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/1536811 - although the developers find it difficult to believe that it - accounts for the observed behavior and suspect a fault in the - RTC chip. + although the developers find it difficult to believe that it accounts + for the observed behavior and suspect a fault in the RTC chip. 2003-02-13 Kevin Kenny - * win/tclWinInit.c: Added conversion from the system encoding - to tcl_platform(user), so that it works with non-ASCII7 user names. - [Bug 685926] - + * win/tclWinInit.c: Added conversion from the system encoding to + tcl_platform(user), so that it works with non-ASCII7 user names. [Bug + 685926] + * doc/tclsh.1: Added language to describe the handling of the - end-of-file character \u001a embedded in a script file. - [Bug 685485] - + end-of-file character \u001a embedded in a script file. [Bug 685485] + 2003-02-11 Vince Darley * tests/fileName.test: - * unix/tclUnixFile.c: fix for [Bug 685445] when using 'glob -l' - on broken symbolic links. Added two new tests for this bug. + * unix/tclUnixFile.c: fix for [Bug 685445] when using 'glob -l' on + broken symbolic links. Added two new tests for this bug. 2003-02-11 Kevin Kenny - * tests/http.test: Corrected a problem where http-4.14 would fail - when run in an environment with a proxy server. Replaced references - to scriptics.com by tcl.tk. - + * tests/http.test: Corrected a problem where http-4.14 would fail when + run in an environment with a proxy server. Replaced references to + scriptics.com by tcl.tk. + 2003-02-11 Jeff Hobbs * tests/lsearch.test: * generic/tclCmdIL.c (Tcl_LsearchObjCmd): protect against the case that lsearch -regepx list and pattern objects are equal. * tests/stringObj.test: * generic/tclStringObj.c (Tcl_GetCharLength): correct ascii char - opt of 2002-11-11 to not stop early on \x00. [Bug #684699] + opt of 2002-11-11 to not stop early on \x00. [Bug 684699] * tests.parse.test: remove excess EOF whitespace * generic/tclParse.c (CommandComplete): more paranoid check to break on (p >= end) instead of just (p == end). 2003-02-11 Miguel Sofer - * generic/tclParse.c (CommandComplete): + * generic/tclParse.c (CommandComplete): * tests/parse.test: fix for [Bug 684744], by Don Porter. 2003-02-11 Jeff Hobbs - * generic/tclIOUtil.c (Tcl_FSJoinPath, Tcl_FSGetNormalizedPath): + * generic/tclIOUtil.c (Tcl_FSJoinPath, Tcl_FSGetNormalizedPath): (UpdateStringOfFsPath): revert the cwdLen == 0 check and instead follow a different code path in Tcl_FSJoinPath. (Tcl_FSConvertToPathType, Tcl_FSGetNormalizedPath): (Tcl_FSGetFileSystemForPath): Update string rep of path objects before freeing the internal object. (darley) * tests/fileSystem.test: added test 8.3 - * generic/tclIOUtil.c (Tcl_FSGetNormalizedPath): - (UpdateStringOfFsPath): handle the cwdLen == 0 case + * generic/tclIOUtil.c (Tcl_FSGetNormalizedPath): + (UpdateStringOfFsPath): handle the cwdLen == 0 case * unix/tclUnixFile.c (TclpMatchInDirectory): simplify the hidden file match check. 2003-02-10 Mo DeJong * win/configure: - * win/configure.in: Generate error when attempting - to build under Cygwin. The Cygwin port of Tcl/Tk - does not build and people are filing bug reports - under the mistaken impression that someone is - actually maintaining the Cygwin port. A post to - comp.lang.tcl asking someone to volunteer as an - area maintainer has generated no results. - Closing bugs 680840, 630199, and 634772 and - marking as "Won't fix". + * win/configure.in: Generate error when attempting to build under + Cygwin. The Cygwin port of Tcl/Tk does not build and people are filing + bug reports under the mistaken impression that someone is actually + maintaining the Cygwin port. A post to comp.lang.tcl asking someone to + volunteer as an area maintainer has generated no results. Closing + [Bugs 680840, 630199, 634772] and marking as "Won't fix". 2003-02-10 Donal K. Fellows * doc/append.n: Return value was not documented. [Bug 683188] @@ -378,83 +5103,76 @@ * generic/tclInt.h: * tests/fileSystem.test: * unix/tclUnixFCmd.c: * unix/tclUnixFile.c: * win/tclWinFile.c: further filesystem optimization, applying - [Patch 682500]. In particular, these code examples are - faster now: - foreach f $flist { if {[file exists $f]} {file stat $f arr;...}} - foreach f [glob -dir $dir *] { # action and/or recursion on $f } - cd $dir - foreach f [glob *] { # action and/or recursion on $f } - cd .. - - * generic/tclTest.c: Fix for [Bug 683181] where test suite - left files in 'tmp'. + [Patch 682500]. In particular, these code examples are faster now: + foreach f $flist { if {[file exists $f]} {file stat $f arr;...}} + foreach f [glob -dir $dir *] { # action and/or recursion on $f } + cd $dir + foreach f [glob *] { # action and/or recursion on $f } + cd .. + + * generic/tclTest.c: Fix for [Bug 683181] where test suite left files + in 'tmp'. 2003-02-08 Jeff Hobbs * library/safe.tcl: code cleanup of eval and string comp use. 2003-02-07 Vince Darley * win/tclWinFCmd.c: cleanup long lines - * win/tclWinFile.c: sped up pure 'glob' by a factor of 2.5 - ('foreach f [glob *] { file exists $f }' is still slow) + * win/tclWinFile.c: sped up pure 'glob' by a factor of 2.5 ('foreach f + [glob *] { file exists $f }' is still slow) * tests/fileSystem.text: - * tests/fileName.test: added new tests to ensure correct - behaviour in optimized filesystem code. + * tests/fileName.test: added new tests to ensure correct behaviour in + optimized filesystem code. 2003-02-07 Vince Darley * generic/tclTest.c: - * tests/fileSystem.text: fixed test 7.2 to avoid a possible - crash, and not change the pwd. - - * tests/http.text: added comment to test 4.15, that it may - fail if you use a proxy server. - -2003-02-06 Mo DeJong - - * generic/tclCompCmds.c (TclCompileIncrCmd): - * tests/incr.test: Don't include the text - "(increment expression)" in the errorInfo - generated by the compiled version of the - incr command since it does not match the - message generated by the non-compiled version - of incr. It is also not possible to match - this error output under Jacl, which does - not support a compiler. - -2003-02-06 Mo DeJong - - * generic/tclExecute.c (TclExecuteByteCode): When an - error is encountered reading the increment value during - a compiled call to incr, add a "(reading increment)" - error string to the errorInfo variable. This makes - the errorInfo variable set by the compiled incr command - match the value set by the non-compiled version. - * tests/incr-old.test: Change errorInfo result for - the compiled incr command case to match the modified - implementation. - * tests/incr.test: Add tests to make sure the compiled - and non-compiled errorInfo messages are the same. - -2003-02-06 Don Porter - - * library/tcltest/tcltest.tcl: Filename arguments to [outputChannel] - and [errorChannel] (also -outfile and -errfile) were [open]ed but - never [closed]. Also, [cleanupTests] could remove output or error - files. [Bug 676978]. + * tests/fileSystem.text: fixed test 7.2 to avoid a possible crash, and + not change the pwd. + + * tests/http.text: added comment to test 4.15, that it may fail if you + use a proxy server. + +2003-02-06 Mo DeJong + + * generic/tclCompCmds.c (TclCompileIncrCmd): + * tests/incr.test: Don't include the text "(increment expression)" in + the errorInfo generated by the compiled version of the incr command + since it does not match the message generated by the non-compiled + version of incr. It is also not possible to match this error output + under Jacl, which does not support a compiler. + +2003-02-06 Mo DeJong + + * generic/tclExecute.c (TclExecuteByteCode): When an error is + encountered reading the increment value during a compiled call to + incr, add a "(reading increment)" error string to the errorInfo + variable. This makes the errorInfo variable set by the compiled incr + command match the value set by the non-compiled version. + * tests/incr-old.test: Change errorInfo result for the compiled incr + command case to match the modified implementation. + * tests/incr.test: Add tests to make sure the compiled and + non-compiled errorInfo messages are the same. + +2003-02-06 Don Porter + + * library/tcltest/tcltest.tcl: Filename arguments to [outputChannel] + and [errorChannel] (also -outfile and -errfile) were [open]ed but + never [closed]. Also, [cleanupTests] could remove output or error + files. [Bug 676978]. * library/tcltest/pkgIndex.tcl: Bumped to version 2.2.2. 2003-02-05 Mo DeJong * tests/interp.test: - * tests/set-old.test: Run test cases that depend - on hash order through lsort so that the tests - also pass under Jacl. Does not change test + * tests/set-old.test: Run test cases that depend on hash order through + lsort so that the tests also pass under Jacl. Does not change test results under Tcl. 2003-02-04 Vince Darley * generic/tclIOUtil.c: @@ -464,465 +5182,425 @@ * unix/tclUnixFCmd.c: * win/tclWin32Dll.c: * win/tclWinFCmd.c: * win/tclWinInit.c: * win/tclWinInt.h: - * tests/fileSystem.test: fix to finalization/unloading/encoding - issues to make filesystem much less dependent on encodings for - its cleanup, and therefore allow it to be finalized later in the - exit process. This fixes fileSystem.test-7.1. Also fixed one - more bug in setting of modification dates of files which have - undergone cross-platform copies. [Patch 676271] - + * tests/fileSystem.test: fix to finalization/unloading/encoding issues + to make filesystem much less dependent on encodings for its cleanup, + and therefore allow it to be finalized later in the exit process. This + fixes fileSystem.test-7.1. Also fixed one more bug in setting of + modification dates of files which have undergone cross-platform + copies. [Patch 676271] + * tests/basic.test: * tests/exec.test: * tests/fileName.test: - * tests/io.test: fixed some test failures when tests are run - from a directory containing spaces. - + * tests/io.test: fixed some test failures when tests are run from a + directory containing spaces. + * tests/fileSystem.test: * generic/tclTest.c: added regression test for the modification date setting of cross-platform file copies. - + 2003-02-03 Kevin Kenny * generic/tclBasic.c: Changed [trace add command] so that 'rename' - callbacks get fully qualified names of the command. [Bug - 651271]. ***POTENTIAL INCOMPATIBILITY*** - * tests/trace.test: Modified the test cases for [trace add - command] to expect fully qualified names on the 'rename' - callbacks. Added a case for renaming a proc within a namespace. - * doc/trace.n: Added language about use of fully qualified names - in trace callbacks. - + callbacks get fully qualified names of the command. [Bug 651271]. + ***POTENTIAL INCOMPATIBILITY*** + * tests/trace.test: Modified the test cases for [trace add command] to + expect fully qualified names on the 'rename' callbacks. Added a case + for renaming a proc within a namespace. + * doc/trace.n: Added language about use of fully qualified names in + trace callbacks. + 2003-02-01 Kevin Kenny * generic/tclCompCmds.c: Removed an unused variable that caused compiler warnings on SGI. [Bug 664379] - - * generic/tclLoad.c: Changed the code so that if Tcl_StaticPackage - is called to report the same package as being loaded in two interps, - it shows up in [info loaded {}] in both of them (previously, - it didn't appear in the static package list in the second. - - * tests/load.test Added regression test for the above bug. - [Bug 670042] - - * generic/tclClock.c: Fixed a bug that incorrectly allowed - [clock clicks {}] and [clock clicks -] to be accepted as if - they were [clock clicks -milliseconds]. - - * tests/clock.test: Added regression tests for the above bug. - [Bug 675356] - - * tests/unixNotfy.test: Added cleanup of working files - [Bug 675609] - + + * generic/tclLoad.c: Changed the code so that if Tcl_StaticPackage is + called to report the same package as being loaded in two interps, it + shows up in [info loaded {}] in both of them (previously, it didn't + appear in the static package list in the second. + + * tests/load.test Added regression test for the above bug. [Bug + 670042] + + * generic/tclClock.c: Fixed a bug that incorrectly allowed [clock + clicks {}] and [clock clicks -] to be accepted as if they were [clock + clicks -milliseconds]. + + * tests/clock.test: Added regression tests for the above bug. [Bug + 675356] + + * tests/unixNotfy.test: Added cleanup of working files [Bug 675609] + * doc/Tcl.n: Added headings to the eleven paragraphs, to improve formatting in the tools that attempt to extract tables of contents from the manual pages. [Bug 627455] - * generic/tclClock.c: Expanded mutex protection around the setting - of env(TZ) and the thread-unsafe call to tzset(). [Bug 656660] - + * generic/tclClock.c: Expanded mutex protection around the setting of + env(TZ) and the thread-unsafe call to tzset(). [Bug 656660] + 2003-01-31 Don Porter * tests/tcltest.test: Cleaned up management of file/directory - creation/deletion to improve "-debug 1" output. [Bug 675614] - The utility [slave] command failed to properly [list]-quote a - constructed [open] command, causing failure when the pathname - contained whitespace. [Bug 678415] + creation/deletion to improve "-debug 1" output. [Bug 675614] The + utility [slave] command failed to properly [list]-quote a constructed + [open] command, causing failure when the pathname contained + whitespace. [Bug 678415] * tests/main.test: Stopped main.test from deleting existing file. Test suite should not delete files that already exist. [Bug 675660] 2003-01-28 Don Porter - * tests/main.test: Constrain tests that do not work on Windows. - [Bug 674387] + * tests/main.test: Constrain tests that do not work on Windows. [Bug + 674387] 2003-01-28 Vince Darley - * generic/tclIOUtil.c: fix to setting modification date - in TclCrossFilesystemCopy. Also added 'panic' in - Tcl_FSGetFileSystemForPath under illegal calling circumstances - which lead to hard-to-track-down bugs. - - * generic/tclTest.c: added test suite code to allow - exercising a vfs-crash-on-exit bug in Tcl's finalization caused - by the encodings being cleaned up before unloading occurs. - * tests/fileSystem.test: added new 'knownBug' test 7.1 - to demonstrate the crash on exit. + * generic/tclIOUtil.c: fix to setting modification date in + TclCrossFilesystemCopy. Also added 'panic' in + Tcl_FSGetFileSystemForPath under illegal calling circumstances which + lead to hard-to-track-down bugs. + + * generic/tclTest.c: added test suite code to allow exercising a + vfs-crash-on-exit bug in Tcl's finalization caused by the encodings + being cleaned up before unloading occurs. + * tests/fileSystem.test: added new 'knownBug' test 7.1 to demonstrate + the crash on exit. 2003-01-28 Mo DeJong - * generic/tcl.h: Add TCL_PREFIX_IDENT and - TCL_DEBUG_IDENT, used only by TclpCreateProcess. + * generic/tcl.h: Add TCL_PREFIX_IDENT and TCL_DEBUG_IDENT, used only + by TclpCreateProcess. * unix/Makefile.in: Define TCL_DBGX. * win/Makefile.in: Define TCL_DBGX. - * win/tclWinPipe.c (TclpCreateProcess): - Check that the Tcl pipe dll actually exists - in the Tcl bin directory and panic if it - is not found. Incorporate TCL_DBGX into - the Tcl pipe dll name. This fixes a really - mysterious error that would show up when - exec'ing a 16 bit application under Win95 - or Win98 when Tcl was compiled with symbols. - The error seemed to indicate that the executable - could not be found, but it was actually the - Tcl pipe dll that could not be found. + * win/tclWinPipe.c (TclpCreateProcess): Check that the Tcl pipe dll + actually exists in the Tcl bin directory and panic if it is not + found. Incorporate TCL_DBGX into the Tcl pipe dll name. This fixes a + really mysterious error that would show up when exec'ing a 16 bit + application under Win95 or Win98 when Tcl was compiled with symbols. + The error seemed to indicate that the executable could not be found, + but it was actually the Tcl pipe dll that could not be found. 2003-01-26 Mo DeJong - * win/README: Update msys+mingw URL to release 6. - This version bundles gcc 3. + * win/README: Update msys+mingw URL to release 6. This version bundles + gcc 3. 2003-01-26 Mo DeJong * win/configure: Regen. - * win/configure.in: Add test that checks to - see if the compiler can cast to a union type. - * win/tclWinTime.c: Squelch compiler warning - about union initializer by casting to union - type when compiling with gcc. + * win/configure.in: Add test that checks to see if the compiler can + cast to a union type. + * win/tclWinTime.c: Squelch compiler warning about union initializer + by casting to union type when compiling with gcc. 2003-01-25 Mo DeJong - * generic/tclIO.c (Tcl_CutChannel, Tcl_SpliceChannel): - Invoke TclpCutFileChannel and TclpSpliceFileChannel. - * generic/tclInt.h: Declare TclpCutFileChannel - and TclpSpliceFileChannel. + * generic/tclIO.c (Tcl_CutChannel, Tcl_SpliceChannel): Invoke + TclpCutFileChannel and TclpSpliceFileChannel. + * generic/tclInt.h: Declare TclpCutFileChannel and + TclpSpliceFileChannel. * unix/tclUnixChan.c (FileCloseProc, TclpOpenFileChannel, - Tcl_MakeFileChannel, TclpCutFileChannel, - TclpSpliceFileChannel): Implement thread load data - cut and splice for file channels. This avoids - an invalid memory ref when compiled with -DDEPRECATED. + (Tcl_MakeFileChannel, TclpCutFileChannel, + (TclpSpliceFileChannel): Implement thread load data cut and splice for + file channels. This avoids an invalid memory ref when compiled with + -DDEPRECATED. * win/tclWinChan.c (FileCloseProc, TclpCutFileChannel, - TclpSpliceFileChannel): Implement thread load data - cut and splice for file channels. This avoids - an invalid memory ref that was showing up in the - thread extension. + (TclpSpliceFileChannel): Implement thread load data cut and splice for + file channels. This avoids an invalid memory ref that was showing up + in the thread extension. 2003-01-25 Mo DeJong * win/tclWin32Dll.c (TclpCheckStackSpace, squelch_warnings): * win/tclWinChan.c (Tcl_MakeFileChannel, squelch_warnings): * win/tclWinFCmd.c (DoRenameFile, DoCopyFile, squelch_warnings): - Re-implement inline ASM SEH handlers for gcc. - The esp and ebp registers are now saved on the - stack instead of in global variables so that - the code is thread safe. Add additional checks - when TCL_MEM_DEBUG is defined to be sure the - values were recovered from the stack properly. - Remove squelch_warnings functions and add - a dummy call in the handler methods to squelch - compiler warnings. + Re-implement inline ASM SEH handlers for gcc. The esp and ebp + registers are now saved on the stack instead of in global variables so + that the code is thread safe. Add additional checks when TCL_MEM_DEBUG + is defined to be sure the values were recovered from the stack + properly. Remove squelch_warnings functions and add a dummy call in + the handler methods to squelch compiler warnings. 2003-01-25 Mo DeJong * win/configure: - * win/configure.in: Define HAVE_ALLOCA_GCC_INLINE - when we detect that no alloca function is found - in malloc.h and we are compiling with GCC. - Remove HAVE_NO_ALLOC_DECL define. - * win/tclWin32Dll.c (TclpCheckStackSpace): - Don't define alloca as a cdecl function. - Doing this caused a tricky runtime bug because - the _alloca function expects the size argument - to be passed in a register and not on the stack. - To fix this problem, we use inline ASM when - compiling with gcc to invoke _alloca with the - size argument loaded into a register. + * win/configure.in: Define HAVE_ALLOCA_GCC_INLINE when we detect that + no alloca function is found in malloc.h and we are compiling with + GCC. Remove HAVE_NO_ALLOC_DECL define. + * win/tclWin32Dll.c (TclpCheckStackSpace): Don't define alloca as a + cdecl function. Doing this caused a tricky runtime bug because the + _alloca function expects the size argument to be passed in a register + and not on the stack. To fix this problem, we use inline ASM when + compiling with gcc to invoke _alloca with the size argument loaded + into a register. 2003-01-24 Jeff Hobbs * win/tclWinDde.c (Dde_Init): clarified use of tsdPtr. (DdeServerProc): better refcount handling of returnPackagePtr. * generic/tclEvent.c (Tcl_Finalize): revert finalize change on - 2002-12-04 to correct the issue with extensions that have TSD - needing to finalize that before they are unloaded. This issue - needs further clarification. + 2002-12-04 to correct the issue with extensions that have TSD needing + to finalize that before they are unloaded. This issue needs further + clarification. * tests/unixFCmd.test: only do groups check on unix 2003-01-24 Vince Darley - * generic/tclStringObj.c: proper fixes for Tcl_SetObjLength and - Tcl_AttemptSetObjectLength dealing with string objects with - both pure-unicode and normal internal representations. - Previous fix didn't handle all cases correctly. - * generic/tclIO.c: Add 'Tcl_GetString()' to ensure the object has - a valid 'objPtr->bytes' field before manipulating it directly. - - This fixes [Bug 635200] and [Bug 671138], but may reduce performance - of Unicode string handling in some cases. A further patch will - be applied to address this, once the code is known to be correct. + * generic/tclStringObj.c: proper fixes for Tcl_SetObjLength and + Tcl_AttemptSetObjectLength dealing with string objects with both + pure-unicode and normal internal representations. Previous fix didn't + handle all cases correctly. + * generic/tclIO.c: Add 'Tcl_GetString()' to ensure the object has a + valid 'objPtr->bytes' field before manipulating it directly. + + This fixes [Bug 635200] and [Bug 671138], but may reduce performance + of Unicode string handling in some cases. A further patch will be + applied to address this, once the code is known to be correct. 2003-01-24 Mo DeJong * win/configure: Regen. - * win/configure.in: Add test to see if alloca - is undefined in malloc.h. - * win/tclWin32Dll.c (TclpCheckStackSpace): Rework - the SEH exception handler logic to avoid using - the stack since alloca will modify the stack. - This was causing a nasty bug that would set the - exception handler to 0 because it tried to pop - the previous exception handler off the top of - the stack. + * win/configure.in: Add test to see if alloca is undefined in + malloc.h. + * win/tclWin32Dll.c (TclpCheckStackSpace): Rework the SEH exception + handler logic to avoid using the stack since alloca will modify the + stack. This was causing a nasty bug that would set the exception + handler to 0 because it tried to pop the previous exception handler + off the top of the stack. 2003-01-23 Donal K. Fellows - * doc/lset.n: Fixed fault in return values from lset in - documentation examples [SF Bug #658463] and tidied up a bit at the - same time. + * doc/lset.n: Fixed fault in return values from lset in documentation + examples [Bug 658463] and tidied up a bit at the same time. 2003-01-21 Joe English * doc/namespace.n (namespace inscope): Clarified documentation - [SF Patch #670110] + [Patch 670110] 2003-01-21 Mo DeJong * win/configure: Regen. - * win/tcl.m4 (SC_CONFIG_CFLAGS): Set SHLIB_SUFFIX - so that TCL_SHLIB_SUFFIX will be set to a useful - value in the generated tclConfig.sh. - Set SHLIB_LD_LIBS to "" or '${LIBS}' based on - the --enable-shared flag. This matches the - UNIX implementation. + * win/tcl.m4 (SC_CONFIG_CFLAGS): Set SHLIB_SUFFIX so that + TCL_SHLIB_SUFFIX will be set to a useful value in the generated + tclConfig.sh. Set SHLIB_LD_LIBS to "" or '${LIBS}' based on the + --enable-shared flag. This matches the UNIX implementation. 2003-01-18 Jeff Hobbs * generic/tclCkalloc.c: change %ud to %u as appropriate. 2003-01-17 Mo DeJong - * win/tclWinDde.c (DdeServerProc): Deallocate - the Tcl_Obj returned by ExecuteRemoteObject - if it was not saved in a connection object. + * win/tclWinDde.c (DdeServerProc): Deallocate the Tcl_Obj returned by + ExecuteRemoteObject if it was not saved in a connection object. 2003-01-17 Mo DeJong - * generic/tcl.h: Revert earlier change that - defined TCL_WIDE_INT_TYPE as long long and - TCL_LL_MODIFIER as L when compiling with - mingw. This change ended up causing some - test case failures when compiling with mingw. - * generic/tclObj.c (UpdateStringOfWideInt): - Describe the warning generated by mingw and - why it needs to be ignored so that someone - is not tempted to "fix" this problem again - in the future. + * generic/tcl.h: Revert earlier change that defined TCL_WIDE_INT_TYPE + as long long and TCL_LL_MODIFIER as L when compiling with mingw. This + change ended up causing some test case failures when compiling with + mingw. + * generic/tclObj.c (UpdateStringOfWideInt): Describe the warning + generated by mingw and why it needs to be ignored so that someone is + not tempted to "fix" this problem again in the future. 2003-01-16 Vince Darley - * generic/tclStringObj.c: Tcl_SetObjLength fix for when - the object has a unicode string rep. Fixes [Bug 635200] - * tests/stringObj.test: removed 'knownBug' constraint from - test 14.1 now that this bug is fixed. - + * generic/tclStringObj.c: Tcl_SetObjLength fix for when the object has + a unicode string rep. Fixes [Bug 635200] + * tests/stringObj.test: removed 'knownBug' constraint from test 14.1 + now that this bug is fixed. + * generic/tclInt.h: * generic/tclBasic.c: * generic/tclCmdMZ.z: * tests/trace.test: execution and command tracing bug fixes and - cleanup. In particular fixed [Bug 655645], [Bug 615043], - [Bug 571385] - - fixed some subtle cleanup problems with tracing. This - required replacing Tcl_Preserve/Tcl_Release with a more - robust refCount approach. Solves at least one known crash - caused by memory corruption. - - fixed some confusion in the code between new style traces - (Tcl 8.4) and the very limited 'Tcl_CreateTrace' which existed - before. - - made behaviour consistent with documentation (several - tests even contradicted the documentation before). + cleanup. In particular fixed [Bugs 655645, 615043, 571385] + - fixed some subtle cleanup problems with tracing. This required + replacing Tcl_Preserve/Tcl_Release with a more robust refCount + approach. Solves at least one known crash caused by memory + corruption. + - fixed some confusion in the code between new style traces (Tcl + 8.4) and the very limited 'Tcl_CreateTrace' which existed before. + - made behaviour consistent with documentation (several tests even + contradicted the documentation before). - fixed some minor error message details - added a number of new tests 2003-01-16 Jeff Hobbs - * win/tclWinSerial.c (SerialOutputProc): add casts for - bytesWritten to allow strict compilation (no warnings). + * win/tclWinSerial.c (SerialOutputProc): add casts for bytesWritten to + allow strict compilation (no warnings). * tests/winDde.test: - * win/tclWinDde.c (Tcl_DdeObjCmd): Prevent crash when empty - service name is passed to 'dde eval' and goto errorNoResult in - request and poke error cases to free up any allocated data. + * win/tclWinDde.c (Tcl_DdeObjCmd): Prevent crash when empty service + name is passed to 'dde eval' and goto errorNoResult in request and + poke error cases to free up any allocated data. 2003-01-16 Mo DeJong - * win/tclWin32Dll.c (squelch_warnings): Squelch - compiler warnings from SEH ASM code. - * win/tclWinChan.c (squelch_warnings): Squelch - compiler warnings from SEH ASM code. - * win/tclWinDde.c: Add casts to avoid compiler - warnings. Pass pointer to DWORD instead of int - to avoid compiler warnings. - * win/tclWinFCmd.c (squelch_warnings): Add casts - and fixup decls to avoid compiler warnings. - Squelch compiler warnings from SEH ASM code. - * win/tclWinFile.c: Add casts and fixup decls - to avoid compiler warnings. Remove unused variable. - * win/tclWinNotify.c: Declare as DWORD instead - of int to avoid compiler warning. - * win/tclWinReg.c: Add casts to avoid compiler - warning. Fix assignment in if expression bug. - * win/tclWinSerial.c: Add casts to avoid compiler + * win/tclWin32Dll.c (squelch_warnings): Squelch compiler warnings from + SEH ASM code. + * win/tclWinChan.c (squelch_warnings): Squelch compiler warnings from + SEH ASM code. + * win/tclWinDde.c: Add casts to avoid compiler warnings. Pass pointer + to DWORD instead of int to avoid compiler warnings. + * win/tclWinFCmd.c (squelch_warnings): Add casts and fixup decls to + avoid compiler warnings. Squelch compiler warnings from SEH ASM code. + * win/tclWinFile.c: Add casts and fixup decls to avoid compiler warnings. Remove unused variable. - * win/tclWinSock.c: Add casts and fixup decls - to avoid compiler warnings. + * win/tclWinNotify.c: Declare as DWORD instead of int to avoid + compiler warning. + * win/tclWinReg.c: Add casts to avoid compiler warning. Fix assignment + in if expression bug. + * win/tclWinSerial.c: Add casts to avoid compiler warnings. Remove + unused variable. + * win/tclWinSock.c: Add casts and fixup decls to avoid compiler + warnings. 2003-01-14 Jeff Hobbs - * generic/tclClock.c (FormatClock): corrected typo that - incorrectly conditionally defined savedTZEnv and savedTimeZone. + * generic/tclClock.c (FormatClock): corrected typo that incorrectly + conditionally defined savedTZEnv and savedTimeZone. 2003-01-13 Mo DeJong Fix mingw build problems and compiler warnings. - * generic/tcl.h: Add if defined(__MINGW32__) - check to code that sets the TCL_WIDE_INT_TYPE - and TCL_LL_MODIFIER. - * generic/tclClock.c (FormatClock): Don't - define savedTimeZone and savedTZEnv if - we are not going to use them. - * generic/tclEnv.c: Add cast to avoid warning. - * win/tclWinChan.c: Use DWORD instead of int - to avoid compiler warning. - * win/tclWinThrd.c: Only define allocLock, - allocLockPtr, and dataKey when TCL_THREADS - is defined. This avoid a compiler warning - about unused variables. - -2003-01-12 Mo DeJong - - * win/README: Update msys + mingw URL, the - new release includes the released 1.0.8 - version of msys which includes a number - of bug fixes. - -2003-01-12 Mo DeJong - - * win/configure: Regen. - * win/tcl.m4 (SC_CONFIG_CFLAGS): Pull in - addition of shell32.lib to LIBS_GUI that - was added to the Tk tcl.m4 but never made - it back into the Tcl version. - -2003-01-12 Mo DeJong - - * generic/tcl.h: Skip Tcl's define of CHAR, - SHORT, and LONG when HAVE_WINNT_IGNORE_VOID - is defined. This avoids a bunch of compiler - warnings when building with Cygwin or Mingw. - * win/configure: Regen. - * win/configure.in: Define HAVE_WINNT_IGNORE_VOID - when we detect a winnt.h that still defines - CHAR, SHORT, and LONG when VOID has already - been defined. - * win/tcl.m4 (SC_LOAD_TCLCONFIG): Subst the - TCL_DEFS loaded from tclConfig.sh so that - Tcl defines can make it into the Tk Makefile. - -2003-01-12 Mo DeJong - - * win/configure: Regen. - * win/configure.in: Check for typedefs like LPFN_ACCEPT - in winsock2.h and define HAVE_NO_LPFN_DECLS if not found. - * win/tclWinSock.c: Define LPFN_* typedefs if - HAVE_NO_LPFN_DECLS is defined. This fixes the build - under Mingw and Cygwin, it was broken by the changes - made on 2002-11-26. - -2003-01-10 Vince Darley - - * 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 filesystem. - - * win/makefile.vc: fix to minor VC++ 5.2 syntax problem - -2003-01-09 Don Porter - - * generic/tclCompCmds.c (TclCompilerReturnCmd): Corrected off-by-one - problem with recent commit. [Bug 633204] - -2003-01-09 Vince Darley - - * generic/tclFileName.c: remove unused variable 'macSpecialCase' - [Bug 664749] - + * generic/tcl.h: Add if defined(__MINGW32__) check to code that sets + the TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER. + * generic/tclClock.c (FormatClock): Don't define savedTimeZone and + savedTZEnv if we are not going to use them. + * generic/tclEnv.c: Add cast to avoid warning. + * win/tclWinChan.c: Use DWORD instead of int to avoid compiler warning + * win/tclWinThrd.c: Only define allocLock, allocLockPtr, and dataKey + when TCL_THREADS is defined. This avoid a compiler warning about + unused variables. + +2003-01-12 Mo DeJong + + * win/README: Update msys + mingw URL, the new release includes the + released 1.0.8 version of msys which includes a number of bug fixes. + +2003-01-12 Mo DeJong + + * win/configure: Regen. + * win/tcl.m4 (SC_CONFIG_CFLAGS): Pull in addition of shell32.lib to + LIBS_GUI that was added to the Tk tcl.m4 but never made it back into + the Tcl version. + +2003-01-12 Mo DeJong + + * generic/tcl.h: Skip Tcl's define of CHAR, SHORT, and LONG when + HAVE_WINNT_IGNORE_VOID is defined. This avoids a bunch of compiler + warnings when building with Cygwin or Mingw. + * win/configure: Regen. + * win/configure.in: Define HAVE_WINNT_IGNORE_VOID when we detect a + winnt.h that still defines CHAR, SHORT, and LONG when VOID has already + been defined. + * win/tcl.m4 (SC_LOAD_TCLCONFIG): Subst the TCL_DEFS loaded from + tclConfig.sh so that Tcl defines can make it into the Tk Makefile. + +2003-01-12 Mo DeJong + + * win/configure: Regen. + * win/configure.in: Check for typedefs like LPFN_ACCEPT in winsock2.h + and define HAVE_NO_LPFN_DECLS if not found. + * win/tclWinSock.c: Define LPFN_* typedefs if HAVE_NO_LPFN_DECLS is + defined. This fixes the build under Mingw and Cygwin, it was broken by + the changes made on 2002-11-26. + +2003-01-10 Vince Darley + + * 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 + filesystem. + + * win/makefile.vc: fix to minor VC++ 5.2 syntax problem + +2003-01-09 Don Porter + + * generic/tclCompCmds.c (TclCompilerReturnCmd): Corrected off-by-one + problem with recent commit. [Bug 633204] + +2003-01-09 Vince Darley + + * generic/tclFileName.c: remove unused variable 'macSpecialCase' [Bug + 664749] + * generic/tclIOUtil.c: * generic/tclInt.h: * unix/tclUnixFile.c: * mac/tclMacFile.c: * win/tclWinFile.c: * win/tclWinInt.h: - * win/tclWin32Dll.c: - * tests/cmdAH.test: fix to non-ascii chars in paths when - setting mtime and atime through 'file (a|m)time $path $time' - [Bug 634151] + * win/tclWin32Dll.c: + * tests/cmdAH.test: fix to non-ascii chars in paths when setting mtime + and atime through 'file (a|m)time $path $time'. [Bug 634151] 2003-01-08 Don Porter - * generic/tclExecute.c (TclExprFloatError): Use the IS_NAN macro - for greater clarity of code. + * generic/tclExecute.c (TclExprFloatError): Use the IS_NAN macro for + greater clarity of code. 2003-01-07 Don Porter - * generic/tclCompCmds.c (TclCompileReturnCmd): - * tests/compile.test: Corrects failure of bytecompiled - [catch {return}] to have result TCL_RETURN (not TCL_OK) [Bug 633204]. - This patch is a workaround for 8.4.X. A new opcode INST_RETURN is a - better long term solution for 8.5 and later. + * generic/tclCompCmds.c (TclCompileReturnCmd): + * tests/compile.test: Corrects failure of bytecompiled [catch + {return}] to have result TCL_RETURN (not TCL_OK) [Bug 633204]. This + patch is a workaround for 8.4.X. A new opcode INST_RETURN is a better + long term solution for 8.5 and later. 2003-01-04 David Gravereaux * win/makefile.vc: - * win/rules.vc: Fixed INSTALLDIR macro problem that blanked itself - by accident causing the install target to put the tree at the root - of the drive built on. Whoops.. - - Renamed the 'linkexten' option to be 'staticpkg'. Added 'thrdalloc' - to allow the switching _on_ of the thread allocator. Under testing, - I found it not to be benificial under windows for the purpose of the - application I was using it for. It was more important for this app + * win/rules.vc: Fixed INSTALLDIR macro problem that blanked itself by + accident causing the install target to put the tree at the root of the + drive built on. Whoops.. + + Renamed the 'linkexten' option to be 'staticpkg'. Added 'thrdalloc' to + allow the switching _on_ of the thread allocator. Under testing, I + found it not to be benificial under windows for the purpose of the + application I was using it for. It was more important for this app that resources for tcl threads be returned to the system rather than - saved/moved to the global recycler. Be extra clean or extra fast - for the default threaded build? Let's move to clean and allow it to - be switched on for users who find it benificial for their use of - threads. + saved/moved to the global recycler. Be extra clean or extra fast for + the default threaded build? Let's move to clean and allow it to be + switched on for users who find it benificial for their use of threads. 2002-12-18 David Gravereaux * win/makefile.vc: some uses of xcopy swapped to the @$(CPY) macro. Reported by Joe Mistachkin . 2002-12-17 Jeff Hobbs - * generic/tclNotify.c (TclFinalizeNotifier, Tcl_SetServiceMode): - (Tcl_ThreadAlert): Check that the stub functions are non-NULL - before calling them. They could be set to NULL by Tcl_SetNotifier. + * generic/tclNotify.c (TclFinalizeNotifier, Tcl_SetServiceMode): + (Tcl_ThreadAlert): Check that the stub functions are non-NULL before + calling them. They could be set to NULL by Tcl_SetNotifier. 2002-12-16 David Gravereaux * generic/tclPipe.c (TclCleanupChildren): * tests/winPipe.test: * win/tclWinPipe.c (Tcl_WaitPid): - * win/tclWinTest.c: Gave Tcl_WaitPid the ability to return a - Win32 exception code translated into a posix style SIG*. This - allows [close] to report "CHILDKILLED" without the meaning - getting lost in a truncated exit code. In TclCleanupChildren(), - TclpGetPid() had to get moved to before Tcl_WaitPid() as the - the handle is removed from the list taking away the ability - to get the process id after the wait is done. This shouldn't - effect the unix implimentaion unless waitpid is called with - a pid of zero, meaning "any". I don't think it is.. + * win/tclWinTest.c: Gave Tcl_WaitPid the ability to return a Win32 + exception code translated into a posix style SIG*. This allows [close] + to report "CHILDKILLED" without the meaning getting lost in a + truncated exit code. In TclCleanupChildren(), TclpGetPid() had to get + moved to before Tcl_WaitPid() as the the handle is removed from the + list taking away the ability to get the process id after the wait is + done. This shouldn't effect the unix implimentaion unless waitpid is + called with a pid of zero, meaning "any". I don't think it is.. 2002-12-13 Don Porter * unix/configure.in: Updated configure of CVS snapshots to reflect * win/configure.in: the 8.4.1.1 patchlevel. @@ -930,126 +5608,123 @@ * unix/configure: autoconf * win/configure autoconf 2002-12-11 Don Porter - * generic/tclProc.c (ProcessProcResultCode): Fix failure to - propagate negative return codes up the call stack. [Bug 647307] + * generic/tclProc.c (ProcessProcResultCode): Fix failure to propagate + negative return codes up the call stack. [Bug 647307] * tests/proc.test (proc-6.1): Test for Bug 647307 * generic/tclParseExpr.c (TclParseInteger): Return 1 for the - string "0x" (recognize leading "0" as an integer). [Bug 648441]. + string "0x" (recognize leading "0" as an integer). [Bug 648441]. * tests/parseExpr.test (parseExpr-19.1): Test for Bug 648441. 2002-12-09 Jeff Hobbs * win/tclWinThrd.c (TclpMasterUnlock): - * generic/tclThread.c (TclFinalizeThreadData): TclpMasterUnlock - must exist and be called unconditional of TCL_THREADS. [Bug #651139] + * generic/tclThread.c (TclFinalizeThreadData): TclpMasterUnlock must + exist and be called unconditional of TCL_THREADS. [Bug 651139] 2002-12-08 David Gravereaux - * win/tclWinSock.c (SocketThreadExitHandler, InitSockets): Check - that the tsdPtr is valid before dereferencing as we call it from - the exit handler, too [Bug 650353]. Another WSAStartup() loaded - version comparison byte swap issue fixed. Although 0x0101 byte - swapped is still 0x0101, properly claiming which is major/minor - is more correct. + * win/tclWinSock.c (SocketThreadExitHandler, InitSockets): Check that + the tsdPtr is valid before dereferencing as we call it from the exit + handler, too [Bug 650353]. Another WSAStartup() loaded version + comparison byte swap issue fixed. Although 0x0101 byte swapped is + still 0x0101, properly claiming which is major/minor is more correct. 2002-12-06 Jeff Hobbs * generic/tclStubInit.c: regen * generic/tclIntPlatDecls.h: regen * generic/tclInt.decls: added TclWinResetInterface * win/tclWin32Dll.c (TclWinResetInterfaces): * win/tclWinInit.c (TclpSetInitialEncodings, WinEncodingsCleanup): - add exit handler that resets the encoding information to a state - where we can reuse Tcl. Following these changes, it is possible - to reuse Tcl (following Tcl_FindExecutable or Tcl_CreateInterp) - following a Tcl_Finalize. + add exit handler that resets the encoding information to a state where + we can reuse Tcl. Following these changes, it is possible to reuse Tcl + (following Tcl_FindExecutable or Tcl_CreateInterp) following a + Tcl_Finalize. - * generic/tclIOUtil.c (TclFinalizeFilesystem): reset statics to - their original values on finalize to allow reuse of the library. + * generic/tclIOUtil.c (TclFinalizeFilesystem): reset statics to their + original values on finalize to allow reuse of the library. 2002-12-04 David Gravereaux * win/tclWinPipe.c: reverted back to -r1.27 due to numerous test - failures that need to be resolved first. The idea was good, - but the details aren't. - + failures that need to be resolved first. The idea was good, but the + details aren't. + 2002-12-04 David Gravereaux - * win/tclWinPipe.c (Tcl_WaitPid): When a process exits with an - exception, pass this notice on to the caller with a SIG* code - rather than truncating the exit code and missing the meaning. - This allows TclCleanupChildren() to report "CHILDKILLED". - - This has a different behavior than unix in that closing the - read pipe to a process sends the SIGPIPE signal which is - returned as a SIGPIPE exit status. On windows, we send the - process a CTRL_BREAK_EVENT and get back a CONTROL_C_EXIT which - is documented to mean a SIGINT which seems wrong as a system, - but is the correct exit status. + * win/tclWinPipe.c (Tcl_WaitPid): When a process exits with an + exception, pass this notice on to the caller with a SIG* code rather + than truncating the exit code and missing the meaning. This allows + TclCleanupChildren() to report "CHILDKILLED". + + This has a different behavior than unix in that closing the read pipe + to a process sends the SIGPIPE signal which is returned as a SIGPIPE + exit status. On windows, we send the process a CTRL_BREAK_EVENT and + get back a CONTROL_C_EXIT which is documented to mean a SIGINT which + seems wrong as a system, but is the correct exit status. 2002-12-04 Vince Darley - * generic/tclIOUtil.c: fix to redirected 'load' in virtual - filesystem for some Unix systems. - - * generic/tclEvent.c: the filesystem must be cleaned up before - the encoding subsystem because it needs access to encodings. - Fixes crash on exit observed in embedded applications. - - * generic/tclTestObj.c: patch omitted from previous change - of 2002-11-13 - + * generic/tclIOUtil.c: fix to redirected 'load' in virtual filesystem + for some Unix systems. + + * generic/tclEvent.c: the filesystem must be cleaned up before the + encoding subsystem because it needs access to encodings. Fixes crash + on exit observed in embedded applications. + + * generic/tclTestObj.c: patch omitted from previous change of + 2002-11-13 + 2002-12-03 Jeff Hobbs * generic/tclStubLib.c (Tcl_InitStubs): prevent the cached check of tclStubsPtr to allow for repeated load/unload of the Tcl dll by hosting apps. [Bug 615304] 2002-12-03 David Gravereaux - * win/tclAppInit.c (sigHandler): Protect from trying to close a - NULL handle. - - * win/tclWinPipe.c (PipeClose2Proc, TclpCreateProcess): Send a - real Win32 signal (CTRL_C_EVENT) when the read channel is brought - down to alert the child to close on its side. Start the process - with CREATE_NEW_PROCESS_GROUP to allow the ability to send these - signals. The following test case now brings down the child - without the use of an external [kill] command. - - % set p [open "|[info name]" w+] - file8d5380 - % pid $p - 2876 - % close $p <- now doesn't block in Tcl_WaitPid() - % - - * win/tclWinPipe.c (PipeClose2Proc): Changed CTRL_C_EVENT - to CTRL_BREAK_EVENT as it can't be ignored by the child and - proved to work on [open "|netstat 1" w+] where CTRL_C_EVENT - didn't. + * win/tclAppInit.c (sigHandler): Protect from trying to close a NULL + handle. + + * win/tclWinPipe.c (PipeClose2Proc, TclpCreateProcess): Send a real + Win32 signal (CTRL_C_EVENT) when the read channel is brought down to + alert the child to close on its side. Start the process with + CREATE_NEW_PROCESS_GROUP to allow the ability to send these signals. + The following test case now brings down the child without the use of + an external [kill] command. + + % set p [open "|[info name]" w+] + file8d5380 + % pid $p + 2876 + % close $p <- now doesn't block in Tcl_WaitPid() + % + + * win/tclWinPipe.c (PipeClose2Proc): Changed CTRL_C_EVENT to + CTRL_BREAK_EVENT as it can't be ignored by the child and proved to + work on [open "|netstat 1" w+] where CTRL_C_EVENT didn't. 2002-11-27 David Gravereaux - * win/tclWinPort.h: Don't turn off winsock prototypes! - TclX didn't like it. Even though the core doesn't use the - prototypes, do offer them. - - * win/tclWinSock.c: Removed shutdown() from the function - table as it wasn't referenced anywhere and cleaned-up some - casting that that wasn't needed. - - * win/tclWinSock.c: WSAStartup() loaded version comparison - error which resulted in 2.0 looking less than 1.1. - - * win/tclWinChan.c (Tcl_MakeFileChannel): return of - DuplicateHandle() incorrectly used [Bug 618852]. + * win/tclWinPort.h: Don't turn off winsock prototypes! TclX didn't + like it. Even though the core doesn't use the prototypes, do offer + them. + + * win/tclWinSock.c: Removed shutdown() from the function table as it + wasn't referenced anywhere and cleaned-up some casting that that + wasn't needed. + + * win/tclWinSock.c: WSAStartup() loaded version comparison error which + resulted in 2.0 looking less than 1.1. + + * win/tclWinChan.c (Tcl_MakeFileChannel): return of DuplicateHandle() + incorrectly used [Bug 618852]. 2002-11-26 Jeff Hobbs * generic/tclEncoding.c (TclFinalizeEncodingSubsystem): properly cleanup all encodings by using Tcl_FirstHashEntry in the while loop. @@ -1064,73 +5739,70 @@ 2002-11-26 David Gravereaux * win/tclWinPort.h: * win/tclWinSock.c: This patch does two things: - 1) Cleans-up the winsock typedefs by using the typedefs - provided by winsock2.h. This has no effect on how winsock - is initialized; just makes the source code easier to read. - [Patch 561305 561301] - - 2) Revamps how the socket message handler thread is brought - up and down to allow for cleaner exits without the use of - TerminateThread(). TerminateThread is evil. No attempt has - been made to resolve [Bug 593810] which may need a new - channel driver version for adding a registering function - within the transfered thread to init the handler thread. - IOW, initialization of the TSD structure is getting bypassed + 1) Cleans-up the winsock typedefs by using the typedefs provided by + winsock2.h. This has no effect on how winsock is initialized; just + makes the source code easier to read. [Patch 561305, 561301] + + 2) Revamps how the socket message handler thread is brought up and + down to allow for cleaner exits without the use of TerminateThread(). + TerminateThread is evil. No attempt has been made to resolve [Bug + 593810] which may need a new channel driver version for adding a + registering function within the transfered thread to init the handler + thread. IOW, initialization of the TSD structure is getting bypassed through the thread extension's [thread::transfer] command. 2002-11-26 David Gravereaux * win/tclWinConsole.c: * win/tclWinPipe.c: * win/tclWinSerial.c: * win/tclWinSock.c: * win/tclWinThrd.c: - * win/tclWinTime.c: General cleanup of all worker threads used - by the channel drivers. Eliminates the normal case where the - worker thread is terminated ('cept the winsock one). Instead, - use kernel events to signal a clean exit. Only when the worker - thread is blocked on an I/O call is the thread terminated. - Essentially, this makes all other channel worker threads behave - like the PipeReaderThread() function for it's cleaner exit - behavior. This appears to fix [Bug 597924] but needs 3rd party - confirmation to close the issue. + * win/tclWinTime.c: General cleanup of all worker threads used by the + channel drivers. Eliminates the normal case where the worker thread is + terminated ('cept the winsock one). Instead, use kernel events to + signal a clean exit. Only when the worker thread is blocked on an I/O + call is the thread terminated. Essentially, this makes all other + channel worker threads behave like the PipeReaderThread() function for + it's cleaner exit behavior. This appears to fix [Bug 597924] but needs + 3rd party confirmation to close the issue. 2002-11-26 Mo DeJong - * win/README: Update msys build env URL. This - release #4 build both tcl and tk without problems. + * win/README: Update msys build env URL. This release #4 build both + tcl and tk without problems. 2002-11-22 Jeff Hobbs - * library/init.tcl: code cleanup to reduce use of + * library/init.tcl: code cleanup to reduce use of * library/opt/optparse.tcl: string compare * tests/interp.test: interp-14.4 - * generic/tclInterp.c (TclPreventAliasLoop): prevent seg fault - when creating an alias command over the interp name. [Bug #641195] + * generic/tclInterp.c (TclPreventAliasLoop): prevent seg fault when + creating an alias command over the interp name. [Bug 641195] 2002-11-18 Jeff Hobbs * generic/tclUtil.c (SetEndOffsetFromAny): handle integer offset after the "end-" prefix. * generic/get.test: * generic/string.test: - * generic/tclObj.c (SetIntFromAny, SetWideIntFromAny): - * generic/tclGet.c (TclGetLong, Tcl_GetInt): simplify sign - handling before calling strtoul(l). [Bug #634856] + * generic/tclObj.c (SetIntFromAny, SetWideIntFromAny): + * generic/tclGet.c (TclGetLong, Tcl_GetInt): simplify sign handling + before calling strtoul(l). [Bug 634856] 2002-11-18 David Gravereaux - * win/tclWinThrd.c (Tcl_CreateThread/TclpThreadExit): Fixed - improper compiler macros that missed the VC++ compiler. This - resulted in VC++ builds using CreateThread()/ExitThread() in place - of the proper _beginthreadex()/_endthreadex(). This was a large - error and am surprised I missed seeing it earlier. + * win/tclWinThrd.c (Tcl_CreateThread/TclpThreadExit): Fixed improper + compiler macros that missed the VC++ compiler. This resulted in VC++ + builds using CreateThread()/ExitThread() in place of the proper + _beginthreadex()/_endthreadex(). This was a large error and am + surprised I missed seeing it earlier. 2002-11-13 Jeff Hobbs * generic/regexpComp.test: added tests 22.* * generic/tclCompCmds.c (TclCompileRegexpCmd): add left and right @@ -1139,169 +5811,165 @@ string equal. 2002-11-13 Vince Darley * generic/tclCmdMZ.c: - * tests/trace.test: applied patch from Hemang Levana to fix - [Bug #615043] in execution traces with 'return -code error'. - + * tests/trace.test: applied patch from Hemang Levana to fix [Bug + 615043] in execution traces with 'return -code error'. + * generic/tclTestObj.c: * tests/stringObj.test: added 'knownBug' test for [Bug 635200] * generic/tclStringObj.c: corrected typos in comments * generic/tclFileName.c: - * tests/fileName.test: applied patch for bug reported against - tclvfs concerning handling of Windows serial ports like 'com1', - 'lpt3' by the virtual filesystem code. + * tests/fileName.test: applied patch for bug reported against tclvfs + concerning handling of Windows serial ports like 'com1', 'lpt3' by the + virtual filesystem code. - * doc/RegExp.3: clarification of the 'extendMatch' return - values. + * doc/RegExp.3: clarification of the 'extendMatch' return values. 2002-11-11 Jeff Hobbs * generic/tclUtil.c (Tcl_Backslash): use TclUtfToUniChar. (Tcl_StringCaseMatch): use TclUtfToUniChar and add further optimizations for the one-byte/char case. - * generic/tclUtf.c: make use of TclUtfToUniChar macro throughout - the functions, and add extra optimization to Tcl_NumUtfChars for + * generic/tclUtf.c: make use of TclUtfToUniChar macro throughout the + functions, and add extra optimization to Tcl_NumUtfChars for one-byte/char case. * generic/tclVar.c (DisposeTraceResult, CallVarTraces): add proper static declarations. - * generic/tclStringObj.c (Tcl_GetCharLength): optimize for the - ascii char case. + * generic/tclStringObj.c (Tcl_GetCharLength): optimize for the ascii + char case. (Tcl_GetUniChar): remove unnecessary use of Tcl_UtfToUniChar. (FillUnicodeRep): Use TclUtfToUniChar. - * generic/tclHash.c (HashStringKey): move string++ lower to save - an instruction. + * generic/tclHash.c (HashStringKey): move string++ lower to save an + instruction. - * generic/tclExecute.c (TclExecuteByteCode): improve INST_STR_CMP - to use memcmp in the one-byte/char case, also use direct index for + * generic/tclExecute.c (TclExecuteByteCode): improve INST_STR_CMP to + use memcmp in the one-byte/char case, also use direct index for INST_STR_INDEX in that case. - * generic/tclEncoding.c (UtfToUtfProc, UtfToUnicodeProc): + * generic/tclEncoding.c (UtfToUtfProc, UtfToUnicodeProc): (TableFromUtfProc, EscapeFromUtfProc): Use TclUtfToUniChar. (UnicodeToUtfProc, TableToUtfProc): add 1-byte char optimizations - for Tcl_UniCharToUtf call. These improve encoded channel - conversion speeds by up to 20%. + for Tcl_UniCharToUtf call. These improve encoded channel conversion + speeds by up to 20%. * tests/split.test: added 1-char string split tests - * generic/tclCmdMZ.c (Tcl_SplitObjCmd): Use TclUtfToUniChar. - Also added a special case for single-ascii-char splits. - (Tcl_StringObjCmd): Use TclUtfToUniChar. - For STR_RANGE, support getting ranges of ByteArrays (reverts - change from 2000-05-26). + * generic/tclCmdMZ.c (Tcl_SplitObjCmd): Use TclUtfToUniChar. Also + added a special case for single-ascii-char splits. + (Tcl_StringObjCmd): Use TclUtfToUniChar. For STR_RANGE, support + getting ranges of ByteArrays (reverts change from 2000-05-26). (TraceExecutionProc) add proper static declaration. * generic/tclInt.h: add macro version of Tcl_UtfToUniChar (TclUtfToUniChar) that does the one-byte utf-char check without - calling Tcl_UtfToUniChar, for use by the core. This brings - notable speedups for primarily ascii string handling. + calling Tcl_UtfToUniChar, for use by the core. This brings notable + speedups for primarily ascii string handling. * generic/tcl.h (TCL_PATCH_LEVEL): bump to 8.4.1.1 for patchlevel - only. This interim number will only be reflected by - [info patchlevel]. + only. This interim number will only be reflected by [info patchlevel] 2002-11-11 Kevin Kenny - * doc/Tcl.n: Corrected indentation of the new language. Oops. - + + * doc/Tcl.n: Corrected indentation of the new language. Oops. + 2002-11-10 Kevin Kenny - * doc/Tcl.n: Added language to the Endekalogue to make it clear - that substitutions always take place from left to right. [Bug - #635644] + * doc/Tcl.n: Added language to the Endekalogue to make it clear that + substitutions always take place from left to right. [Bug 635644] 2002-11-06 Mo DeJong * changes: Note TclInExit TclInThreadExit changes. * generic/tclEvent.c (TclInExit, TclInThreadExit): - Split out functionality of TclInExit to make it - clear which one should be called in each situation. + Split out functionality of TclInExit to make it clear which one should + be called in each situation. * generic/tclInt.decls: Declare TclInThreadExit. * generic/tclIntDecls.h: Regen. * generic/tclStubInit.c: Regen. * mac/tclMacChan.c (StdIOClose): * unix/tclUnixChan.c (FileCloseProc): * win/tclWinChan.c (FileCloseProc): * win/tclWinConsole.c (ConsoleCloseProc): * win/tclWinPipe.c (TclpCloseFile): - * win/tclWinSerial.c (SerialCloseProc): Invoke the - new TclInThreadExit method instead of TclInExit. + * win/tclWinSerial.c (SerialCloseProc): Invoke the new TclInThreadExit + method instead of TclInExit. 2002-11-06 Mo DeJong * unix/configure: Regen. - * unix/tcl.m4 (SC_CONFIG_CFLAGS): Generate a fatal - configure error if no ar program can be found on the - path. [Bug #582039] + * unix/tcl.m4 (SC_CONFIG_CFLAGS): Generate a fatal configure error if + no ar program can be found on the path. [Bug 582039] * win/configure: Regen. - * win/configure.in: Check that AR, RANLIB, and RC - are found on the path when building with gcc. + * win/configure.in: Check that AR, RANLIB, and RC are found on the + path when building with gcc. 2002-11-03 David Gravereaux * win/tclAppInit.c: Calls Registry_Init() and Dde_Init() when STATIC_BUILD and TCL_USE_STATIC_PACKAGES macros are set. * win/makefile.vc: - * win/rules.vc: linkexten option now sets the TCL_USE_STATIC_PACKAGES + * win/rules.vc: linkexten option now sets the TCL_USE_STATIC_PACKAGES macro which also adds the registry and dde object files to the link of the shell. [Patch 479697] Also factored some additional macros - that will be helpful for extension authors. Version grepping of tcl.h + that will be helpful for extension authors. Version grepping of tcl.h will need to be added to complete this. * win/buildall.vc.bat: Added more descriptive commentary. 2002-11-01 David Gravereaux - * win/tclWinReg.c: Changed the Tcl_PkgProvide() line to declare - the registry extension at version 1.1 from 1.0. + * win/tclWinReg.c: Changed the Tcl_PkgProvide() line to declare the + registry extension at version 1.1 from 1.0. 2002-10-31 Andreas Kupries - * library/word.tcl: Changed $tcl_platform to $::tcl_platform to - avoid possible scope trouble. + * library/word.tcl: Changed $tcl_platform to $::tcl_platform to avoid + possible scope trouble. 2002-10-29 Vince Darley * win/tclWinInt.h: * win/tclWin32Dll.c: added comments about certain NULL function - pointers which will be filled in when Tcl_FindExecutable is - called, so that users don't report invalid bugs on this topic. - (No code changes at all). - + pointers which will be filled in when Tcl_FindExecutable is called, so + that users don't report invalid bugs on this topic. (No code changes + at all). + 2002-10-29 Daniel Steffen - * unix/tclLoadDyld.c (TclpFindSymbol): pass all dyld error - messages upstream [Bug #627546]. + * unix/tclLoadDyld.c (TclpFindSymbol): pass all dyld error messages + upstream [Bug 627546]. 2002-10-28 Andreas Kupries * library/dde/pkgIndex.tcl: - * library/reg/pkgIndex.tcl: Changed the hardwired debug suffix - (d) to the correct suffix (g). + * library/reg/pkgIndex.tcl: Changed the hardwired debug suffix (d) to + the correct suffix (g). 2002-10-28 Don Porter * library/auto.tcl: Converted the Mac-specific [package unknown] * library/init.tcl: behavior to use a chaining mechanism to extend - * library/package.tcl: the default [tclPkgUnknown]. [Bug 627660] + * library/package.tcl: the default [tclPkgUnknown]. [Bug 627660] * library/tclIndex: [Patch 624509] (steffen) 2002-10-26 David Gravereaux * win/makefile.vc: xcopy on NT 4.0 doesn't support the /Y switch - (overwrite). Added logic to handle this. [Bug 618019] + (overwrite). Added logic to handle this. [Bug 618019] 2002-10-23 Donal K. Fellows - * generic/tclInt.h: Removed definitions of obsolete HistoryEvent - and HistoryRev structures (the history mechanism has been written - in Tcl for some time now.) + * generic/tclInt.h: Removed definitions of obsolete HistoryEvent and + HistoryRev structures (the history mechanism has been written in Tcl + for some time now). 2002-10-22 Jeff Hobbs *** 8.4.1 TAGGED FOR RELEASE *** @@ -1316,17 +5984,17 @@ 2002-10-22 Daniel Steffen * library/auto.tcl (tcl_findLibrary): * library/package.tcl (tclPkgUnknown): on macosx, search inside the Resources/Scripts subdirectory of any potential package directory - * macosx/Tcl.pbproj/project.pbxproj: add standard Frameworks dirs - to TCL_PACKAGE_PATH make argument. + * macosx/Tcl.pbproj/project.pbxproj: add standard Frameworks dirs to + TCL_PACKAGE_PATH make argument. * unix/tclUnixInit.c (TclpSetVariables): on macosx, add embedded framework dirs to tcl_pkgPath: @executable_path/../Frameworks and - @executable_path/../PrivateFrameworks (if they exist), as well as - the dirs in DYLD_FRAMEWORK_PATH (if set). [Patch #624509] - use standard MAXPATHLEN instead of literal 1024 + @executable_path/../PrivateFrameworks (if they exist), as well as the + dirs in DYLD_FRAMEWORK_PATH (if set). [Patch 624509] use standard + MAXPATHLEN instead of literal 1024 2002-10-22 Donal K. Fellows * doc/StringObj.3, doc/Object.3: Documented that Tcl_Obj's standard string form is a modified UTF-8; apparently, this was not @@ -1345,64 +6013,64 @@ * win/configure.in: * win/Makefile.in: * win/makefile.vc: * win/makefile.bc: Updated to reg1.1 - * doc/registry.n: Added support for broadcasting changes to - * tests/registry.test: the registry Environment. Noted proper code - * win/tclWinReg.c: in the docs. [Patch #625453] + * doc/registry.n: Added support for broadcasting changes to the + * tests/registry.test: registry Environment. Noted proper code in ths + * win/tclWinReg.c: docs. [Patch 625453] * unix/Makefile.in (dist): add any mac/tcl*.sea.hqx files 2002-10-17 Don Porter * generic/tclVar.c: Fixed code that check for proper # of args to - * tests/var.test: [array names]. Added test. [Bug 624755] + * tests/var.test: [array names]. Added test. [Bug 624755] 2002-10-16 Jeff Hobbs - * win/configure: add workaround for cygwin windres - * win/tcl.m4 (SC_CONFIG_CFLAGS): problem. [Patch #624010] (howell) + * win/configure: add workaround for cygwin windres + * win/tcl.m4 (SC_CONFIG_CFLAGS): problem. [Patch 624010] (howell) 2002-10-15 Jeff Hobbs * README: added archives.tcl.tk note * unix/configure: - * unix/tcl.m4: Correct AIX-5 ppc build flags. - Correct HP 11 64-bit gcc building. [Patch #601051] (martin) + * unix/tcl.m4: Correct AIX-5 ppc build flags. Correct HP 11 64-bit gcc + building. [Patch 601051] (martin) 2002-10-15 Vince Darley * generic/tclCmdMZ.c: - * tests/trace.test: applied patch from Hemang Levana to fix - [Bug #615043] in execution traces with idle tasks firing. + * tests/trace.test: applied patch from Hemang Levana to fix [Bug + 615043] in execution traces with idle tasks firing. 2002-10-14 Jeff Hobbs * generic/tclEnv.c (Tcl_PutEnv): correct possible mem leak. - [Patch #623269] (brouwers) + [Patch 623269] (brouwers) 2002-10-11 Donal K. Fellows * generic/tcl.h: Need a different strategy through the maze of #defines to let people building with Cygwin build correctly. Also made some comments less misleading... 2002-10-10 Jeff Hobbs - * README: fixed minor nits [Bug #607776] (virden) + * README: fixed minor nits [Bug 607776] (virden) * win/configure: * win/tcl.m4: enable USE_THREAD_ALLOC (new threaded allocator) by default in cygwin configure on Windows. 2002-10-10 Don Porter * doc/Tcl.n: Clarified that namespace separators are legal in the variable names during $-subtitution. [Bug 615139] - + * doc/regexp.n: Typo correction. Thanks Ronnie Brunner. [Bug 606826] 2002-10-10 Vince Darley * unix/tclLoadAout.c @@ -1410,14 +6078,13 @@ * unix/tclLoadDld.c * unix/tclLoadDyld.c * unix/tclLoadNext.c * unix/tclLoadOSF.c * unix/tclLoadShl.c - * win/tclWinLoad.c: allow either full paths or simply dll names - to be specified when loading files (the latter will be looked - up by the OS on your PATH/LD_LIBRARY_PATH as appropriate). - Fixes [Bug 611108] + * win/tclWinLoad.c: allow either full paths or simply dll names to be + specified when loading files (the latter will be looked up by the OS + on your PATH/LD_LIBRARY_PATH as appropriate). Fixes [Bug 611108] 2002-10-09 Jeff Hobbs * unix/README: doc'ed --enable-symbols options. * unix/Makefile.in: removed @MEM_DEBUG_FLAGS@ subst. @@ -1426,14 +6093,13 @@ * unix/tcl.m4: replaced SC_ENABLE_MEMDEBUG with a more intelligent SC_ENABLE_SYMBOLS that takes yes|no|mem|compile|all as options now. 2002-10-09 Kevin B. Kenny - * win/tclWinTime.c: Added code to set an exit handler that - terminates the thread that calibrates the performance counter, so - that the thread won't outlive unloading the Tcl DLL. [Tcl bug - 620735]. + * win/tclWinTime.c: Added code to set an exit handler that terminates + the thread that calibrates the performance counter, so that the thread + won't outlive unloading the Tcl DLL. [Bug 620735]. 2002-10-09 Donal K. Fellows * doc/binary.n: More clarification of [binary scan]'s behaviour. @@ -1447,38 +6113,38 @@ generic as it is used on mac & aqua as well. * generic/tclIntDecls.h: * generic/tclStubInit.c: regen. * generic/tclCompile.h: added prototype for TclCompileVariableCmd. - * mac/tclMacPort.h: removed incorrect definitions - and obsolete definitions. - * mac/tclMacChan.c: removed obsolete GetOpenMode() and replaced - associated constants with the analogues (they existing - defs were inconsistent with which was causing havoc when + * mac/tclMacPort.h: removed incorrect definitions and + obsolete definitions. + * mac/tclMacChan.c: removed obsolete GetOpenMode() and replaced + associated constants with the analogues (they existing defs + were inconsistent with which was causing havoc when Tcl_GetOpenMode was used instead of private GetOpenMode). - * mac/tclMacFCmd.c: removed GenerateUniqueName(), use equivalent - (and identically named) routine from MoreFiles instead. + * mac/tclMacFCmd.c: removed GenerateUniqueName(), use equivalent (and + identically named) routine from MoreFiles instead. * mac/tclMacLoad.c: CONSTification, fixes to Vince's last changes. - * mac/tclMacFile.c: + * mac/tclMacFile.c: * mac/tclMacTest.c: * mac/tclMacUnix.c: CONSTification. * mac/tclMacOSA.c: CONSTification, sprintf fixes, UH 3.4.x changes; fix for missing autoname token from TclOSACompileCmd. (bdesgraupes) * mac/AppleScript.html(AppleScript delete): doc fix. (bdesgraupes) - * mac/tcltkMacBuildSupport.sea.hqx: updated MoreFiles to 1.5.3, + * mac/tcltkMacBuildSupport.sea.hqx: updated MoreFiles to 1.5.3, updated build instructions for 8.4. * mac/tclMacProjects.sea.hqx: rebuilt archive. 2002-10-09 Donal K. Fellows - * doc/Alloc.3: Added a note to mention that attempting to allocate - a zero-length block can return NULL. [Tk bug 619544] + * doc/Alloc.3: Added a note to mention that attempting to allocate a + zero-length block can return NULL. [Tk Bug 619544] 2002-10-04 Donal K. Fellows * doc/binary.n: Doc improvements [Patch 616480] @@ -1490,48 +6156,48 @@ * doc/tcltest.n: fixed typo [Bug 618018]. Thanks to "JJM". 2002-10-03 Donal K. Fellows - * tools/man2help2.tcl: - * tests/http.test, tests/httpd, tests/httpold.test: - * tests/env.test, tests/binary.test, tests/autoMkindex.test: - * library/init.tcl, library/http/http.tcl: [info exist] should - really be [info exists]. [Bug 602566] - - * doc/lsearch.n: Better specification of what happens when -sorted - is mixed with other options. [Bug 617816] + * tools/man2help2.tcl: + * tests/http.test, tests/httpd, tests/httpold.test: + * tests/env.test, tests/binary.test, tests/autoMkindex.test: + * library/init.tcl, library/http/http.tcl: [info exist] should really + be [info exists]. [Bug 602566] + + * doc/lsearch.n: Better specification of what happens when -sorted is + mixed with other options. [Bug 617816] 2002-10-01 Jeff Hobbs * generic/tclProc.c (TclCreateProc): mask out VAR_UNDEFINED for precompiled locals to support 8.3 precompiled code. (Tcl_ProcObjCmd): correct 2002-09-26 fix to look for tclProcBodyType. 2002-10-01 Donal K. Fellows - * doc/socket.n: Mentioned that ports may be specified as serivce - names as well as integers. [Bug 616843] + * doc/socket.n: Mentioned that ports may be specified as serivce names + as well as integers. [Bug 616843] 2002-09-30 Jeff Hobbs - * generic/tclCompCmds.c (TclCompileRegexpCmd): correct the - checking for bad re's that didn't terminate the re string. - Resultant compiles were correct, but much slower than necessary. + * generic/tclCompCmds.c (TclCompileRegexpCmd): correct the checking + for bad re's that didn't terminate the re string. Resultant compiles + were correct, but much slower than necessary. 2002-09-29 David Gravereaux * win/tclAppInit.c: Added proper exiting conditions using Win32 - console signals. This handles the existing lack of a Ctrl+C exit - to call exit handlers when built for thread support. Also, properly + console signals. This handles the existing lack of a Ctrl+C exit to + call exit handlers when built for thread support. Also, properly handles exits from other conditions such as CTRL_CLOSE_EVENT, - CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals. In all cases, - exit handlers will be called. [Bug 219355] + CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals. In all cases, exit + handlers will be called. [Bug 219355] - * win/makefile.vc: Added missing tclThreadAlloc.c to the build - rules and defines USE_THREAD_ALLOC when TCL_THREADS is defined - to get the new behavior by default. + * win/makefile.vc: Added missing tclThreadAlloc.c to the build rules + and defines USE_THREAD_ALLOC when TCL_THREADS is defined to get the + new behavior by default. 2002-09-27 Don Porter * README: Bumped to version 8.4.1 to avoid confusion * generic/tcl.h: of CVS snapshots with the actual 8.4.0 @@ -1546,135 +6212,131 @@ 2002-09-26 Jeff Hobbs * unix/configure: regen. * unix/tcl.m4: improve AIX-4/5 64bit compilation support. - * generic/tclProc.c (Tcl_ProcObjCmd): correct overeager - optimization of noop proc to handle the precompiled case. (sofer) + * generic/tclProc.c (Tcl_ProcObjCmd): correct overeager optimization + of noop proc to handle the precompiled case. (sofer) * unix/ldAix (nmopts): add -X32_64 to make it work for 32 or 64bit mode compilation. - * library/encoding/koi8-u.enc: removed extraneous spaces that - confused encoding reader. [Bug #615115] + * library/encoding/koi8-u.enc: removed extraneous spaces that confused + encoding reader. [Bug 615115] - * unix/Makefile.in: generate source dists with -src designator and - do not generate .Z anymore (just .gz and .zip). + * unix/Makefile.in: generate source dists with -src designator and do + not generate .Z anymore (just .gz and .zip). 2002-09-18 Mumit Khan Added basic Cygwin support. * win/tcl.m4 (SC_PATH_TCLCONFIG): Support one-tree build. (SC_PATH_TKCONFIG): Likewise. (SC_PROG_TCLSH): Likewise. - (SC_CONFIG_CFLAGS): Assume real Cygwin port and remove -mno-cygwin - flags. Add -mwin32 to extra_cflags and extra_ldflags. - Remove ``-e _WinMain@16'' from LDFLAGS_WINDOW. + (SC_CONFIG_CFLAGS): Assume real Cygwin port and remove -mno-cygwin + flags. Add -mwin32 to extra_cflags and extra_ldflags. Remove ``-e + _WinMain@16'' from LDFLAGS_WINDOW. * win/configure.in: Allow Cygwin build. (SEH test): Define to be 1 instead of empty value. (EXCEPTION_DISPOSITION): Add test. * win/configure: Regenerate. - * generic/tcl.h: Don't explicitly define __WIN32__ for Cygwin, let - the user decide whether to use Windows or POSIX personality. - (TCL_WIDE_INT_TYPE, TCL_LL_MODIFIER, struct Tcl_StatBuf): Define - for Cygwin. - * generic/tclEnv.c (Tcl_CygwinPutenv): putenv replacement for + * generic/tcl.h: Don't explicitly define __WIN32__ for Cygwin, let the + user decide whether to use Windows or POSIX personality. + (TCL_WIDE_INT_TYPE, TCL_LL_MODIFIER, struct Tcl_StatBuf): Define for Cygwin. - * generic/tclFileName.c (Tcl_TranslateFileName): Convert POSIX - to native format. + * generic/tclEnv.c (Tcl_CygwinPutenv): putenv replacement for Cygwin. + * generic/tclFileName.c (Tcl_TranslateFileName): Convert POSIX to + native format. (TclDoGlob): Likewise. * generic/tclPlatDecls.h (TCHAR): Define for Cygwin. - * win/tclWinPort.h (putenv, TclpSysAlloc, TclpSysFree, - TclpSysRealloc): Define for Cygwin. + * win/tclWinPort.h (putenv, TclpSysAlloc, TclpSysFree) + (TclpSysRealloc): Define for Cygwin. 2002-09-26 Daniel Steffen - * macosx/Makefile: preserve environment value of INSTALL_ROOT. - When embedding only use deployment build. Force relink before - embedded build to ensure new linker flags are picked up. - - * macosx/Tcl.pbproj/project.pbxproj: add symbolic links to - debug lib, stub libs and tclConfig.sh in framework toplevel. - Configure target dependency fix. Fix to 'clean' action. Added - private tcl headers to framework. Install tclsh symbolic link. - Html doc build works when no installed tclsh available. Made - html doc structure in framework more like in Apple frameworks. + * macosx/Makefile: preserve environment value of INSTALL_ROOT. When + embedding only use deployment build. Force relink before embedded + build to ensure new linker flags are picked up. + + * macosx/Tcl.pbproj/project.pbxproj: add symbolic links to debug lib, + stub libs and tclConfig.sh in framework toplevel. Configure target + dependency fix. Fix to 'clean' action. Added private tcl headers to + framework. Install tclsh symbolic link. Html doc build works when no + installed tclsh available. Made html doc structure in framework more + like in Apple frameworks. 2002-09-24 Donal K. Fellows * unix/tcl.m4 (SC_TCL_64BIT_FLAGS): Yet more robust 64-bit value detection to close [Bug 613117] on more systems. * generic/tclCompile.c (TclPrintSource): More CONSTifying. - * generic/tclExecute.c (EvalStatsCmd): Object-ify to reduce - warnings. Thanks to 'CoderX2' on the chat for bringing this to my - attention... + * generic/tclExecute.c (EvalStatsCmd): Object-ify to reduce warnings. + Thanks to 'CoderX2' on the chat for bringing this to my attention... * unix/tcl.m4: Forgot to define TCL_WIDE_INT_IS_LONG at the - appropriate moment. I believe this is the cause of [Bug 613117] + appropriate moment. I believe this is the cause of [Bug 613117] - * doc/lset.n: Changed 'list' to 'varName' for consistency with - lappend documentation. Thanks to Glenn Jackman [Bug 611719] + * doc/lset.n: Changed 'list' to 'varName' for consistency with lappend + documentation. Thanks to Glenn Jackman [Bug 611719] 2002-09-22 Don Porter - * library/tcltest/tcltest.tcl: Corrected [puts -nonewline] within - test bodies. Thanks to Harald Kirsch. [Bug 612786, Patch 612788] - Also corrected reporting of body return code. Thanks to David - Taback [Bug 611922] + * library/tcltest/tcltest.tcl: Corrected [puts -nonewline] within + test bodies. Thanks to Harald Kirsch. [Bug 612786, Patch 612788] Also + corrected reporting of body return code. Thanks to David Taback [Bug + 611922] * library/tcltest/pkgIndex.tcl: Bump to version 2.2.1. * tests/tcltest.test: added tests for these bugs. 2002-09-15 Mo DeJong * unix/configure: Regen. - * unix/tcl.m4 (SC_CONFIG_CFLAGS): Add PEEK_XCLOSEIM - define under Linux. This is used by Tk to double - check that an X input context is cleaned up - before it is closed. + * unix/tcl.m4 (SC_CONFIG_CFLAGS): Add PEEK_XCLOSEIM define under + Linux. This is used by Tk to double check that an X input context is + cleaned up before it is closed. 2002-09-12 David Gravereaux - * win/coffbase.txt: Added BLT to the virtual base address - listings table should BLT's build tools decide to use it. + * win/coffbase.txt: Added BLT to the virtual base address listings + table should BLT's build tools decide to use it. 2002-09-12 Daniel Steffen * generic/tcl.h: * mac/tclMacApplication.r: * mac/tclMacLibrary.r: - * mac/tclMacResource.r: unified use of the two equivalent - resource compiler header inclusion defines RC_INVOKED and - RESOURCE_INCLUDED, now use RC_INVOKED throughout. + * mac/tclMacResource.r: unified use of the two equivalent resource + compiler header inclusion defines RC_INVOKED and RESOURCE_INCLUDED, + now use RC_INVOKED throughout. 2002-09-10 Mo DeJong - * unix/README: Add note about building extensions - with the same compiler Tcl was built with. - [Tk Bug 592096] + * unix/README: Add note about building extensions with the same + compiler Tcl was built with. [Tk Bug 592096] 2002-09-10 Daniel Steffen * macosx/Tcl.pbproj/project.pbxproj: disabled building html documentation during embedded build. 2002-09-10 Daniel Steffen - * unix/Makefile.in: added DYLIB_INSTALL_DIR variable for macosx - and set it to default value ${LIB_RUNTIME_DIR} + * unix/Makefile.in: added DYLIB_INSTALL_DIR variable for macosx and + set it to default value ${LIB_RUNTIME_DIR} * unix/tcl.m4 (Darwin): use DYLIB_INSTALL_DIR instead of LIB_RUNTIME_DIR in the -install_name argument to ld. * unix/configure: regen. * macosx/Tcl.pbproj/project.pbxproj: * macosx/Makefile: added support for building Tcl as an embedded framework, i.e. using an dyld install_name containing @executable_path/../Frameworks via the new DYLIB_INSTALL_DIR unix/Makefile variable. - + 2002-09-10 Jeff Hobbs *** 8.4.0 TAGGED FOR RELEASE *** 2002-09-06 Don Porter @@ -1692,42 +6354,42 @@ * doc/tcltest.n: Clarified phrasing. * generic/tclBasic.c (TclRenameCommand,CallCommandTraces): * tests/trace.test (trace-27.1): Corrected memory leak when a rename - trace deleted the command being traced. Test added. Thanks to - Hemang Lavana for the fix. [Bug 604609] + trace deleted the command being traced. Test added. Thanks to Hemang + Lavana for the fix. [Bug 604609] * generic/tclVar.c (TclDeleteVars): Corrected logic for setting the TCL_INTERP_DESTROYED flag when calling variable traces. [Tk Bug 605121] 2002-09-04 Miguel Sofer - * generic/tclVar.c (DeleteArray): leak plug [Bug 604239]. Thanks - to dkf and dgp for the long and difficult discussion in the chat. + * generic/tclVar.c (DeleteArray): leak plug [Bug 604239]. Thanks to + dkf and dgp for the long and difficult discussion in the chat. 2002-09-03 Jeff Hobbs * generic/tclVar.c (Tcl_UpVar2): code cleanup to not use goto * unix/configure: remove -pthread from LIBS on FreeBSD in thread - * unix/tcl.m4: enabled build. [Bug #602849] + * unix/tcl.m4: enabled build. [Bug 602849] 2002-09-03 Miguel Sofer * generic/tclInterp.c (AliasCreate): a Tcl_Obj was leaked on error return from TclPreventAliasLoop. - + 2002-09-03 Daniel Steffen - * macosx/Tcl.pbproj/project.pbxproj: Bumped version number to - 8.4.0 and updated copyright info. + * macosx/Tcl.pbproj/project.pbxproj: Bumped version number to 8.4.0 + and updated copyright info. 2002-09-03 Miguel Sofer - * generic/tclVar.c (Tcl_UpVar2): a Tcl_Obj was being leaked on - error return from TclGetFrame. + * generic/tclVar.c (Tcl_UpVar2): a Tcl_Obj was being leaked on error + return from TclGetFrame. 2002-09-03 Don Porter * changes: Updated changes for 8.4.0 release. @@ -1739,11 +6401,11 @@ * unix/tclUnixChan.c (Tcl_MakeTcpClientChannel): make sure to init flags field of TcpState ptr to 0. * unix/configure: * unix/tcl.m4: added 64-bit gcc compilation support on HP-11. - [Patch #601051] (martin) + [Patch 601051] (martin) * README: Bumped version number to 8.4.0 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure: @@ -1752,16 +6414,16 @@ * win/README.binary: * win/configure: * win/configure.in: * generic/tclInterp.c (SlaveCreate): make sure that the memory and - checkmem commands are initialized in non-safe slave interpreters - when TCL_MEM_DEBUG is used. [Bug #583445] + checkmem commands are initialized in non-safe slave interpreters when + TCL_MEM_DEBUG is used. [Bug 583445] - * win/tclWinConsole.c (ConsoleCloseProc): only wait on writable - pipe if there was something to write. This may prevent infinite - wait on exit. + * win/tclWinConsole.c (ConsoleCloseProc): only wait on writable pipe + if there was something to write. This may prevent infinite wait on + exit. * tests/exec.test: marked exec-18.1 unixOnly until the Windows incompatability (in the test, not the core) can be resolved. * tests/http.test (http-3.11): added close $fp that was causing an @@ -1777,133 +6439,130 @@ * unix/configure: regen 2002-08-31 Daniel Steffen - *** macosx-8-4-branch merged into the mainline [tcl patch #602770] *** + *** macosx-8-4-branch merged into the mainline [Patch 602770] *** * generic/tcl.decls: added new macosx specific entry to stubs table. - * tools/genStubs.tcl: added generation of platform guards for - macosx. This is a little more complex than it seems, because MacOS - X IS "unix" plus a little bit, for the purposes of Tcl. BUT - unfortunately, Tk uses "unix" to mean X11. So added platform keys - for macosx (the little added to "unix"), "aqua" and "x11" to - distinguish these for Tk. - - * generic/tcl.h: added a #ifnded RESOURCE_INCLUDED so that tcl.h - can be passed to the resource compiler. - + * tools/genStubs.tcl: added generation of platform guards for macosx. + This is a little more complex than it seems, because MacOS X IS "unix" + plus a little bit, for the purposes of Tcl. BUT unfortunately, Tk uses + "unix" to mean X11. So added platform keys for macosx (the little + added to "unix"), "aqua" and "x11" to distinguish these for Tk. + + * generic/tcl.h: added a #ifnded RESOURCE_INCLUDED so that tcl.h can + be passed to the resource compiler. + * generic/tcl.h: * generic/tclNotify.c: added a few Notifier procs, to be able to - modify more bits of the Tcl notifier dynamically. Required to get - Mac OS X Tk to live on top of the Tcl Unix threaded notifier. - Changes the size of the Tcl_NotifierProcs structure, but doesn't - move any elements around. + modify more bits of the Tcl notifier dynamically. Required to get Mac + OS X Tk to live on top of the Tcl Unix threaded notifier. Changes the + size of the Tcl_NotifierProcs structure, but doesn't move any elements + around. * unix/tclUnixNotfy.c: moved the call to Tcl_ConditionNotify till - AFTER we are done mucking with the pointer swap. Fixes cases where - the thread waiting on the condition wakes & accesses the - waitingListPtr before it gets reset, causing a hang. + AFTER we are done mucking with the pointer swap. Fixes cases where the + thread waiting on the condition wakes & accesses the waitingListPtr + before it gets reset, causing a hang. - * library/auto.tcl (tcl_findLibrary): added checking the - directories in the tcl_pkgPath for library files on macosx to - enable support of the standard Mac OSX library locations + * library/auto.tcl (tcl_findLibrary): added checking the directories + in the tcl_pkgPath for library files on macosx to enable support of + the standard Mac OSX library locations * unix/Makefile.in: * unix/configure.in: - * unix/tcl.m4: added MAC_OSX_DIR. Added PLAT_OBJS to the OBJS: - there are some MacOS X specific files now for Tcl, and when I get - he resource & applescript stuff ported over, and restore support - for FindFiles, etc, there will be a few more. - Added LD_LIBRARY_PATH_VAR configure variable to avoid having to set - all possible LD_LIBRARY_PATH analogues on all platforms. - LD_LIBRARY_PATH_VAR is "LD_LIBRARY_PATH" by default, "LIBPATH" on - AIX, "SHLIB_PATH" on HPUX and "DYLD_LIBRARY_PATH" on Mac OSX. - Added configure option to package Tcl as a framework on Mac OSX. + * unix/tcl.m4: added MAC_OSX_DIR. Added PLAT_OBJS to the OBJS: there + are some MacOS X specific files now for Tcl, and when I get he + resource & applescript stuff ported over, and restore support for + FindFiles, etc, there will be a few more. Added LD_LIBRARY_PATH_VAR + configure variable to avoid having to set all possible LD_LIBRARY_PATH + analogues on all platforms. LD_LIBRARY_PATH_VAR is "LD_LIBRARY_PATH" + by default, "LIBPATH" on AIX, "SHLIB_PATH" on HPUX and + "DYLD_LIBRARY_PATH" on Mac OSX. Added configure option to package Tcl + as a framework on Mac OSX. * macosx/tclMacOSXBundle.c (new): support for finding Tcl extension packaged as 'bundles' in the standard Mac OSX library locations. - * unix/tclUnixInit.c: added support for findig the tcl script - library inside Tcl packaged as a framework on Mac OSX. + * unix/tclUnixInit.c: added support for findig the tcl script library + inside Tcl packaged as a framework on Mac OSX. * macosx/Tcl.pbproj/jingham.pbxuser (new): * macosx/Tcl.pbproj/project.pbxproj (new): project for Apple's ProjectBuilder IDE. - * macosx/Makefile (new): simple makefile for building the project - from the command line via the ProjectBuilder tool 'pbxbuild'. + * macosx/Makefile (new): simple makefile for building the project from + the command line via the ProjectBuilder tool 'pbxbuild'. * unix/configure: * generic/tclStubInit.c: * generic/tclPlatDecls.h: regen 2002-08-29 Andreas Kupries * win/tclWinThrd.c (TclpFinalizeThreadData, TclWinFreeAllocCache): - Applied patch for bug #599428, provided by Miguel Sofer - . + Applied patch for [Bug 599428] (sofer) 2002-08-28 David Gravereaux * generic/tclEnv.c: * unix/configure.in: - * win/tclWinPort.h: putenv() on some systems copies the buffer - rather than taking reference to it. This causes memory leaks - and is know to effect mswindows (msvcrt) and NetBSD 1.5.2 . This - patch tests for this behavior and turns on -DHAVE_PUTENV_THAT_COPIES=1 - when approriate. Thanks to David Welton for assistance. - [Bug 414910] + * win/tclWinPort.h: putenv() on some systems copies the buffer rather + than taking reference to it. This causes memory leaks and is know to + effect mswindows (msvcrt) and NetBSD 1.5.2. This patch tests for this + behavior and turns on -DHAVE_PUTENV_THAT_COPIES=1 when approriate. + Thanks to David Welton for assistance. [Bug 414910] * unix/configure: regen'd 2002-08-28 Donal K. Fellows * doc/eval.n: Added mention of list command and corrected "SEE ALSO". - * unix/configure.in: Cache handling of ac_cv_type_socklen_t was - wrong. [Bug 600931] reported by John Ellson. Fixed by putting the - brackets where they belong. - -2002-08-26 Miguel Sofer - - * generic/tclCompCmds.c: fix for [Bug 599788] (error in element - name causing segfault), reported by Tom Wilkason. Fixed by copying - the tokens instead of the source string. - -2002-08-26 Miguel Sofer - - * generic/tclThreadAlloc.c: small optimisation, reducing the - new allocator's overhead. - -2002-08-23 Miguel Sofer - - * generic/tclObj.c (USE_THREAD_ALLOC): fixed leak [Bug 597936]. - Thanks to Zoran Vasiljevic. - -2002-08-23 Miguel Sofer - - * generic/tclThreadAlloc.c (USE_THREAD_ALLOC): moving objects - between caches as a block, instead of one-by-one. + * unix/configure.in: Cache handling of ac_cv_type_socklen_t was wrong. + [Bug 600931] reported by John Ellson. Fixed by putting the brackets + where they belong. + +2002-08-26 Miguel Sofer + + * generic/tclCompCmds.c: fix for [Bug 599788] (error in element name + causing segfault), reported by Tom Wilkason. Fixed by copying the + tokens instead of the source string. + +2002-08-26 Miguel Sofer + + * generic/tclThreadAlloc.c: small optimisation, reducing the new + allocator's overhead. + +2002-08-23 Miguel Sofer + + * generic/tclObj.c (USE_THREAD_ALLOC): fixed leak [Bug 597936]. Thanks + to Zoran Vasiljevic. + +2002-08-23 Miguel Sofer + + * generic/tclThreadAlloc.c (USE_THREAD_ALLOC): moving objects between + caches as a block, instead of one-by-one. 2002-08-22 Miguel Sofer * generic/tclBasic.c: - * generic/tclCmdMZ.c: fix for freed memory r/w in delete traces - [Bug 589863], patch by Hemang Lavana. + * generic/tclCmdMZ.c: fix for freed memory r/w in delete traces [Bug + 589863], patch by Hemang Lavana. 2002-08-20 Andreas Kupries - * win/Makefile.in (CFLAGS): + * win/Makefile.in (CFLAGS): * unix/Makefile.in (MEM_DEBUG_FLAGS): Added usage of @MEM_DEBUG_FLAGS@. * win/configure.in: * unix/configure.in: Added usage of SC_ENABLE_MEMDEBUG. * win/tcl.m4: * unix/tcl.m4: Added macro SC_ENABLE_MEMDEBUG. Allows a user of - configure to (de)activate memory validation and debugging - (TCL_MEM_DEBUG). No need to modify the makefile anymore. + configure to (de)activate memory validation and debugging + (TCL_MEM_DEBUG). No need to modify the makefile anymore. 2002-08-20 Don Porter * generic/tclCkalloc.c: CONSTified MemoryCmd and CheckmemCmd. @@ -1919,62 +6578,60 @@ * win/configure: * library/http/http.tcl: Corrected installation directory of * library/msgcat/msgcat.tcl: the package tcltest 2.2. Added * library/opt/optparse.tcl: comments in other packages to remind - * library/tcltest/tcltest.tcl: that installation directories need + * library/tcltest/tcltest.tcl: that installation directories need * unix/Makefile.in: updates to match increasing version * win/Makefile.in: numbers. [Bug 597450] * win/makefile.bc: * win/makefile.vc: 2002-08-19 Andreas Kupries * unix/tclUnixTest.c (TestfilehandlerCmd): Changed - readable/writable to the more common readable|writable. - - Fixes SF #596034 reported by Larry Virden - . + readable/writable to the more common readable|writable. + Fixes [Bug 596034] (lvirden) 2002-08-16 Donal K. Fellows * tests/fCmd.test: Added test to make sure that the cause of the problem is detectable with an unpatched Tcl. - * doc/ObjectType.3: Added note on the root cause of this problem - to the documentation, since it is possible for user code to - trigger this sort of behaviour too. + * doc/ObjectType.3: Added note on the root cause of this problem to + the documentation, since it is possible for user code to trigger this + sort of behaviour too. * generic/tclIOUtil.c (SetFsPathFromAny): Objects should only have their old representation deleted when we know that we are about to install a new one. This stops a weird TclX bug under Linux with - certain kinds of memory debugging enabled which essentally came - down to a double-free of a string. + certain kinds of memory debugging enabled which essentally came down + to a double-free of a string. 2002-08-14 Miguel Sofer * generic/tclInt.h: - * generic/tclObj.c: (code cleanup) factored the parts in the macros - TclNewObj() / TclDecrRefCount() into a common part for all - memory allocators and two new macros TclAllocObjStorage() / + * generic/tclObj.c: (code cleanup) factored the parts in the macros + TclNewObj() / TclDecrRefCount() into a common part for all memory + allocators and two new macros TclAllocObjStorage() / TclFreeObjStorage() that are specific to each allocator and fully describe the differences. Removed allocator-specific code from tclObj.c by using the macros. - + 2002-08-12 Miguel Sofer * generic/tclCmdMZ.c: fixing UMR in delete traces, [Bug 589863]. - + 2002-08-08 David Gravereaux - * tools/man2help.tcl: Fixed $argv handling bug where if -bitmap - wasn't specified $argc was off by one. + * tools/man2help.tcl: Fixed $argv handling bug where if -bitmap wasn't + specified $argc was off by one. 2002-08-08 Miguel Sofer * tests/uplevel.test: added 6.1 to test [uplevel] with shadowed commands [Bug 524383] - * tests/subst.test: added 5.8-10 as further tests for [Bug 495207] + * tests/subst.test: added 5.8-10 as further tests for [Bug 495207] 2002-08-08 Don Porter * tests/README: Noted removal of defs.tcl. @@ -1985,138 +6642,134 @@ *** 8.4b2 TAGGED FOR RELEASE *** * tests/fCmd.test: * tests/unixFCmd.test: updated tests for new link copy behavior. * generic/tclFCmd.c (CopyRenameOneFile): changed the behavior to - follow links to endpoints and copy that file/directory instead of - just copying the surface link. This means that trying to copy a - link that has no endpoint (danling link) is an error. - [Patch #591647] (darley) + follow links to endpoints and copy that file/directory instead of just + copying the surface link. This means that trying to copy a link that + has no endpoint (danling link) is an error. [Patch 591647] (darley) (CopyRenameOneFile): this is currently disabled by default until - further issues with such behavior (like relative links) can be - handled correctly. + further issues with such behavior (like relative links) can be handled + correctly. * tests/README: slight wording improvements 2002-08-07 Miguel Sofer - * docs/BoolObj.3: added description of valid string reps for a - boolean object [Bug 584794] + * docs/BoolObj.3: added description of valid string reps for a boolean + object [Bug 584794] * generic/tclObj.c: optimised Tcl_GetBooleanFromObj and SetBooleanFromAny to avoid parsing the string rep when it can be avoided [Bugs 584650, 472576] - + 2002-08-07 Miguel Sofer * generic/tclCompile.h: - * generic/tclObj.c: making tclCmdNameType static ([Bug 584567], - Don Porter). - + * generic/tclObj.c: making tclCmdNameType static [Bug 584567] (dgp) + 2002-08-07 Miguel Sofer * generic/tclObj.c (Tcl_NewObj): added conditional code for USE_THREAD_ALLOC; objects allocated through Tcl_NewObj() were otherwise being leaked. [Bug 587488] reported by Sven Sass. - + 2002-08-06 Daniel Steffen * generic/tclInt.decls: - * unix/tclUnixThrd.c: Added stubs and implementations for - non-threaded build for the tclUnixThrd.c procs TclpReaddir, - TclpLocaltime, TclpGmtime and TclpInetNtoa. - Fixes link errors in stubbed & threaded extensions that include - tclUnixPort.h and use any of the procs readdir, localtime, - gmtime or inet_ntoa (e.g. TclX 8.4) [Bug 589526] + * unix/tclUnixThrd.c: Added stubs and implementations for non-threaded + build for the tclUnixThrd.c procs TclpReaddir, TclpLocaltime, + TclpGmtime and TclpInetNtoa. Fixes link errors in stubbed & threaded + extensions that include tclUnixPort.h and use any of the procs + readdir, localtime, gmtime or inet_ntoa (e.g. TclX 8.4) [Bug 589526] * generic/tclIntPlatDecls.h: * generic/tclStubInit.c: Regen. 2002-08-05 Don Porter * library/tcltest/tcltest.tcl: The setup and cleanup scripts are now * library/tcltest/pkgIndex.tcl: skipped when a test is skipped, fixing - * tests/tcltest.test: [Bug 589859]. Test for bug added, and + * tests/tcltest.test: [Bug 589859]. Test for bug added, and corrected tcltest package bumped to version 2.2. - * generic/tcl.decls: Restored Tcl_Concat to return (char *). Like + * generic/tcl.decls: Restored Tcl_Concat to return (char *). Like * generic/tclDecls.h: Tcl_Merge, it transfers ownership of a dynamic * generic/tclUtil.c: allocated string to the caller. 2002-08-04 Don Porter * doc/CmdCmplt.3: Applied Patch 585105 to fully CONST-ify * doc/Concat.3: all remaining public interfaces of Tcl. - * doc/CrtCommand.3: Notably, the parser no longer writes on + * doc/CrtCommand.3: Notably, the parser no longer writes on * doc/CrtSlave.3: the string it is parsing, so it is no * doc/CrtTrace.3: longer necessary for Tcl_Eval() to be * doc/Eval.3: given a writable string. Also, the * doc/ExprLong.3: refactoring of the Tcl_*Var* routines * doc/LinkVar.3: by Miguel Sofer is included, so that the * doc/ParseCmd.3: "part1" argument for them no longer needs * doc/SetVar.3: to be writable either. * doc/TraceVar.3: * doc/UpVar.3: Compatibility support has been enhanced so - * generic/tcl.decls that a #define of USE_NON_CONST will remove - * generic/tcl.h all possible source incompatibilities with - * generic/tclBasic.c the 8.3 version of the header file(s). - * generic/tclCmdMZ.c The new #define of USE_COMPAT_CONST now does - * generic/tclCompCmds.c what USE_NON_CONST used to do -- disable - * generic/tclCompExpr.c only those new CONST's that introduce - * generic/tclCompile.c irreconcilable incompatibilities. - * generic/tclCompile.h - * generic/tclDecls.h Several bugs are also fixed by this patch. - * generic/tclEnv.c [Bugs 584051,580433] [Patches 585105,582429] - * generic/tclEvent.c - * generic/tclInt.decls - * generic/tclInt.h - * generic/tclIntDecls.h - * generic/tclInterp.c - * generic/tclLink.c - * generic/tclObj.c - * generic/tclParse.c - * generic/tclParseExpr.c - * generic/tclProc.c - * generic/tclTest.c - * generic/tclUtf.c - * generic/tclUtil.c - * generic/tclVar.c - * mac/tclMacTest.c - * tests/expr-old.test - * tests/parseExpr.test - * unix/tclUnixTest.c - * unix/tclXtTest.c - * win/tclWinTest.c + * generic/tcl.decls: that a #define of USE_NON_CONST will remove + * generic/tcl.h: all possible source incompatibilities with + * generic/tclBasic.c: the 8.3 version of the header file(s). + * generic/tclCmdMZ.c: The new #define of USE_COMPAT_CONST now does + * generic/tclCompCmds.c:what USE_NON_CONST used to do -- disable + * generic/tclCompExpr.c:only those new CONST's that introduce + * generic/tclCompile.c: irreconcilable incompatibilities. + * generic/tclCompile.h: + * generic/tclDecls.h: Several bugs are also fixed by this patch. + * generic/tclEnv.c: [Bugs 584051,580433] [Patches 585105,582429] + * generic/tclEvent.c: + * generic/tclInt.decls: + * generic/tclInt.h: + * generic/tclIntDecls.h: + * generic/tclInterp.c: + * generic/tclLink.c: + * generic/tclObj.c: + * generic/tclParse.c: + * generic/tclParseExpr.c: + * generic/tclProc.c: + * generic/tclTest.c: + * generic/tclUtf.c: + * generic/tclUtil.c: + * generic/tclVar.c: + * mac/tclMacTest.c: + * tests/expr-old.test: + * tests/parseExpr.test: + * unix/tclUnixTest.c: + * unix/tclXtTest.c: + * win/tclWinTest.c: 2002-08-01 Miguel Sofer * generic/tclExecute.c: bugfix (reading freed memory). Testsuite passed on linux/i386, compile-13.1 hung on linux/alpha. 2002-08-01 Miguel Sofer * generic/tclExecute.c: added a reference count for the complete - execution stack, instead of Tcl_Preserve/Tcl_Release. + execution stack, instead of Tcl_Preserve/Tcl_Release. 2002-08-01 Mo DeJong - * generic/tclCkalloc.c (TclFinalizeMemorySubsystem): - Don't lock the ckalloc mutex before invoking the - Tcl_DumpActiveMemory function since it also - locks the same mutex. This code is only executed - when "memory onexit filename" has been executed - and Tcl is compiled with -DTCL_MEM_DEBUG. + * generic/tclCkalloc.c (TclFinalizeMemorySubsystem): Don't lock the + ckalloc mutex before invoking the Tcl_DumpActiveMemory function since + it also locks the same mutex. This code is only executed when "memory + onexit filename" has been executed and Tcl is compiled with + -DTCL_MEM_DEBUG. 2002-08-01 Reinhard Max - * win/tclWinPort.h: The windows headers don't provide socklen_t, - so we have to do it. + * win/tclWinPort.h: The windows headers don't provide socklen_t, so we + have to do it. 2002-07-31 Miguel Sofer * generic/tclInt.h (USE_THREAD_ALLOC): for unshared objects, TclDecrRefCount now frees the internal rep before the string rep - - just like the non-macro Tcl_DecrRefCount/TclFreeObj [Bug 524802]. - For the other allocators the fix was done on 2002-03-06. + just like the non-macro Tcl_DecrRefCount/TclFreeObj [Bug 524802]. For + the other allocators the fix was done on 2002-03-06. 2002-07-31 Miguel Sofer * generic/tclInterp.c: signed/unsigned comparison warning fixed (Vince Darley). @@ -2126,207 +6779,198 @@ * unix/tcl.m4 (SC_BUGGY_STRTOD): Enabled caching of test results. * unix/tcl.m4 (SC_BUGGY_STRTOD): Solaris 2.8 still has a buggy strtod() implementation; make sure we detect it. - * tests/expr.test (expr-22.*): Marked as non-portable because it - seems that these tests have an annoying tendency to fail in - unexpected ways. [Bugs 584825, 584950, 585986] + * tests/expr.test (expr-22.*): Marked as non-portable because it seems + that these tests have an annoying tendency to fail in unexpected ways. + [Bugs 584825, 584950, 585986] 2002-07-30 Andreas Kupries - * tests/io.test: + * tests/io.test: * generic/tclIO.c (WriteChars): Added flag to break out of loop if - nothing of the input is consumed at all, to prevent infinite - looping of called with a non-UTF-8 string. Fixes Bug 584603 - (partially). Added new test "io-60.1". Might need additional - changes to Tcl_Main so that unprintable results are printed as - binary data. + nothing of the input is consumed at all, to prevent infinite looping + of called with a non-UTF-8 string. Fixes [Bug 584603] partially. + Added new test "io-60.1". Might need additional changes to Tcl_Main so + that unprintable results are printed as binary data. 2002-07-29 Mo DeJong - * unix/Makefile.in: Use CC_SEARCH_FLAGS instead of - LD_SEARCH_FLAGS when linking with ${CC}. + * unix/Makefile.in: Use CC_SEARCH_FLAGS instead of LD_SEARCH_FLAGS + when linking with ${CC}. * unix/configure: Regen. - * unix/configure.in: Don't subst CC_SEARCH_FLAGS or - LD_SEARCH_FLAGS since this is now done in tcl.m4. - * unix/tcl.m4 (SC_CONFIG_CFLAGS): Document and - set CC_SEARCH_FLAGS whenever LD_SEARCH_FLAGS is set. - [Tcl patch 588290] + * unix/configure.in: Don't subst CC_SEARCH_FLAGS or LD_SEARCH_FLAGS + since this is now done in tcl.m4. + * unix/tcl.m4 (SC_CONFIG_CFLAGS): Document and set CC_SEARCH_FLAGS + whenever LD_SEARCH_FLAGS is set. [Patch 588290] 2002-07-29 Reinhard Max * unix/tcl.m4 (SC_SERIAL_PORT): Fixed detection for cases when - configure's stdin is not a tty. - - * unix/tclUnixPort.h: - * generic/tclIOSock.c: Changed size_t to socklen_t in - socket-related function calls. - - * unix/configure.in: Added test and fallback definition - for socklen_t. - - * unix/configure: generated. + configure's stdin is not a tty. + + * unix/tclUnixPort.h: + * generic/tclIOSock.c: Changed size_t to socklen_t in + socket-related function calls. + + * unix/configure.in: Added test and fallback definition + for socklen_t. + + * unix/configure: generated. 2002-07-29 Miguel Sofer * generic/tclObj.c: fixed a comment - * generic/tcl.h: - * generic/tclBasic.c: - * generic/tclInterp.c: added the new flag TCL_EVAL_INVOKE to - the interface of the Tcl_Eval* functions, removing the - TCL_EVAL_NO_TRACEBACK added yesterday: alias invocations not only - require no tracebacks, but also look up the command name in the - global scope - see new test interp-9.4 - * tests/interp.test: added 9.3 to test for safety of aliases to - hidden commands, 9.4 to test for correct command lookup scope. + * generic/tcl.h: + * generic/tclBasic.c: + * generic/tclInterp.c: added the new flag TCL_EVAL_INVOKE to the + interface of the Tcl_Eval* functions, removing the + TCL_EVAL_NO_TRACEBACK added yesterday: alias invocations not only + require no tracebacks, but also look up the command name in the global + scope - see new test interp-9.4 + * tests/interp.test: added 9.3 to test for safety of aliases to hidden + commands, 9.4 to test for correct command lookup scope. 2002-07-29 Donal K. Fellows * generic/regc_locale.c (cclass): [[:xdigit:]] is only a defined - concept on western characters, so should not allow any unicode - digit, and hence number of ranges in [[:xdigit:]] is fixed. + concept on western characters, so should not allow any unicode digit, + and hence number of ranges in [[:xdigit:]] is fixed. * tests/reg.test: Added test to detect the bug. * generic/regc_cvec.c (newcvec): Corrected initial size value in - character vector structure. [Bug 578363] Many thanks to + character vector structure. [Bug 578363] Many thanks to pvgoran@users.sf.net for tracking this down. 2002-07-28 Miguel Sofer - * generic/tcl.h: - * generic/tclBasic.c: added the new flag TCL_EVAL_NO_TRACEBACK to - the interface of the Tcl_Eval* functions. Modified the error - message for too many nested evaluations. + * generic/tcl.h: + * generic/tclBasic.c: added the new flag TCL_EVAL_NO_TRACEBACK to the + interface of the Tcl_Eval* functions. Modified the error message for + too many nested evaluations. * generic/tclInterp.h: changed the Alias struct to be of variable - length and store the prefix arguments directly (instead of a - pointer to a Tcl_Obj list). Made AliasObjCmd call Tcl_EvalObjv - instead of TclObjInvoke - thus making aliases trigger execution - traces [Bug 582522]. + length and store the prefix arguments directly (instead of a pointer + to a Tcl_Obj list). Made AliasObjCmd call Tcl_EvalObjv instead of + TclObjInvoke - thus making aliases trigger execution traces. [Bug + 582522] * tests/interp.test: * tests/stack.test: adapted to the new error message. - * tests/trace.test: added tests for aliases firing the exec - traces. + * tests/trace.test: added tests for aliases firing the exec traces. 2002-07-27 Mo DeJong - * unix/Makefile.in: Revert fix for Tcl bug 529801 - since it was incorrect and broke the build on - other systems. Fix Tcl bug 587299. - Add MAJOR_VERSION, MINOR_VERSION, PATCH_LEVEL, - SHLIB_LD_FLAGS, SHLIB_LD_LIBS, CC_SEARCH_FLAGS, - LD_SEARCH_FLAGS, and LIB_FILE variables to support - more generic library build/install rules. + * unix/Makefile.in: Revert fix for Tcl bug 529801 since it was + incorrect and broke the build on other systems. Fix [Bug 587299]. Add + MAJOR_VERSION, MINOR_VERSION, PATCH_LEVEL, SHLIB_LD_FLAGS, + SHLIB_LD_LIBS, CC_SEARCH_FLAGS, LD_SEARCH_FLAGS, and LIB_FILE + variables to support more generic library build/install rules. * unix/configure: Regen. - * unix/configure.in: Move AC_PROG_RANLIB into - tcl.m4. Move shared build test and setting - of MAKE_LIB and MAKE_STUB_LIB into tcl.m4. - Move subst of a number of variables into - tcl.m4 where they are defined. + * unix/configure.in: Move AC_PROG_RANLIB into tcl.m4. Move shared + build test and setting of MAKE_LIB and MAKE_STUB_LIB into tcl.m4. Move + subst of a number of variables into tcl.m4 where they are defined. * unix/tcl.m4 (SC_ENABLE_SYMBOLS, SC_CONFIG_CFLAGS): - Subst vars where they are defined. Add MAKE_LIB, - MAKE_STUB_LIB, INSTALL_LIB, and INSTALL_STUB_LIB - rules to deal with the ugly details of running - ranlib on static libs at build and install time. - Replace TCL_SHLIB_LD_EXTRAS with SHLIB_LD_FLAGS - and use it when building a shared library. + Subst vars where they are defined. Add MAKE_LIB, MAKE_STUB_LIB, + INSTALL_LIB, and INSTALL_STUB_LIB rules to deal with the ugly details + of running ranlib on static libs at build and install time. Replace + TCL_SHLIB_LD_EXTRAS with SHLIB_LD_FLAGS and use it when building a + shared library. * unix/tclConfig.sh.in: Add TCL_CC_SEARCH_FLAGS. 2002-07-26 Miguel Sofer - * generic/tclExecute.c: fixed Tcl_Obj leak in code corresponding - to the macro NEXT_INST_V(x, 0, 1) [Bug 587495]. - + * generic/tclExecute.c: fixed Tcl_Obj leak in code corresponding to + the macro NEXT_INST_V(x, 0, 1). [Bug 587495] + 2002-07-26 Miguel Sofer - * generic/tclVar.c (TclObjLookupVar): leak fix and improved - comments. + * generic/tclVar.c (TclObjLookupVar): leak fix and improved comments. 2002-07-26 Jeff Hobbs * generic/tclVar.c (TclLookupVar): removed early returns that - prevented the parens from being restored. also removed goto label - as it was not necessary. + prevented the parens from being restored. also removed goto label as + it was not necessary. 2002-07-24 Miguel Sofer - * generic/tclExecute.c: + * generic/tclExecute.c: * tests/expr-old.test: fix for erroneous error messages in [expr], - [Bug 587140] reported by Martin Lemburg. + [Bug 587140] reported by Martin Lemburg. 2002-07-25 Joe English - * generic/tclProc.c: fix for Tk Bug #219218 "error handling - with bgerror in Tk" + + * generic/tclProc.c: fix for [Tk Bug 219218] "error handling with + bgerror in Tk" 2002-07-24 Miguel Sofer * generic/tclExecute.c: restoring full TCL_COMPILE_DEBUG functionality. 2002-07-24 Don Porter - * tests/unixInit.test: relaxed unixInit-3.1 to accept iso8859-15 - as a valid C encoding. [Bug 575336] + * tests/unixInit.test: relaxed unixInit-3.1 to accept iso8859-15 as a + valid C encoding. [Bug 575336] 2002-07-24 Miguel Sofer - * generic/tclExecute.c: restoring the tcl_traceCompile - functionality while I repair tcl_traceExec. The core now compiles - and runs also under TCL_COMPILE_DEBUG, but execution in the - bytecode engine can still not be traced. + * generic/tclExecute.c: restoring the tcl_traceCompile functionality + while I repair tcl_traceExec. The core now compiles and runs also + under TCL_COMPILE_DEBUG, but execution in the bytecode engine can + still not be traced. 2002-07-24 Daniel Steffen * unix/Makefile.in: - * unix/configure.in: corrected fix for [Bug 529801]: ranlib - only needed for static builds on Mac OS X. + * unix/configure.in: corrected fix for [Bug 529801]: ranlib only + needed for static builds on Mac OS X. * unix/configure: Regen. * unix/tclLoadDyld.c: fixed small bugs introduced by Vince, implemented library unloading correctly (needs OS X 10.2). 2002-07-23 Joe English * doc/OpenFileChnl.3: (Updates from Larry Virden) * doc/open.n: * doc/tclsh.1: Fix section numbers in Unix man page references. - * doc/lset.n: In EXAMPLES section, include command to set the - initial value used in subsequent examples. + * doc/lset.n: In EXAMPLES section, include command to set the initial + value used in subsequent examples. * doc/http.n: Package version updated to 2.4. 2002-07-23 Mo DeJong * unix/configure: Regen. - * unix/tcl.m4 (SC_CONFIG_CFLAGS): Enable 64 bit compilation - when using the native compiler on a 64 bit version of IRIX. - [Tcl bug 219220] + * unix/tcl.m4 (SC_CONFIG_CFLAGS): Enable 64 bit compilation when using + the native compiler on a 64 bit version of IRIX. [Bug 219220] 2002-07-23 Mo DeJong - * unix/Makefile.in: Combine ranlib tests and - avoid printing unless ranlib is actually run. + * unix/Makefile.in: Combine ranlib tests and avoid printing unless + ranlib is actually run. 2002-07-23 Mo DeJong - * unix/tcl.m4 (SC_PATH_X): Set XINCLUDES to "" instead - of "# no special path needed" or "# no include files found" - when x headers cannot be located. + * unix/tcl.m4 (SC_PATH_X): Set XINCLUDES to "" instead of "# no + special path needed" or "# no include files found" when x headers + cannot be located. 2002-07-22 Vince Darley - * generic/tclIOUtil.c: made tclNativeFilesystem static - (since 07-19 changes removed its usage elsewhere), and - added comments about its usage. + * generic/tclIOUtil.c: made tclNativeFilesystem static (since 07-19 + changes removed its usage elsewhere), and added comments about its + usage. * generic/tclLoad.c: * generic/tcl.h: - * generic/tcl.decls: - * doc/FileSystem.3: converted last load-related ClientData - parameter to Tcl_LoadHandle opaque structure, removing a - couple of casts in the process. - - * generic/tclInt.h: removed tclNativeFilesystem declaration - since it is now static again. - + * generic/tcl.decls: + * doc/FileSystem.3: converted last load-related ClientData parameter + to Tcl_LoadHandle opaque structure, removing a couple of casts in the + process. + + * generic/tclInt.h: removed tclNativeFilesystem declaration since it + is now static again. + 2002-07-22 Donal K. Fellows * tests/expr.test (expr-22.*): Added tests to help detect the corrected handling. * generic/tclExecute.c (IllegalExprOperandType): Improved error @@ -2340,100 +6984,98 @@ 2002-07-19 Vince Darley * generic/tclIOUtil.c: fix to GetFilesystemRecord * win/tclWinFile.c: - * unix/tclUnixFile.c: fix to subtle problem with links shown - up by latest tclkit builds. + * unix/tclUnixFile.c: fix to subtle problem with links shown up by + latest tclkit builds. 2002-07-19 Mo DeJong * unix/configure: * unix/configure.in: * win/configure: - * win/configure.in: Add AC_PREREQ(2.13) in an attempt - to make it more clear that the configure scripts - must be generated with autoconf version 2.13. - [Bug 583573] + * win/configure.in: Add AC_PREREQ(2.13) in an attempt to make it more + clear that the configure scripts must be generated with autoconf + version 2.13. [Bug 583573] 2002-07-19 Vince Darley - * unix/Makefile.in: fix to build on MacOS X [Bug 529801], bug - report and fix from jcw. + * unix/Makefile.in: fix to build on MacOS X [Bug 529801], bug report + and fix from jcw. 2002-07-19 Donal K. Fellows * win/tclWinSerial.c (no_timeout): Made this variable static. - * generic/tclExecute.c, generic/tclCompile.c, generic/tclBasic.c: + * generic/tclExecute.c, generic/tclCompile.c, generic/tclBasic.c: * generic/tclCompile.h (builtinFuncTable, instructionTable): Added prefix to these symbols because they are visible outside the Tcl library. - * generic/tclCompExpr.c (operatorTable): + * generic/tclCompExpr.c (operatorTable): * unix/tclUnixTime.c (tmKey): * generic/tclIOUtil.c (theFilesystemEpoch, filesystemWantToModify, - filesystemIteratorsInProgress, filesystemOkToModify): Made these + (filesystemIteratorsInProgress, filesystemOkToModify): Made these variables static. * unix/tclUnixFile.c: Renamed nativeFilesystem to * win/tclWinFile.c: tclNativeFilesystem and declared * generic/tclIOUtil.c: it properly in tclInt.h - * generic/tclInt.h: + * generic/tclInt.h: * generic/tclUtf.c (totalBytes): Made this array static and const. * generic/tclParse.c (typeTable): Made this array static and const. - (Tcl_ParseBraces): Simplified error handling case so that scans - are only performed when needed, and flags are simpler too. + (Tcl_ParseBraces): Simplified error handling case so that scans are + only performed when needed, and flags are simpler too. - * license.terms: Added AS to list of copyright holders; it's only - fair for the current gatekeepers to be listed here! + * license.terms: Added AS to list of copyright holders; it's only fair + for the current gatekeepers to be listed here! - * tests/cmdMZ.test: Renamed constraint for clarity. [Bug#583427] + * tests/cmdMZ.test: Renamed constraint for clarity. [Bug 583427] Added tests for the [time] command, which was previously only indirectly tested! 2002-07-18 Vince Darley * generic/tclInt.h: * generic/tcl.h: - * */*Load*.c: added comments on changes of 07/17 and - replaced clientData with Tcl_LoadHandle in all locations. + * */*Load*.c: added comments on changes of 07/17 and replaced + clientData with Tcl_LoadHandle in all locations. * generic/tclFCmd.c: * tests/fileSystem.test: fixed a 'knownBug' with 'file attributes ""' - * tests/winFCmd.test: + * tests/winFCmd.test: * tests/winPipe.test: * tests/fCmd.test: - * tessts/winFile.test: added 'pcOnly' constraint to some - tests to make for more useful 'tests skipped' log from - running all tests on non-Windows platforms. - + * tessts/winFile.test: added 'pcOnly' constraint to some tests to make + for more useful 'tests skipped' log from running all tests on + non-Windows platforms. + 2002-07-17 Miguel Sofer - * generic/tclBasic.c (CallCommandTraces): delete traces now - receive the FQ old name of the command. - [Bug 582532] (Don Porter) + * generic/tclBasic.c (CallCommandTraces): delete traces now receive + the FQ old name of the command. [Bug 582532] (Don Porter) 2002-07-18 Vince Darley - * tests/ioUtil.test: added constraints to 1.4,2.4 so they - don't run outside of tcltest. [Bugs 583276,583277] - + * tests/ioUtil.test: added constraints to 1.4,2.4 so they don't run + outside of tcltest. [Bugs 583276,583277] + 2002-07-17 Miguel Sofer - * generic/tclVar.c (DupParsedVarName): nasty bug fixed, reported - by Vince Darley. + * generic/tclVar.c (DupParsedVarName): nasty bug fixed, reported by + Vince Darley. 2002-07-17 Miguel Sofer * generic/tclVar.c (TclPtrIncrVar): missing CONST in declarations, - inconsistent with tclInt.h. Thanks to Vince Darley for reporting, - boo to gcc for not complaining. - + inconsistent with tclInt.h. Thanks to Vince Darley for reporting, boo + to gcc for not complaining. + 2002-07-17 Vince Darley * generic/tclInt.h: * generic/tclIOUtil.c: * generic/tclLoadNone.c: @@ -2443,128 +7085,126 @@ * unix/tclLoadDyld.c: * unix/tclLoadNext.c: * unix/tclLoadOSF.c: * unix/tclLoadShl.c: * mac/tclMacLoad.c: - * win/tclWinLoad.c: modified to move more functionality - to the generic code and avoid duplication. Partial replacement - of internal uses of clientData with opaque Tcl_LoadHandle. A - little further work still needed, but significant changes are done. + * win/tclWinLoad.c: modified to move more functionality to the generic + code and avoid duplication. Partial replacement of internal uses of + clientData with opaque Tcl_LoadHandle. A little further work still + needed, but significant changes are done. 2002-07-17 D. Richard Hipp - * library/msgcat/msgcat.tcl: fix a comment that was causing - problems for programs (ex: mktclapp) that embed the initialization - scripts in strings. + * library/msgcat/msgcat.tcl: fix a comment that was causing problems + for programs (ex: mktclapp) that embed the initialization scripts in + strings. 2002-07-17 Miguel Sofer * generic/tclInt.decls: * generic/tclIntDecls.h: * generic/tclStubInit.c: * generic/tclVar.c: removing the now redundant functions to access indexed variables: Tcl(Get|Set|Incr)IndexedScalar() and - Tcl(Get|Set|Incr)ElementOfIndexedArray(). + Tcl(Get|Set|Incr)ElementOfIndexedArray(). 2002-07-17 Donal K. Fellows - * generic/tclExecute.c (TclExecuteByteCode): Minor fixes to make - this file compile with SunPro CC... + * generic/tclExecute.c (TclExecuteByteCode): Minor fixes to make this + file compile with SunPro CC... 2002-07-17 Miguel Sofer - * generic/tclExecute.c: modified to do variable lookup explicitly, - and then either inlining the variable access or else calling the new + * generic/tclExecute.c: modified to do variable lookup explicitly, and + then either inlining the variable access or else calling the new TclPtr(Set|Get|Incr)Var functions in tclVar.c * generic/tclInt.h: declare some functions previously local to tclVar.c for usage by TEBC. * generic/tclVar.c: removed local declarations; moved all special - accessor functions for indexed variables to the end of the file - - they are unused and ready for removal, but left there for the time - being as they are in the internal stubs table. + accessor functions for indexed variables to the end of the file - they + are unused and ready for removal, but left there for the time being as + they are in the internal stubs table. ** WARNING FOR BYTECODE MAINTAINERS ** TCL_COMPILE_DEBUG is currently not functional; will be fixed ASAP. - + 2002-07-16 Mo DeJong * unix/Makefile.in: - * win/Makefile.in: Add a more descriptive warning - in the event `make genstubs` needs to be rerun. + * win/Makefile.in: Add a more descriptive warning in the event `make + genstubs` needs to be rerun. 2002-07-16 Mo DeJong - * unix/Makefile.in: Use dltest.marker file - to keep track of when the dltest package - is up to date. This fixes [Tcl bug 575768] - since tcltest is no longer linked every time. - * unix/dltest/Makefile.in: Create ../dltest.marker - after a successful `make all` run in dltest. + * unix/Makefile.in: Use dltest.marker file to keep track of when the + dltest package is up to date. This fixes [Bug 575768] since tcltest is + no longer linked every time. + * unix/dltest/Makefile.in: Create ../dltest.marker after a successful + `make all` run in dltest. 2002-07-16 Mo DeJong * unix/configure: Regen. * unix/configure.in: Remove useless subst of TCL_BIN_DIR. 2002-07-15 Miguel Sofer * generic/tclVar.c: inaccurate comment fixed - + 2002-07-15 Miguel Sofer * generic/tclBasic.c (Tcl_AddObjErrorInfo): * generic/tclExecute.c (TclUpdateReturnInfo): - * generic/tclInt.h: - * generic/tclProc.c: - Added two Tcl_Obj to the ExecEnv structure to hold the fully - qualified names "::errorInfo" and "::errorCode" to cache the - addresses of the corresponding variables. The two most frequent - setters of these variables now profit from the new variable name - caching. + * generic/tclInt.h: + * generic/tclProc.c: + Added two Tcl_Obj to the ExecEnv structure to hold the fully qualified + names "::errorInfo" and "::errorCode" to cache the addresses of the + corresponding variables. The two most frequent setters of these + variables now profit from the new variable name caching. 2002-07-15 Miguel Sofer * generic/tclVar.c: refactorisation to reuse already looked-up Var - pointers; definition of three new Tcl_Obj types to cache variable - name parsing and lookup for later reuse; modification of internal - functions to profit from the caching. - + pointers; definition of three new Tcl_Obj types to cache variable name + parsing and lookup for later reuse; modification of internal functions + to profit from the caching. + * generic/tclInt.decls: * generic/tclInt.h: * generic/tclIntDecls.h: * generic/tclNamesp.c: adding CONST qualifiers to variable names - passed to Tcl_FindNamespaceVar and to variable resolvers; adding - CONST qualifier to the 'msg' argument to TclLookupVar. Needed to - avoid code duplication in the new tclVar.c code. + passed to Tcl_FindNamespaceVar and to variable resolvers; adding CONST + qualifier to the 'msg' argument to TclLookupVar. Needed to avoid code + duplication in the new tclVar.c code. * tests/set-old.test: * tests/var.test: slight modification of error messages due to the modifications in the tclVar.c code. 2002-07-15 Don Porter - * tests/unixInit.test: Improved constraints to protect /tmp. - [Bug 581403] + * tests/unixInit.test: Improved constraints to protect /tmp. [Bug + 581403] 2002-07-15 Vince Darley - * tests/winFCmd.test: renamed 'win2000' and 'notWin2000' to - more appropriate constraint names. + * tests/winFCmd.test: renamed 'win2000' and 'notWin2000' to more + appropriate constraint names. * win/tclWinFile.c: updated comments to reflect 07-11 changes. - * win/tclWinFCmd.c: made ConvertFileNameFormat static again, - since no longer used in tclWinFile.c - * mac/tclMacFile.c: completed TclpObjLink implementation which - was previously lacking. + * win/tclWinFCmd.c: made ConvertFileNameFormat static again, since no + longer used in tclWinFile.c + * mac/tclMacFile.c: completed TclpObjLink implementation which was + previously lacking. * generic/tclIOUtil.c: comment cleanup and code speedup. - + 2002-07-14 Don Porter * generic/tclInt.h: Removed declarations that duplicated entries - in the (internal) stub table. - - * library/tcltest/tcltest.tcl: Corrected errors in handling of - configuration options -constraints and -limitconstraints. + in the (internal) stub table. + + * library/tcltest/tcltest.tcl: Corrected errors in handling of + configuration options -constraints and -limitconstraints. * README: Bumped HEAD to version 8.4b2 so we can * generic/tcl.h: distinguish it from the 8.4b1 release. * tools/tcl.wse.in: * unix/configure*: @@ -2573,15 +7213,15 @@ * win/configure*: 2002-07-11 Vince Darley * doc/file.n: - * win/tclWinFile.c: on Win 95/98/ME the long form of the path - is used as a normalized form. This is required because short - forms are not a robust representation. The file normalization - function has been sped up, but more performance gains might be - possible, if speed is still an issue on these platforms. + * win/tclWinFile.c: on Win 95/98/ME the long form of the path is used + as a normalized form. This is required because short forms are not a + robust representation. The file normalization function has been sped + up, but more performance gains might be possible, if speed is still an + issue on these platforms. 2002-07-11 Don Porter * library/tcltest/tcltest.tcl: Corrected reaction to existing but false ::tcl_interactive. @@ -2588,38 +7228,38 @@ * doc/Hash.3: Overlooked CONST documentation update. 2002-07-11 Donal K. Fellows - * generic/tclCkalloc.c: ckalloc() and friends take the block size - as an unsigned, so we should use %ud when reporting it in fprintf() - and panic(). + * generic/tclCkalloc.c: ckalloc() and friends take the block size as + an unsigned, so we should use %ud when reporting it in fprintf() and + panic(). 2002-07-11 Miguel Sofer - * generic/tclCompile.c: now setting local vars undefined at - compile time, instead of waiting until the proc is initialized. - * generic/tclProc.c: use macro TclSetVarUndefined instead of - directly etting the flag. + * generic/tclCompile.c: now setting local vars undefined at compile + time, instead of waiting until the proc is initialized. + * generic/tclProc.c: use macro TclSetVarUndefined instead of directly + setting the flag. 2002-07-11 Donal K. Fellows * tests/cmdAH.test: [file attr -perm] is Unix-only, so add [catch] when not inside a suitably-protected test. 2002-07-10 Donal K. Fellows - * tests/unixFCmd.test, tests/fileName.test: + * tests/unixFCmd.test, tests/fileName.test: * tests/fCmd.test: Removed [exec] of Unix utilities that have - equivalents in standard Tcl. [Bug 579268] Also simplified some - of unixFCmd.test while I was at it. + equivalents in standard Tcl. [Bug 579268] Also simplified some of + unixFCmd.test while I was at it. 2002-07-10 Don Porter * tests/tcltest.test: Greatly reduced the number of [exec]s, using slave interps instead. - * library/tcltest/tcltest.tcl: Fixed bug uncovered in the conversion + * library/tcltest/tcltest.tcl: Fixed bug uncovered in the conversion where a message was written to stdout instead of [outputChannel]. * tests/basic.test: Cleaned up, constrained, and reduced the * tests/compile.test: amount of [exec] usage in the test suite. * tests/encoding.test: @@ -2639,24 +7279,24 @@ 2002-07-10 Donal K. Fellows * tests/cmdAH.test: Removed [exec] of Unix utilities. [Bug 579211] * tests/expr.test: Added tests to make sure that this works. - * generic/tclExecute.c (ExprCallMathFunc): Functions should also - be able to return wide-ints. [Bug 579284] + * generic/tclExecute.c (ExprCallMathFunc): Functions should also be + able to return wide-ints. [Bug 579284] 2002-07-08 Andreas Kupries - * tests/socket.test: Fixed bug #578164. The original reason for - the was a DNS outage while running the testsuite. Changed [info - hostname] to 127.0.0.1 to bypass DNS, knowing that we operate on - the local host. + * tests/socket.test: Fixed [Bug 578164]. The original reason for the + was a DNS outage while running the testsuite. Changed [info hostname] + to 127.0.0.1 to bypass DNS, knowing that we operate on the local + host. 2002-07-08 Don Porter * doc/tcltest.n: Fixed incompatibility in [viewFile]. - * library/tcltest/tcltest.tcl: Corrected docs. Bumped to 2.2.1. + * library/tcltest/tcltest.tcl: Corrected docs. Bumped to 2.2.1. * library/tcltest/pkgIndex.tcl: [Bug 578163] 2002-07-08 Vince Darley * tests/cmdAH.test: @@ -2669,51 +7309,52 @@ * generic/tclTest.c: * mac/tclMacChan.c: * unix/tclUnixChan.c: * win/tclWinChan.c: * doc/FileSystem.3: cleaned up internal handling of - Tcl_FSOpenFileChannel to remove duplicate code, and make - writing external vfs's clearer and easier. No - functionality change. Also clarify that objects with refCount - zero should not be passed in to the Tcl_FS API, and prevent - segfaults from occuring on such user errors. [Bug 578617] - + Tcl_FSOpenFileChannel to remove duplicate code, and make writing + external vfs's clearer and easier. No functionality change. Also + clarify that objects with refCount zero should not be passed in to the + Tcl_FS API, and prevent segfaults from occuring on such user errors. + [Bug 578617] + 2002-07-06 Don Porter * tests/pkgMkIndex.test: Constrained tests of [load] package indexing to those platforms where the testing shared libraries have been built. [Bug 578166]. 2002-07-05 Don Porter + * changes: added recent changes 2002-07-05 Reinhard Max * generic/tclClock.c (FormatClock): Convert the format string to - UTF8 before calling TclpStrftime, so that non-ASCII characters - don't get mangled when the result string is being converted back. + UTF8 before calling TclpStrftime, so that non-ASCII characters don't + get mangled when the result string is being converted back. * tests/clock.test: Added a test for that. 2002-07-05 Donal K. Fellows - * unix/Makefile.in (ro-test,ddd,GDB,DDD): Created new targets to - allow running the test suite with a read-only current directory, - running under ddd instead of gdb, and factored out some executable - names for broken sites (like mine) where gdb and ddd are installed - with non-standard names... - - * tests/httpold.test: Altered test names to httpold-* to avoid - clashes with http.test, and stopped tests from failing when the - current directory is not writable... + * unix/Makefile.in (ro-test,ddd,GDB,DDD): Created new targets to allow + running the test suite with a read-only current directory, running + under ddd instead of gdb, and factored out some executable names for + broken sites (like mine) where gdb and ddd are installed with + non-standard names... + + * tests/httpold.test: Altered test names to httpold-* to avoid clashes + with http.test, and stopped tests from failing when the current + directory is not writable... * tests/event.test: Stop these tests from failing * tests/ioUtil.test: when the current directory is * tests/regexp.test: not writable... - * tests/regexpComp.test: - * tests/source.test: - * tests/unixFile.test: - * tests/unixNotfy.test: + * tests/regexpComp.test: + * tests/source.test: + * tests/unixFile.test: + * tests/unixNotfy.test: * tests/unixFCmd.test: Trying to make these test-files * tests/macFCmd.test: not bomb out with an error when * tests/http.test: the current directory is not * tests/fileName.test: writable... @@ -2723,39 +7364,39 @@ *** 8.4b1 TAGGED FOR RELEASE *** 2002-07-04 Donal K. Fellows - * tests/cmdMZ.test (cmdMZ-1.4): - * tests/cmdAH.test: More fixing of writable-current-dir - assumption. [Bug 575824] + * tests/cmdMZ.test (cmdMZ-1.4): + * tests/cmdAH.test: More fixing of writable-current-dir assumption. + [Bug 575824] 2002-07-04 Miguel Sofer * tests/basic.test: Same issue as below; fixed [Bug 575817] - + 2002-07-04 Andreas Kupries - * tests/socket.test: - * tests/winPipe.test: - * tests/pid.test: Fixed SF Bug #575848. See below for a - description the general problem. - - * All the bugs below are instances of the same problem: The - testsuite assumes [pwd] = [temporaryDirectory] and writable. - - * tests/iogt.test: Fixed bug #575860. - * tests/io.test: Fixed bug #575862. - * tests/exec.test: - * tests/ioCmd.test: Fixed bug #575836. + * tests/socket.test: + * tests/winPipe.test: + * tests/pid.test: Fixed [Bug 575848]. See below for a description the + general problem. + + All the bugs below are instances of the same problem: The testsuite + assumes [pwd] = [temporaryDirectory] and writable. + + * tests/iogt.test: Fixed [Bug 575860] + * tests/io.test: Fixed [Bug 575862] + * tests/exec.test: + * tests/ioCmd.test: Fixed [Bug 575836] 2002-07-03 Don Porter * tests/pkg1/direct1.tcl: removed * tests/pkg1/pkgIndex.tcl: removed - * tests/pkgMkIndex.test: Imported auxilliary files from tests/pkg1 - into the test file pkgMkIndex.test itself. Formatting fixes. + * tests/pkgMkIndex.test: Imported auxilliary files from tests/pkg1 + into the test file pkgMkIndex.test itself. Formatting fixes. * unix/Makefile.in: removed tests/pkg/* from `make dist` * tests/pkg/circ1.tcl: removed * tests/pkg/circ2.tcl: removed @@ -2772,26 +7413,25 @@ * tests/pkg/samename.tcl: removed * tests/pkg/simple.tcl: removed * tests/pkg/spacename.tcl: removed * tests/pkg/std.tcl: removed * tests/pkgMkIndex.test: Fixed [Bug 575857] where this test file - expected to be able to write to [file join [testsDirectory] - pkg]. Part of the fix was to import several auxilliary files - into the test file itself. + expected to be able to write to [file join [testsDirectory] pkg]. Part + of the fix was to import several auxilliary files into the test file + itself. - * tests/main.test: Cheap fix for [Bugs 575851, 575858]. Avoid + * tests/main.test: Cheap fix for [Bugs 575851, 575858]. Avoid * tests/tcltest.test: non-writable . by [cd [temporaryDirectory]]. - * library/auto.tcl: Fix [tcl_findLibrary] to be sure it sets - $varName only if a successful library script is found. - [Bug 577033] + * library/auto.tcl: Fix [tcl_findLibrary] to be sure it sets $varName + only if a successful library script is found. [Bug 577033] 2002-07-03 Miguel Sofer * generic/tclCompCmds.c (TclCompileCatchCmd): return - TCL_OUT_LINE_COMPILE instead of TCL_ERROR: let the failure - happen at runtime so that it can be caught [Bug 577015]. + TCL_OUT_LINE_COMPILE instead of TCL_ERROR: let the failure happen at + runtime so that it can be caught [Bug 577015]. 2002-07-02 Joe English * doc/tcltest.n: Markup fixes, spellcheck. @@ -2798,31 +7438,30 @@ 2002-07-02 Don Porter * doc/tcltest.n: more refinements of the documentation. * library/tcltest/tcltest.tcl: Added trace to be sure the stdio - constraint is updated whenever the [interpreter] changes. + constraint is updated whenever the [interpreter] changes. * doc/tcltest.n: Reverted [makeFile] and [viewFile] to * library/tcltest/tcltest.tcl: their former behavior, and documented - * tests/cmdAH.test: it. Corrected misspelling of hook - * tests/event.test: procedure. Restored tests. + * tests/cmdAH.test: it. Corrected misspelling of hook + * tests/event.test: procedure. Restored tests. * tests/http.test: * tests/io.test: - * library/tcltest/tcltest.tcl: Simplified logic of - [GetMatchingFiles] and [GetMatchingDirectories], removing - special case processing. + * library/tcltest/tcltest.tcl: Simplified logic of [GetMatchingFiles] + and [GetMatchingDirectories], removing special case processing. - * doc/tcltest.n: More documentation updates. Reference sections - are complete. Only examples need adding. + * doc/tcltest.n: More documentation updates. Reference sections are + complete. Only examples need adding. 2002-07-02 Vince Darley - * tests/fCmd.test: - * generic/tclCmdAH.c: clearer error msgs for 'file link', - as per the man page. + * tests/fCmd.test: + * generic/tclCmdAH.c: clearer error msgs for 'file link', as per the + man page. 2002-07-01 Joe English * doc/Access.3: * doc/AddErrInfo.3: @@ -2856,30 +7495,29 @@ * doc/pkgMkIndex.n: * doc/registry.n: * doc/resource.n: * doc/safe.n: * doc/scan.n: - * doc/tclvars.n: Spell-check, fixed typos (Updates from Larry Virden). + * doc/tclvars.n: Spell-check, fixed typos (Updates from Larry Virden) 2002-07-01 Donal K. Fellows * unix/tcl.m4 (SC_CONFIG_CFLAGS): Made Solaris use gcc for linking when building with gcc to resolve problems with undefined symbols being present when tcl library used with non-gcc linker at later stage. Symbols were compiler-generated, so it is the compiler's - business to define them. [Bug #541181] + business to define them. [Bug 541181] 2002-07-01 Don Porter * doc/tcltest.n: more work in progress updating tcltest docs. - * library/tcltest/tcltest.tcl: Change [configure -match] to - stop treating an empty list as a list of the single pattern "*". - Changed the default value to [list *] so default operation - remains the same. + * library/tcltest/tcltest.tcl: Change [configure -match] to stop + treating an empty list as a list of the single pattern "*". Changed + the default value to [list *] so default operation remains the same. - * tests/pkg/samename.tcl: restored. needed by pkgMkIndex.test. + * tests/pkg/samename.tcl: restored. Needed by pkgMkIndex.test. * library/tcltest/tcltest.tcl: restored writeability testing of -tmpdir, augmented by a special exception for the deafault value. 2002-07-01 Donal K. Fellows @@ -2895,21 +7533,21 @@ * tests/encoding.test: several tests, mostly to correctly create * tests/fCmd.test: and destroy any temporary files in the * tests/info.test: [temporaryDirectory] of tcltest. * tests/interp.test: - * library/tcltest/tcltest.tcl: Stopped checking for writeability - of -tmpdir value because no default directory can be guaranteed to - be writeable. + * library/tcltest/tcltest.tcl: Stopped checking for writeability of + -tmpdir value because no default directory can be guaranteed to be + writeable. * tests/autoMkindex.tcl: removed. * tests/pkg/samename.tcl: removed. * tests/pkg/magicchar.tcl: removed. * tests/pkg/magicchar2.tcl: removed. - * tests/autoMkindex.test: Updated auto_mkIndex tests to use - [makeFile] and [removeFile] so tests are done in [temporaryDirecotry] - where write access is guaranteed. + * tests/autoMkindex.test: Updated auto_mkIndex tests to use [makeFile] + and [removeFile] so tests are done in [temporaryDirecotry] where write + access is guaranteed. * library/tcltest/tcltest.tcl: Fixed [makeFile] and [viewFile] to * tests/cmdAH.test: accurately reflect a file's contents. * tests/event.test: Updated tests that depended on buggy * tests/http.test: behavior. Also added warning messages @@ -2918,94 +7556,92 @@ * unix/mkLinks: `make mklinks` on 6-27 commits. 2002-06-28 Miguel Sofer - * generic/tclCompile.h: modified the macro TclEmitPush to not - call its first argument repeatedly or pass it to other macros, - [Bug 575194] reported by Peter Spjuth. + * generic/tclCompile.h: modified the macro TclEmitPush to not call its + first argument repeatedly or pass it to other macros, [Bug 575194] + reported by Peter Spjuth. 2002-06-28 Don Porter * docs/tcltest.n: Doc revisions in progress. - * library/tcltest/tcltest.tcl: Corrected -testdir default value. - Was not reliable, and disagreed with docs! Thanks to Hemang Lavana. - [Bug 575150] + * library/tcltest/tcltest.tcl: Corrected -testdir default value. Was + not reliable, and disagreed with docs! Thanks to Hemang Lavana. [Bug + 575150] 2002-06-28 Donal K. Fellows * unix/tclUnixThrd.c: Renamed the Tcl_Platform* #defines to * unix/tclUnixPipe.c: TclOS* because they are only used * unix/tclUnixFile.c: internally. Also stopped double-#def - * unix/tclUnixFCmd.c: of TclOSlstat [Bug #566099, post-rename] + * unix/tclUnixFCmd.c: of TclOSlstat [Bug 566099, post-rename] * unix/tclUnixChan.c: * unix/tclUnixPort.h: - * doc/string.n: Improved documentation for [string last] along - lines described in Bug #574799 so it indicates that the supplied - index marks the end of the search space. + * doc/string.n: Improved documentation for [string last] along lines + described in [Bug 574799] so it indicates that the supplied index + marks the end of the search space. 2002-06-27 Don Porter * doc/dde.n: Work in progress updating the documentation * doc/http.n: of the packages that come bundled with * doc/msgcat.n: the Tcl source distribution, notably tcltest. * doc/registry.n: * doc/tcltest.n: - * library/tcltest/tcltest.tcl: Made sure that the TCLTEST_OPTIONS + * library/tcltest/tcltest.tcl: Made sure that the TCLTEST_OPTIONS environment variablle configures tcltest at package load time. 2002-06-26 Vince Darley - * tests/fileSystem.test: - * generic/tclIOUtil.c: fix to handling of empty paths "" - which are not claimed by any filesystem (Bug #573758). - Ensure good error messages are given in all cases. + * tests/fileSystem.test: + * generic/tclIOUtil.c: fix to handling of empty paths "" which are not + claimed by any filesystem [Bug 573758]. Ensure good error messages are + given in all cases. * tests/cmdAH.test: - * unix/tclUnixFCmd.c: fix to bug reported as part of - (Patch #566669). Thanks to Taguchi, Takeshi for the report. - + * unix/tclUnixFCmd.c: fix to bug reported as part of [Patch 566669]. + Thanks to Taguchi, Takeshi for the report. + 2002-06-26 Reinhard Max * unix/tclUnixTime.c: Make [clock format] respect locale settings. - * tests/clock.test: Bug #565880. ***POTENTIAL INCOMPATIBILITY*** + * tests/clock.test: [Bug 565880]. ***POTENTIAL INCOMPATIBILITY*** 2002-06-26 Miguel Sofer * doc/CrtInterp.3: - * doc/StringObj.3: clarifications by Don Porter, bugs #493995 and - #500930. - + * doc/StringObj.3: clarifications by Don Porter, [Bugs 493995, 500930] + 2002-06-24 Don Porter * library/tcltest/tcltest.tcl: Corrected suppression of -verbose skip - * tests/tcltest.test: and start by [test -output]. Also - corrected test suite errors exposed by corrected code. [Bug 564656] + * tests/tcltest.test: and start by [test -output]. Also + corrected test suite errors exposed by corrected code. [Bug 564656] 2002-06-25 Reinhard Max - * unix/tcl.m4: New macro SC_CONFIG_MANPAGES. + * unix/tcl.m4: New macro SC_CONFIG_MANPAGES. * unix/configure.in: Added support for symlinks and compression * unix/Makefile.in: when installing the manpages. [Patch 518052] * unix/mkLinks.tcl: Default is still hardlinks and no compression. - * unix/mkLinks: generated + * unix/mkLinks: generated * unix/configure: - * unix/README: Added documentation for the new features. + * unix/README: Added documentation for the new features. * unix/tcl.m4 (SC_PATH_TCLCONFIG): Replaced ${exec_prefix}/lib by ${libdir}. 2002-06-25 Donal K. Fellows - * generic/tclUtil.c (TclGetIntForIndex): Fix of critical bug - #533364 generated when the index is bad and the result is a shared - object. The T_ASTO(T_GOR, ...) idiom likely exists elsewhere - though. Also removed some cruft that just complicated things to - no advantage. + * generic/tclUtil.c (TclGetIntForIndex): Fix of critical [Bug 533364] + generated when the index is bad and the result is a shared object. The + T_ASTO(T_GOR, ...) idiom likely exists elsewhere though. Also removed + some cruft that just complicated things to no advantage. (SetEndOffsetFromAny): Same fix, though this wasn't on the path excited by the bug. 2002-06-24 Don Porter @@ -3019,11 +7655,11 @@ * library/tcltest/tcltest.tcl: Corrections to tcltest and the * tests/basic.test: Tcl test suite so that a test * tests/cmdInfo.test: with options -constraints knownBug * tests/compile.test: -limitConstraints 1 only tests the - * tests/encoding.test: knownBug tests. Mostly involves + * tests/encoding.test: knownBug tests. Mostly involves * tests/env.test: replacing direct access to the * tests/event.test: testConstraints array with calls * tests/exec.test: to the testConstraint command * tests/execute.test: (which requires tcltest version 2) * tests/fCmd.test: @@ -3040,115 +7676,114 @@ * tests/scan.test: * tests/stack.test: 2002-06-22 Donal K. Fellows - * tools/tcl.wse.in (Disk Label), unix/tcl.spec (version): - * win/README.binary, README, win/configure.in, unix/configure.in: + * tools/tcl.wse.in (Disk Label), unix/tcl.spec (version): + * win/README.binary, README, win/configure.in, unix/configure.in: * generic/tcl.h (TCL_RELEASE_*, TCL_PATCH_LEVEL): Bump to beta1. 2002-06-21 Joe English * generic/tclCompExpr.c: - * generic/tclParseExpr.c: LogSyntaxError() should reset - the interpreter result [Bug 550142 "Tcl_ExprObj -> abort"] + * generic/tclParseExpr.c: LogSyntaxError() should reset the + interpreter result [Bug 550142 "Tcl_ExprObj -> abort"] 2002-06-21 Don Porter - - * unix/Makefile.in: Updated all package install directories - * win/Makefile.in: to match current Major.minor versions - * win/makefile.bc: of the packages. Added tcltest package - * win/makefile.vc: to installation on Windows. - - * library/init.tcl: Corrected comments and namespace style - issues. Thanks to Bruce Stephens. [Bug 572025] + + * unix/Makefile.in: Updated all package install directories to + * win/Makefile.in: match current Major.minor versions of the + * win/makefile.bc: packages. Added tcltest package to + * win/makefile.vc: installation on Windows. + + * library/init.tcl: Corrected comments and namespace style issues. + Thanks to Bruce Stephens. [Bug 572025] 2002-06-21 Vince Darley - * tests/cmdAH.test: Added TIP#99 implementation - * tests/fCmd.test: of 'file link'. Supports creation - * tests/fileName.test: of symbolic and hard links in the - * tests/fileSystem.test: native filesystems and in vfs's, - * generic/tclTest.c: when the individual filesystem - * generic/tclCmdAH.c: supports the concept. - * generic/tclIOUtil.c: + * tests/cmdAH.test: Added TIP#99 implementation of 'file + * tests/fCmd.test: link'. Supports creation of symbolic and + * tests/fileName.test: hard links in the native filesystems and + * tests/fileSystem.test: in vfs's, when the individual filesystem + * generic/tclTest.c: supports the concept. + * generic/tclCmdAH.c: + * generic/tclIOUtil.c: * generic/tcl.h: * generic/tcl.decls: * doc/FileSystem.3: * doc/file.n: * mac/tclMacFile.c: * unix/tclUnixFile.c: - * win/tclWinFile.c: Also enhanced speed of 'file normalize' on - Windows. + * win/tclWinFile.c: Also enhanced speed of 'file normalize' on Windows 2002-06-20 Miguel Sofer - * generic/tclBasic.c (TclEvalObjvInternal): fix for [Bug 571385] - in the implementation of TIP#62 (command tracing). Vince Darley, - Hemang Lavana & Don Porter: thanks. + * generic/tclBasic.c (TclEvalObjvInternal): fix for [Bug 571385] in + the implementation of TIP#62 (command tracing). Vince Darley, Hemang + Lavana & Don Porter: thanks. 2002-06-20 Miguel Sofer - * generic/tclExecute.c (TclCompEvalObj): clarified and simplified - the logic for compilation/recompilation. + * generic/tclExecute.c (TclCompEvalObj): clarified and simplified the + logic for compilation/recompilation. 2002-06-19 Joe English + * doc/file.n: Fixed indentation. No substantive changes. 2002-06-19 Jeff Hobbs - * generic/tclCmdMZ.c (Tcl_RegexpObjCmd): get the resultPtr again - as the Tcl_ObjSetVar2 may cause the result to change. - [Patch #558324] (watson) + * generic/tclCmdMZ.c (Tcl_RegexpObjCmd): get the resultPtr again as + the Tcl_ObjSetVar2 may cause the result to change. + [Patch 558324] (watson) 2002-06-19 Miguel Sofer * generic/tclExecute.c (TEBC): removing unused "for(;;)" loop; improved comments; re-indentation. 2002-06-18 Miguel Sofer - * generic/tclExecute.c (TEBC): + * generic/tclExecute.c (TEBC): - elimination of duplicated code in the non-immediate INST_INCR - instructions. + instructions. - elimination of 103 (!) TclDecrRefCount macros. The different - instructions now jump back to a common "DecrRefCount zone" at - the top of the loop. The macro "ADJUST_PC" was replaced by two - macros "NEXT_INST_F" and "NEXT_INST_V" that take three params - (pcAdjustment, # of stack objects to discard, resultObjPtr - handling flag). The only instructions that retain a - TclDecrRefCount are INST_POP (for speed), the common code for - the non-immediate INST_INCR, INST_FOREACH_STEP and the two - INST_LSET. - - The object size of tclExecute.o was reduced by approx 20% since - the start of the consolidation drive, while making room for some - peep-hole optimisation at runtime. + instructions now jump back to a common "DecrRefCount zone" at the + top of the loop. The macro "ADJUST_PC" was replaced by two macros + "NEXT_INST_F" and "NEXT_INST_V" that take three params + (pcAdjustment, # of stack objects to discard, resultObjPtr handling + flag). The only instructions that retain a TclDecrRefCount are + INST_POP (for speed), the common code for the non-immediate + INST_INCR, INST_FOREACH_STEP and the two INST_LSET. + + The object size of tclExecute.o was reduced by approx 20% since the + start of the consolidation drive, while making room for some peep-hole + optimisation at runtime. 2002-06-18 Miguel Sofer - * generic/tclExecute.c (TEBC, INST_DONE): small bug in the panic - code for tcl-stack corruption. + * generic/tclExecute.c (TEBC, INST_DONE): small bug in the panic code + for tcl-stack corruption. 2002-06-17 David Gravereaux - Trims to support the removal of RESOURCE_INCLUDED from rc - scripts from FR #565088. + Trims to support the removal of RESOURCE_INCLUDED from rc scripts from + [FRQ 565088]. - * generic/tcl.h: moved the #ifndef RC_INVOKED start block up in - the file. rc scripts don't need to know thread mutexes. + * generic/tcl.h: moved the #ifndef RC_INVOKED start block up in the + file. rc scripts don't need to know thread mutexes. * win/tcl.rc: * win/tclsh.rc: removed the #define RESOURCE_INCLUDED to let the built-in -DRC_INVOKED to the work. 2002-06-17 Jeff Hobbs - * doc/CrtTrace.3: Added TIP#62 implementation of command - * doc/trace.n: execution tracing [FR #462580] (lavana). - * generic/tcl.h: This includes enter/leave tracing as well - * generic/tclBasic.c: as inter-procedure stepping. + * doc/CrtTrace.3: Added TIP#62 implementation of command + * doc/trace.n: execution tracing [FRQ 462580] (lavana). + * generic/tcl.h: This includes enter/leave tracing as well + * generic/tclBasic.c: as inter-procedure stepping. * generic/tclCmdMZ.c: * generic/tclCompile.c: * generic/tclExecute.c: * generic/tclInt.decls: * generic/tclInt.h: @@ -3157,114 +7792,111 @@ * generic/tclVar.c: * tests/trace.test: 2002-06-17 Andreas Kupries - * win/tclWinPipe.c (BuildCommandLine): Fixed bug #554068 ([exec] - on windows did not treat { in filenames well.). Bug reported by - Vince Darley , patch - provided by Vince too. + * win/tclWinPipe.c (BuildCommandLine): Fixed [bug 554068] ([exec] on + windows did not treat { in filenames well.). Bug reported by Vince + Darley , patch provided by Vince + too. 2002-06-17 Joe English * generic/tcl.h: #ifdef logic for K&R C backwards compatibility - changed to assume modern C by default. See SF FR #565088 for - full details. + changed to assume modern C by default. See [FRQ 565088] for full + details. 2002-06-17 Don Porter - * doc/msgcat.n: Corrected en_UK references to en_GB. UK is not - a country designation recognized in ISO 3166. + * doc/msgcat.n: Corrected en_UK references to en_GB. UK is not a + country designation recognized in ISO 3166. - * library/msgcat/msgcat.tcl: More Windows Registry locale codes - from Bruno Haible. + * library/msgcat/msgcat.tcl: More Windows Registry locale codes from + Bruno Haible. * doc/msgcat.n: * library/msgcat/msgcat.tcl: * library/msgcat/pkgIndex.tcl: * tests/msgcat.test: Revised locale initialization to interpret - environment variable locale values according to XPG4, and to - recognize the LC_ALL and LC_MESSAGES values over that of LANG. - Also added many Windows Registry locale values to those - recognized by msgcat. Revised tests and docs. Bumped to - version 1.3. Thanks to Bruno Haible for the report and - assistance crafting the solution. [Bug 525522, 525525] - -2002-06-16 Miguel Sofer - - * generic/tclCompile.c (TclCompileTokens): a better algorithm for - the previous bug fix. - -2002-06-16 Miguel Sofer - - * generic/tclCompile.c (TclCompileTokens): - * tests/compile.test: [Bug 569438] in the processing of dollar - variables; report by Georgios Petasis. - -2002-06-16 Miguel Sofer - - * generic/tclExecute.c: bug in the consolidation of the - INCR_..._STK instructions; the bug could not be exercised as the - (faulty) instruction INST_INCR_ARRAY_STK was never compiled-in - (related to [Bug 569438]). + environment variable locale values according to XPG4, and to recognize + the LC_ALL and LC_MESSAGES values over that of LANG. Also added many + Windows Registry locale values to those recognized by msgcat. Revised + tests and docs. Bumped to version 1.3. Thanks to Bruno Haible for the + report and assistance crafting the solution. [Bug 525522, 525525] + +2002-06-16 Miguel Sofer + + * generic/tclCompile.c (TclCompileTokens): a better algorithm for the + previous bug fix. + +2002-06-16 Miguel Sofer + + * generic/tclCompile.c (TclCompileTokens): + * tests/compile.test: [Bug 569438] in the processing of dollar + variables; report by Georgios Petasis. + +2002-06-16 Miguel Sofer + + * generic/tclExecute.c: bug in the consolidation of the INCR_..._STK + instructions; the bug could not be exercised as the (faulty) + instruction INST_INCR_ARRAY_STK was never compiled-in (related to [Bug + 569438]). 2002-06-14 Miguel Sofer * generic/tclExecute.c (TclExecuteByteCode): runtime peep-hole optimisation of variables (INST_STORE, INST_INCR) and commands (INST_INVOKE); faster check for the existence of a catch. - (TclExecuteByteCode): runtime peep-hole optimisation of - comparisons. - (TclExecuteByteCode): runtime peep-hole optimisation of - INST_FOREACH - relies on peculiarities of the code produced by the - bytecode compiler. + (TclExecuteByteCode): runtime peep-hole optimisation of comparisons. + (TclExecuteByteCode): runtime peep-hole optimisation of INST_FOREACH - + relies on peculiarities of the code produced by the bytecode compiler. 2002-06-14 David Gravereaux * win/rules.vc: The test for compiler optimizations was in error. - Thanks goes to Roy Terry for his - assistance with this. + Thanks goes to Roy Terry for his assistance + with this. 2002-06-14 Donal K. Fellows - * doc/trace.n, tests/trace.test: + * doc/trace.n, tests/trace.test: * generic/tclCmdMZ.c (Tcl_TraceObjCmd,TclTraceCommandObjCmd) - (TclTraceVariableObjCmd): Changed references to "trace list" to - "trace info" as mandated by TIP#102. + (TclTraceVariableObjCmd): Changed references to "trace list" to "trace + info" as mandated by TIP#102. 2002-06-13 Miguel Sofer - * generic/tclExecute.c (TclExecuteByteCode): consolidated code for - the conditional branch instructions. + * generic/tclExecute.c (TclExecuteByteCode): consolidated code for the + conditional branch instructions. 2002-06-13 Miguel Sofer * generic/tclExecute.c (TclExecuteByteCode): fixed the previous patch - wouldn't compile with TCL_COMPILE_DEBUG set. 2002-06-13 Miguel Sofer - * generic/tclExecute.c (TclExecuteByteCode): consolidated the - handling of exception returns to INST_INVOKE and INST_EVAL, as - well as most of the code for INST_CONTINUE and INST_BREAK, in the - new jump target "processExceptionReturn". + * generic/tclExecute.c (TclExecuteByteCode): consolidated the handling + of exception returns to INST_INVOKE and INST_EVAL, as well as most of + the code for INST_CONTINUE and INST_BREAK, in the new jump target + "processExceptionReturn". 2002-06-13 Miguel Sofer * generic/tclExecute.c (TclExecuteByteCode): consolidated variable handling opcodes, replaced redundant code with some 'goto'. All - store/append/lappend opcodes on the same data type now share the - main code; same with incr opcodes. + store/append/lappend opcodes on the same data type now share the main + code; same with incr opcodes. * generic/tclVar.c: added the bit TCL_TRACE_READS to the possible - flags to Tcl_SetVar2Ex - it causes read traces to be fired prior - to setting the variable. This is used in the core for [lappend]. + flags to Tcl_SetVar2Ex - it causes read traces to be fired prior to + setting the variable. This is used in the core for [lappend]. - ***NOTE*** the usage of TCL_TRACE_READS in Tcl_(Obj)?GetVar.* is - not documented; there, it causes the call to create the variable - if it does not exist. The new usage in Tcl_(Obj)?SetVar.* remains + ***NOTE*** the usage of TCL_TRACE_READS in Tcl_(Obj)?GetVar.* is not + documented; there, it causes the call to create the variable if it + does not exist. The new usage in Tcl_(Obj)?SetVar.* remains undocumented too ... - + 2002-06-13 Vince Darley * tests/fCmd.test: * tests/winFile.test: * tests/fileSystem.test: @@ -3272,129 +7904,127 @@ * generic/tclCmdAH.c: * generic/tclIOUtil.c: * doc/FileSystem.3: * mac/tclMacFile.c: * unix/tclUnixFile.c: - * win/tclWinFile.c: fixed up further so both compiles and - actually works with VC++ 5 or 6. - * win/tclWinInt.h: - * win/tclWin32Dll.c: cleaned up code and vfs tests and - added tests for the internal changes of 2002-06-12, to see - whether WinTcl on NTFS can coexist peacefully with links - in the filesystem. Added new test command 'testfilelink' - to enable the newer code to be tested. - * tests/fCmd.test: (made certain tests of 'testfilelink' not - run on unix). + * win/tclWinFile.c: fixed up further so both compiles and actually + works with VC++ 5 or 6. + * win/tclWinInt.h: + * win/tclWin32Dll.c: cleaned up code and vfs tests and added tests for + the internal changes of 2002-06-12, to see whether WinTcl on NTFS can + coexist peacefully with links in the filesystem. Added new test + command 'testfilelink' to enable the newer code to be tested. + * tests/fCmd.test: (made certain tests of 'testfilelink' not run on + unix). 2002-06-12 Miguel Sofer * tclBasic.c (Tcl_DeleteTrace): fixed [Bug 568123] (thanks to Hemang Lavana) - + 2002-06-12 Jeff Hobbs * win/tclWinFile.c: corrected the symbolic link handling code to - allow it to compile. Added real definition of REPARSE_DATA_BUFFER - (found in winnt.h). Most of the added definitions appear to have + allow it to compile. Added real definition of REPARSE_DATA_BUFFER + (found in winnt.h). Most of the added definitions appear to have correct, cross-Win-version equivalents in winnt.h and should be removed, but just making things "work" for now. 2002-06-12 Vince Darley * generic/tclIOUtil.c: * generic/tcl.decls: - * generic/tclDecls.h: made code for Tcl_FSNewNativePath - agree with man pages. - - * doc/FileSystem.3: clarified the circumstances under which - certain functions are called in the presence of symlinks. - + * generic/tclDecls.h: made code for Tcl_FSNewNativePath agree with man + pages. + + * doc/FileSystem.3: clarified the circumstances under which certain + functions are called in the presence of symlinks. + * win/tclWinFile.c: - * win/tclWinPort.h: - * win/tclWinInt.h: - * win/tclWinFCmd.c: Fix for Windows to allow 'file lstat', - 'file type', 'glob -type l', 'file copy', 'file delete', - 'file normalize', and all VFS code to work correctly in the - presence of symlinks (previously Tcl's behaviour was not very - well defined). This also fixes possible serious problems in - all versions of WinTcl where 'file delete' on a NTFS symlink - could delete the original, not the symlink. + * win/tclWinPort.h: + * win/tclWinInt.h: + * win/tclWinFCmd.c: Fix for Windows to allow 'file lstat', 'file + type', 'glob -type l', 'file copy', 'file delete', 'file normalize', + and all VFS code to work correctly in the presence of symlinks + (previously Tcl's behaviour was not very well defined). This also + fixes possible serious problems in all versions of WinTcl where 'file + delete' on a NTFS symlink could delete the original, not the symlink. Note: symlinks cannot yet be created in pure Tcl. 2002-06-11 Miguel Sofer - * generic/tclBasic.c: + * generic/tclBasic.c: * generic/tclCompCmds.c: - * generic/tclInt.h: reverted the new compilation functions; - replaced by a more general approach described below. + * generic/tclInt.h: reverted the new compilation functions; replaced + by a more general approach described below. * generic/tclCompCmds.c: - * generic/tclCompile.c: made *all* compiled variable access - attempts create an indexed variable - even get or incr without - previous set. This allows indexed access to local variables that - are created and set at runtime, for example by [global], [upvar], - [variable], [regexp], [regsub]. + * generic/tclCompile.c: made *all* compiled variable access attempts + create an indexed variable - even get or incr without previous set. + This allows indexed access to local variables that are created and set + at runtime, for example by [global], [upvar], [variable], [regexp], + [regsub]. 2002-06-11 Miguel Sofer * doc/global.n: * doc/info.n: * test/info.test: * generic/tclCmdIL.c: fix for [Bug 567386], [info locals] was reporting some linked variables. - - * generic/tclBasic.c: + + * generic/tclBasic.c: * generic/tclCompCmds.c: - * generic/tclInt.h: added compile functions for [global], - [variable] and [upvar]. They just declare the new local variables, - the commands themselves are not compiled-in. This gives a notably - faster read access to these linked variables. + * generic/tclInt.h: added compile functions for [global], [variable] + and [upvar]. They just declare the new local variables, the commands + themselves are not compiled-in. This gives a notably faster read + access to these linked variables. 2002-06-11 Miguel Sofer * generic/tclExecute.c: optimised algorithm for exception range lookup; part of [Patch 453709]. 2002-06-10 Vince Darley - * unix/tclUnixFCmd.c: fixed [Bug #566669] - * generic/tclIOUtil.c: improved and sped up handling of - native paths (duplication and conversion to normalized paths), - particularly on Windows. - * modified part of above commit, due to problems on Linux. - Will re-examine bug report and evaluate more closely. + * unix/tclUnixFCmd.c: fixed [Bug 566669] + * generic/tclIOUtil.c: improved and sped up handling of native paths + (duplication and conversion to normalized paths), particularly on + Windows. + * modified part of above commit, due to problems on Linux. Will + re-examine bug report and evaluate more closely. 2002-06-07 Don Porter - * tests/tcltest.test: More corrections to test suite so that tests - of failing [test]s don't show up themselves as failing tests. + * tests/tcltest.test: More corrections to test suite so that tests of + failing [test]s don't show up themselves as failing tests. 2002-06-07 Donal K. Fellows - * generic/tclExecute.c: Tidied up headers in relation to float.h - to cut the cruft and ensure DBL_MAX is defined since doubles seem - to be the same size everywhere; if the assumption isn't true, the - variant platforms had better have run configure... - - * unix/tclUnixPort.h (EOVERFLOW): Added code to define it if it - wasn't previously defined. Also some other general tidying and - adding of comments. [Tcl bugs 563122, 564595] + * generic/tclExecute.c: Tidied up headers in relation to float.h to + cut the cruft and ensure DBL_MAX is defined since doubles seem to be + the same size everywhere; if the assumption isn't true, the variant + platforms had better have run configure... + + * unix/tclUnixPort.h (EOVERFLOW): Added code to define it if it wasn't + previously defined. Also some other general tidying and adding of + comments. [Bugs 563122, 564595] * compat/tclErrno.h: Added definition for EOVERFLOW copied from - Solaris headers; I've been unable to find any uses of EFTYPE, - which was the error code previously occupying the slot, in Tcl, or - any definition of it in the Solaris headers. + Solaris headers; I've been unable to find any uses of EFTYPE, which + was the error code previously occupying the slot, in Tcl, or any + definition of it in the Solaris headers. 2002-06-06 Mo DeJong - * unix/dltest/Makefile.in: Remove hard coded CFLAGS=-g - and add CFLAGS_DEBUG, CFLAGS_OPTIMIZE, and - CFLAGS_DEFAULT varaibles. [Tcl bug 565488] + * unix/dltest/Makefile.in: Remove hard coded CFLAGS=-g and add + CFLAGS_DEBUG, CFLAGS_OPTIMIZE, and CFLAGS_DEFAULT varaibles. [Bug + 565488] 2002-06-06 Don Porter - * tests/tcltest.test: Corrections to test suite so that tests - of failing [test]s don't show up themselves as failing tests. + * tests/tcltest.test: Corrections to test suite so that tests of + failing [test]s don't show up themselves as failing tests. * tests/io.test: Fixed up namespace variable resolution issues revealed by running test suite with "-singleproc 1". * doc/tcltest.n: @@ -3407,30 +8037,30 @@ [Patch 512214, Bug 558742, Bug 461000, Bug 534903] 2002-06-06 Daniel Steffen * unix/tclUnixThrd.c (TclpReaddir, TclpLocaltime, TclpGmtime): - added mutex wrapped calls to readdir, localtime & gmtime in - case their thread-safe *_r counterparts are not available. + added mutex wrapped calls to readdir, localtime & gmtime in case their + thread-safe *_r counterparts are not available. * unix/tcl.m4: added configure check for readdir_r - * unix/tcl.m4 (Darwin): set TCL_DEFAULT_ENCODING to utf-8 on - MacOSX (where posix file apis expect utf-8, not iso8859-1). + * unix/tcl.m4 (Darwin): set TCL_DEFAULT_ENCODING to utf-8 on MacOSX + (where posix file apis expect utf-8, not iso8859-1). * unix/configure: regen - * unix/Makefile.in: set DYLD_LIBRARY_PATH in parallel - to LD_LIBRARY_PATH for MacOSX dynamic linker. - * generic/tclEnv.c (TclSetEnv): fix env var setting on - MacOSX (adapted from patch #524352 by jkbonfield). + * unix/Makefile.in: set DYLD_LIBRARY_PATH in parallel to + LD_LIBRARY_PATH for MacOSX dynamic linker. + * generic/tclEnv.c (TclSetEnv): fix env var setting on MacOSX. Adapted + from [Patch 524352] (jkbonfield). 2002-06-05 Don Porter * doc/Tcl_Main.3: Documented $tcl_rcFileName and added more clarifications about the intended use of Tcl_Main(). [Bug 505651] 2002-06-05 Daniel Steffen - * generic/tclFileName.c (TclGlob): mac specific fix to - recent changes in 'glob -tails' handling. + * generic/tclFileName.c (TclGlob): mac specific fix to recent changes + in 'glob -tails' handling. * mac/tclMacPort.h: * mac/tclMacChan.c: fixed TIP#91 bustage. * mac/tclMacResource.c (Tcl_MacConvertTextResource): added utf conversion of text resource contents. * tests/macFCmd.test (macFCmd-1.2): allow CWIE creator. @@ -3438,11 +8068,11 @@ 2002-06-04 Don Porter * library/tcltest/tcltest.tcl: * tests/init.test: * tests/tcltest.test: Added more TIP 85 tests from Arjen Markus. - Converted tcltest.test to use a private namespace. Fixed bugs in + Converted tcltest.test to use a private namespace. Fixed bugs in [tcltest::Eval] revealed by calling [tcltest::test] from a non-global namespace, and namespace errors in init.test. 2002-06-04 Mo DeJong @@ -3451,167 +8081,163 @@ 2002-06-03 Don Porter * doc/tcltest.n: * library/tcltest/tcltest.tcl: * library/tcltest/pkgIndex.tcl: - * tests/tcltest.test: Implementation of TIP 85. Allows tcltest - users to add new legal values of the -match option to [test], - associating each with a Tcl command that does the matching of - expected results with actual results of tests. Thanks to - Arjen Markus. => tcltest 2.1 [Patch 521362] + * tests/tcltest.test: Implementation of TIP 85. Allows tcltest users + to add new legal values of the -match option to [test], associating + each with a Tcl command that does the matching of expected results + with actual results of tests. Thanks to Arjen Markus. => tcltest 2.1 + [Patch 521362] 2002-06-03 Miguel Sofer - * doc/namespace.n: added description of [namepace forget] - behaviour for unqualified patterns [Bug 559268] + * doc/namespace.n: added description of [namepace forget] behaviour + for unqualified patterns [Bug 559268] 2002-06-03 Miguel Sofer - * generic/tclExecute.c: reverting an accidental modification in - the last commit. - + * generic/tclExecute.c: reverting an accidental modification in the + last commit. + 2002-06-03 Miguel Sofer * doc/Tcl.n: clarify the empty variable name issue ([Bug 549285] reported by Tom Krehbiel, patch by Don Porter). 2002-05-31 Don Porter - * library/package.tcl: Fixed leak of slave interp in [pkg_mkIndex]. - Thanks to Helmut for report. [Bug 550534] + * library/package.tcl: Fixed leak of slave interp in [pkg_mkIndex]. + Thanks to Helmut for report. [Bug 550534] * tests/io.test: - * tests/main.test: Use the "stdio" constraint to control whether - an [open "|[interpreter]"] is attempted. + * tests/main.test: Use the "stdio" constraint to control whether an + [open "|[interpreter]"] is attempted. * generic/tclExecute.c (TclMathInProgress,TclExecuteByteCode - ExprCallMathFunc): + (ExprCallMathFunc): * generic/tclInt.h (TclMathInProgress): * unix/Makefile.in (tclMtherr.*): * unix/configure.in (NEED_MATHERR): * unix/tclAppInit.c (matherr): * unix/tclMtherr.c (removed file): * win/tclWinMtherr.c (_matherr): Removed internal routine - TclMathInProgress and Unix implementation of matherr(). These - are now obsolete, dealing with very old versions of the C math - library. Windows version is retained in case Borland compilers - require it, but it is inactive. Thanks to Joe English. - [Bug 474335, Patch 555635]. + TclMathInProgress and Unix implementation of matherr(). These are now + obsolete, dealing with very old versions of the C math library. + Windows version is retained in case Borland compilers require it, but + it is inactive. Thanks to Joe English. [Bug 474335, Patch 555635] * unix/configure: regen 2002-05-30 Miguel Sofer * generic/tclCompExpr.c: * generic/tclCompile.c: * generic/tclCompile.h: removed exprIsJustVarRef and - exprIsComparison from the ExprInfo and CompileEnv structs. These - were set, but not used since dec 1999 [Bug 562383]. + exprIsComparison from the ExprInfo and CompileEnv structs. These were + set, but not used since dec 1999 [Bug 562383]. 2002-05-30 Vince Darley - * generic/tclFileName.c (TclGlob): fix to longstanding - 'knownBug' in fileName tests 15.2-15.4, and fix to a new - Tcl 8.4 bug in certain uses of 'glob -tails'. - * tests/fileName.test: removed 'knownBug' flag from some tests, - added some new tests for above bugs. - + * generic/tclFileName.c (TclGlob): fix to longstanding 'knownBug' in + fileName tests 15.2-15.4, and fix to a new Tcl 8.4 bug in certain uses + of 'glob -tails'. + * tests/fileName.test: removed 'knownBug' flag from some tests, added + some new tests for above bugs. + 2002-05-29 Jeff Hobbs * unix/configure: regen'ed - * unix/configure.in: replaced bigendian check with autoconf - standard AC_C_BIG_ENDIAN, which defined WORDS_BIGENDIAN on - bigendian systems. - * generic/tclUtf.c (Tcl_UniCharNcmp): + * unix/configure.in: replaced bigendian check with autoconf standard + AC_C_BIG_ENDIAN, which defined WORDS_BIGENDIAN on bigendian systems. + * generic/tclUtf.c (Tcl_UniCharNcmp): * generic/tclInt.h (TclUniCharNcmp): use WORDS_BIGENDIAN instead of TCL_OPTIMIZE_UNICODE_COMPARE to enable memcmp alternative. * generic/tclExecute.c (TclExecuteByteCode INST_STR_CMP): - * generic/tclCmdMZ.c (Tcl_StringObjCmd): changed the case for - choosing the Tcl_UniCharNcmp compare to when both objs are of - StringType, as benchmarks show that is the optimal check (both - bigendian and littleendian systems). + * generic/tclCmdMZ.c (Tcl_StringObjCmd): changed the case for choosing + the Tcl_UniCharNcmp compare to when both objs are of StringType, as + benchmarks show that is the optimal check (both bigendian and + littleendian systems). 2002-05-29 Don Porter - * generic/tclMain.c: Removed "dummy" reference to Tcl_LinkVar. - It is no longer needed since Tcl_Main() now actually calls - Tcl_LinkVar(). Thanks to Joe English for pointing that out. + * generic/tclMain.c: Removed "dummy" reference to Tcl_LinkVar. It is + no longer needed since Tcl_Main() now actually calls Tcl_LinkVar(). + Thanks to Joe English for pointing that out. 2002-05-29 Donal K. Fellows - * generic/tclExecute.c (TclExecuteByteCode): + * generic/tclExecute.c (TclExecuteByteCode): * generic/tclCmdMZ.c (Tcl_StringObjCmd): Use the macro version. - * generic/tclInt.h (TclUniCharNcmp): Optimised still further with - a macro for use in sensitive places like tclExecute.c - - * generic/tclUtf.c (Tcl_UniCharNcmp): Use new flag to figure out - when we can use an optimal comparison scheme, and default to the - old scheme in other cases which is at least safe. - * unix/configure.in (TCL_OPTIMIZE_UNICODE_COMPARE): New optional - flag that indicates when we can use memcmp() to compare Unicode - strings (i.e. when the high-byte of a Tcl_UniChar precedes the - low-byte.) + * generic/tclInt.h (TclUniCharNcmp): Optimised still further with a + macro for use in sensitive places like tclExecute.c + + * generic/tclUtf.c (Tcl_UniCharNcmp): Use new flag to figure out when + we can use an optimal comparison scheme, and default to the old scheme + in other cases which is at least safe. + * unix/configure.in (TCL_OPTIMIZE_UNICODE_COMPARE): New optional flag + that indicates when we can use memcmp() to compare Unicode strings + (i.e. when the high-byte of a Tcl_UniChar precedes the low-byte.) 2002-05-29 Jeff Hobbs * generic/tclInt.decls: * generic/tclIntDecls.h: * generic/tclStubInit.c: - * generic/tclUtf.c: added TclpUtfNcmp2 private command that - mirrors Tcl_UtfNcmp, but takes n in bytes, not utf-8 chars. This - provides a faster alternative for comparing utf strings internally. - (Tcl_UniCharNcmp, Tcl_UniCharNcasecmp): removed the explicit end - of string check as it wasn't correct for the function (by doc and - logic). + * generic/tclUtf.c: added TclpUtfNcmp2 private command that mirrors + Tcl_UtfNcmp, but takes n in bytes, not utf-8 chars. This provides a + faster alternative for comparing utf strings internally. + (Tcl_UniCharNcmp, Tcl_UniCharNcasecmp): removed the explicit end of + string check as it wasn't correct for the function (by doc and logic). * generic/tclCmdMZ.c (Tcl_StringObjCmd): reworked the string equal - comparison code to use TclpUtfNcmp2 as well as short-circuit for - equal objects or unequal length strings in the equal case. - Removed the use of goto and streamlined the other parts. - - * generic/tclExecute.c (TclExecuteByteCode): added check for - object equality in the comparison instructions. Added - short-circuit for != length strings in INST_EQ, INST_NEQ and - INST_STR_CMP. Reworked INST_STR_CMP to use TclpUtfNcmp2 where - appropriate, and only use Tcl_UniCharNcmp when at least one of the - objects is a Unicode obj with no utf bytes. - - * generic/tclCompCmds.c (TclCompileStringCmd): removed error - creation in code that no longer throws an error. + comparison code to use TclpUtfNcmp2 as well as short-circuit for equal + objects or unequal length strings in the equal case. Removed the use + of goto and streamlined the other parts. + + * generic/tclExecute.c (TclExecuteByteCode): added check for object + equality in the comparison instructions. Added short-circuit for != + length strings in INST_EQ, INST_NEQ and INST_STR_CMP. Reworked + INST_STR_CMP to use TclpUtfNcmp2 where appropriate, and only use + Tcl_UniCharNcmp when at least one of the objects is a Unicode obj with + no utf bytes. + + * generic/tclCompCmds.c (TclCompileStringCmd): removed error creation + in code that no longer throws an error. * tests/string.test: * tests/stringComp.test: added more string comparison checks. * tests/clock.test: better qualified 9.1 constraint check for %s. 2002-05-28 Jeff Hobbs - * generic/tclThreadAlloc.c (TclpRealloc, TclpFree): protect - against the case when NULL is based. + * generic/tclThreadAlloc.c (TclpRealloc, TclpFree): protect against + the case when NULL is based. * tests/clock.test: added clock-9.1 * compat/strftime.c: * generic/tclClock.c: * generic/tclInt.decls: * generic/tclIntDecls.h: - * unix/tclUnixTime.c: fix for Windows msvcrt mem leak caused by - using an env(TZ) setting trick for in clock format -gmt 1. This - also makes %s seem to work correctly with -gmt 1 as well as - making it a lot faster by avoid the env(TZ) hack. TclpStrftime - now takes useGMT as an arg. [Bug #559376] + * unix/tclUnixTime.c: fix for Windows msvcrt mem leak caused by using + an env(TZ) setting trick for in clock format -gmt 1. This also makes + %s seem to work correctly with -gmt 1 as well as making it a lot + faster by avoid the env(TZ) hack. TclpStrftime now takes useGMT as an + arg. [Bug 559376] 2002-05-28 Vince Darley - * generic/tclIOUtil.c: fixes to Tcl_FSLoadFile when called on - a file inside a vfs. This should avoid leaving temporary - files sitting around on exit. [Bug #545579] - + * generic/tclIOUtil.c: fixes to Tcl_FSLoadFile when called on a file + inside a vfs. This should avoid leaving temporary files sitting around + on exit. [Bug 545579] + 2002-05-27 Donal K. Fellows * win/tclWinError.c: Added comment on conversion of - ERROR_NEGATIVE_SEEK because that is a mapping that really belongs, - and not a catch-all case. + ERROR_NEGATIVE_SEEK because that is a mapping that really belongs, and + not a catch-all case. * win/tclWinPort.h (EOVERFLOW): Should be either EFBIG or EINVAL * generic/tclPosixStr.c (Tcl_ErrnoId, Tcl_ErrnoMsg): EOVERFLOW can potentially be a synonym for EINVAL. 2002-05-24 Donal K. Fellows @@ -3621,21 +8247,21 @@ * win/tclWinPort.h: Added declaration of EOVERFLOW. * doc/CrtChannel.3: Added documentation of wideSeekProc. * generic/tclIOGT.c (TransformSeekProc, TransformWideSeekProc): Adapted to use the new channel mechanism. * unix/tclUnixChan.c (FileSeekProc, FileWideSeekProc): Renamed - FileSeekProc to FileWideSeekProc and created new FileSeekProc - which has the old-style interface and which errors out with - EOVERFLOW when the returned file position can't fit into the - return type (int for historical reasons.) + FileSeekProc to FileWideSeekProc and created new FileSeekProc which + has the old-style interface and which errors out with EOVERFLOW when + the returned file position can't fit into the return type (int for + historical reasons.) * win/tclWinChan.c (FileSeekProc, FileWideSeekProc): Renamed - FileSeekProc to FileWideSeekProc and created new FileSeekProc - which has the old-style interface and which errors out with - EOVERFLOW when the returned file position can't fit into the - return type (int for historical reasons.) - * mac/tclMacChan.c (FileSeek): Reverted to old interface; Macs - lack large-file support because I can't see how to add it. + FileSeekProc to FileWideSeekProc and created new FileSeekProc which + has the old-style interface and which errors out with EOVERFLOW when + the returned file position can't fit into the return type (int for + historical reasons.) + * mac/tclMacChan.c (FileSeek): Reverted to old interface; Macs lack + large-file support because I can't see how to add it. * generic/tclIO.c (Tcl_Seek, Tcl_Tell): Given these functions knowledge of the new arrangement of channel types. (Tcl_ChannelVersion): Added recognition of new version code. (HaveVersion): New function to do version checking. (Tcl_ChannelBlockModeProc, Tcl_ChannelFlushProc) @@ -3645,130 +8271,123 @@ * generic/tcl.h (Tcl_ChannelType): New wideSeekProc field, and seekProc type restored to old interpretation. (TCL_CHANNEL_VERSION_3): New channel version. 2002-05-24 Andreas Kupries - - * tests/winPipe.test: Applied patch for SF Tcl Bug #549617. Patch - and bug report by Kevin Kenny . - - * win/tclWinSock.c (TcpWatchProc): Fixed SF Tcl Bug #557878. We - are not allowed to mess with the watch mask if the socket is a - server socket. I believe that the original reporter is George - Peter Staplin. + + * tests/winPipe.test: Applied patch for [Bug 549617]. Patch and bug + report by Kevin Kenny . + + * win/tclWinSock.c (TcpWatchProc): Fixed [Bug 557878]. We are not + allowed to mess with the watch mask if the socket is a server socket. + I believe that the original reporter is George Peter Staplin. 2002-05-21 Mo DeJong * unix/configure: Regen. - * unix/configure.in: Invoke SC_ENABLE_SHARED before - calling SC_CONFIG_CFLAGS so that the SHARED_BUILD - variable can be checked inside SC_CONFIG_CFLAGS. - * unix/tcl.m4 (SC_CONFIG_CFLAGS): Pass -non_shared - instead of -shared to ld when configured with - --disable-shared under OSF. [Tcl bug 540390] + * unix/configure.in: Invoke SC_ENABLE_SHARED before calling + SC_CONFIG_CFLAGS so that the SHARED_BUILD variable can be checked + inside SC_CONFIG_CFLAGS. + * unix/tcl.m4 (SC_CONFIG_CFLAGS): Pass -non_shared instead of -shared + to ld when configured with --disable-shared under OSF. [Bug 540390] 2002-05-20 Daniel Steffen * generic/tclInt.h: added prototype for TclpFilesystemPathType(). - * mac/tclMacChan.c: use MSL provided creator type if available - instead of the default 'MPW '. + * mac/tclMacChan.c: use MSL provided creator type if available instead + of the default 'MPW '. 2002-05-16 Joe English - * doc/CrtObjCmd.3: - Added Tcl_GetCommandFromObj, Tcl_GetCommandFullName - (Tcl Bug #547987, #414921) + * doc/CrtObjCmd.3: Added Tcl_GetCommandFromObj, Tcl_GetCommandFullName + [Bugs 547987, 414921] 2002-05-14 Donal K. Fellows - * unix/tclUnixChan.c (TtyOutputProc): #if/#endif-ed this function - out to stop compiler warnings. Also much general tidying of - comments in this file and removal of whitespace from blank lines. + * unix/tclUnixChan.c (TtyOutputProc): #if/#endif-ed this function out + to stop compiler warnings. Also much general tidying of comments in + this file and removal of whitespace from blank lines. 2002-05-13 Donal K. Fellows - * unix/tclUnixChan.c (SETBREAK): Solaris thinks ioctl() takes a - signed second argument, and Linux thinks ioctl() takes an unsigned - second argument. So need a longer definition of this macro to get - neither to spew warnings... + * unix/tclUnixChan.c (SETBREAK): Solaris thinks ioctl() takes a signed + second argument, and Linux thinks ioctl() takes an unsigned second + argument. So need a longer definition of this macro to get neither to + spew warnings... 2002-05-13 Vince Darley - * generic/tclEvent.c: + * generic/tclEvent.c: * generic/tclIOUtil.c: - * generic/tclInt.h: clean up all memory allocated by the - filesystem, via introduction of 'TclFinalizeFilesystem'. - Move TclFinalizeLoad into TclFinalizeFilesystem so we can - be sure it is called at just the right time. - Fix bad comment also. [Bug #555078 and 'fs' part of #543549] + * generic/tclInt.h: clean up all memory allocated by the filesystem, + via introduction of 'TclFinalizeFilesystem'. Move TclFinalizeLoad into + TclFinalizeFilesystem so we can be sure it is called at just the right + time. Fix bad comment also. [Bug 555078 and 'fs' part of 543549] * win/tclWinChan.c: fix comment referring to wrong function. - + 2002-05-10 Don Porter * tests/load.test: * tests/safe.test: - * tests/tcltest.test: Corrected some list-quoting issues and - other matters that cause tests to fail when the patch includes - special characters. Report from Vince Darley. [Bug 554068]. + * tests/tcltest.test: Corrected some list-quoting issues and other + matters that cause tests to fail when the patch includes special + characters. Report from Vince Darley. [Bug 554068]. 2002-05-08 David Gravereaux * doc/file.n: * tools/man2tcl.c: - * tools/man2help2.tcl: Thanks to Peter Spjuth - , again. My prior fix for - single-quote macro mis-understanding was wrong. Reverted to - reimpliment the 'macro2' proc which handles single-quote macros - and restored file.n text arrangement to avoid single-quotes on - the first line. Sorry for all the confusion. + * tools/man2help2.tcl: Thanks to Peter Spjuth , + again. My prior fix for single-quote macro mis-understanding was + wrong. Reverted to reimpliment the 'macro2' proc which handles + single-quote macros and restored file.n text arrangement to avoid + single-quotes on the first line. Sorry for all the confusion. 2002-05-08 David Gravereaux * tools/man2tcl.c: - * tools/man2help2.tcl: Proper source of macro error mis- - understanding single-quote as the leading macro command found - and repaired. + * tools/man2help2.tcl: Proper source of macro error mis-understanding + single-quote as the leading macro command found and repaired. - * doc/file.n: Reverted to prior state before I messed with - it. + * doc/file.n: Reverted to prior state before I messed with it. 2002-05-08 Don Porter * library/tcltest/tcltest.tcl: Corrected [uplevel] quoting when [source]-ing test script in subdirectories. * tests/fileName.test: * tests/load.test: * tests/main.test: - * tests/tcltest.test: - * tests/unixInit.test: Fixes to test suite when there's a space - in the working path. Thanks to Kevin Kenny. + * tests/tcltest.test: + * tests/unixInit.test: Fixes to test suite when there's a space in the + working path. Thanks to Kevin Kenny. 2002-05-07 David Gravereaux -- Changes from Peter Spjuth - * tools/man2tcl.c: Increased line buffer size and a bail-out if - that should ever be over-run. + * tools/man2tcl.c: Increased line buffer size and a bail-out if that + should ever be over-run. * tools/man2help.tcl: Include Courier New font in rtf header. - * tools/man2help2.tcl: Improved handling of CS/CE fields. Use - Courier New for code samples and indent better. + * tools/man2help2.tcl: Improved handling of CS/CE fields. Use Courier + New for code samples and indent better. * doc/file.n: - * doc/TraceCmd.3: winhelp conversion tools where understanding - a ' as the first character on a line to be an unknown macro. - Not knowing how to repair tools/man2tcl.c, I decided to rearrange - the text in the docs instead. + * doc/TraceCmd.3: winhelp conversion tools where understanding a ' as + the first character on a line to be an unknown macro. Not knowing how + to repair tools/man2tcl.c, I decided to rearrange the text in the docs + instead. 2002-05-07 Vince Darley - * generic/tclFileName.c: fix to similar segfault when using + * generic/tclFileName.c: fix to similar segfault when using 'glob -types nonsense -dir dirname -join * *'. [Bug 553320] - + * doc/FileSystem.3: further documentation on vfs. * tests/cmdAH.test: * tests/fileSystem.test: - * tests/pkgMkindex.test: Fix to testsuite bugs when running out - of directory whose name contains '{' or '['. + * tests/pkgMkindex.test: Fix to testsuite bugs when running out of + directory whose name contains '{' or '['. 2002-05-07 Miguel Sofer * tests/basic.test: Fix for [Bug 549607] * tests/encoding.test: Fix for [Bug 549610] @@ -3775,61 +8394,59 @@ These are testsuite bugs that caused failures when the filename contained spaces. Report & fix by Kevin Kenny. 2002-05-02 Vince Darley - * generic/tclFileName.c: fix to freeing a bad object - (i.e. segfault) when using 'glob -types nonsense -dir dirname'. - * generic/tclWinFile.c: fix to [Bug 551306], also wrapped some - long lines. + * generic/tclFileName.c: fix to freeing a bad object (i.e. segfault) + when using 'glob -types nonsense -dir dirname'. + * generic/tclWinFile.c: fix to [Bug 551306], also wrapped some long + lines. * tests/fileName.test: added several tests for the above bugs. - * doc/FileSystem.3: clarified documentation on refCount - requirements of the object returned by the path type function. + * doc/FileSystem.3: clarified documentation on refCount requirements + of the object returned by the path type function. * generic/tclIOUtil.c: * win/tclWinFile.c: * unix/tclUnixFile.c: - * mac/tclMacFile.c: moved TclpFilesystemPathType to the - platform specific directories, so we can add missing platform- - specific implementations. On Windows, 'file system' now returns - useful results like "native NTFS", "native FAT" for that system. - Unix and MacOS still only return "native". + * mac/tclMacFile.c: moved TclpFilesystemPathType to the platform + specific directories, so we can add missing platform-specific + implementations. On Windows, 'file system' now returns useful results + like "native NTFS", "native FAT" for that system. Unix and MacOS still + only return "native". * doc/file.n: clarified documentation. - * tests/winFile.test: test for 'file system' returning correct - values. + * tests/winFile.test: test for 'file system' returning correct values. * tests/fileSystem.test: test for 'file system' returning correct - values. Clean up after failed previous test run. - + values. Clean up after failed previous test run. + 2002-04-26 Jeff Hobbs * unix/configure: - * unix/tcl.m4: change HP-11 SHLIB_LD_LIBS from "" to ${LIBS} so - that the .sl knows its dependent libs. + * unix/tcl.m4: change HP-11 SHLIB_LD_LIBS from "" to ${LIBS} so that + the .sl knows its dependent libs. 2002-04-26 Donal K. Fellows * tests/obj.test (obj-11.[56]): Test conversion to boolean more thoroughly. * generic/tclObj.c (SetBooleanFromAny): Was not calling an integer - parsing function on native 64-bit platforms! [Bug 548686] + parsing function on native 64-bit platforms! [Bug 548686] 2002-04-24 Jeff Hobbs - * generic/tclInt.h: corrected TclRememberJoinableThread decl to - use VOID instead of void. + * generic/tclInt.h: corrected TclRememberJoinableThread decl to use + VOID instead of void. * generic/tclThreadJoin.c: noted that this code isn't needed on Unix. 2002-04-23 Jeff Hobbs - * doc/exec.n: - * doc/tclvars.n: doc updates [Patch #509426] (gravereaux) + * doc/exec.n: + * doc/tclvars.n: doc updates [Patch 509426] (gravereaux) 2002-04-24 Daniel Steffen - * mac/tclMacResource.r: added check of - TCLTK_NO_LIBRARY_TEXT_RESOURCES #define to allow disabling the - inclusion of the tcl library code in the resource fork of Tcl - executables and shared libraries. + * mac/tclMacResource.r: added check of TCLTK_NO_LIBRARY_TEXT_RESOURCES + #define to allow disabling the inclusion of the tcl library code in + the resource fork of Tcl executables and shared libraries. 2002-04-23 Donal K. Fellows * doc/TraceCmd.3: New file that documents Tcl_CommandTraceInfo, Tcl_TraceCommand and Tcl_UntraceCommand [Bug 414927] @@ -3841,281 +8458,275 @@ * generic/tclThreadAlloc.c (new): * unix/Makefile.in: * unix/tclUnixThrd.c: * win/Makefile.in: * win/tclWinInt.h: - * win/tclWinThrd.c: added new threaded allocator contributed by - AOL that significantly reduces lock contention when multiple - threads are in use. Only Windows and Unix implementations are - ready, and the Windows one may need work. It is only used by - default on Unix for now, and requires that USE_THREAD_ALLOC be - defined (--enable-threads on Unix will define this). - - * generic/tclIOUtil.c (Tcl_FSRegister, Tcl_FSUnregister): - corrected calling of Tcl_ConditionWait to ensure that there would - be a condition to wait upon. + * win/tclWinThrd.c: added new threaded allocator contributed by AOL + that significantly reduces lock contention when multiple threads are + in use. Only Windows and Unix implementations are ready, and the + Windows one may need work. It is only used by default on Unix for now, + and requires that USE_THREAD_ALLOC be defined (--enable-threads on + Unix will define this). + + * generic/tclIOUtil.c (Tcl_FSRegister, Tcl_FSUnregister): corrected + calling of Tcl_ConditionWait to ensure that there would be a condition + to wait upon. * generic/tclCmdAH.c (Tcl_FileObjCmd): added cast in FILE_SIZE. - * win/tclWinFCmd.c (DoDeleteFile): check return of setattr API - calls in file deletion for correct Win32 API handling. + * win/tclWinFCmd.c (DoDeleteFile): check return of setattr API calls + in file deletion for correct Win32 API handling. * win/Makefile.in: correct dependencies for shell, gdb, runtest targets. * doc/clock.n: * compat/strftime.c (_fmt): change strftime to correctly handle - localized %c, %x and %X on Windows. Added some notes about how - the other values could be further localized. + localized %c, %x and %X on Windows. Added some notes about how the + other values could be further localized. 2002-04-19 Don Porter - * generic/tclMain.c (Tcl_Main): Free the memory allocated for the - startup script path. [Bug 543549] + * generic/tclMain.c (Tcl_Main): Free the memory allocated for the + startup script path. [Bug 543549] - * library/msgcat/msgcat.tcl: [mcmax] wasn't using the caller's - namespace when determining the max translated length. Also - made revisions for better use of namespace variables and more - efficient [uplevel]s. + * library/msgcat/msgcat.tcl: [mcmax] wasn't using the caller's + namespace when determining the max translated length. Also made + revisions for better use of namespace variables and more efficient + [uplevel]s. * doc/msgcat.n: * library/msgcat/msgcat.tcl: - * library/msgcat/pkgIndex.tcl: Added [mcload] to the export list - of msgcat; bumped to 1.2.3. [Bug 544727] + * library/msgcat/pkgIndex.tcl: Added [mcload] to the export list of + msgcat; bumped to 1.2.3. [Bug 544727] 2002-04-20 Daniel Steffen * generic/tclInt.decls: * generic/tclIntPlatDecls.h: * generic/tclStubInit.c: * mac/tclMacFCmd.c: * mac/tclMacFile.c: - * mac/tclMacUtil.c: Modified TclpObjNormalizePath to be alias - file aware, and replaced various calls to FSpLocationFrom*Path - by calls to new alias file aware versions FSpLLocationFrom*Path. - The alias file aware routines don't resolve the last component of - a path if it is an alias. This allows [file copy/delete] etc. to - act correctly on alias files. (c.f. discussion in Bug #511666) + * mac/tclMacUtil.c: Modified TclpObjNormalizePath to be alias file + aware, and replaced various calls to FSpLocationFrom*Path by calls to + new alias file aware versions FSpLLocationFrom*Path. The alias file + aware routines don't resolve the last component of a path if it is an + alias. This allows [file copy/delete] etc. to act correctly on alias + files. (c.f. discussion in [Bug 511666]) 2002-04-19 Donal K. Fellows - * tests/lindex.test (lindex-3.7): - * generic/tclUtil.c (TclGetIntForIndex): Stopped indexes from - hitting wide ints. [Bug #526717] + * tests/lindex.test (lindex-3.7): + * generic/tclUtil.c (TclGetIntForIndex): Stopped indexes from hitting + wide ints. [Bug 526717] 2002-04-18 Miguel Sofer * generic/tclNamesp.c: - * tests/info.test: [Bug 545325] info level didn't report - namespace eval, bug report by Richard Suchenwirth. + * tests/info.test: [Bug 545325] info level didn't report namespace + eval, bug report by Richard Suchenwirth. 2002-04-18 Don Porter - * doc/subst.n: Clarified documentation on handling unusual return - codes during substitution, and on variable substitutions implied - by command substitution, and vice versa. [Bug 536838] + * doc/subst.n: Clarified documentation on handling unusual return + codes during substitution, and on variable substitutions implied by + command substitution, and vice versa. [Bug 536838] 2002-04-18 Donal K. Fellows - * generic/tclCmdIL.c (InfoBodyCmd): - * tests/info.test (info-2.6): Proc bodies without string reps - would report as empty [Bug #545644] - - * generic/tclCmdMZ.c (Tcl_SubstObj): More clarification for - comment on behaviour when substitutions are not well-formed, - prompted by [Bug #536831]; alas, removing the ill-defined - behaviour is a lot of work. + * generic/tclCmdIL.c (InfoBodyCmd): + * tests/info.test (info-2.6): Proc bodies without string reps would + report as empty [Bug 545644] + + * generic/tclCmdMZ.c (Tcl_SubstObj): More clarification for comment on + behaviour when substitutions are not well-formed, prompted by [Bug + 536831]; alas, removing the ill-defined behaviour is a lot of work. 2002-04-18 Miguel Sofer * generic/tclExecute.c: - * tests/expr-old.test: fix for [Bug #542588] (Phil Ehrens), where - "too large integers" were reported as "floating-point value" in - [expr] error messages. + * tests/expr-old.test: fix for [Bug 542588] (Phil Ehrens), where "too + large integers" were reported as "floating-point value" in [expr] + error messages. 2002-04-17 Jeff Hobbs - * generic/tclEncoding.c (EscapeFromUtfProc): - * generic/tclIO.c (WriteChars, Tcl_Close): corrected the handling - of outputting end escapes for escape-based encodings. - [Bug #526524] (yamamoto) + * generic/tclEncoding.c (EscapeFromUtfProc): + * generic/tclIO.c (WriteChars, Tcl_Close): corrected the handling of + outputting end escapes for escape-based encodings. + [Bug 526524] (yamamoto) 2002-04-17 Don Porter - * doc/tcltest.n: Removed [saveState] and [restoreState] from - tcltest 2 documentation, effectively deprecating them. [Bug 495660] - * library/tcltest/tcltest.tcl: Made separate export for commands - kept only for tcltest 1 compatibility. + * doc/tcltest.n: Removed [saveState] and [restoreState] from tcltest + 2 documentation, effectively deprecating them. [Bug 495660] + * library/tcltest/tcltest.tcl: Made separate export for commands kept + only for tcltest 1 compatibility. * tests/iogt.test: Revised to run tests in a namespace, rather than - use the useless and buggy [saveState] and [restoreState] commands - of tcltest. Updated to use tcltest 2 as well. [Patch 544911] + use the useless and buggy [saveState] and [restoreState] commands of + tcltest. Updated to use tcltest 2 as well. [Patch 544911] 2002-04-16 Don Porter - * tests/io.test: Revised to run tests in a namespace, rather than - use the useless and buggy [saveState] and [restoreState] commands - of tcltest. Updated to use tcltest 2 as well. [Patch 544546] + * tests/io.test: Revised to run tests in a namespace, rather than use + the useless and buggy [saveState] and [restoreState] commands of + tcltest. Updated to use tcltest 2 as well. [Patch 544546] 2002-04-15 Miguel Sofer * generic/tclProc.c: * tests/proc-old.test: Improved stack trace for TCL_BREAK and - TCL_CONTINUE returns from procs. Patch by Don Porter - [Bug 536955]. - + TCL_CONTINUE returns from procs. [Bug 536955] (dgp) + * generic/tclExecute.c: * tests/compile.test: made bytecodes check for a catch before - returning; the compiled [return] is otherwise non-catchable. - [Bug 542142] reported by Andreas Kupries. + returning; the compiled [return] is otherwise non-catchable. [Bug + 542142] reported by Andreas Kupries. 2002-04-15 Don Porter - * tests/socket.test: Increased timeout values so that tests have - time to successfully complete even on slow/busy machines. [Bug 523470] + * tests/socket.test: Increased timeout values so that tests have time + to successfully complete even on slow/busy machines. [Bug 523470] * doc/tcltest.n: * library/tcltest/tcltest.tcl: - * tests/tcltest.test: Revised [tcltest::test] to return errors - when called with invalid syntax and to accept exactly two arguments - as documented. Improved error messages. [Bug 497446, Patch 513983] + * tests/tcltest.test: Revised [tcltest::test] to return errors when + called with invalid syntax and to accept exactly two arguments as + documented. Improved error messages. [Bug 497446, Patch 513983] ***POTENTIAL INCOMPATIBILITY***: Incompatible with previous tcltest 2.* releases, found only in alpha releases of Tcl 8.4. 2002-04-11 Jeff Hobbs * generic/tclNotify.c (TclFinalizeNotifier): remove remaining unserviced events on finalization. * win/tcl.m4: Enabled COFF as well as CV style debug info with - --enable-symbols to allow Dr. Watson users to see function info. - More info on debugging levels can be obtained at: + --enable-symbols to allow Dr. Watson users to see function info. More + info on debugging levels can be obtained at: http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp * tests/ioCmd.test: fixed iocmd-8.15 to have mac and unixPc variants. - * generic/tclParse.c (Tcl_ParseVar): conditionally incr obj - refcount to prevent possible mem leak. + * generic/tclParse.c (Tcl_ParseVar): conditionally incr obj refcount + to prevent possible mem leak. 2002-04-08 Daniel Steffen * generic/tcl.h: no on mac. * mac/tclMacFile.c: minor fixes to Vince's changes from 03-24. * mac/tclMacOSA.c: * mac/tclMacResource.c: added missing Tcl_UtfToExternalDString conversions of resource file names. - * mac/tclMacSock.c (TcpGetOptionProc): fixed bug introduced - by Andreas on 02-25; changed strcmp's to strncmp's so that - option comparison behaves like on other platforms. - * mac/tcltkMacBuildSupport.sea.hqx (CW Pro6 changes): added - support to allow Tk to hookup C library stderr/stdout to TkConsole. + * mac/tclMacSock.c (TcpGetOptionProc): fixed bug introduced by Andreas + on 02-25; changed strcmp's to strncmp's so that option comparison + behaves like on other platforms. + * mac/tcltkMacBuildSupport.sea.hqx (CW Pro6 changes): added support to + allow Tk to hookup C library stderr/stdout to TkConsole. * tests/basic.test: * tests/cmdAH.test: * tests/encoding.test: * tests/fileSystem.test: - * tests/ioCmd.test: fixed tests failing on mac: check for - existence of [exec], changed some result strings. + * tests/ioCmd.test: fixed tests failing on mac: check for existence of + [exec], changed some result strings. 2002-04-06 Jeff Hobbs * unix/tclUnixFCmd.c (Realpath): added a little extra code to - initialize a realpath arg when compiling in PURIFY mode in order - to prevent spurious purify warnings. We should really create our - own realpath implementation, but this will at least quiet purify - for now. + initialize a realpath arg when compiling in PURIFY mode in order to + prevent spurious purify warnings. We should really create our own + realpath implementation, but this will at least quiet purify for now. 2002-04-05 Don Porter * generic/tclCmdMZ.c (Tcl_SubstObj): - * tests/subst.test: Corrected [subst] so that return codes - TCL_BREAK and TCL_CONTINUE returned by variable substitution - have the same effect as when those codes are returned by command - substitution. [Bug 536879] + * tests/subst.test: Corrected [subst] so that return codes TCL_BREAK + and TCL_CONTINUE returned by variable substitution have the same + effect as when those codes are returned by command substitution. [Bug + 536879] 2002-04-03 Jeff Hobbs * library/tcltest/tcltest.tcl: added getMatchingFiles back (alias to GetMatchingFiles), which was a public function in tcltest 1.0. 2002-04-01 Vince Darley * generic/tclEnv.c: - * generic/tclIOUtil.c: invalidate filesystem cache when the - user changes env(HOME). Fixes [Bug #535621]. Also cleaned up - some of the documentation. + * generic/tclIOUtil.c: invalidate filesystem cache when the user + changes env(HOME). Fixes [Bug 535621]. Also cleaned up some of the + documentation. * tests/fileSystem.test: added test for bug just fixed. - + 2002-04-01 Kevin Kenny - * win/tclWinTime.c (Tcl_GetTime): made the checks of clock - frequency more permissive to cope with the fact that Win98SE - is observed to return 1.19318 in place of 1.193182 for the - performance counter frequency. - + * win/tclWinTime.c (Tcl_GetTime): made the checks of clock frequency + more permissive to cope with the fact that Win98SE is observed to + return 1.19318 in place of 1.193182 for the performance counter + frequency. + 2002-03-29 Jeff Hobbs * generic/tclCmdMZ.c (Tcl_TraceObjCmd, TraceVarProc) - (TraceCommandProc, TclTraceCommandObjCmd): corrected - potential double-free of traces on variables by flagging in - Trace*Proc that it will free the var in case the eval wants to - delete the var trace as well. [Bug #536937] + (TraceCommandProc, TclTraceCommandObjCmd): corrected potential + double-free of traces on variables by flagging in Trace*Proc that it + will free the var in case the eval wants to delete the var trace as + well. [Bug 536937] Also converted Tcl_UntraceVar -> Tcl_UntraceVar2 and Tcl_Eval to Tcl_EvalEx in Trace*Proc for slight efficiency improvement. 2002-03-29 Don Porter * doc/AllowExc.3: * generic/tclBasic.c (Tcl_EvalObjv,Tcl_EvalEx,Tcl_EvalObjEx): * generic/tclCompile.h (TclCompEvalObj): * generic/tclExecute.c (TclCompEvalObj,TclExecuteByteCode): - * tests/basic.test: Corrected problems with Tcl_AllowExceptions - having influence over the wrong scope of Tcl_*Eval* calls. Patch - from Miguel Sofer. Report from Jean-Claude Wippler. [Bug 219181] + * tests/basic.test: Corrected problems with Tcl_AllowExceptions having + influence over the wrong scope of Tcl_*Eval* calls. Patch from Miguel + Sofer. Report from Jean-Claude Wippler. [Bug 219181] 2002-03-28 Don Porter - * generic/tclVar.c: Refactored CallTraces to collect repeated - handling of its returned value into CallTraces itself. + * generic/tclVar.c: Refactored CallTraces to collect repeated handling + of its returned value into CallTraces itself. 2002-03-28 David Gravereaux * tools/feather.bmp: * tools/man2help.tcl: * tools/man2help2.tcl: - * win/makefile.vc: More winhelp target fixups. Added a feather - bitmap to the non-scrollable area and changed the color to be - yellow from a plain white. The colors can be whatever we want - them to be, but thought I would start with something bold. - [Bug 527941] + * win/makefile.vc: More winhelp target fixups. Added a feather bitmap + to the non-scrollable area and changed the color to be yellow from a + plain white. The colors can be whatever we want them to be, but + thought I would start with something bold. [Bug 527941] * doc/SetVar.3: * doc/TraceVar.3: - * doc/UpVar.3: .AP macro syntax repair. + * doc/UpVar.3: .AP macro syntax repair. 2002-03-27 David Gravereaux * tools/man2help.tcl: - * win/makefile.vc: winhelp target now copies all needed files - from tools/ to a workarea under $(OUT_DIR) and builds it from - there. No build cruft is left in tools/ anymore. All paths - used in man2help.tcl are now relative to where the script is. - [Bug 527941] + * win/makefile.vc: winhelp target now copies all needed files from + tools/ to a workarea under $(OUT_DIR) and builds it from there. No + build cruft is left in tools/ anymore. All paths used in man2help.tcl + are now relative to where the script is. [Bug 527941] 2002-03-27 David Gravereaux * win/.cvsignore: * win/buildall.vc.bat: * win/coffbase.txt: * win/makefile.vc: * win/nmakehlp.c (new): - * win/rules.vc: First draft fix for [Bug 527941]. More changes - need to done to the makehelp target to get to stop leaving build - files in the tools/ directory. This does not address the syntax - errors in the man files. Having the contents of tcl.hpj(.in) - inside makefile.vc allows for version numbers to be replaced with - macros. - + * win/rules.vc: First draft fix for [Bug 527941]. More changes need to + done to the makehelp target to get to stop leaving build files in the + tools/ directory. This does not address the syntax errors in the man + files. Having the contents of tcl.hpj(.in) inside makefile.vc allows + for version numbers to be replaced with macros. + The new nmakehlp.c is built by rules.vc in preprocessing and removes the need to use tricky shell syntax that wasn't compatible on Win9x systems. Clean targets made Win9x complient. This is a first draft repair for [Bug 533862]. @@ -4125,12 +8736,12 @@ to TclEvalObjvInternal. [Bug 219362], fix by David Knoll. 2002-03-28 Miguel Sofer * generic/tclBasic.c (Tcl_EvalEx): - * tests/basic.test: avoid exceptional returns at level 0 - [Bug 219181] + * tests/basic.test: avoid exceptional returns at level 0 + [Bug 219181] 2002-03-27 Don Porter * doc/tcltest.n ([mainThread]): * library/tcltest/tcltest.tcl: @@ -4142,17 +8753,17 @@ 2002-03-25 Don Porter * tests/main.test: Removed workarounds for Bug 495977. - * library/tcltest/tcltest.tcl: Keep the value of $::auto_path + * library/tcltest/tcltest.tcl: Keep the value of $::auto_path unchanged, so that the tcltest package can test code that depends - on auto-loading. If a testing application needs $::auto_path pruned, - it should do that itself. [Bug 495726] + on auto-loading. If a testing application needs $::auto_path pruned, + it should do that itself. [Bug 495726] Improve the processing of the -constraints option to [test] so that constraint lists can have arbitrary whitespace, and non-lists don't - blow things up. [Bug 495977] + blow things up. [Bug 495977] Corrected faulty variable initialization. [Bug 534845] 2002-03-25 Miguel Sofer * doc/CrtTrace.3: small doc correction @@ -4164,15 +8775,15 @@ * generic/tclBasic.c (Tcl_EvalObjv): replaced obscure, incorrect code as described in [Bug 533907] (Don Porter). 2002-03-24 Don Porter - * library/tcltest/tcltest.tcl: Use [interpreter] to set/query the - executable currently running the tcltest package. [Bug 454050] + * library/tcltest/tcltest.tcl: Use [interpreter] to set/query the + executable currently running the tcltest package. [Bug 454050] - * library/tcltest/tcltest.tcl: Allow non-proc commands to be used - as the customization hooks. [Bug 495662] + * library/tcltest/tcltest.tcl: Allow non-proc commands to be used + as the customization hooks. [Bug 495662] 2002-03-24 Vince Darley * generic/tclFilename.c: * generic/tclFCmd.c: @@ -4187,48 +8798,45 @@ * mac/tclMacFile.c: * doc/FileSystem.3: * doc/file.n: * tests/cmdAH.test: * tests/fileName.test: - * tests/fileSystem.test: (new file) - * tests/winFCmd.test: fix [Bug 511666] and [Bug 511658], - and improved documentation of some aspects of the filesystem, - particularly 'Tcl_FSMatchInDirectory' which now might match - a single file/directory only, and 'file normalize' which - wasn't very clear before. Removed inconsistency betweens - docs and the Tcl_Filesystem structure. Also fixed - [Bug 523217] and corrected file normalization on Unix so that - it expands symbolic links. Added some new tests of the - filesystem code (in the new file 'fileSystem.test'), and - some extra tests for correct handling of symbolic links. - Fix to [Bug 530960] which shows up on Win98. Made comparison - with ".com" case insensitive in tclWinPipe.c - - ***POTENTIAL INCOMPATIBILITY***: But only between alpha - releases (users of the new Tcl_Filesystem lookup table in Tcl - 8.4a4 need to handle the new way in which Tcl may call - Tcl_FSMatchInDirectory, and 'file normalize' on unix now - behaves correctly). Only known impact is with the 'tclvfs' - extension. + * tests/fileSystem.test: (new file) + * tests/winFCmd.test: fix [Bug 511666] and [Bug 511658], and improved + documentation of some aspects of the filesystem, particularly + 'Tcl_FSMatchInDirectory' which now might match a single file/directory + only, and 'file normalize' which wasn't very clear before. Removed + inconsistency betweens docs and the Tcl_Filesystem structure. Also + fixed [Bug 523217] and corrected file normalization on Unix so that it + expands symbolic links. Added some new tests of the filesystem code + (in the new file 'fileSystem.test'), and some extra tests for correct + handling of symbolic links. Fix to [Bug 530960] which shows up on + Win98. Made comparison with ".com" case insensitive in tclWinPipe.c + + ***POTENTIAL INCOMPATIBILITY***: But only between alpha releases + (users of the new Tcl_Filesystem lookup table in Tcl 8.4a4 need to + handle the new way in which Tcl may call Tcl_FSMatchInDirectory, and + 'file normalize' on unix now behaves correctly). Only known impact is + with the 'tclvfs' extension. 2002-03-22 Miguel Sofer - * tests/basic.test (basic-46.1): adding test for [Bug 533758], - fixed earlier today. - + * tests/basic.test (basic-46.1): adding test for [Bug 533758], fixed + earlier today. + 2002-03-22 Jeff Hobbs - * win/tclWinInt.h: moved undef of TCL_STORAGE_CLASS. [Bug #478579] + * win/tclWinInt.h: moved undef of TCL_STORAGE_CLASS. [Bug 478579] 2002-03-22 Miguel Sofer * generic/tclBasic.c (Tcl_EvalObjEx): * generic/tclExecute.c (TclCompEvalObj): fixed the errorInfo for - return codes other than (TCL_OK, TCL_ERROR) to runLevel 0 - [Bug 533758]. Removed the static RecordTracebackInfo(), as its - functionality is easily replicated by Tcl_LogCommandInfo. Bug - and redundancy noted by Don Porter. + return codes other than (TCL_OK, TCL_ERROR) to runLevel 0 [Bug + 533758]. Removed the static RecordTracebackInfo(), as its + functionality is easily replicated by Tcl_LogCommandInfo. Bug and + redundancy noted by Don Porter. 2002-03-21 Donal K. Fellows * doc/expr.n: Improved documentation for ceil and floor [Bug 530535] @@ -4236,26 +8844,26 @@ * doc/SetVar.3: * doc/TraceVar.3: * doc/UpVar.3: * generic/tcl.h (Tcl_VarTraceProc): - * generic/tcl.decls (Tcl_GetVar2, Tcl_SetVar2, Tcl_TraceVar2, - Tcl_UnsetVar2, Tcl_UntraceVar2, Tcl_UpVar2, Tcl_VarTraceInfo2, - Tcl_GetVar2Ex, TclSetVar2Ex): + * generic/tcl.decls (Tcl_GetVar2, Tcl_SetVar2, Tcl_TraceVar2) + (Tcl_UnsetVar2, Tcl_UntraceVar2, Tcl_UpVar2, Tcl_VarTraceInfo2) + (Tcl_GetVar2Ex, TclSetVar2Ex): * generic/tclCmdMZ.c (TraceVarProc): * generic/tclEnv.c (EnvTraceProc): * generic/tclEvent.c (VwaitVarProc): * generic/tclInt.decls (TclLookupVar,TclPrecTraceProc): * generic/tclLink.c (LinkTraceProc): * generic/tclUtil.c (TclPrecTraceProc): * generic/tclVar.c (CallTraces, MakeUpvar, VarErrMsg, TclLookupVar, - Tcl_GetVar2, Tcl_SetVar2, Tcl_TraceVar2, Tcl_UnsetVar2, - Tcl_UntraceVar2, Tcl_UpVar2, Tcl_VarTraceInfo2, Tcl_GetVar2Ex, - TclSetVar2Ex): Updated interfaces of generic/tclVar.c according - to TIP 27. In particular, the "part2" arguments were CONSTified. + (Tcl_GetVar2, Tcl_SetVar2, Tcl_TraceVar2, Tcl_UnsetVar2) + (Tcl_UntraceVar2, Tcl_UpVar2, Tcl_VarTraceInfo2, Tcl_GetVar2Ex) + (TclSetVar2Ex): Updated interfaces of generic/tclVar.c according to + TIP 27. In particular, the "part2" arguments were CONSTified. [Patch 532642] - * generic/tclDecls.h: + * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs 2002-03-15 Donal K. Fellows * tests/compile.test (compile-12.3): Test to detect bug 530320. @@ -4263,81 +8871,76 @@ reported in bug 530320. 2002-03-14 Mo DeJong * win/configure: Regen. - * win/configure.in: Add configure time test for SEH - support in the compiler. + * win/configure.in: Add configure time test for SEH support in the + compiler. * win/tclWin32Dll.c (ESP, EBP, TclpCheckStackSpace, - _except_checkstackspace_handler): + (_except_checkstackspace_handler): * win/tclWinChan.c (ESP, EBP, Tcl_MakeFileChannel, - _except_makefilechannel_handler): - * win/tclWinFCmd.c (ESP, EBP, DoRenameFile, - _except_dorenamefile_handler, - DoCopyFile, _except_docopyfile_handler): - Implement SEH support under gcc using inline asm. - Tcl and Tk should now compile with Mingw 1.1. [Patch 525746] + (_except_makefilechannel_handler): + * win/tclWinFCmd.c (ESP, EBP, DoRenameFile, DoCopyFile, + (_except_dorenamefile_handler, _except_docopyfile_handler): Implement + SEH support under gcc using inline asm. Tcl and Tk should now compile + with Mingw 1.1. [Patch 525746] 2002-03-14 Mo DeJong - * win/tclWinFCmd.c (DoRenameFile, DoCopyFile): Handle - an SEH exception with EXCEPTION_EXECUTE_HANDLER instead - of restarting the faulting instruction with - EXCEPTION_CONTINUE_EXECUTION. Bug 466102 provides an - example of how restarting could send Tcl into an - infinite loop. [Patch 525746] + * win/tclWinFCmd.c (DoRenameFile, DoCopyFile): Handle an SEH exception + with EXCEPTION_EXECUTE_HANDLER instead of restarting the faulting + instruction with EXCEPTION_CONTINUE_EXECUTION. Bug 466102 provides an + example of how restarting could send Tcl into an infinite loop. [Patch + 525746] 2002-03-11 Mo DeJong * win/tclWinFCmd.c (DoRenameFile, DoCopyFile, DoDeleteFile, - DoRemoveJustDirectory): Make sure we don't pass NULL or "" - as a path name to Win32 API functions since this was - crashing under Windows 98. + (DoRemoveJustDirectory): Make sure we don't pass NULL or "" as a path + name to Win32 API functions since this was crashing under Windows 98. 2002-03-11 Don Porter * library/tcltest/tcltest.tcl: * library/tcltest/pkgIndex.tcl: Bumped tcltest package to 2.0.2. 2002-03-11 Mo DeJong - * library/tcltest/tcltest.tcl (getMatchingFiles): Pass - a proper list to foreach to avoid munging a Windows - patch like D:\Foo\Bar into D:FooBar before the glob. + * library/tcltest/tcltest.tcl (getMatchingFiles): Pass a proper list + to foreach to avoid munging a Windows patch like D:\Foo\Bar into + D:FooBar before the glob. 2002-03-11 Mo DeJong * generic/tclEncoding.c: Fix typo in comment. - * generic/tclIO.c (DoReadChars, ReadBytes, ReadChars): - Use NULL value instead of pointer set to NULL to make - things more clear. Reorder arguments so that they - match the function signatures. Cleanup little typos - and add more descriptive comment. + * generic/tclIO.c (DoReadChars, ReadBytes, ReadChars): Use NULL value + instead of pointer set to NULL to make things more clear. Reorder + arguments so that they match the function signatures. Cleanup little + typos and add more descriptive comment. 2002-03-08 Mo DeJong - * win/README: Update to indicate that Mingw 1.1 is - required to build Tcl. Add section describing new - msys based build process. Update Cygwin build - instructions so users know where to find Mingw 1.1. + * win/README: Update to indicate that Mingw 1.1 is required to build + Tcl. Add section describing new msys based build process. Update + Cygwin build instructions so users know where to find Mingw 1.1. 2002-03-08 Jeff Hobbs * win/tclWinFCmd.c (DoCopyFile): correctly set retval to TCL_OK. 2002-03-07 Mo DeJong * win/tclWin32Dll.c (TclpCheckStackSpace): - * win/tclWinFCmd.c (DoRenameFile, DoCopyFile): Replace - hard coded constants with Win32 symbolic names. - Move control flow statements out of __try blocks - since the documentation indicates it is frowned upon. + * win/tclWinFCmd.c (DoRenameFile, DoCopyFile): Replace hard coded + constants with Win32 symbolic names. Move control flow statements out + of __try blocks since the documentation indicates it is frowned upon. 2002-03-07 Don Porter * doc/interp.n: - * generic/tclInterp.c(Tcl_InterpObjCmd,SlaveObjCmd,SlaveRecursionLimit): + * generic/tclInterp.c (Tcl_InterpObjCmd,SlaveObjCmd, + (SlaveRecursionLimit): * generic/tclTest.c: * tests/interp.test: Added the [interp recursionlimit] command to set/query the recursion limit of an interpreter. Proposal and implementation from Stephen Trier. [TIP 87, Patch 522849] @@ -4349,13 +8952,13 @@ will help us distinguish between the CVS version and the most recent released version. 2002-03-06 Miguel Sofer - * generic/tclInt.h: for unshared objects, TclDecrRefCount now - frees the internal rep before the string rep - just like the - non-macro Tcl_DecrRefCount/TclFreeObj [Bug 524802]. + * generic/tclInt.h: for unshared objects, TclDecrRefCount now frees + the internal rep before the string rep - just like the non-macro + Tcl_DecrRefCount/TclFreeObj [Bug 524802]. 2002-03-06 Donal K. Fellows * doc/lsearch.n: Documentation of new features, plus examples. * tests/lsearch.test: Tests of new features. @@ -4364,14 +8967,13 @@ 2002-03-05 Jeff Hobbs *** 8.4a4 TAGGED FOR RELEASE *** - * unix/tclUnixChan.c: initial remedy for [Bug #525783] flush - problem introduced by TIP #35. This may not satisfy true serial - channels, but it restores the correct flushing of std* channels on - exit. + * unix/tclUnixChan.c: initial remedy for [Bug 525783] flush problem + introduced by TIP #35. This may not satisfy true serial channels, but + it restores the correct flushing of std* channels on exit. * unix/README: added --enable-langinfo doc. * unix/tcl.spec: * tools/tcl.wse.in: fixed URL refs to use www.tcl.tk or SF. @@ -4389,25 +8991,25 @@ * tests/io.test: * tests/encoding.test: corrected iso2022 encoding results. added encoding-24.* * generic/tclEncoding.c (EscapeFromUtfProc): corrected output of - escape codes as per RFC 1468. [Patch #474358] (taguchi) + escape codes as per RFC 1468. [Patch 474358] (taguchi) (TclFinalizeEncodingSubsystem): corrected potential double-free - when encodings were finalized on exit. [Bug #219314, #524674] + when encodings were finalized on exit. [Bug 219314, 524674] 2002-03-01 Jeff Hobbs - * library/encoding/iso2022-jp.enc: - * library/encoding/iso2022.enc: + * library/encoding/iso2022-jp.enc: + * library/encoding/iso2022.enc: * tools/encoding/iso2022-jp.esc: * tools/encoding/iso2022.esc: gave $B precedence over $@, - based on comments (point 1) in [Bug #219283] (rfc 1468) + based on comments (point 1) in [Bug 219283] (RFC 1468) * tests/encoding.test: added encoding-23.* tests * generic/tclIO.c (FilterInputBytes): reset the TCL_ENCODING_START - flags in the ChannelState when using 'gets'. [Bug #523988] + flags in the ChannelState when using 'gets'. [Bug 523988] Also reduced the value of ENCODING_LINESIZE from 30 to 20 as this seems to improve the performance of 'gets' according to tclbench. 2002-02-28 Jeff Hobbs @@ -4421,18 +9023,18 @@ * generic/tclTimer.c (TimerExitProc): remove remaining events in tls on thread exit. 2002-02-28 Miguel Sofer - * generic/tclNamesp.c: allow cached fully-qualified namespace - names to be usable from different namespaces within the same - interpreter without forcing a new lookup [Patch 458872]. + * generic/tclNamesp.c: allow cached fully-qualified namespace names to + be usable from different namespaces within the same interpreter + without forcing a new lookup [Patch 458872]. 2002-02-28 Miguel Sofer - * generic/tclExecute.c: Replaced a few direct stack accesses - with the POP_OBJECT() macro [Bug 507181] (Don Porter). + * generic/tclExecute.c: Replaced a few direct stack accesses with the + POP_OBJECT() macro [Bug 507181] (Don Porter). 2002-02-27 Don Porter * doc/GetIndex.3: * generic/tcl.decls (Tcl_GetIndexFromObjStruct): @@ -4445,11 +9047,11 @@ * generic/tclDecls.h: make genstubs * generic/tclMain.c (Tcl_Main,StdinProc): Corrected some reference count management errors on the interactive command Tcl_Obj found by - Purify. Thanks to Jeff Hobbs for the report and assistance. + Purify. Thanks to Jeff Hobbs for the report and assistance. 2002-02-27 Jeff Hobbs * generic/tclBasic.c (Tcl_EvalTokensStandard): corrected mem leak in error case. @@ -4458,58 +9060,56 @@ * generic/tclLink.c (Tcl_LinkVar): correct mem leak in error case. 2002-02-27 Andreas Kupries - * tests/socket.test (2.7): Accepted and applied patch for Tcl SF - bug #523470 provided by Don Porter - to avoid timing problems in that test. + * tests/socket.test (2.7): Accepted and applied patch for [Bug 523470] + provided by Don Porter to avoid timing + problems in that test. * unix/tclUnixChan.c (TclpOpenFileChannel): Added code to regonize - "/dev/tty" (by name) and to not handle it as tty / serial - line. This is the controlling terminal and is special. Setting - it into raw mode as is done for other tty's is a bad idea. This - is a hackish fix for expect SGF Bug #520624. The fix has - limitation: Tcl_MakeFileChannel handles tty's specially too, but - is unable to recognize /dev/tty as it only gets a file - descriptor, and no name for it. + "/dev/tty" (by name) and to not handle it as tty / serial line. This + is the controlling terminal and is special. Setting it into raw mode + as is done for other tty's is a bad idea. This is a hackish fix for + expect [Bug 520624]. The fix has limitation: Tcl_MakeFileChannel + handles tty's specially too, but is unable to recognize /dev/tty as it + only gets a file descriptor, and no name for it. 2002-02-26 Jeff Hobbs * generic/tclCmdAH.c (StoreStatData): corrected mem leak. - * generic/tclCmdMZ.c (Tcl_RegsubObjCmd): prevent obj leak in - remedial regsub case. + * generic/tclCmdMZ.c (Tcl_RegsubObjCmd): prevent obj leak in remedial + regsub case. * generic/tclFileName.c (Tcl_TranslateFileName): decr refcount for - error case to prevent mem leak. + error case to prevent mem leak. * generic/tclVar.c (Tcl_ArrayObjCmd): removed extra obj allocation. - * unix/tclUnixSock.c (Tcl_GetHostName): added an extra - gethostbyname check to guard against failure with truncated - names returned by uname. + * unix/tclUnixSock.c (Tcl_GetHostName): added an extra gethostbyname + check to guard against failure with truncated names returned by uname. * unix/configure: * unix/tcl.m4 (SC_SERIAL_PORT): added sys/modem.h check and defined - _XOPEN_SOURCE_EXTENDED for HP-11 to get updated header decls. + _XOPEN_SOURCE_EXTENDED for HP-11 to get updated header decls. * unix/tclUnixChan.c: added Unix implementation of TIP #35, serial - port support. [Patch #438509] (schroedter) + port support. [Patch 438509] (schroedter) 2002-02-26 Miguel Sofer * generic/tclCmpCmds.c: (bugfix to the bugfix, hopefully the last) - Bugfix to the new [for] compiling code: was setting a - exceptArray parameter using another param which wasn't yet - initialised, thus filling it with noise. + Bugfix to the new [for] compiling code: was setting a exceptArray + parameter using another param which wasn't yet initialised, thus + filling it with noise. 2002-02-25 Andreas Kupries - * mac/tclMacSock.c (TcpGetOptionProc): Changed to recognize the - option "-error". Essentially ignores the option, always - returning an empty string. + * mac/tclMacSock.c (TcpGetOptionProc): Changed to recognize the option + "-error". Essentially ignores the option, always returning an empty + string. 2002-02-25 Jeff Hobbs * doc/Alloc.3: * doc/LinkVar.3: @@ -4516,25 +9116,24 @@ * doc/ObjectType.3: * doc/PkgRequire.3: * doc/Preserve.3: * doc/TCL_MEM_DEBUG.3: Updated documentation to describe the ckalloc, ckfree, ckrealloc, attemptckalloc, and attemptckrealloc macros, and - to accurately describe when and how they are used. [Bug #497459] (dgp) - - * generic/tclHash.c (AllocArrayEntry, AllocStringEntry): - Before invoking ckalloc when creating a Tcl_HashEntry, - check that the amount of memory being allocated is - at least as large as sizeof(Tcl_HashEntry). The previous - code was allocating memory regions that were one - or two bytes short. [Bug #521950] (dejong) + to accurately describe when and how they are used. [Bug 497459] (dgp) + + * generic/tclHash.c (AllocArrayEntry, AllocStringEntry): Before + invoking ckalloc when creating a Tcl_HashEntry, check that the amount + of memory being allocated is at least as large as + sizeof(Tcl_HashEntry). The previous code was allocating memory regions + that were one or two bytes short. [Bug 521950] (dejong) 2002-02-25 Miguel Sofer - * generic/tclBasic.c (Tcl_EvalEx): avoiding a buffer overrun - reported by Joe English, and restoring tcl7.6 behaviour for - [subst]: badly terminated nested scripts will raise an error - and not be evaluated. [Bug #495207] + * generic/tclBasic.c (Tcl_EvalEx): avoiding a buffer overrun reported + by Joe English, and restoring tcl7.6 behaviour for [subst]: badly + terminated nested scripts will raise an error and not be evaluated. + [Bug 495207] 2002-02-25 Don Porter * unix/tclUnixPort.h: corrected strtoll prototype mismatch on Tru64. * compat/strtod.c (strtod): simplified #includes @@ -4541,42 +9140,40 @@ * compat/strtol.c (strtol): gather result in a long before returning as a long: necessary on platforms where sizeof(int) != sizeof(long). 2002-02-25 Daniel Steffen - * unix/tclLoadDyld.c: updated to use Mac OS X 10.1 dyld APIs that - have more libdl-like semantics. (bug #514392) + * unix/tclLoadDyld.c: updated to use Mac OS X 10.1 dyld APIs that have + more libdl-like semantics. [Bug 514392] 2002-02-25 Miguel Sofer - * generic/tclCompCmds: fixing a bug in patch dated 2002-02-22, in - the code for [for] and [while]. Under certain conditions, for long - bodies, the exception range parameters were badly computed. Tests - forthcoming: I still can't reproduce the conditions in the - testsuite (!), although the bug (with assorted segfault or panic!) - can be triggered from the console or with the new parse.bench in - tclbench. - + * generic/tclCompCmds: fixing a bug in patch dated 2002-02-22, in the + code for [for] and [while]. Under certain conditions, for long bodies, + the exception range parameters were badly computed. Tests forthcoming: + I still can't reproduce the conditions in the testsuite (!), although + the bug (with assorted segfault or panic!) can be triggered from the + console or with the new parse.bench in tclbench. + 2002-02-25 Donal K. Fellows * compat/strtoul.c, compat/strtol.c, compat/strtod.c: Added UCHAR, CONST and #includes to clean up GCC output. 2002-02-23 Don Porter * compat/strtoull.c (strtoull): * compat/strtoll.c (strtoll): - * compat/strtoul.c (strtoul): Fixed failure to handle leading - sign symbols '+' and '-' and '0X' and raise overflow errors. - [Bug 440916] Also corrects prototype and errno problems. + * compat/strtoul.c (strtoul): Fixed failure to handle leading sign + symbols '+' and '-' and '0X' and raise overflow errors. [Bug 440916] + Also corrects prototype and errno problems. 2002-02-23 Mo DeJong * configure: Regen. - * unix/tcl.m4 (SC_CONFIG_CFLAGS): Link with -n32 - instead of -32 when building on IRIX64-6.* system. - [Tcl bug 521707] + * unix/tcl.m4 (SC_CONFIG_CFLAGS): Link with -n32 instead of -32 when + building on IRIX64-6.* system. [Bug 521707] 2002-02-22 Don Porter * generic/tclInt.h: * generic/tclObj.c: renamed global variable emptyString -> @@ -4595,29 +9192,29 @@ * tests/safe.test: updated safe-8.5 and safe-8.7 * library/safe.tcl (CheckFileName): removed the limit on sourceable file names (was only *.tcl or tclIndex files with no more than one dot and 14 chars). There is enough internal - protection in a safe interpreter already. Fixes [Tk Bug #521560]. + protection in a safe interpreter already. Fixes [Tk Bug 521560]. 2002-02-22 Miguel Sofer * generic/tclCompCmds: [FR 465811]. Optimising [if], [for] and - [while] for constant conditions; in addition, [for] and [while] - are now compiled with the "loop rotation" optimisation (thanks to - Kevin Kenny). + [while] for constant conditions; in addition, [for] and [while] are + now compiled with the "loop rotation" optimisation (thanks to Kevin + Kenny). 2002-02-22 Donal K. Fellows --- TIP#76 CHANGES --- * generic/tclCmdMZ.c (Tcl_RegsubObjCmd): Final-argument-less [regsub] returns the modified string. * doc/regsub.n: Updated docs. * tests/regexp.test: Updated and added tests. - * compat/strtoll.c (strtoll): - * compat/strtoull.c (strtoull): + * compat/strtoll.c (strtoll): + * compat/strtoull.c (strtoull): * unix/tclUnixPort.h: * win/tclWinPort.h: Const-ing 64-bit compatability declarations. Note that the return pointer is non-const because it is entirely legal for the functions to be called from somewhere that owns the string being passed. Fixes problem reported by Larry Virden. @@ -4625,47 +9222,44 @@ 2002-02-21 David Gravereaux * win/mkd.bat (removed): * win/coffbase.txt (new): * win/makefile.bc: - * win/makefile.vc: Changed the 'setup' target to stop using - the mkd.bat file and just make the directory right in the rule. - Same change to makefile.bc. configure.in nor Makefile.in use - it. - - coffbase.txt will be the master list for our "prefered base - addresses" set by the linker. This should improve load-time - (NT only) by avoiding relocations. Submissions to the list - by extension authors are encouraged. - - Added a 'tidy' target to compliment 'clean' and 'hose' to remove - just the outputs. Also removed the $(winlibs) macro as it wasn't - being used. + * win/makefile.vc: Changed the 'setup' target to stop using the + mkd.bat file and just make the directory right in the rule. Same + change to makefile.bc. configure.in nor Makefile.in use it. + + coffbase.txt will be the master list for our "prefered base addresses" + set by the linker. This should improve load-time (NT only) by avoiding + relocations. Submissions to the list by extension authors are + encouraged. + + Added a 'tidy' target to compliment 'clean' and 'hose' to remove just + the outputs. Also removed the $(winlibs) macro as it wasn't being + used. Stuff left to do: - 1) get the winhelp target to stop building in the tools/ - directory. + 1) get the winhelp target to stop building in the tools/ directory. 2) stop using rmd.bat 3) add more dependacy rules. - * win/tclAppInit.c: Reverted back to -r1.6, as the header file - change to tclPort.h won't allow for easy embedded support - outside of the source dist. Thanks to Don Porter for pointing - this out to me. + * win/tclAppInit.c: Reverted back to -r1.6, as the header file change + to tclPort.h won't allow for easy embedded support outside of the + source dist. Thanks to Don Porter for pointing this out to me. 2002-02-21 David Gravereaux * win/makefile.vc: - * win/rules.vc: Added a new "loimpact" option that sets the - -ws:aggressive linker option. Off by default. It's said to - keep the heap use low at the expense of alloc speed. - - * win/tclAppInit.c: Changed #include "tcl.h" to be tclPort.h to - remove the raw windows.h include. tclPort.h brings in windows.h - already and lessens the pre-compiled-header mush and the randomly - useless #pragma comment (lib,...) references throughout the big - windows.h tree (as observed at high linker warning levels). + * win/rules.vc: Added a new "loimpact" option that sets the + -ws:aggressive linker option. Off by default. It's said to keep the + heap use low at the expense of alloc speed. + + * win/tclAppInit.c: Changed #include "tcl.h" to be tclPort.h to remove + the raw windows.h include. tclPort.h brings in windows.h already and + lessens the pre-compiled-header mush and the randomly useless #pragma + comment (lib,...) references throughout the big windows.h tree (as + observed at high linker warning levels). 2002-02-21 Donal K. Fellows * generic/tcl.h: Better guessing of LP64/ILP32 architecture, but now sensitive to presence of (suitable) @@ -4680,55 +9274,55 @@ 2002-02-20 David Gravereaux * win/buildall.vc.bat: * win/makefile.vc: - * win/rules.vc: General clean-ups. Added compiler and linker tests - for a) the pentium 0x0F errata, b) optimizing (not all have this), - and c) linker v6 section alignment confusion. All these are tested - first to make sure any D4002 or LNK1117 warnings aren't displayed. - The pentium 0x0F errata is a recommended switch. The v5 linker's - section alignment default is 512, but the v6 linker was changed - to 4096 in an attempt to speed loading on Win98. I changed the - default to always be 512 across both linkers, unless linking - statically, then 4096 is used for the claimed speed effect. Using - a 512 alignment saves 12k bytes of dead space in the DLL. + * win/rules.vc: General clean-ups. Added compiler and linker tests for + a) the pentium 0x0F errata, b) optimizing (not all have this), and c) + linker v6 section alignment confusion. All these are tested first to + make sure any D4002 or LNK1117 warnings aren't displayed. The pentium + 0x0F errata is a recommended switch. The v5 linker's section alignment + default is 512, but the v6 linker was changed to 4096 in an attempt to + speed loading on Win98. I changed the default to always be 512 across + both linkers, unless linking statically, then 4096 is used for the + claimed speed effect. Using a 512 alignment saves 12k bytes of dead + space in the DLL. Added IA64 B-stepping errata switch when the compiler supports it. Added profiling to $(lflags) when requested and also removed the explict -entry option as the default works fine as is. - Removed win/tclWinInit.c from the special case section to let it - use the common implicit rule as the $(EXTFLAGS) macro it had was - never referenced anywhere. + Removed win/tclWinInit.c from the special case section to let it use + the common implicit rule as the $(EXTFLAGS) macro it had was never + referenced anywhere. 2002-02-20 Donal K. Fellows * generic/tcl.h: Added code to guess the correct settings for - TCL_WIDE_INT_IS_LONG and TCL_WIDE_INT_TYPE when configure doesn't - tell us them, as can happen with extensions. + TCL_WIDE_INT_IS_LONG and TCL_WIDE_INT_TYPE when configure doesn't tell + us them, as can happen with extensions. 2002-02-19 Donal K. Fellows * doc/format.n: Updated docs to list the specification. * generic/tclCmdAH.c (Tcl_FormatObjCmd): Made behaviour on 64-bit platforms correctly meet the specification, that %d works with the - native word-sized integer, instead of trying to guess (wrongly) - from the value being passed. + native word-sized integer, instead of trying to guess (wrongly) from + the value being passed. 2002-02-19 Don Porter * changes: First draft of updated changes for 8.4a4 release. 2002-02-15 Jeff Hobbs - * unix/tclUnixPort.h: add strtoll/strtoull declarations for - platforms that do not define them. + * unix/tclUnixPort.h: add strtoll/strtoull declarations for platforms + that do not define them. - * generic/tclIndexObj.c (STRING_AT): removed ptrdiff_t cast and - use of VOID* in default case (GNU-ism). + * generic/tclIndexObj.c (STRING_AT): removed ptrdiff_t cast and use of + VOID* in default case (GNU-ism). 2002-02-15 Kevin Kenny * compat/strtoll.c: * compat/strtoul.c: @@ -4738,29 +9332,28 @@ * generic/tclTest.c: * generic/tclTestObj.c: * tests/get.test: * win/Makefile.vc: Further tweaks to the TIP 72 patch to make it compile under VC++. - + 2002-02-15 Andreas Kupries * tclExecute.c: * tclIOGT.c: - * tclIndexObj.c: Touchups to the TIP 72 patch to make it - compileable under Windows again. The changes are not complete, - there is one nasty regarding _stati64 + * tclIndexObj.c: Touchups to the TIP 72 patch to make it compileable + under Windows again. The changes are not complete, there is one nasty + regarding _stati64 2002-02-15 Donal K. Fellows +----------------------+ | TIP #72 IMPLEMENTED. | +----------------------+ There are a lot of changes from this TIP, so please see - http://purl.org/tcl/tip/72.html for discussion of - backward-compatability issues, but the main ones modifications are - in: + http://tip.tcl.tk/72.html for discussion of backward-compatability + issues, but the main ones modifications are in: * generic/tcl.h: New types. * generic/tcl.decls: New public functions. * generic/tclExecute.c: 64-bit aware bytecode engine. * generic/tclBinary.c: 64-bit handling in [binary] command. @@ -4772,59 +9365,57 @@ * generic/tclIO.c: Large-file support (with many consequences.) * compat/strtoll.c, compat/strtoull.c: New support functions. * unix/tcl.m4, unix/configure: 64-bit support and greatly enhanced cacheing. - Most other changes, including all those in doc/* and test/* as - well as the majority in the platform directories, follow on from - these. + Most other changes, including all those in doc/* and test/* as well as + the majority in the platform directories, follow on from these. Also coming out of the woodwork: * generic/tclIndex.c: Better support for Cray PVP. * win/tclWinMtherr.c: Better Borland support. - Note that, in a number of places through the Unix part of the - platform support, there are Tcl_Platform* references. These are - expanded into the correct way to call that particular underlying - function, i.e. with or without a '64' suffix, and should be used - by people working on the core in preference to the API functions - they overlay so that the code remains portable depending on the - presence or absence of 64-bit support on the underlying platform. + Note that, in a number of places through the Unix part of the platform + support, there are Tcl_Platform* references. These are expanded into + the correct way to call that particular underlying function, i.e. with + or without a '64' suffix, and should be used by people working on the + core in preference to the API functions they overlay so that the code + remains portable depending on the presence or absence of 64-bit + support on the underlying platform. ***POTENTIAL INCOMPATIBILITY***: Extracted from the TIP - SUMMARY OF INCOMPATIBILITIES AND FIXES + SUMMARY OF INCOMPATIBILITIES AND FIXES ====================================== - The behaviour of expressions containing constants that appear - positive but which have a negative internal representation will - change, as these will now usually be interpreted as wide - integers. This is always fixable by replacing the constant with - int(constant). + The behaviour of expressions containing constants that appear positive + but which have a negative internal representation will change, as + these will now usually be interpreted as wide integers. This is always + fixable by replacing the constant with int(constant). Extensions creating new channel types will need to be altered as different types are now in use in those areas. The change to the - declaration of Tcl_FSStat and Tcl_FSLstat (which are the new - preferred API in any case) are less serious as no non-alpha - releases have been made yet with those API functions. + declaration of Tcl_FSStat and Tcl_FSLstat (which are the new preferred + API in any case) are less serious as no non-alpha releases have been + made yet with those API functions. Scripts that are lax about the use of the l modifier in format and - scan will probably need to be rewritten. This should be very - uncommon though as previously it had absolutely no effect. + scan will probably need to be rewritten. This should be very uncommon + though as previously it had absolutely no effect. Extensions that create new math functions that take more than one - argument will need to be recompiled (the size of Tcl_Value - changes), and functions that accept arguments of any type - (TCL_EITHER) will need to be rewritten to handle wide integer - values. (I do not expect this to affect many extensions at all.) + argument will need to be recompiled (the size of Tcl_Value changes), + and functions that accept arguments of any type (TCL_EITHER) will need + to be rewritten to handle wide integer values. (I do not expect this + to affect many extensions at all.) 2002-02-14 Andreas Kupries - * generic/tclIOCmd.c (Tcl_GetsObjCmd): Trivial fix for bug - #517503, a memory leak reported by Miguel Sofer - . The leak happens if an error - occurs for "set var [gets $chan]" and leak one empty object. + * generic/tclIOCmd.c (Tcl_GetsObjCmd): Trivial fix for [Bug 517503], a + memory leak reported by Miguel Sofer . + The leak happens if an error occurs for "set var [gets $chan]" and + leak one empty object. 2002-02-12 David Gravereaux * djgpp/ (new directory) * djgpp/Makefile (new): @@ -4831,16 +9422,15 @@ * unix/tclAppInit.c: * unix/tclMtherr.c: * unix/tclUnixFCmd.c: * unix/tclUnixFile.c: * unix/tclUnixInit.c: - * unix/tclUnixPort.h: Early stage of DJGPP support for building - Tcl on DOS. Dynamic loading isn't working, yet. Requires watt32 - for the TCP/IP stack. No autoconf, yet. Barely tested, but - makes a working exe that runs Tcl in protected-mode, flat memory. - [exec] and pipes will need the most work as multi-tasking on DOS - has to be carefully. + * unix/tclUnixPort.h: Early stage of DJGPP support for building Tcl + on DOS. Dynamic loading isn't working, yet. Requires watt32 for the + TCP/IP stack. No autoconf, yet. Barely tested, but makes a working exe + that runs Tcl in protected-mode, flat memory. [exec] and pipes will + need the most work as multi-tasking on DOS has to be carefully. 2002-02-10 Kevin Kenny * doc/CrtObjCmd.3: * doc/CrtTrace.3: @@ -4853,11 +9443,11 @@ Tcl_GetCommandInfoFromToken and Tcl_SetCommandInfoFromToken. (TIPs #32 and #79.) * generic/tclDecls.h: * generic/tclStubInit.c: Regenerated Stubs tables. - + 2002-02-08 Jeff Hobbs * unix/configure: * unix/tcl.m4: added -pthread for FreeBSD to EXTRA_CFLAGS and LDFLAGS. Also triggered nodots only for FreeBSD-3. @@ -4895,12 +9485,12 @@ * win/tclWinFile.c: * win/tclWinInit.c: Partial TIP 27 rollback. Following routines restored to return (char *): Tcl_DStringAppend, Tcl_DStringAppendElement, Tcl_JoinPath, Tcl_TranslateFileName, Tcl_ExternalToUtfDString, Tcl_UtfToExternalDString, - Tcl_UniCharToUtfDString, Tcl_GetCwd, Tcl_WinTCharToUtf. Also - restored Tcl_WinUtfToTChar to return (TCHAR *) and + Tcl_UniCharToUtfDString, Tcl_GetCwd, Tcl_WinTCharToUtf. Also + restored Tcl_WinUtfToTChar to return (TCHAR *) and Tcl_UtfToUniCharDString to return (Tcl_UniChar *). Modified some callers. This change recognizes that Tcl_DStrings are de-facto white-box objects. * generic/tclDecls.h: @@ -4909,13 +9499,13 @@ * generic/tclCmdMZ.c: corrected use of C++-style comment. 2002-02-06 Jeff Hobbs * tests/scan.test: - * generic/tclScan.c (Tcl_ScanObjCmd): corrected scan 0x... %x - handling that didn't accept the 0x as a prelude to a base 16 - number. [Bug #495213] + * generic/tclScan.c (Tcl_ScanObjCmd): corrected scan 0x... %x handling + that didn't accept the 0x as a prelude to a base 16 number. [Bug + 495213] * generic/tclCompCmds.c (TclCompileRegexpCmd): made early check for bad RE to stop checking further. * generic/tclCmdMZ.c (Tcl_RegsubObjCmd): added special case to @@ -4938,60 +9528,58 @@ * library/http/pkgIndex.tcl: Corrected use of http::error when ::error was intended. Bump to http 2.4.2. 2002-02-04 Andreas Kupries - * unix/tclUnixChan.c (FileOutputProc): Fixed [bug 465765] reported - by Dale Talcott . Avoid - writing nothing into a file as STREAM based implementations will - consider this a EOF (if the file is a pipe). Not done in the - generic layer as this type of writing is actually useful to - check the state of a socket. - - * doc/open.n: Fixed [Bug 511540], added cross-reference to 'pid' - as the command to use to retrieve the pid of a command pipeline - created via 'open'. + * unix/tclUnixChan.c (FileOutputProc): Fixed [bug 465765] reported by + Dale Talcott . Avoid writing + nothing into a file as STREAM based implementations will consider this + a EOF (if the file is a pipe). Not done in the generic layer as this + type of writing is actually useful to check the state of a socket. + + * doc/open.n: Fixed [Bug 511540], added cross-reference to 'pid' as + the command to use to retrieve the pid of a command pipeline created + via 'open'. 2002-02-01 Jeff Hobbs * generic/tclCmdMZ.c (Tcl_RegexpObjCmd): handle quirky about case earlier to avoid shimmering problem. 2002-02-01 Andreas Kupries * tests/io.test: io-39.22 split into two tests, one platform - dependent, the other not. -eofchar is not empty on the windows - platform. + dependent, the other not. -eofchar is not empty on the windows + platform. 2002-02-01 Vince Darley - * generic/tclTest.c: fix to picky windows compiler problem - with the 'MainLoop' function declaration. + * generic/tclTest.c: fix to picky windows compiler problem with the + 'MainLoop' function declaration. 2002-01-31 Andreas Kupries * win/tclWinFCmd.c: TIP 27: Applied patch fixing CONST warnings on - behalf of Don Porter . + behalf of Don Porter . 2002-01-30 Don Porter * generic/tcl.decls: * generic/tcl.h: * generic/tclInt.h: For each interface identified in the TIP 27 - changes below as a POTENTIAL INCOMPATIBILITY, the source of the - incompatibility has been parameterized so that it can be - removed. When compiling extension code against the Tcl header - files, use the compiler flag -DUSE_NON_CONST to remove the - irresolvable source incompatibilities introduced by the TIP 27 - changes. Resolvable changes are left for extension authors to - resolve. + changes below as a POTENTIAL INCOMPATIBILITY, the source of the + incompatibility has been parameterized so that it can be removed. When + compiling extension code against the Tcl header files, use the + compiler flag -DUSE_NON_CONST to remove the irresolvable source + incompatibilities introduced by the TIP 27 changes. Resolvable changes + are left for extension authors to resolve. * generic/tclDecls.h: make genstubs 2002-01-30 Vince Darley - * doc/FileSystem.3: added documentation for 3 public - functions which had been overlooked. Fixes [Bug 507701]. + * doc/FileSystem.3: added documentation for 3 public functions which + had been overlooked. Fixes [Bug 507701] * unix/mkLinks: make mklinks 2002-01-29 Jeff Hobbs * tests/regexpComp.test: @@ -4999,18 +9587,16 @@ -nocase and -- options. 2002-01-28 Mo DeJong * unix/tcl.m4 (SC_LOAD_TCLCONFIG): - * win/tcl.m4 (SC_LOAD_TCLCONFIG): Set TCL_LIB_SPEC, - TCL_STUB_LIB_SPEC, and TCL_STUB_LIB_PATH to the - values of TCL_BUILD_LIB_SPEC, TCL_BUILD_STUB_LIB_SPEC, - and TCL_BUILD_STUB_LIB_PATH when tclConfig.sh is loaded - from the build directory. A Tcl extension should - make use of the non-build versions of these variables - since they will work in both cases. This modification - was described in TIP 34. + * win/tcl.m4 (SC_LOAD_TCLCONFIG): Set TCL_LIB_SPEC, TCL_STUB_LIB_SPEC, + and TCL_STUB_LIB_PATH to the values of TCL_BUILD_LIB_SPEC, + TCL_BUILD_STUB_LIB_SPEC, and TCL_BUILD_STUB_LIB_PATH when tclConfig.sh + is loaded from the build directory. A Tcl extension should make use of + the non-build versions of these variables since they will work in both + cases. This modification was described in TIP #34. 2002-01-28 Jeff Hobbs * win/tclWinReg.c (regConnectRegistryProc,RecursiveDeleteKey) (DeleteKey,GetKeyNames,GetType,GetValue,OpenSubKey,SetValue): @@ -5036,17 +9622,17 @@ * win/tclWinReg.c (OpenSubKey): corrected bug introduced in CONSTification that dropped pointer reference. * ChangeLog.2000 (new file): * ChangeLog: broke changes from 2000 into ChangeLog.2000 to reduce - size of the main ChangeLog. + size of the main ChangeLog. 2002-01-28 David Gravereaux - * generic/tclPlatDecls.h: Added preprocessor logic to force a - typedef of TCHAR when __STDC__ is defined when using the uncommon - -Za compiler switch with the microsoft compiler. + * generic/tclPlatDecls.h: Added preprocessor logic to force a typedef + of TCHAR when __STDC__ is defined when using the uncommon -Za compiler + switch with the microsoft compiler. 2002-01-27 Don Porter * doc/package.n: Documented global namespace context for script evaluation by [package require]. @@ -5062,28 +9648,27 @@ * mac/tclMacLoad.c: * mac/tclMacResource.c: * mac/tclMacSock.c: TIP 27 CONSTification induced changes * tests/event.test: - * tests/main.test: added catches/constraints to test that - use features that don't exist on the mac. + * tests/main.test: added catches/constraints to test that use features + that don't exist on the mac. 2002-01-25 Mo DeJong - Make -eofchar and -translation options read only for - server sockets. [Bug 496733] - + Make -eofchar and -translation options read only for server sockets. + [Bug 496733] + * generic/tclIO.c (Tcl_GetChannelOption, Tcl_SetChannelOption): - Instead of returning nothing for the -translation option - on a server socket, always return "auto". Return the empty - string enclosed in quotes for the -eofchar option on - a server socket. Fixup -eofchar usage message so that - it matches the implementation. - * tests/io.test: Add -eofchar tests and -translation tests - to ensure options are read only on server sockets. - * tests/socket.test: Update tests to account for -eofchar - and -translation option changes. + Instead of returning nothing for the -translation option on a server + socket, always return "auto". Return the empty string enclosed in + quotes for the -eofchar option on a server socket. Fixup -eofchar + usage message so that it matches the implementation. + * tests/io.test: Add -eofchar tests and -translation tests to ensure + options are read only on server sockets. + * tests/socket.test: Update tests to account for -eofchar and + -translation option changes. 2002-01-25 Don Porter * compat/strstr.c (strstr): * generic/tclCmdAH.c (Tcl_FormatObjCmd): @@ -5093,25 +9678,25 @@ * generic/tclIO.c (FlushChannel,Tcl_BadChannelOption): * generic/tclStringObj.c (AppendUnicodeToUtfRep): * generic/tclThreadTest.c (TclCreateThread): * generic/tclUtf.c (Tcl_UtfPrev): * mac/tclMacFCmd.c (TclpObjListVolumes): - * mac/tclMacResource.c (TclMacRegisterResourceFork, - BuildResourceForkList): - * win/tclWinInit.c (AppendEnvironment): Sought out and eliminated + * mac/tclMacResource.c (TclMacRegisterResourceFork) + (BuildResourceForkList): + * win/tclWinInit.c (AppendEnvironment): Sought out and eliminated instances of CONST-casting that are no longer needed after the TIP 27 effort. * Following is [Patch 501006] - * generic/tclInt.decls (Tcl_AddInterpResolvers, Tcl_Export, - Tcl_FindNamespace, Tcl_GetInterpResolvers, Tcl_ForgetImport, - Tcl_Import, Tcl_RemoveInterpResolvers): - * generic/tclNamesp.c (Tcl_Export, Tcl_Import, Tcl_ForgetImport, - Tcl_FindNamespace): + * generic/tclInt.decls (Tcl_AddInterpResolvers, Tcl_Export) + (Tcl_FindNamespace, Tcl_GetInterpResolvers, Tcl_ForgetImport) + (Tcl_Import, Tcl_RemoveInterpResolvers): + * generic/tclNamesp.c (Tcl_Export, Tcl_Import, Tcl_ForgetImport) + (Tcl_FindNamespace): * generic/tclResolve.c (Tcl_AddInterpResolvers,Tcl_GetInterpResolvers, - Tcl_RemoveInterpResolvers): Updated APIs in generic/tclResolve.c - and generic/tclNamesp.c according to the guidelines of TIP 27. + (Tcl_RemoveInterpResolvers): Updated APIs in generic/tclResolve.c and + generic/tclNamesp.c according to the guidelines of TIP 27. * generic/tclIntDecls.h: make genstubs * Following is [Patch 505630] * doc/AddErrorInfo.3: * generic/tcl.decls (Tcl_LogCommandInfo): @@ -5140,16 +9725,16 @@ * win/tclWin32Dll.c (Tcl_WinUtfToTChar,Tcl_WinTCharToUtf): Updated interfaces in win/tclWin32Dll.c according to TIP 27. * generic/tclPlatDecls.h: make genstubs * generic/tclIOUtil.c (TclpNativeToNormalized): * win/tclWinFCmd.c (TclpObjNormalizePath): - * win/tclWinFile.c (TclpFindExecutable,TclpMatchInDirectory, - NativeIsExec,NativeStat): + * win/tclWinFile.c (TclpFindExecutable,TclpMatchInDirectory) + (NativeIsExec,NativeStat): * win/tclWinLoad.c (TclpLoadFile): * win/tclWinPipe.c (TclpOpenFile,ApplicationType): - * win/tclWinReg.c (regConnectRegistryProc,RecursiveDeleteKey,DeleteKey, - GetKeyNames,GetType,GetValue,OpenSubKey,SetValue): + * win/tclWinReg.c (regConnectRegistryProc,RecursiveDeleteKey,DeleteKey) + (GetKeyNames,GetType,GetValue,OpenSubKey,SetValue): * win/tclWinSerial.c (SerialSetOptionProc): Update callers. * Following is [Patch 505072] * doc/Concat.3: * doc/Encoding.3: @@ -5162,53 +9747,53 @@ * doc/SplitPath.3: * doc/Translate.3: * generic/tcl.h (Tcl_FSMatchInDirectoryProc): * generic/tclInt.h (TclpMatchInDirectory): * generic/tcl.decls (Tcl_Concat,Tcl_GetStringResult,Tcl_GetVar, - Tcl_GetVar2,Tcl_JoinPath,Tcl_Merge,Tcl_OpenCommandChannel,Tcl_SetVar, - Tcl_SetVar2,Tcl_SplitList,Tcl_SplitPath,Tcl_TranslateFileName, - Tcl_ExternalToUtfDString,Tcl_GetEncodingName,Tcl_UtfToExternalDString, - Tcl_GetDefaultEncodingDir,Tcl_SetDefaultEncodingDir, - Tcl_FSMatchInDirectory,Tcl_MacEvalResource,Tcl_MacFindResource): + (Tcl_GetVar2,Tcl_JoinPath,Tcl_Merge,Tcl_OpenCommandChannel,Tcl_SetVar) + (Tcl_SetVar2,Tcl_SplitList,Tcl_SplitPath,Tcl_TranslateFileName) + (Tcl_ExternalToUtfDString,Tcl_GetEncodingName,Tcl_UtfToExternalDString) + (Tcl_GetDefaultEncodingDir,Tcl_SetDefaultEncodingDir) + (Tcl_FSMatchInDirectory,Tcl_MacEvalResource,Tcl_MacFindResource): * generic/tclInt.decls (TclCreatePipeline,TclGetEnv,TclpGetCwd, - TclpCreateProcess): + (TclpCreateProcess): * mac/tclMacFile.c (TclpGetCwd): - * generic/tclEncoding.c (Tcl_GetDefaultEncodingDir, - Tcl_SetDefaultEncodingDir,Tcl_GetEncodingName, - Tcl_ExternalToUtfDString,Tcl_UtfToExternalDString, OpenEncodingFile, - LoadEscapeEncoding): + * generic/tclEncoding.c (Tcl_GetDefaultEncodingDir) + (Tcl_SetDefaultEncodingDir,Tcl_GetEncodingName) + (Tcl_ExternalToUtfDString,Tcl_UtfToExternalDString, OpenEncodingFile) + (LoadEscapeEncoding): * generic/tclFileName.c (DoTildeSubst,Tcl_JoinPath,Tcl_SplitPath, - Tcl_TranslateFileName): + (Tcl_TranslateFileName): * generic/tclIOUtil.c (Tcl_FSMatchInDirectory): - * generic/tclPipe.c (FileForRedirect,TclCreatePipeline, - Tcl_OpenCommandChannel): + * generic/tclPipe.c (FileForRedirect,TclCreatePipeline) + (Tcl_OpenCommandChannel): * generic/tclResult.c (Tcl_GetStringResult): * generic/tclUtil.c (Tcl_Concat,Tcl_SplitList,Tcl_Merge): * generic/tclVar.c (Tcl_GetVar,Tcl_GetVar2,Tcl_SetVar,Tcl_SetVar2): * mac/tclMacResource.c (Tcl_MacEvalResource,Tcl_MacFindResource): Updated interfaces of generic/tclEncoding, generic/tclFilename.c, generic/tclIOUtil.c, generic/tclPipe.c, generic/tclResult.c, generic/tclUtil.c, generic/tclVar.c and mac/tclMacResource.c according to TIP 27. Tcl_TranslateFileName rewritten as wrapper around VFS-aware version. - ***POTENTIAL INCOMPATIBILITY*** + ***POTENTIAL INCOMPATIBILITY*** Includes source incompatibilities: argv arguments of Tcl_Concat, Tcl_JoinPath, Tcl_OpenCommandChannel, Tcl_Merge; argvPtr arguments of Tcl_SplitList and Tcl_SplitPath. - * generic/tclDecls.h: + * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs * generic/tclCkalloc.c (MemoryCmd): * generic/tclClock.c (FormatClock): * generic/tclCmdAH.c (Tcl_CaseObjCmd,Tcl_EncodingObjCmd,Tcl_FileObjCmd): * generic/tclCmdIL.c (InfoLibraryCmd,InfoPatchLevelCmd, - InfoTclVersionCmd): + (InfoTclVersionCmd): * generic/tclCompCmds.c (TclCompileForeachCmd): * generic/tclCompCmds.h (TclCompileForeachCmd): * generic/tclCompile.c (TclFindCompiledLocal): * generic/tclEnv.c (TclSetupEnv,TclSetEnv,Tcl_PutEnv,TclGetEnv, - EnvTraceProc): + (EnvTraceProc): * generic/tclEvent.c (Tcl_BackgroundError): * generic/tclIO.c (Tcl_BadChannelOption,Tcl_SetChannelOption): * generic/tclIOCmd.c (Tcl_ExecObjCmd,Tcl_OpenObjCmd): * generic/tclIOSock.c (TclSockGetPort): * generic/tclIOUtil.c (SetFsPathFromAny): @@ -5215,109 +9800,107 @@ * generic/tclLink.c (LinkTraceProc): * generic/tclMain.c (Tcl_Main): * generic/tclNamesp.c (TclTeardownNamespace): * generic/tclProc.c (TclCreateProc): * generic/tclTest.c (TestregexpObjCmd,TesttranslatefilenameCmd, - TestchmodCmd,GetTimesCmd,TestsetCmd,TestOpenFileChannelProc1, - TestOpenFileChannelProc2,TestOpenFileChannelProc3,AsyncHandlerProc, - TestpanicCmd): + (TestchmodCmd,GetTimesCmd,TestsetCmd,TestOpenFileChannelProc1, + (TestOpenFileChannelProc2,TestOpenFileChannelProc3,AsyncHandlerProc, + (TestpanicCmd): * generic/tclThreadTest.c (ThreadErrorProc,ThreadEventProc): * generic/tclUtil.c (TclPrecTraceProc): * mac/tclMacFCmd.c (GetFileSpecs): * mac/tclMacFile.c (TclpMatchInDirectory): * mac/tclMacInit.c (TclpInitLibraryPath,Tcl_SourceRCFile): * mac/tclMacOSA.c (tclOSAStore,tclOSALoad): * mac/tclMacResource.c (Tcl_MacEvalResource): * unix/tclUnixFCmd.c (TclpObjNormalizePath): * unix/tclUnixFile.c (TclpMatchInDirectory,TclpGetUserHome,TclpGetCwd, - TclpReadLink): + (TclpReadLink): * unix/tclUnixInit.c (TclpInitLibraryPath,TclpSetVariables, - Tcl_SourceRCFile): + (Tcl_SourceRCFile): * unix/tclUnixPipe.c (TclpOpenFile,TclpCreateTempFile, - TclpCreateProcess): + (TclpCreateProcess): * win/tclWinFile.c (TclpGetCwd,TclpMatchInDirectory): * win/tclWinInit.c (TclpInitLibraryPath,Tcl_SourceRCFile, - TclpSetVariables): + (TclpSetVariables): * win/tclWinPipe.c (TclpCreateProcess): Updated callers. 2002-01-24 Don Porter * generic/tclIOUtil.c (SetFsPathFromAny): Corrected tilde-substitution - of pathnames where > 1 separator follows the ~. [Bug 504950] + of pathnames where > 1 separator follows the ~. [Bug 504950] 2002-01-24 Jeff Hobbs * library/http/pkgIndex.tcl: * library/http/http.tcl: don't add port in default case to handle - broken servers. http bumped to 2.4.1 [Bug #504508] + broken servers. http bumped to 2.4.1 [Bug 504508] 2002-01-23 Andreas Kupries * unix/mkLinks: Regenerated. * doc/CrtChannel.3: - * doc/ChnlStack.3: Moved documentation for 'Tcl_GetTopChannel' - from 'CrtChannel' to 'ChnlStack'. Added documentation of - 'Tcl_GetStackedChannel'. Bug #506147 reported by Mark Patton - . + * doc/ChnlStack.3: Moved documentation for 'Tcl_GetTopChannel' from + 'CrtChannel' to 'ChnlStack'. Added documentation of + 'Tcl_GetStackedChannel'. [Bug 506147] reported by Mark Patton + 2002-01-23 Don Porter * win/tclWinFile.c (NativeAccess,NativeStat,NativeIsExec, - TclpGetUserHome): + (TclpGetUserHome): * win/tclWinPort.h (TclWinSerialReopen): * win/tclWinSerial.c (TclWinSerialReopen): - * win/tclWinSock.c (Tcl_OpenTcpServer): Corrections to earlier - TIP 27 changes. Thanks to Andreas Kupries for the feedback. + * win/tclWinSock.c (Tcl_OpenTcpServer): Corrections to earlier TIP + #27 changes. Thanks to Andreas Kupries for the feedback. * generic/tclPlatDecls.h: make genstubs * doc/GetHostName.3: * doc/GetOpnFl.3: * doc/OpenTcp.3: * tcl.decls (Tcl_GetHostName,Tcl_GetOpenFile,Tcl_OpenTcpClient, - Tcl_OpenTclServer): + (Tcl_OpenTclServer): * mac/tclMacSock.c (CreateSocket,Tcl_OpenTcpClient,Tcl_OpenTcpServer, - Tcl_GetHostName,GetHostFromString): + (Tcl_GetHostName,GetHostFromString): * unix/tclUnixChan.c (CreateSocket,CreateSocketAddress, - Tcl_OpenTcpClient,Tcl_OpenTcpServer,Tcl_GetOpenFile): + (Tcl_OpenTcpClient,Tcl_OpenTcpServer,Tcl_GetOpenFile): * unix/tclUnixSock.c (Tcl_GetHostName): * win/tclWinSock.c (CreateSocket,CreateSocketAddress, - Tcl_OpenTcpClient,Tcl_OpenTcpServer,Tcl_GetHostName): + (Tcl_OpenTcpClient,Tcl_OpenTcpServer,Tcl_GetHostName): Updated socket interfaces according to TIP 27. * generic/tclCmdIL.c (InfoHostnameCmd): Updated callers. * generic/tclDecls.h: make genstubs 2002-01-21 David Gravereaux - * generic/tclLoadNone.c: TclpLoadFile() didn't match proto of - typedef Tcl_FSLoadFileProc. OK'd by vincentdarley. - [Patch #502488] + * generic/tclLoadNone.c: TclpLoadFile() didn't match proto of typedef + Tcl_FSLoadFileProc. OK'd by vincentdarley. [Patch 502488] 2002-01-21 Andreas Kupries - * generic/tclIO.c (WriteChars): Fix for SF #506297, reported by - Martin Forssen . The encoding - chosen in the script exposing the bug writes out three intro - characters when TCL_ENCODING_START is set, but does not consume - any input as TCL_ENCODING_END is cleared. As some output was - generated the enclosing loop calls UtfToExternal again, again - with START set. Three more characters in the out and still no - use of input ... To break this infinite loop we remove - TCL_ENCODING_START from the set of flags after the first call - (no condition is required, the later calls remove an unset flag, - which is a no-op). This causes the subsequent calls to - UtfToExternal to consume and convert the actual input. + * generic/tclIO.c (WriteChars): Fix for [Bug 506297], reported by + Martin Forssen . The encoding chosen in + the script exposing the bug writes out three intro characters when + TCL_ENCODING_START is set, but does not consume any input as + TCL_ENCODING_END is cleared. As some output was generated the + enclosing loop calls UtfToExternal again, again with START set. Three + more characters in the out and still no use of input ... To break this + infinite loop we remove TCL_ENCODING_START from the set of flags after + the first call (no condition is required, the later calls remove an + unset flag, which is a no-op). This causes the subsequent calls to + UtfToExternal to consume and convert the actual input. 2002-01-21 Don Porter * generic/tclTest.c: Converted declarations of TestReport file system - to more portable form. [Bug 501417]. + to more portable form. [Bug 501417]. * generic/tcl.decls (Tcl_TraceCommand,Tcl_UntraceCommand, - Tcl_CommandTraceInfo): + (Tcl_CommandTraceInfo): * generic/tclCmdMZ.c (Tcl_TraceCommand,Tcl_UntraceCommand, - Tcl_CommandTraceInfo): Updated APIs in generic/tclCmdMZ.c - according to the guidelines of TIP 27. + (Tcl_CommandTraceInfo): Updated APIs in generic/tclCmdMZ.c + according to the guidelines of TIP 27. * generic/tclDecls.h: make genstubs 2002-01-18 Don Porter * win/tclWinChan.c: @@ -5332,85 +9915,82 @@ * generic/tclThreadTest.c: * mac/tclMacChan.c: * mac/tclMacFCmd.c: * mac/tclMacFile.c: * mac/tclMacLoad.c: - * mac/tclMacResource.c: TIP 27 CONSTification broke the mac - build in a number of places. + * mac/tclMacResource.c: TIP 27 CONSTification broke the mac build in a + number of places. 2002-01-17 Andreas Kupries - * generic/tclIOCmd.c (Tcl_GetsObjCmd): Fixed bug #504642 as - reported by Brian Griffin , - using his patch. Before the patch the generic I/O layer held an - unannounced reference to the interp result to store the read - line into. This unfortunately has disastrous results if the - channel driver executes a tcl script to perform its operation, - this freeing the interp result. In that case we are - dereferencing essentially a dangling reference. It is not truly - dangling because the object is in the free list, but this only - causes us to smash the free list and have the error occur later - somewhere else. The patch simply creates a new object for the - line and later sets it into the interp result when we are done - with reading. + * generic/tclIOCmd.c (Tcl_GetsObjCmd): Fixed [Bug 504642] as reported + by Brian Griffin , using his patch. + Before the patch the generic I/O layer held an unannounced reference + to the interp result to store the read line into. This unfortunately + has disastrous results if the channel driver executes a Tcl script to + perform its operation, this freeing the interp result. In that case we + are dereferencing essentially a dangling reference. It is not truly + dangling because the object is in the free list, but this only causes + us to smash the free list and have the error occur later somewhere + else. The patch simply creates a new object for the line and later + sets it into the interp result when we are done with reading. 2002-01-16 Mo DeJong * unix/tcl.m4 (SC_LOAD_TCLCONFIG): - * win/tcl.m4 (SC_LOAD_TCLCONFIG): Subst TCL_DBGX - into TCL_STUB_LIB_FILE and TCL_STUB_LIB_FLAG - variables so that an extension does not need - to subst TCL_DBGX into its makefile. [Tk Bug 504356] + * win/tcl.m4 (SC_LOAD_TCLCONFIG): Subst TCL_DBGX into + TCL_STUB_LIB_FILE and TCL_STUB_LIB_FLAG variables so that an extension + does not need to subst TCL_DBGX into its makefile. [Tk Bug 504356] 2002-01-16 Don Porter * doc/FileSystem.3: * doc/GetCwd.3: * doc/GetIndex.3: * generic/tcl.decls (Tcl_GetIndexFromObj, Tcl_GetIndexFromObjStruct, - Tcl_GetCwd, Tcl_FSFileAttrStrings, Tcl_FSGetNativePath, - Tcl_FSGetTranslatedStringPath): + (Tcl_GetCwd, Tcl_FSFileAttrStrings, Tcl_FSGetNativePath, + (Tcl_FSGetTranslatedStringPath): * generic/tcl.h (Tcl_FSFileAttrStringsProc): * generic/tclFCmd.c (TclFileAttrsCmd): * generic/tclIOUtil.c (Tcl_GetCwd,NativeFileAttrStrings, - Tcl_FSFileAttrStrings,Tcl_FSGetTranslatedStringPath, - Tcl_FSGetNativePath): + (Tcl_FSFileAttrStrings,Tcl_FSGetTranslatedStringPath, + (Tcl_FSGetNativePath): * generic/tclIndexObj.c (Tcl_GetIndexFromObj,Tcl_GetIndexFromObjStruct): More TIP 27 updates in tclIOUtil.c and tclIndexObj.c that were - overlooked before. [Patch 504671] - ***POTENTIAL INCOMPATIBILITY*** - Includes a source incompatibility in the tablePtr arguments of - the Tcl_GetIndexFromObj* routines. + overlooked before. [Patch 504671] + ***POTENTIAL INCOMPATIBILITY*** + Includes a source incompatibility in the tablePtr arguments of the + Tcl_GetIndexFromObj* routines. * generic/tclDecls.h: make genstubs * generic/tclBinary.c (Tcl_BinaryObjCmd): * generic/tclClock.c (Tcl_ClockObjCmd): * generic/tclCmdAH.c (Tcl_EncodingObjCmd, Tcl_FileObjCmd): * generic/tclCmdIL.c (Tcl_InfoObjCmd,Tcl_LsearchObjCmd,Tcl_LsortObjCmd): * generic/tclCmdMZ.c (Tcl_TraceObjCmd,Tcl_RegexpObjCmd,Tcl_RegsubObjCmd, - Tcl_StringObjCmd,Tcl_SubstObjCmd,Tcl_SwitchObjCmd, - TclTraceCommandObjCmd,TclTraceVariableObjCmd): + (Tcl_StringObjCmd,Tcl_SubstObjCmd,Tcl_SwitchObjCmd, + (TclTraceCommandObjCmd,TclTraceVariableObjCmd): * generic/tclCompCmds.c (TclCompileStringCmd): * generic/tclEvent.c (Tcl_UpdateObjCmd): * generic/tclFileName.c (Tcl_GlobObjCmd): * generic/tclIO.c (Tcl_FileEventObjCmd): * generic/tclIOCmd.c (Tcl_SeekObjCmd,Tcl_ExecObjCmd,Tcl_SocketObjCmd, - Tcl_FcopyObjCmd): + (Tcl_FcopyObjCmd): * generic/tclInterp.c (Tcl_InterpObjCmd,SlaveObjCmd): * generic/tclNamesp.c (Tcl_NamespaceObjCmd): * generic/tclPkg.c (Tcl_PackageObjCmd): * generic/tclTest.c (Tcltest_Init,TestencodingObjCmd,TestgetplatformCmd, - TestlocaleCmd,TestregexpObjCmd,TestsaveresultCmd, - TestGetIndexFromObjStructObjCmd,TestReportFileAttrStrings): + (TestlocaleCmd,TestregexpObjCmd,TestsaveresultCmd, + (TestGetIndexFromObjStructObjCmd,TestReportFileAttrStrings): * generic/tclTestObj.c (TestindexObjCmd,TeststringObjCmd): * generic/tclTimer.c (Tcl_AfterObjCmd): * generic/tclVar.c (Tcl_ArrayObjCmd): * mac/tclMacFCmd.c (SetFileFinderAttributes): * unix/tclUnixChan.c (TclpOpenFileChannel): * unix/tclUnixFCmd.c (tclpFileAttrStrings): * unix/tclUnixFile.c (TclpObjAccess,TclpObjChdir,TclpObjStat, - TclpObjLstat): + (TclpObjLstat): * win/tclWinFCmd.c (tclpFileAttrStrings): Updated callers. * doc/RegExp.3: * doc/Utf.3: * generic/tcl.decls: @@ -5425,19 +10005,19 @@ * generic/tclFileName.c (TclpGetNativePathType,SplitMacPath): * generic/tclIO.c (ReadChars): * mac/tclMacLoad.c (TclpLoadFile): * win/tclWinFile.c (TclpGetUserHome): Updated callers. - * generic/tclDecls.h: + * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs * doc/ParseCmd.3 (Tcl_ParseVar): * generic/tcl.decls (Tcl_ParseVar): * generic/tclParse.c (Tcl_ParseVar): * generic/tclTest.c (TestparsevarObjCmd): Updated APIs in - generic/tclParse.c according to the guidelines of TIP 27. Updated - callers. [Patch 501046] + generic/tclParse.c according to the guidelines of TIP 27. Updated + callers. [Patch 501046] * generic/tclDecls.h: make genstubs * generic/tcl.decls (Tcl_RecordAndEval): * generic/tclDecls.h: make genstubs * generic/tclHistory.c (Tcl_RecordAndEval): Updated APIs in @@ -5444,108 +10024,108 @@ generic/tclHistory.c according to the guidelines of TIP 27. [Patch 504091] * doc/CrtSlave.3: * generic/tcl.decls (Tcl_CreateAlias, Tcl_CreateAliasObj, - Tcl_CreateSlave, Tcl_GetAlias, Tcl_GetAliasObj, Tcl_GetSlave): + (Tcl_CreateSlave, Tcl_GetAlias, Tcl_GetAliasObj, Tcl_GetSlave): * generic/tclInterp.c (Tcl_CreateAlias, Tcl_CreateAliasObj, - Tcl_CreateSlave, Tcl_GetAlias, Tcl_GetAliasObj, Tcl_GetSlave): + (Tcl_CreateSlave, Tcl_GetAlias, Tcl_GetAliasObj, Tcl_GetSlave): Updated APIs in the file generic/tclInterp.c according to the - guidelines of TIP 27. [Patch 501371] - ***POTENTIAL INCOMPATIBILITY*** + guidelines of TIP 27. [Patch 501371] + ***POTENTIAL INCOMPATIBILITY*** Includes a source incompatibility in the targetCmdPtr arguments of the Tcl_GetAlias* routines. * generic/tclDecls.h: make genstubs 2002-01-15 Don Porter * doc/SetErrno.3 (Tcl_ErrnoMsg): Corrected documentation for - Tcl_ErrnoMsg; it takes an integer argument. Thanks to Georgios - Petasis. [Bug 468183] + Tcl_ErrnoMsg; it takes an integer argument. Thanks to Georgios + Petasis. [Bug 468183] * doc/AddErrInfo.3 (Tcl_PosixError): * doc/Eval.3 (Tcl_EvalFile): * doc/FileSystem.c (Tcl_FSOpenFileChannel,Tcl_FSOpenFileChannelProc): * doc/OpenFileChnl.3 (Tcl_OpenFileChannel): * doc/SetErrno.3 (Tcl_ErrnoId,Tcl_ErrnoMsg): * doc/Signal.3 (Tcl_SignalId,Tcl_SignalMsg): * generic/tcl.decls (Tcl_ErrnoId,TclErrnoMsg,Tcl_EvalFile, - Tcl_OpenFileChannel,Tcl_PosixError,Tcl_SignalId,Tcl_SignalMsg, - Tcl_FSOpenFileChannel): + (Tcl_OpenFileChannel,Tcl_PosixError,Tcl_SignalId,Tcl_SignalMsg, + (Tcl_FSOpenFileChannel): * generic/tcl.h (Tcl_FSOpenFileChannelProc): * generic/tclIO.c (FlushChannel): * generic/tclIOUtil.c (Tcl_OpenFileChannel,Tcl_EvalFile,TclGetOpenMode, - Tcl_PosixError,Tcl_FSOpenFileChannel): + (Tcl_PosixError,Tcl_FSOpenFileChannel): * generic/tclInt.decls (TclGetOpenMode): * generic/tclInt.h (TclOpenFileChannelProc_,TclGetOpenMode, - TclpOpenFileChannel): + (TclpOpenFileChannel): * generic/tclPipe.c (TclCleanupChildren): * generic/tclPosixStr.c (Tcl_ErrnoId,Tcl_ErrnoMsg,Tcl_SignalId, - Tcl_SignalMsg): + (Tcl_SignalMsg): * generic.tclTest.c (PretendTclpOpenFileChannel, - TestOpenFileChannelProc1,TestOpenFileChannelProc2, - TestOpenFileChannelProc3,TestReportOpenFileChannel): + (TestOpenFileChannelProc1,TestOpenFileChannelProc2, + (TestOpenFileChannelProc3,TestReportOpenFileChannel): * mac/tclMacChan.c (TclpOpenFileChannel): * unix/tclUnixChan.c (TclpOpenFileChannel): * win/tclWinChan.c (TclpOpenFileChannel): Updated APIs in - generic/tclIOUtil.c and generic/tclPosixStr.c according to the - guidelines of TIP 27. Updated callers. [Patch 499196] + generic/tclIOUtil.c and generic/tclPosixStr.c according to the + guidelines of TIP 27. Updated callers. [Patch 499196] * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs * doc/CrtChannel.3: * doc/OpenFileChnl.3: * generic/tcl.decls: * generic/tclIO.h: * generic/tclIO.c (DoWrite, Tcl_RegisterChannel, Tcl_GetChannel, - Tcl_CreateChannel, Tcl_GetChannelName, CloseChannel, Tcl_Write, - Tcl_WriteRaw, Tcl_Ungets, Tcl_BadChannelOption, Tcl_GetChannelOption, - Tcl_SetChannelOption, Tcl_GetChannelNamesEx, Tcl_ChannelName): + (Tcl_CreateChannel, Tcl_GetChannelName, CloseChannel, Tcl_Write, + (Tcl_WriteRaw, Tcl_Ungets, Tcl_BadChannelOption, Tcl_GetChannelOption, + (Tcl_SetChannelOption, Tcl_GetChannelNamesEx, Tcl_ChannelName): Updated APIs in the file generic/tclIO.c according to the guidelines - of TIP 27. Several minor documentation corrections as well. - [Patch 503565] + of TIP 27. Several minor documentation corrections as well. [Patch + 503565] * generic/tclDecls.h: make genstubs * generic/tcl.h (Tcl_DriverOutputProc, Tcl_DriverGetOptionProc, - Tcl_DriverSetOptionProc): + (Tcl_DriverSetOptionProc): * generic/tclIOGT.c (TransformOutputProc, TransformGetOptionProc, - TransformSetOptionProc): + (TransformSetOptionProc): * mac/tclMacChan.c (FileOutput, StdIOOutput): * man/tclMacSock.c (TcpGetOptionProc, TcpOutput): * unix/tclUnixChan.c (FileOutputProc, TcpGetOptionProc, TcpOutputProc, - TtyGetOptionProc, TtySetOptionProc): + (TtyGetOptionProc, TtySetOptionProc): * unix/tclUnixPipe.c (PipeOuputProc): * win/tclWinChan.c (FileOutputProc): * win/tclWinConsole.c (ConsleOutputProc): * win/tclWinPipe.c (PipeOuputProc): * win/tclWinSerial.c (SerialOutputProc, SerialGetOptionProc, - SerialSetOptionProc): + (SerialSetOptionProc): * win/tclWinSock.c (TcpGetOptionProc, TcpOutput): Updated channel - driver interface according to the guidelines of TIP 27. See also - [Bug 500348]. + driver interface according to the guidelines of TIP 27. See also [Bug + 500348]. * doc/CrtChannel.3: * generic/tcl.h: * generic/tclIO.c: * generic/tclIO.h: * generic/tclInt.h: * tools/checkLibraryDoc.tcl: Moved Tcl_EolTranslation enum declaration from generic/tcl.h to - generic/tclInt.h (renamed to TclEolTranslation). It is not used + generic/tclInt.h (renamed to TclEolTranslation). It is not used anywhere in Tcl's public interface. 2002-01-14 Don Porter * doc/GetIndex.3: * doc/WrongNumArgs.3: * generic/tcl.decls (Tcl_GetIndexFromObj, Tcl_GetIndexFromObjStruct, - Tcl_WrongNumArgs): + (Tcl_WrongNumArgs): * generic/tclIndexObj.c (Tcl_GetIndexFromObj, Tcl_GetIndexFromObjStruct, - Tcl_WrongNumArgs): Updated APIs in the file generic/tclIndexObj.c - according to the guidelines of TIP 27. [Patch 501491] + (Tcl_WrongNumArgs): Updated APIs in the file generic/tclIndexObj.c + according to the guidelines of TIP 27. [Patch 501491] * generic/tclDecls.h: make genstubs 2002-01-11 Mo DeJong * unix/configure: Regen. @@ -5552,40 +10132,39 @@ * unix/configure.in: * win/configure: Regen. * win/configure.in: Use ${libdir} instead of ${exec_prefix}/lib to properly support the --libdir option to configure. [Bug 489370] -2002-01-11 Andreas Kupries +2002-01-11 Andreas Kupries - * win/tclWinSerial.c (SerialSetOptionProc): Applied patch for SF - bug #500348 supplied by Rolf Schroedter - . The function modified the - contents of the the 'value' string and now does not do this - anymore. This is a followup to the change made on 2001-12-17. + * win/tclWinSerial.c (SerialSetOptionProc): Applied patch for [Bug + 500348] supplied by Rolf Schroedter . The + function modified the contents of the the 'value' string and now does + not do this anymore. This is a followup to the change made on + 2001-12-17. 2002-01-11 David Gravereaux - * win/makefile.vc: Removed -GD compiler option. It was intended - for future use, but MS is again changing the future at their whim. - The D4002 warning was harmless though, but someone using VC .NET - logged it as a concern. [Bug #501565] + * win/makefile.vc: Removed -GD compiler option. It was intended for + future use, but MS is again changing the future at their whim. The + D4002 warning was harmless though, but someone using VC .NET logged it + as a concern. [Bug 501565] 2002-01-11 Mo DeJong - * unix/Makefile.in: Burn Tcl build directory - into tcltest executable to avoid crashes caused - by ld loading a previously installed version + * unix/Makefile.in: Burn Tcl build directory into tcltest executable + to avoid crashes caused by ld loading a previously installed version of the tcl shared library. [Bug 218110] 2002-01-10 Don Porter , Kevin Kenny - - * unix/tclLoadDld.c (TclpLoadFile): syntax error: unbalanced - parens. Kevin notes that it's far from clear that this file is - ever included in an actual build; Linux without dlopen appears to - be a nonexistent configuration. - + + * unix/tclLoadDld.c (TclpLoadFile): syntax error: unbalanced parens. + Kevin notes that it's far from clear that this file is ever included + in an actual build; Linux without dlopen appears to be a nonexistent + configuration. + 2002-01-08 Don Porter , Kevin Kenny * doc/StaticPkg.3 (Tcl_StaticPackage): * generic/tcl.decls (Tcl_StaticPackage): @@ -5600,13 +10179,12 @@ * unix/tclLoadDld.c (TclGuessPackageName): * unix/tclLoadDyld.c (TclGuessPackageName): * unix/tclLoadNext.c (TclGuessPackageName): * unix/tclLoadOSF.c (TclGuessPackageName): * unix/tclLoadShl.c (TclGuessPackageName): - * win/tclWinLoad.c (TclGuessPackageName): Updated APIs in - the files */tcl*Load*.c according to the guidelines of TIP 27. - [Patch 501096] + * win/tclWinLoad.c (TclGuessPackageName): Updated APIs in the files + */tcl*Load*.c according to the guidelines of TIP 27. [Patch 501096] 2002-01-09 Don Porter * generic/tclTest.c (MainLoop): * tests/main.test (Tcl_Main-1.{3,4,5,6}): Corrected some non-portable @@ -5614,61 +10192,62 @@ 2002-01-07 Don Porter * generic/tclEvent.c (TclInExit): * generic/tclIOUtil.c (SetFsPathFromAbsoluteNormalized, - SetFsPathFromAny,Tcl_FSNewNativePath,DupFsPathInternalRep): + (SetFsPathFromAny,Tcl_FSNewNativePath,DupFsPathInternalRep): * generic/tclListObj.c (TclLsetList,TclLsetFlat): Added some type casts to satisfy picky compilers. * generic/tclMain.c: Bug fix: neglected the NULL case in - TclGetStartupScriptFileName(). Broke Tk/wish. + TclGetStartupScriptFileName(). Broke Tk/wish. 2002-01-05 Don Porter * doc/Tcl_Main.3: * generic/tclMain.c: Substantial rewrite and expanded documentation of Tcl_Main to correct a number of bugs and flaws: - * Interactive Tcl_Main can now enter a main loop, exit - that loop and continue interactive operations. The loop - may even exit in the midst of interactive command typing - without loss of the partial command. [Bugs 486453, 474131] + * Interactive Tcl_Main can now enter a main loop, exit that + loop and continue interactive operations. The loop may even + exit in the midst of interactive command typing without loss + of the partial command. [Bugs 486453, 474131] * Tcl_Main now gracefully handles deletion of its master interpreter. * Interactive Tcl_Main can now operate with non-blocking stdin * Interactive Tcl_Main can now detect EOF on stdin even in - mid-command. [Bug 491341] - * Added VFS-aware internal routines for managing the - startup script selection. + mid-command. [Bug 491341] + * Added VFS-aware internal routines for managing the startup + script selection. * Tcl variable 'tcl_interactive' is now linked to C variable - 'tty' so that one can disable/enable interactive prompts - at the script level when there is no startup script. This - is meant for use by the test suite. + 'tty' so that one can disable/enable interactive prompts at + the script level when there is no startup script. This is + meant for use by the test suite. * Consistent use of the Tcl libraries standard channels as returned by Tcl_GetStdChannel(); as opposed to the channels named 'stdin', 'stdout', and 'stderr' in the master interp, which can be different or unavailable. * Tcl_Main now calls Tcl_Exit() if evaluation of [exit] in the - master interpreter returns, assuring Tcl_Main does not return. + master interpreter returns, assuring Tcl_Main does not + return. * Documented Tcl_Main's absence from public stub table * Documented that Tcl_Main does not return. * Documented Tcl variables set by Tcl_Main. * All prompts are done from a single procedure, Prompt. * Use of Tcl_Obj-enabled interfaces everywhere. * generic/tclInt.decls (TclGetStartupScriptPath, - TclSetStartupScriptPath): New internal VFS-aware routines for + (TclSetStartupScriptPath): New internal VFS-aware routines for managing the startup script of Tcl_Main. * generic/tclIntDecls.h: * generic/tclStubInit.c: make genstubs * generic/tclTest.c (TestsetmainloopCmd,TestexitmainloopCmd, - Tcltest_Init,TestinterpdeleteCmd): - * tests/main.test (new): Added new file to test suite that - thoroughly tests generic/tclMain.c; added some new test commands - for testing Tcl_SetMainLoop(). + (Tcltest_Init,TestinterpdeleteCmd): + * tests/main.test (new): Added new file to test suite that thoroughly + tests generic/tclMain.c; added some new test commands for testing + Tcl_SetMainLoop(). 2002-01-04 Don Porter * doc/Alloc.3: * doc/Concat.3: @@ -5681,54 +10260,55 @@ * doc/Preserve.3: * doc/SetResult.3: * doc/SplitList.3: * doc/SplitPath.3: * doc/TCL_MEM_DEBUG.3: Updated documentation to describe the ckalloc, - ckfree, ckrealloc, attemptckalloc, and attemptckrealloc macros, and - to accurately describe when and how they are used. [Bug 497459] + ckfree, ckrealloc, attemptckalloc, and attemptckrealloc macros, and to + accurately describe when and how they are used. [Bug 497459] * generic/tclThreadJoin.c (TclRememberJoinableThread,TclJoinThread): Replaced Tcl_Alloc and Tcl_Free calls with ckalloc and ckfree so that memory debugging is supported. 2002-01-04 Daniel Steffen - * mac/tclMacTime.c (TclpGetTZName): fix for daylight savings TZName bug + * mac/tclMacTime.c (TclpGetTZName): fix for daylight savings TZName + bug 2002-01-03 Don Porter * doc/FileSystem.3: - * generic/tclIOUtil.c: Updated some old uses of "fileName" to - new VFS terminology, "pathPtr". + * generic/tclIOUtil.c: Updated some old uses of "fileName" to new VFS + terminology, "pathPtr". 2002-01-03 Donal K. Fellows - * tests/basic.test (basic-39.4): Greatly simplified test while - still leaving it so that it crashes when run without the fix to - the [foreach] implementation. - * generic/tclCmdAH.c (Tcl_ForeachObjCmd): Stopped Bug #494348 from + * tests/basic.test (basic-39.4): Greatly simplified test while still + leaving it so that it crashes when run without the fix to the + [foreach] implementation. + * generic/tclCmdAH.c (Tcl_ForeachObjCmd): Stopped [Bug 494348] from happening by not trying to be so clever with cacheing; if nothing - untoward is happening anyway, the less efficient technique will - only add a few instruction cycles (one function call and a few - derefs/assigns per list per iteration, with no change in the - number of tests) and if something odd *is* going on, the code is - now far more robust. + untoward is happening anyway, the less efficient technique will only + add a few instruction cycles (one function call and a few + derefs/assigns per list per iteration, with no change in the number of + tests) and if something odd *is* going on, the code is now far more + robust. - * tests/basic.test (basic-39.4): Reproducable script from Bug #494348 + * tests/basic.test (basic-39.4): Reproducable script from [Bug 494348] 2002-01-02 Donal K. Fellows - * tests/util.test (Wrapper_Tcl_StringMatch,util-5.*): Rewrote so - the test is performed with the right internal function since - [string match] no longer uses Tcl_StringCaseMatch internally. + * tests/util.test (Wrapper_Tcl_StringMatch,util-5.*): Rewrote so the + test is performed with the right internal function since [string + match] no longer uses Tcl_StringCaseMatch internally. * tests/string.test (string-11.51): * generic/tclUtf.c (Tcl_UniCharCaseMatch): * generic/tclUtil.c (Tcl_StringCaseMatch): Fault with matching - case-insensitive non-ASCII patterns containing upper case - characters. [Bug #233257] + case-insensitive non-ASCII patterns containing upper case characters. + [Bug 233257] ****************************************************************** - *** CHANGELOG ENTRIES FOR 2001 IN "ChangeLog.2001" *** - *** CHANGELOG ENTRIES FOR 2000 IN "ChangeLog.2000" *** + *** CHANGELOG ENTRIES FOR 2001 IN "ChangeLog.2001" *** + *** CHANGELOG ENTRIES FOR 2000 IN "ChangeLog.2000" *** *** CHANGELOG ENTRIES FOR 1999 AND EARLIER IN "ChangeLog.1999" *** ****************************************************************** Index: README ================================================================== --- README +++ README @@ -1,13 +1,13 @@ README: Tcl - This is the Tcl 8.4.2 source distribution. + This is the Tcl 8.4.16 source distribution. Tcl/Tk is also available through NetCVS: http://tcl.sourceforge.net/ You can get any source release of Tcl from the file distributions link at the above URL. -RCS: @(#) $Id: README,v 1.49 2003/02/15 02:16:28 hobbs Exp $ +RCS: @(#) $Id: README,v 1.49.2.19 2007/05/30 14:05:17 dgp Exp $ Contents -------- 1. Introduction 2. Documentation @@ -53,14 +53,14 @@ Detailed release notes can be found at the file distributions page by clicking on the relevant version. http://sourceforge.net/project/showfiles.php?group_id=10894 Information about Tcl itself can be found at - http://www.tcl.tk/scripting/ + http://www.tcl.tk/about/ -There have been many Tcl books on the market. Most are listed at - http://www.tcl.tk/resource/doc/books/ +There have been many Tcl books on the market. Many are mentioned in the Wiki: + http://wiki.tcl.tk/book 2a. Unix Documentation ---------------------- The "doc" subdirectory in this release contains a complete set of @@ -90,11 +90,11 @@ Start | Programs | Tcl | Tcl Help 3. Compiling and installing Tcl ------------------------------- -There are brief notes in the unix/README, win/README, and mac/README about +There are brief notes in the unix/README, win/README, and macosx/README about compiling on these different platforms. There is additional information about building Tcl from sources at http://www.tcl.tk/doc/howto/compile.html @@ -133,19 +133,18 @@ (aka ftp://ftp.procplace.com/pub/tcl). You can access the archive using anonymous FTP. The archive also contains several FAQ ("frequently asked questions") documents that provide solutions to problems that are commonly encountered by Tcl newcomers. -7. Tcl Resource Center ----------------------- - -Visit http://www.tcl.tk/resource/ to see an annotated index of -many Tcl resources available on the World Wide Web. This includes -papers, books, and FAQs, as well as development tools, extensions, -applications, binary releases, and patches. You can also recommend -additional URLs for the resource center using the forms labeled "Add a -Resource". +7. The Tcler's Wiki +------------------- + +A Wiki-based open community site covering all aspects of Tcl/Tk is at: + + http://wiki.tcl.tk/ + +A wealth of useful information can be found there. 8. Mailing lists ---------------- Several mailing lists are hosted at SourceForge to discuss development or @@ -179,16 +178,16 @@ The Tcl community is too large for us to provide much individual support for users. If you need help we suggest that you post questions to comp.lang.tcl. We read the newsgroup and will attempt to answer esoteric questions for which no one else is likely to know the answer. In addition, -see the following Web site for links to other organizations that offer +see the following page on the Wiki for links to other organizations that offer Tcl/Tk training: - http://www.tcl.tk/resource/community/commercial/training + http://wiki.tcl.tk/training 10. Thank You ------------- We'd like to express our thanks to the Tcl community for all the helpful suggestions, bug reports, and patches we have received. Tcl/Tk has improved vastly and will continue to do so with your help. Index: changes ================================================================== --- changes +++ changes @@ -1,8 +1,8 @@ Recent user-visible changes to Tcl: -RCS: @(#) $Id: changes,v 1.79 2003/03/03 20:04:50 hobbs Exp $ +RCS: @(#) $Id: changes,v 1.79.2.50 2007/05/16 22:13:07 das Exp $ 1. No more [command1] [command2] construct for grouping multiple commands on a single command line. 2. Semi-colon now available for grouping commands on a line. @@ -4216,11 +4216,11 @@ 3/23/99 (bug fix) Added a new Tcl_ServiceModeHook interface. This is used on Windows to avoid the various problems that people have been seeing where the system hangs when tclsh is running outside of the event loop. As part of this, renamed -TclpAlertNotifier back to Tcl_AlertNotifier since it is public. +TcapAlertNotifier back to Tcl_AlertNotifier since it is public. (stanton) 3/23/99 (feature change) Test suite now uses "tcltest" namespace to define the test procedure and other auxiliary procedures as well as global variables. The previously chosen "test" namespace was thought @@ -5755,5 +5755,697 @@ *** POTENTIAL INCOMPATIBILITY *** 2003-02-27 (bug fix)[694232] stop [lsearch -start 0 {} x] segfault --- Released 8.4.2, March 3, 2003 --- See ChangeLog for details --- + +2003-03-06 (bug fix)[699042] Correct case-insensitive unicode string +comparison in Tcl_UniCharNcasecmp + +2003-03-11 (bug fix) Corrected loading of tclpip8x.dll on Win9x + +2003-03-12 (bug fix)[702383] Corrected parsing of interp create -- + +2003-03-12 (bug fix)[685106] Correct Tcl_SubstObj handling of \x00 bytes + +2003-03-14 (bug fix)[702622 699060] Correct wide int issues in 'format' + +2003-03-14 (bug fix)[698146] Remove assumption that file times and longs +are the same size. + +2003-03-18 (bug fix)[697862] Allow Tcl to differentiate between reparse +points which are symlinks and mounted drives on Windows + +2003-03-19 (bug fix)[705406] Bad command count on TCL_OUT_LINE_COMPILE + +2003-03-20 (bug fix)[707174] Store pointers to notifier funcs in a struct +to work around some platform linker issues + +2003-03-22 (bug fix)[708218] Load correct (non-)debug dll for dde or +registry + +2003-03-24 (bug fix)[631741 696893] Fixing ObjMakeUpvar's lookup algorithm +for the created local variable + +2003-04-07 (bug fix)[713562] Make sure that tclWideIntType is defined and +somewhat sensible everywhere + +2003-04-07 (bug fix)[711371] Corrected string limits of arguments +interpolated in error messages for 'if' + +2003-04-11 (bug fix)[718878] Corrected inconsistent results of +[string is integer] observed on systems where sizeof(long) != sizeof(int) + +2003-04-12 (bug fix) Substantial changes to the Windows clock synch +phase-locked loop in a quest for improved loop stability + +2003-04-16 [713562] Made changes so that the "wideInt" Tcl_ObjType is +defined on all platforms, even those where TCL_WIDE_INT_IS_LONG is defined. +Also made the Tcl_Value struct have a wideValue field on all platforms. +Potential incompatibility for TCL_WIDE_INT_IS_LONG platforms because that +struct changes size. + *** POTENTIAL INCOMPATIBILITY *** + +2003-04-25 (bug fix)[727271] Catch any errors returned by the Windows +functions handling TLS ASAP instead of waiting to get some mysterious crash +later on due to bogus pointers. + +2003-04-29 (bug fix) Correct 'glob -path {[tcl]} *', where leading +special character instead lists files in '/'. Bug only occurs on Windows +where '\' is also a directory separator. + +2003-05-09 (bug fix)[731754] Fixed memory leak in threaded allocator on +Windows caused by treating cachePtr as a TLS index + +2003-05-10 (bug fix)[710642] Ensure cd is thread-safe + +2003-05-10 (bug fix)[718002] Correct mem leak on closing a Windows serial +port + +2003-05-10 (bug fix)[714106] Prevent string repeat crash when overflow +sizes were given (throws error). + +2003-05-13 (feature enhancement)[736774] Use new versioned bundle resource +API to get tcl runtime library for TCL_VERSION on Mac OS X. + +2003-05-13 (bug fix)[711232] Worked around the issue of realpath() not +being thread-safe on Mac OS X by defining NO_REALPATH for threaded builds +on Mac OS X. + +2003-05-14 (bug fix)[557030] Correct handling of the gb2312 encoding by +making it an alias of the euc-cn encoding and creating a gb2312-raw +encoding for the original. Most uses of gb2312 really mean euc-cn. + +2003-05-14 (bug fix)[736421] Corrected another putenv() copy behavior +problem when compiling on Windows and using Microsoft's runtime. + +--- Released 8.4.3, May 20, 2003 --- See ChangeLog for details --- + +2003-05-23 (bug fix)[726018] reverted internals change to the +'cmdName' Tcl_ObjType that broke several extensions (TclBlend, e4graph...) +in the 8.4.3 release. + +2003-06-10 (bug fix)[495830] stop eval of bytecode in deleted interp. + +2003-06-17 (bug fix) corrections to regexp when matching emtpy string. + +2003-06-25 (bug fix)[748957] -*ieee compiler flags for Tru64 builds. + +2003-07-11 (bug fix) [pkg_mkIndex] indexes provided packages, not indexed ones. + +2003-07-15 (feature enhancement) MacOSX build system rewrite. + +2003-07-15 (bug fix)[771613] corrected segfault in [if] (buffer overflow) + +2003-07-16 (bug fix)[756791] corrected assumption that Tcl_Free == free + +2003-07-16 (feature enhancement) -DTCL_UTF_MAX=6 compile option forces +internal UCS-4 representation of Unicode (default is recommended UCS-2). + +2003-07-16 (bug fix)[767578] 64-bit corrections in thread notifier. + +2003-07-16 (bug fix)[759607] Safe Base tests normalized paths. + +2003-07-16 (feature enhancement)[Patch 679315] improved Cygwin path support + +2003-07-18 (bug fix)[706359] corrected broken -output option of [tcltest::test] +=> tcltest 2.4.4 + +2003-07-18 (bug fix)[753315] MT-safety of VFS records. + +2003-07-18 (bug fix)[759888] support for user:pass in URL by [http::geturl] +=> http 2.4.4 + +Improved documentation, new tests, and some code cleanup. +[655300, 720634, 735364, 748700, 756112, 756744, 756951, 758488, 760768, +763312, 769895, 771539, 771840, 771947, 771949, 772333] + +--- Released 8.4.4, July 22, 2003 --- See ChangeLog for details --- + +2003-07-23 (bug fix)[775976] fix registry compilation for VC7. + +2003-08-05 (enhancement)[781585] Use Tcl_ResetResult in bytecodes to +prevent potential costly Tcl_Obj duplication. + +2003-08-06 (bug fix)[781609] prevent non-Windows platforms from trying to +use the registry package inside msgcat. + +2003-08-27 (bug fix)[411825] Fix TclNeedSpace to handle non-breaking space +(\u00A0) and backslash escapes correctly. + +2003-09-01 (bug fix)[788780] Fix thread-safety issues in filesystem records. + +2003-09-19 (bug fix)[804681] Protect ::errorInfo and ::errorCode traces +from corrupting stack. + +2003-09-23 (bug fix)[218871] Fix handling of glob-sensitive chars in +auto_load and auto_import. + +2003-10-03 (bug fix)[811483] Fixed refcount management for command and +execution traces. + +2003-10-04 (bug fix)[789040] Fixed exec command.com error for Win9x. + +2003-10-06 (bug fix)[767834, 813273] Fixed volumerelative file +normalization and 'file join' inconsistencies. + +2003-10-08 (bug fix)[769812] Fix Tcl_NumUtfChars string length calculation +when negative parameter is given. + +2003-10-22 (bug fix)[800106] Handle VFS mountpoints inside glob'd dirs. + +2003-10-22 (bug fix)[599468] Watch for FD_CLOSE too on Windows when +asked for writable events by the generic layer. + +2003-10-23 (bug fix)[813606] Detect OS X pipes correctly. + +2003-11-05 (bug fix)[832657] Allow .. in libpath initialization. + +2003-11-11 (bug fix) Improve AIX-64 build configuration. + +2003-11-17 (bug fix)[230589, 504785, 505048, 703709, 840258] fixes to +various odd regexp "can't happen" bugs. + +--- Released 8.4.5, November 20, 2003 --- See ChangeLog for details --- + +2003-12-02 (bug fix)[851747] object sharing fix in [binary scan] + +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-17 (bug fix)[839519] fixed two memory leaks (vasiljevic) + +2004-01-09 (bug fix)[873311] fixed infinite loop in TclFinalizeFilesystem + +2004-02-02 (bug fix)[405995] Tcl_Ungets buffer filling fix + +2004-02-04 (bug fix)[833910] tcltest command line option parsing error +=> tcltest 2.4.5 + +2004-02-04 (bug fix)[833637] code error in tcltest -preservecore operation + +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)[772288] Unix std channels forced to exist at startup. + +2004-02-17 (new default) tcltest::configure -verbose {body error} + +2004-02-19 (bug fix) init.tcl search path with unusual --libdir (samson) + +2004-02-25 (bug fix)[554068] stopped broken [exec] quoting of { (gravereaux) + +2004-02-25 (bug fix)[888777] plugged memory leak with long host names (cassoff) + +2004-03-01 (bug fix)[462580] corrected level interpretation of Tcl_CreateTrace + +2004-03-01 (platform support)[218561] Allow 64-bit configure on IRIX64-6.5* + +--- Released 8.4.6, March 1, 2004 --- See ChangeLog for details --- + +2004-03-08 (bug fix)[910525] [glob -path] in root directory (darley) + +2004-03-15 (bug fix)[916795] syntax error -> compiler segfault (sofer,porter) + +2004-03-29 (bug fix)[920667] install into any Unicode path on Win (hobbs) + +2004-03-31 (bug fix)[811457] support translation to "" (porter) +2004-03-31 (bug fix)[811461] ignore locales with no "language" part (porter) +=> msgcat 1.3.2 + +2004-04-07 (platform support) properly substitute more values in Windows +tclConfig.sh (hobbs) + +2004-04-23 (bug fix)[930851] reset channel EOF when eofchar changes (kupries) + +2004-05-03 (bug fix)[947070] stack overflow prevention on Win (kenny) + +2004-05-03 (bug fix)[868853] fix leak in [fconfigure $serial -xchar] (cassoff) + +2004-04-05 (bug fix)[928353,929892,928808,947440,948177] test fixes: OSX +(abner) + +2004-05-04 (bug fix) crash: [cd] w/ volumerelative $HOME (hobbs) + +2004-05-05 (bug fix)[794839] socket connect error -> r/w fileevents +(gravereaux) + +2004-05-14 (bug fix)[940278,922848] [clock] notices $::env(TZ) changes, +gmt works on all platforms. (kenny, welton, glessner) + +2004-05-18 (bug fix)[500285,500389,852944] [clock %G %V] ISO8601 week numbers +(kenny) + +2004-05-22 (bug fix)[735335,736729] variable name resolution error (sofer) + +2004-05-24 (bug fix) support for non-WIDE_INT aware math functions (hobbs) + +2004-05-25 (new feature) [http::config -urlencoding] (hobbs) +=> http 2.5.0 + +2004-05-26 (bug fix)[960926] file count doubled when -singleproc 1 (porter) +=> tcltest 2.2.6 + +2004-05-27 (bug fix)[949905] corrected utf-8 encoding of \u0000 on I/O (max) + +2004-06-05 (bug fix)[976722] hi-res clock fixes: Win +(godfrey, suchenwirth, kenny) + +2004-06-10 (bug fix)[932314] bad return values from Tcl_FSChdir() (vasiljevic) + +2004-06-14 (bug fix) correct dde hangs w/non-responsive apps (thoyts) +=> dde 1.2.3 + +2004-06-21 (platform support) exceptions w/ gcc -O3 on Win (dejong) + +2004-06-29 (bug fix)[981733] SafeBase global pollution (fellows) + +2004-07-02 (new feature)[TIP 202] pipe redirection 2>@1 (hobbs) + +2004-07-03 (bug fix)[908375] round() wide integer support (lavana, sofer) + +2004-07-15 (bug fix)[770053] crash in thread finalize of notifier (vasiljevic) + +2004-07-15 (bug fix)[990453] plug mutex leaks on reinit +(mistachkin, vasiljevic) + +2004-07-16 (bug fix)[990500] clean exit of notifier thread +(mistachkin, kupries) + +2004-07-19 (bug fix)[987967] improved self-init of mutexes on Win (vasiljevic) + +2004-07-19 (bug fix)[874058] improved build configuration on 64-bit systems. +Corrects Tcl_StatBuf definition issues. (hobbs) + +2004-07-20 (bug fix) pure Darwin/CFLite support (steffen) + +2004-07-20 (bug fix)[736426] plug leaky allocator reinit (mistachkin, kenny) + +--- Released 8.4.7, July 26, 2004 --- See ChangeLog for details --- + +2004-07-28 (bug fix)[999084] no deadlock in re-entrant Tcl_Finalize (porter) + +2004-08-10 (bug fix) thread IDs on 64-bit systems (ratcliff,vasiljevic) + +2004-08-13 (bug fix) avoid malicious code acceptance by [mclocale] (porter) +=> msgcat 1.3.3 + +2004-08-16 (bug fix)[1008314] Tcl_SetVar TCL_LIST_ELEMENT (sofer,porter) + +2004-08-19 (bug fix)[1011860] [scan %ld] fix on LP64 (fellows,porter) + +2004-08-30 (bug fix) [string map $x $x] crash (fellows) + +2004-09-01 (bug fix)[1020445] WIN64 support (hobbs) + +2004-09-07 (bug fix)[1016167] [after] overwrites its imports (kenny) + +2004-09-08 (bug fix) fixed [clock format 0 -format %k] (kenny) + +2004-09-09 (bug fix)[560297] fixed broken [namespace forget] logic (porter) + +2004-09-09 (bug fix)[1017299] fixed [namespace import] cycle prevention (porter) + +2004-09-10 (performance) $x[set x {}] is now fast [K $x [set x {}]] (sofer) + +2004-09-10 (bug fix)[868489] better control over int <-> wideInt (fellows,kenny) + +2004-09-10 (bug fix)[1025359] POSIX errorCode from wide seeks (kupries,fellows) + +2004-09-18 (bug fix)[868467] fix [expr 5>>32] => 0, not 5 (hintermayer,fellows) + +2004-09-23 (bug fix)[1016726] fix `make clean` in static config (leitgeb,dejong) + +2004-09-29 (bug fix)[1036649] syntax error in [subst] => buffer overflow (sofer) + +2004-09-30 (bug fix)[1038021] save/restore error state: var traces (porter) + +2004-10-08 (bug fix)[954263] case insensitive [file exec] for Win (hobbs,darley) + +2004-10-14 (performance) [info commands/globals/procs/vars $pattern] faster + when $pattern is trivial (fellows) + +2004-10-28 (bug fix)[1030548] restore the --enable-symbols --enable-threads + build on Win (mistachkin,kenny,kupries) + +2004-10-29 (bug fix)[1055673] fix command line syntax error message (porter) +=> tcltest 2.2.7 + +2004-10-31 (bug fix)[1057461] fix [info globals ::varName] (fellows) + +2004-11-02 (bug fix)[761471] fix [expr {NaN == NaN}] (sofer) + +2004-11-02 (bug fix)[1017151] misleading errorInfo after tests (seeger,porter) + +2004-11-11 (bug fix)[1034337] recursive file delete, MacOSX (steffen) + +2004-11-12 (bug fix)[1004065] stop crash when TCL_UTF_MAX==6 (hobbs,porter) + +2004-11-15 (bug fix)[10653678] [trace variable],[trace remove] interop (porter) + +2004-11-16 (bug fix)[695441] [tcl_findLibrary] search $::auto_path too (porter) + +2004-11-16 (bug fix)[1067709] crash in [fconfigure -ttycontrol] (hobbs) + +2004-11-18 (new feature) configure options --enable-man-suffix (max) + +Documentation improvements [759545,1058446,1062647,1065732,etc.] +Test suite expansion [1036649,1001997,etc.] + +--- Released 8.4.8, November 18, 2004 --- See ChangeLog for details --- + +2004-11-22 (bug fix)[1030465] Improve HAVE_TYPE_OFF64_T check (dejong) + +2004-11-23 (bug fix)[1072654] Fixed segfault in info vars trivial +matching branch (new in 8.4.8) (porter) + +2004-11-23 (bug fix)[1043129] Fixed the treatment of backslashes in file +join on Windows (darley) + +2004-11-24 (bug fix)[1001325, 1071701] Fixed readdir_r detection and usage +(dejong, kenny, porter) + +2004-11-24 (bug fix)[1071807] Fixed all uses of 'select' to use standard +macros rather than older bit-whacking style (kenny) + +2004-11-26 (bug fix)[1072136] Remove file normalize on tcl_findLibrary +search path uniqification added in 8.4.8 (porter) + +2004-12-02 (bug fix)[1074671] Ensure tilde paths are not returned specially +by 'glob' (darley) + +--- Released 8.4.9, December 6, 2004 --- See ChangeLog for details --- + +2004-12-29 (platform support)[1092952,1091967] MSVC7, gcc OPT compiles (hobbs) + +2005-01-05 (bug fix)[1084595] encoding maps for some Chinese locales (fellows) + +2005-01-06 (performance)[1020491] [http::mapReply] (fellows) +=> http 2.5.1 + +2005-01-25 (bug fix)[1101670] [auto_reset] update for [namespace] (porter) + +2005-01-27 (new feature)[TIP 218] Tcl_Channel API update for threads (kupries) + +2005-01-27 (bug fix)[1109484] Tcl_Expr* updates for Tcl_WideInt (hobbs) + +2005-01-28 (platform support)[1021871] Solaris gcc 64-bit support (hobbs) + +2005-02-10 (bug fix)[1119369] Tcl_EvalObjEx: avoid shimmer loss of List intrep +(sofer,macdonald) + +2005-02-10 (platform support) correct gcc builds for AIX-4+, HP-UX-11 (hobbs) + +2005-02-24 (bug fix)[1119798] prevent [source $directory] (porter,mpettigr) +=> tcltest 2.2.8 + +2005-03-10 (bug fix)[1153871] bad ClientData cast (porter,victorovich) + +2005-03-15 (platform support) OpenBSD ports patch (thoyts) + +2005-03-15 (platform support)[1163422] time_t wider than long (kenny) + +2005-03-18 (bug fix)[1115904] restore recursion limit in direct eval (porter) + +2005-03-29 (platform support) allow msys builds without cygwin (hobbs) + +2005-04-06 (bug fix)[1178445] fix memory waste at thread exit (vasiljevic) + +2005-04-13 (bug fix) min buffer size dropped from 10 to 1 byte (gravereaux) + +2005-04-19 (bug fix)[947693] Windows pipes honor -blocking during close +(gravereaux) ***POTENTIAL INCOMPATIBILITY*** +async pipes on windows, set -blocking 1 before [close] to receive exit status + +2005-04-20 (bug fix)[1090869] Tcl_GetInt accept 0x80000000, 64-bit +(porter,singh) + +2005-04-22 (bug fix)[1187123] [string is boolean] respect EIAS (porter) + +2005-04-25 (platform support) builds on Mac OS X 10.1 (steffen) + +2005-05-06 (platform support) x86_64 Solarix cc and Solaris 10 builds (hobbs) + +2005-05-14 (platform support) Mac OSX: configurable CoreFoundation API +(steffen) + +2005-05-14 (platform support) Mac OSX: use realpath when threadsafe (steffen) + +2005-05-20 (bug fix)[1201589] boolean literal prefix in expressions (porter) + +2005-05-24 (platform support) Darwin build support merged into unix (steffen) + +2005-05-24 (new feature)[1202209] Mac OSX: support [load] of .bundle binaries +Can support [load] from memory as well (steffen) + +2005-05-24 (new feature)[1202178] [time] returns non-integer result (steffen) + +2005-05-31 (bug fix)[1082283] Unix: notifier thread now joinable (vasiljevic) + +Documentation improvements [1075433,1085127,1117017,1124160,1149605,etc.] + +--- Released 8.4.10, June 4, 2005 --- See ChangeLog for details --- + +2005-06-06 (bug fix)[1213678] Windows/gcc: crash in stack.test (kenny) + +2005-06-07 (bug fix) Unix: --enable-threads compile failure (fellows) + +2005-06-18 (bug fix)[1154163] [format %h] on 64-bit OS's (kraft,fellows) + +2005-06-21 (bug fix)[1201035,1224585] execution trace crashes (porter) + +2005-06-21 (bug fix)[1194458] Windows: [file split] (kenny,porter) + +2005-06-22 (bug fix)[1225727] Windows: pipe finalization crash (kenny) + +2005-06-22 (bug fix)[1225571] Windows: [file pathtype] buffer overflow (thoyts) + +2005-06-22 (bug fix)[1225044] Windows: UMR in pipe close (kenny) + +2005-06-23 (bug fix)[1225957] Windows/gcc: crashes in assembler code (kenny) + +2005-06-27 (revert)[1101670] [auto_reset] disabled in non-global namespace. +Restores Tcl 8.4.9 behavior (porter) + +--- Released 8.4.11, June 28, 2005 --- See ChangeLog for details --- + +2005-07-01 (bug fix)[1222872] notifier spurious wake-up protection (vasiljevic) + +2005-07-05 (bug fix)[1077262] improved Tcl_Encoding lifetimes (porter) + +2005-07-05 (bug fix)[1230597] allow idempotent [namespace import] (porter) + +2005-07-07 (bug fix)[1095909] readdir_r usage purged (hobbs) + +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-26 (bug fix)[1047286] cmd delete traces during namespace delete (porter) + +2005-07-26 (new unix feature)[1231015] ${prefix}/share on ::tcl_pkgPath (dejong) + +2005-07-28 (unix bug fix)[1245953] O_APPEND for >> redirection (fellows) + +2005-07-29 (bug fix)[1247135] [info globals] return only existing vars (fellows) + +2005-07-30 (new Darwin feature) TCL_LOAD_FROM_MEMORY configuration (steffen) + +2005-08-05 (bug fix)[1241572] correct [expr abs($LONG_MIN)] (kenny) + +2005-08-05 (Solaris bug fix)[1252475] recognize cp1251 encoding (wagner,fellows) + +2005-08-17 (bug fix)[1217375] [file mkdir] race (diekhans,darley) + +2005-08-25 (bug fix)[1267380] [lrepeat] buffer overflow prevention (fellows) + +2005-08-29 (bug fix)[1275043] restore round() away from zero (kenny) + +2005-09-07 (bug fix)[1283976] invalid [format %c -1] result (porter) + +2005-09-15 (RHEL bug fix)[1287638] support open >2GB files RHEL 3 (palan) + +2005-09-30 (bug fix)[1306162] $argv encoding and list formatting (porter) + +2005-10-04 (bug fix)[1067708] [fconfigure -ttycontrol] leak (hobbs) + +2005-10-04 (bug fix)[1182373] [http::mapReply] update to RFC 3986 (aho,hobbs) +=> http 2.5.2 + +2005-10-04 (HPUX bug fix)[1204237] shl_load() and DYNAMIC_PATH (collins,hobbs) + +2005-10-05 (bug fix)[979640] buffer overrun mixing putenv(), ::env (bold,hobbs) + +2005-10-13 (bug fix)[1284178] [format] accept all integer values (porter) + +2005-10-22 (bug fix)[1251791] optimization exposed wide/int difference(sofer) + +2005-10-23 (bug fix)[1334947] value refcount error in var setting (sofer) + +2005-11-01 (bug fix)[1337941] Tcl_TraceCommand() -> crash (devilliers,porter) + +2005-11-03 (new Win NT/XP feature) Unicode console support (kovalenko,thoyts) + +2005-11-03 (bug fix)[1201171] [encoding system] in Tclkit (schekin,porter) + +2005-11-04 (bug fix)[1337229,1338280] [namespace delete] / unset traces (porter) + +2005-11-04 (enhancement) Korean timezone abbreviations (kenny) + +2005-11-04 (bug fix)[1317477] double encoding of time zone (kenny) + +2005-11-04 (Win enhancement)[1267871] extended exit codes (newman,thoyts) + +2005-11-04 (platform support)[1163896] LynxOS [load] (heidibr) + +2005-11-08 (bug fix)[1348775] unset trace memory leak (sofer) + +2005-11-08 (bug fix)[1162286] [package ifneeded] warns reported (lavana,porter) + *** POTENTIAL INCOMPATIBILITY *** + +2005-11-09 (bug fix)[1350293] [after $negative $script] fixed (kenny) + +2005-11-15 (Win bug fix)[926016,1353840] correct [file mtime] (kenny) + +2005-11-18 (bug fix)[1358369] URL parsing standards compliance (wu,fellows) + +2005-11-18 (bug fix)[1359094] Tclkit crash (thoyts, kupries) + +2005-11-18 (bug fix)[1355942,1355342] cmd delete trace/ namespace delete (sofer) + +2005-11-20 (bug fix)[1091431] Tcl_InitStubs failure crashes wish (english) + +2005-11-29 (bug fix)[1366683] [lsearch -regexp] backrefs (cleverly,fellows) + +2005-11-29 (enhancement)[1369597] Win 64: --enable-64bit=amd64|ia64 (hobbs) + +2005-12-05 (Darwin bug fix)[1034337] NFS recursive file delete (steffen) + +--- Released 8.4.12, December 3, 2005 --- See ChangeLog for details --- + +2005-12-09 (bug fix)[1374778] [lsearch -start $pastEnd] => -1 (fellows) + +2005-12-12 (bug fix)[1241572] correct [expr abs($LONG_MIN)] again (max) + +2005-12-12 (bug fix)[1377619] configure syntax error exposed in bash-3.1 (hobbs) + +2006-01-09 (bug fix)[1400572] [info level $l] => "namespace inscope" (porter) + +2006-01-23 (bug fix)[1410553] Tcl_GetRange Unicode confusion (twylite,spjuth) + +2006-03-06 (bug fix)[1439836,1444291] fix TCL_EVAL_{GLOBAL,INVOKE} handling +when auto-loading or exec traces are present (porter) + +2006-03-10 (bug fix)[1437595] Win socket finalize with threads (vasiljevic) + +2005-03-13 (revert 2005-07-26 change) ${prefix}/share on ::tcl_pkgPath (porter) + +2006-03-14 (bug fix)[1381436,859820] threadsafe Tcl_WaitPid (gravereaux,kupries) + +2006-03-14 (bug fix)[768659] pipeline error when last command missing (kupries) + +2006-03-18 (bug fix)[1193497] Win porting of [file writable] (darley,vogel) + +2006-03-28 (bug fix)[1064247] BSD: path normalization with realpath() (steffen) + +2006-03-28 (revert 2005-11-03 feature) Unicode console support (hobbs) + *** POTENTIAL INCOMPATIBILITY *** + +2006-04-03 (bug fix)[1462248] crash reading utf-8 chars spanning multiple +buffers at end of file (kraft,kupries) + +2006-04-04 (revert 2005-11-08)[1162286] [package ifneeded] warns (porter) + *** POTENTIAL INCOMPATIBILITY *** + +2006-04-05 (bug fix)[1464039] Tcl_GetIndexFromObj: empty key (fellows) + +2006-04-05 (bug fix) overdue dde, registry patchelevel increments (porter) +=> dde 1.2.4 +=> registry 1.1.4 + +2006-04-06 (bug fix)[1457515] TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING +removed (steffen) + +2006-04-11 (bug fix)[1458266] enter/enterstep trace interference (leunissen) + +--- Released 8.4.13, April 19, 2006 --- See ChangeLog for details --- + +2006-05-04 (bug fix)[1480509] srand() accept wide input (porter,afredd) + +2006-05-05 (bug fix)[1481986] interactive Tcl_Main blocks main loop (porter,lin) + +2006-05-13 (bug fix)[1482718] proc re-compile: preserve the previous +bytecode while references still on the stack (porter,ryazanov) + +2006-05-13 (bug fix)[943995] fixed [glob] on VFS (porter) + +2006-05-27 (bug fix)[923072] Darwin: made unthreaded CoreFoundation notifier +naked-fork safe on Tiger (steffen) + +2006-05-31 (revert 2006-01-09)[1400572] namespace inscope & info level (porter) + *** POTENTIAL INCOMPATIBILITY *** + +2006-06-14 (platform support)[1424909] MS VS2005 support (thoyts) + +2006-07-20 (platform support) Mac OS X weak linking (steffen) + +2006-07-20 (bug fix) Darwin: execve() works iff event loop not yet run (steffen) + +2006-08-18 (bug fix) intermittent failures in TclUnixWaitForFile() (steffen) + +2006-08-18 (platform support) Darwin x86_64 (steffen) + +2006-08-21 (bug fix)[1457797] Darwin 64-bit notifier hang (steffen) + +2006-08-21 (bug fix) Darwin: recursively called event loop (steffen) + +2006-08-30 (bug fix)[1548263] filesystem segfaults (hobbs,mccormack) + +2006-09-06 (bug fix)[999544] use of MT-safe system calls (vasiljevic) + +2006-09-10 (platform support) Darwin: msgcat use CFLocale (steffen) +=> msgcat 1.3.4 + +2006-09-22 (bug fix)[1562528] NULL terminates variadic calls (fellows,ryazanov) + +2006-09-26 (platform support) MSVC8 AMD64 support (thoyts) + +2006-10-05 (bug fix)[1570718] make [lappend $nonList] complain (sofer,virden) + +2006-10-05 (bug fix)[1122671] alignment fixes in unicode encoding routines +(hobbs,staplin) + +2006-10-05 (new feature) [set ::http::strict 1] (default value is 0) to enable +URL validity checking against RFC 2986 (hobbs) +=> http 2.5.3 + +--- Released 8.4.14, October 19, 2006 --- See ChangeLog for details --- + +2006-10-31 (platform support)[1582769] Fix build with VC2003 (thoyts) + +2006-11-07 (bug fix)[1586470] [file copy] on afs (kupries,dionizio) + +2006-11-26 (platform support)[1230558] --enable-64bit on more systems (steffen) + +2006-11-27 (bug fix)[1602208] use > 32 async sockets on 64bit system (fontaine) + +2007-01-25 (configure change) ensure CPPFLAGS env var used when set (steffen) + +2007-01-30 (enhancement) new target: `install-private-headers` (hobbs, steffen) + +2007-02-12 (bug fix)[1516109] escape encodings crossing chan buffers (dejong) + +2007-03-01 (bug fix)[1671138] compiled [foreach {} x {}] hangs (fellows) + +2007-03-10 (bug fix)[1675116] list shimmer crash in [lsort] (fellows) + +2007-03-13 (bug fix)[1671087] list shimmer crash in [foreach] (porter) + +2007-03-13 (bug fix)[1669489] list shimmer crash in [array set] (porter) + +2007-03-17 (bug fix)[1682211] buffer overflow in [registry keys] (kenny) +=> registry 1.1.5 + +2007-04-29 (bug fix) fts_open() crash on 64bit Darwin 8 or earlier (steffen) + +--- Released 8.4.15, May 25, 2007 --- See ChangeLog for details --- Index: compat/memcmp.c ================================================================== --- compat/memcmp.c +++ compat/memcmp.c @@ -46,15 +46,16 @@ memcmp(s1, s2, n) CONST VOID *s1; /* First string. */ CONST VOID *s2; /* Second string. */ size_t n; /* Length to compare. */ { - unsigned char u1, u2; + CONST unsigned char *ptr1 = (CONST unsigned char *) s1; + CONST unsigned char *ptr2 = (CONST unsigned char *) s2; - for ( ; n-- ; s1++, s2++) { - u1 = * (unsigned char *) s1; - u2 = * (unsigned char *) s2; + for ( ; n-- ; ptr1++, ptr2++) { + unsigned char u1 = *s1, u2 = *s2; + if ( u1 != u2) { return (u1-u2); } } return 0; Index: compat/strftime.c ================================================================== --- compat/strftime.c +++ compat/strftime.c @@ -8,11 +8,11 @@ * source. See the copyright notice below for details on redistribution * restrictions. The "license.terms" file does not apply to this file. * * Changes 2002 Copyright (c) 2002 ActiveState Corporation. * - * RCS: @(#) $Id: strftime.c,v 1.10 2002/05/29 00:19:39 hobbs Exp $ + * RCS: @(#) $Id: strftime.c,v 1.10.2.3 2005/11/04 18:18:04 kennykb Exp $ */ /* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. @@ -45,11 +45,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) -static char *rcsid = "$Id: strftime.c,v 1.10 2002/05/29 00:19:39 hobbs Exp $"; +static char *rcsid = "$Id: strftime.c,v 1.10.2.3 2005/11/04 18:18:04 kennykb Exp $"; #endif /* LIBC_SCCS */ #include #include #include @@ -111,10 +111,11 @@ static int _add _ANSI_ARGS_((const char* str)); static int _conv _ANSI_ARGS_((int n, int digits, int pad)); static int _secs _ANSI_ARGS_((const struct tm *t)); static size_t _fmt _ANSI_ARGS_((const char *format, const struct tm *t)); +static int ISO8601Week _ANSI_ARGS_((CONST struct tm* t, int *year )); size_t TclpStrftime(s, maxsize, format, t, useGMT) char *s; size_t maxsize; @@ -227,10 +228,28 @@ continue; case 'e': if (!_conv(t->tm_mday, 2, ' ')) return(0); continue; + case 'g': + { + int year; + ISO8601Week( t, &year ); + if ( !_conv( year%100, 2, '0' ) ) { + return( 0 ); + } + continue; + } + case 'G': + { + int year; + ISO8601Week( t, &year ); + if ( !_conv( year, 4, '0' ) ) { + return( 0 ); + } + continue; + } case 'H': if (!_conv(t->tm_hour, 2, '0')) return(0); continue; case 'I': @@ -299,29 +318,11 @@ if (!_conv(t->tm_wday ? t->tm_wday : 7, 1, '0')) return(0); continue; case 'V': { - /* ISO 8601 Week Of Year: - If the week (Monday - Sunday) containing - January 1 has four or more days in the new - year, then it is week 1; otherwise it is - week 53 of the previous year and the next - week is week one. */ - - int week = MON_WEEK(t); - - int days = (((t)->tm_yday + 7 - \ - ((t)->tm_wday ? (t)->tm_wday - 1 : 6)) % 7); - - - if (days >= 4) { - week++; - } else if (week == 0) { - week = 53; - } - + int week = ISO8601Week( t, NULL ); if (!_conv(week, 2, '0')) return(0); continue; } case 'W': @@ -336,28 +337,34 @@ /* * To properly handle the localized time routines on Windows, * we must make use of the special localized calls. */ case 'c': - if (!GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, - &syst, NULL, buf, BUF_SIZ) || !_add(buf) - || !_add(" ")) { + if (!GetDateFormat(LOCALE_USER_DEFAULT, + DATE_LONGDATE | LOCALE_USE_CP_ACP, + &syst, NULL, buf, BUF_SIZ) + || !_add(buf) + || !_add(" ")) { return(0); } /* * %c is created with LONGDATE + " " + TIME on Windows, * so continue to %X case here. */ case 'X': - if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, - &syst, NULL, buf, BUF_SIZ) || !_add(buf)) { + if (!GetTimeFormat(LOCALE_USER_DEFAULT, + LOCALE_USE_CP_ACP, + &syst, NULL, buf, BUF_SIZ) + || !_add(buf)) { return(0); } continue; case 'x': - if (!GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, - &syst, NULL, buf, BUF_SIZ) || !_add(buf)) { + if (!GetDateFormat(LOCALE_USER_DEFAULT, + DATE_SHORTDATE | LOCALE_USE_CP_ACP, + &syst, NULL, buf, BUF_SIZ) + || !_add(buf)) { return(0); } continue; #else case 'c': @@ -382,13 +389,15 @@ if (!_conv((t->tm_year + TM_YEAR_BASE), 4, '0')) return(0); continue; case 'Z': { char *name = (isGMT ? "GMT" : TclpGetTZName(t->tm_isdst)); - if (name && !_add(name)) { - return 0; - } + int wrote; + Tcl_UtfToExternal(NULL, NULL, name, -1, 0, NULL, + pt, gsize, NULL, &wrote, NULL); + pt += wrote; + gsize -= wrote; continue; } case '%': /* * X311J/88-090 (4.12.3.5): if conversion char is @@ -429,12 +438,18 @@ int pad; { static char buf[10]; register char *p; - for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits) - *p-- = (char)(n % 10 + '0'); + p = buf + sizeof( buf ) - 1; + *p-- = '\0'; + if ( n == 0 ) { + *p-- = '0'; --digits; + } else { + for (; n > 0 && p > buf; n /= 10, --digits) + *p-- = (char)(n % 10 + '0'); + } while (p > buf && digits-- > 0) *p-- = (char) pad; return(_add(++p)); } @@ -447,5 +462,60 @@ return(0); if (!(*pt = *str++)) return(1); } } + +static int +ISO8601Week( t, year ) + CONST struct tm* t; + int* year; +{ + /* Find the day-of-year of the Thursday in + * the week in question. */ + + int ydayThursday; + int week; + if ( t->tm_wday == 0 ) { + ydayThursday = t->tm_yday - 3; + } else { + ydayThursday = t->tm_yday - t->tm_wday + 4; + } + + if ( ydayThursday < 0 ) { + + /* This is the last week of the previous year. */ + if ( IsLeapYear(( t->tm_year + TM_YEAR_BASE - 1 )) ) { + ydayThursday += 366; + } else { + ydayThursday += 365; + } + week = ydayThursday / 7 + 1; + if ( year != NULL ) { + *year = t->tm_year + 1899; + } + + } else if ( ( IsLeapYear(( t -> tm_year + TM_YEAR_BASE )) + && ydayThursday >= 366 ) + || ( !IsLeapYear(( t -> tm_year + + TM_YEAR_BASE )) + && ydayThursday >= 365 ) ) { + + /* This is week 1 of the following year */ + + week = 1; + if ( year != NULL ) { + *year = t->tm_year + 1901; + } + + } else { + + week = ydayThursday / 7 + 1; + if ( year != NULL ) { + *year = t->tm_year + 1900; + } + + } + + return week; + +} Index: compat/string.h ================================================================== --- compat/string.h +++ compat/string.h @@ -7,11 +7,11 @@ * Copyright (c) 1994-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: string.h,v 1.4 2000/07/18 18:16:17 ericm Exp $ + * RCS: @(#) $Id: string.h,v 1.4.18.1 2005/04/26 00:46:02 das Exp $ */ #ifndef _STRING #define _STRING @@ -26,11 +26,15 @@ #ifndef MAC_TCL #include #endif +#ifdef __APPLE__ +extern VOID * memchr _ANSI_ARGS_((CONST VOID *s, int c, size_t n)); +#else extern char * memchr _ANSI_ARGS_((CONST VOID *s, int c, size_t n)); +#endif extern int memcmp _ANSI_ARGS_((CONST VOID *s1, CONST VOID *s2, size_t n)); extern char * memcpy _ANSI_ARGS_((VOID *t, CONST VOID *f, size_t n)); #ifdef NO_MEMMOVE #define memmove(d, s, n) bcopy ((s), (d), (n)) Index: compat/strstr.c ================================================================== --- compat/strstr.c +++ compat/strstr.c @@ -7,12 +7,17 @@ * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: strstr.c,v 1.3 2002/01/26 01:10:08 dgp Exp $ + * RCS: @(#) $Id: strstr.c,v 1.3.2.1 2005/04/12 18:28:56 kennykb Exp $ */ + +#include +#ifndef NULL +#define NULL 0 +#endif /* *---------------------------------------------------------------------- * * strstr -- Index: doc/AddErrInfo.3 ================================================================== --- doc/AddErrInfo.3 +++ doc/AddErrInfo.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: AddErrInfo.3,v 1.8 2002/07/01 18:24:38 jenglish Exp $ +'\" RCS: @(#) $Id: AddErrInfo.3,v 1.8.2.1 2003/07/18 16:56:24 dgp Exp $ '\" .so man.macros .TH Tcl_AddErrorInfo 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -58,11 +58,11 @@ .AP "CONST char" *script in Pointer to first character in script containing command (must be <= command) .AP "CONST char" *command in Pointer to first character in command that generated the error .AP int commandLength in -Number of bytes in command; -1 means use all bytes up to first NULL byte +Number of bytes in command; -1 means use all bytes up to first null byte .BE .SH DESCRIPTION .PP These procedures are used to manipulate two Tcl global variables Index: doc/AppInit.3 ================================================================== --- doc/AppInit.3 +++ doc/AppInit.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: AppInit.3,v 1.3 2000/04/14 23:01:48 hobbs Exp $ +'\" RCS: @(#) $Id: AppInit.3,v 1.3.24.1 2006/07/30 16:18:41 jenglish Exp $ '\" .so man.macros .TH Tcl_AppInit 3 7.0 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -32,11 +32,11 @@ modifying the main programs provided as part of Tcl and Tk. To create a new application you write a new version of \fBTcl_AppInit\fR to replace the default version provided by Tcl, then link your new \fBTcl_AppInit\fR with the Tcl library. .PP -\fBTcl_AppInit\fR is invoked after by \fBTcl_Main\fR and \fBTk_Main\fR +\fBTcl_AppInit\fR is invoked by \fBTcl_Main\fR and \fBTk_Main\fR after their own initialization and before entering the main loop to process commands. Here are some examples of things that \fBTcl_AppInit\fR might do: .IP [1] Call initialization procedures for various packages used by Index: doc/Async.3 ================================================================== --- doc/Async.3 +++ doc/Async.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: Async.3,v 1.5 2000/07/26 01:29:00 davidg Exp $ +'\" RCS: @(#) $Id: Async.3,v 1.5.18.1 2004/12/09 09:24:54 dkf Exp $ '\" .so man.macros .TH Tcl_AsyncCreate 3 7.0 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -60,15 +60,15 @@ occurred, then handle the event later when the world has returned to a clean state, such as after the current Tcl command completes. .PP \fBTcl_AsyncCreate\fR, \fBTcl_AsyncDelete\fR, and \fBTcl_AsyncReady\fR are thread sensitive. They access and/or set a thread-specific data -structure in the event of an --enable-thread built core. The token -created by Tcl_AsyncCreate contains the needed thread information it -was called from so that calling Tcl_AsyncMark(token) will only yield -the origin thread into the AsyncProc. -.PP +structure in the event of a core built with \fI\-\-enable\-threads\fR. The token +created by \fBTcl_AsyncCreate\fR contains the needed thread information it +was called from so that calling \fBTcl_AsyncMark\fR(\fItoken\fR) will only yield +the origin thread into the asynchronous handler. +.PP \fBTcl_AsyncCreate\fR creates an asynchronous handler and returns a token for it. The asynchronous handler must be created before any occurrences of the asynchronous event that it is intended to handle (it is not safe to create a handler at the time of @@ -83,13 +83,13 @@ the actions associated with the asynchronous event. \fIProc\fR should have arguments and result that match the type \fBTcl_AsyncProc\fR: .CS typedef int Tcl_AsyncProc( - ClientData \fIclientData\fR, - Tcl_Interp *\fIinterp\fR, - int \fIcode\fR); + ClientData \fIclientData\fR, + Tcl_Interp *\fIinterp\fR, + int \fIcode\fR); .CE The \fIclientData\fR will be the same as the \fIclientData\fR argument passed to \fBTcl_AsyncCreate\fR when the handler was created. If \fIproc\fR is invoked just after a command has completed Index: doc/ChnlStack.3 ================================================================== --- doc/ChnlStack.3 +++ doc/ChnlStack.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1999-2000 Ajuba Solutions. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: ChnlStack.3,v 1.4 2002/01/23 21:22:06 andreas_kupries Exp $ +'\" RCS: @(#) $Id: ChnlStack.3,v 1.4.4.1 2004/07/16 20:10:58 andreas_kupries Exp $ .so man.macros .TH Tcl_StackChannel 3 8.3 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME @@ -29,11 +29,11 @@ \fBTcl_GetTopChannel\fR(\fIchannel\fR) .sp .SH ARGUMENTS .AS Tcl_ChannelType .AP Tcl_Interp *interp in -Interpreter for error reporting - can be NULL. +Interpreter for error reporting. .AP Tcl_ChannelType *typePtr in The new channel I/O procedures to use for \fIchannel\fP. .AP ClientData clientData in Arbitrary one-word value to pass to channel I/O procedures. .AP int mask in Index: doc/CrtChannel.3 ================================================================== --- doc/CrtChannel.3 +++ doc/CrtChannel.3 @@ -3,17 +3,17 @@ '\" Copyright (c) 1997-2000 Ajuba Solutions. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: CrtChannel.3,v 1.16 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: CrtChannel.3,v 1.16.2.5 2005/10/05 20:35:45 andreas_kupries Exp $ .so man.macros -.TH Tcl_CreateChannel 3 8.3 Tcl "Tcl Library Procedures" +.TH Tcl_CreateChannel 3 8.4 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME -Tcl_CreateChannel, Tcl_GetChannelInstanceData, Tcl_GetChannelType, Tcl_GetChannelName, Tcl_GetChannelHandle, Tcl_GetChannelMode, Tcl_GetChannelBufferSize, Tcl_SetChannelBufferSize, Tcl_NotifyChannel, Tcl_BadChannelOption, Tcl_ChannelName, Tcl_ChannelVersion, Tcl_ChannelBlockModeProc, Tcl_ChannelCloseProc, Tcl_ChannelClose2Proc, Tcl_ChannelInputProc, Tcl_ChannelOutputProc, Tcl_ChannelSeekProc, Tcl_ChannelWideSeekProc, Tcl_ChannelSetOptionProc, Tcl_ChannelGetOptionProc, Tcl_ChannelWatchProc, Tcl_ChannelGetHandleProc, Tcl_ChannelFlushProc, Tcl_ChannelHandlerProc, Tcl_IsChannelShared, Tcl_IsChannelRegistered, Tcl_CutChannel, Tcl_SpliceChannel, Tcl_IsChannelExisting, Tcl_ClearChannelHandlers, Tcl_GetChannelThread, Tcl_ChannelBuffered \- procedures for creating and manipulating channels +Tcl_CreateChannel, Tcl_GetChannelInstanceData, Tcl_GetChannelType, Tcl_GetChannelName, Tcl_GetChannelHandle, Tcl_GetChannelMode, Tcl_GetChannelBufferSize, Tcl_SetChannelBufferSize, Tcl_NotifyChannel, Tcl_BadChannelOption, Tcl_ChannelName, Tcl_ChannelVersion, Tcl_ChannelBlockModeProc, Tcl_ChannelCloseProc, Tcl_ChannelClose2Proc, Tcl_ChannelInputProc, Tcl_ChannelOutputProc, Tcl_ChannelSeekProc, Tcl_ChannelWideSeekProc, Tcl_ChannelSetOptionProc, Tcl_ChannelGetOptionProc, Tcl_ChannelWatchProc, Tcl_ChannelGetHandleProc, Tcl_ChannelFlushProc, Tcl_ChannelHandlerProc, Tcl_ChannelThreadActionProc, Tcl_IsChannelShared, Tcl_IsChannelRegistered, Tcl_CutChannel, Tcl_SpliceChannel, Tcl_IsChannelExisting, Tcl_ClearChannelHandlers, Tcl_GetChannelThread, Tcl_ChannelBuffered \- procedures for creating and manipulating channels .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Channel @@ -34,10 +34,13 @@ .VS 8.4 Tcl_ThreadId \fBTcl_GetChannelThread\fR(\fIchannel\fR) .VE 8.4 .sp +int +\fBTcl_GetChannelMode\fR(\fIchannel\fR) +.sp int \fBTcl_GetChannelBufferSize\fR(\fIchannel\fR) .sp \fBTcl_SetChannelBufferSize\fR(\fIchannel, size\fR) .sp @@ -94,10 +97,13 @@ \fBTcl_ChannelSeekProc\fR(\fItypePtr\fR) .sp .VS 8.4 Tcl_DriverWideSeekProc * \fBTcl_ChannelWideSeekProc\fR(\fItypePtr\fR) +.sp +Tcl_DriverThreadActionProc * +\fBTcl_ChannelThreadActionProc\fR(\fItypePtr\fR) .VE 8.4 .sp Tcl_DriverSetOptionProc * \fBTcl_ChannelSetOptionProc\fR(\fItypePtr\fR) .sp @@ -230,12 +236,12 @@ location specified by \fIhandlePtr\fR and returns \fBTCL_OK\fR. If the channel does not have a device handle for the specified direction, then \fBTCL_ERROR\fR is returned instead. Different channel drivers will return different types of handle. Refer to the manual entries for each driver to determine what type of handle is returned. +.PP .VS 8.4 -.PP \fBTcl_GetChannelThread\fR returns the id of the thread currently managing the specified \fIchannel\fR. This allows channel drivers to send their file events to the correct event queue even for a multi-threaded core. .VE 8.4 .PP @@ -284,14 +290,24 @@ .PP \fBTcl_CutChannel\fR removes the specified \fIchannel\fR from the (thread)global list of all channels (of the current thread). Application to a channel still registered in some interpreter is not allowed. +.VS 8.4 +Also notifies the driver if the \fBTcl_ChannelType\fR version is +\fBTCL_CHANNEL_VERSION_4\fR (or higher), and +\fBTcl_DriverThreadActionProc\fR is defined for it. +.VE 8.4 .PP \fBTcl_SpliceChannel\fR adds the specified \fIchannel\fR to the (thread)global list of all channels (of the current thread). Application to a channel registered in some interpreter is not allowed. +.VS 8.4 +Also notifies the driver if the \fBTcl_ChannelType\fR version is +\fBTCL_CHANNEL_VERSION_4\fR (or higher), and +\fBTcl_DriverThreadActionProc\fR is defined for it. +.VE 8.4 .PP \fBTcl_ClearChannelHandlers\fR removes all channelhandlers and event scripts associated with the specified \fIchannel\fR, thus shutting down all event processing for this channel. .VE 8.4 @@ -321,20 +337,23 @@ Tcl_DriverClose2Proc *\fIclose2Proc\fR; Tcl_DriverBlockModeProc *\fIblockModeProc\fR; Tcl_DriverFlushProc *\fIflushProc\fR; Tcl_DriverHandlerProc *\fIhandlerProc\fR; Tcl_DriverWideSeekProc *\fIwideSeekProc\fR; + Tcl_DriverThreadActionProc *\fIthreadActionProc\fR; } Tcl_ChannelType; .CE .PP -The driver must provide implementations for all functions except -\fIblockModeProc\fR, \fIseekProc\fR, \fIsetOptionProc\fR, -\fIgetOptionProc\fR, and \fIclose2Proc\fR, which may be specified as -NULL. Other functions that can not be implemented for this type of -device should return \fBEINVAL\fR when invoked to indicate that they -are not implemented, except in the case of \fIflushProc\fR and -\fIhandlerProc\fR, which should specified as NULL if not otherwise defined. +It is not necessary to provide implementations for all channel +operations. Those which are not necessary may be set to NULL in the +struct: \fIblockModeProc\fR, \fIseekProc\fR, \fIsetOptionProc\fR, +\fIgetOptionProc\fR, and \fIclose2Proc\fR, in addition to +\fIflushProc\fR, \fIhandlerProc\fR, and \fIthreadActionProc\fR. Other +functions that cannot be implemented in a meaningful way should return +\fBEINVAL\fR when called, to indicate that the operations they +represent are not available. Also note that \fIwideSeekProc\fR can be +NULL if \fIseekProc\fR is. .PP The user should only use the above structure for \fBTcl_ChannelType\fR instantiation. When referencing fields in a \fBTcl_ChannelType\fR structure, the following functions should be used to obtain the values: \fBTcl_ChannelName\fR, \fBTcl_ChannelVersion\fR, @@ -341,10 +360,11 @@ \fBTcl_ChannelBlockModeProc\fR, \fBTcl_ChannelCloseProc\fR, \fBTcl_ChannelClose2Proc\fR, \fBTcl_ChannelInputProc\fR, \fBTcl_ChannelOutputProc\fR, \fBTcl_ChannelSeekProc\fR, .VS 8.4 \fBTcl_ChannelWideSeekProc\fR, +\fBTcl_ChannelThreadActionProc\fR, .VE 8.4 \fBTcl_ChannelSetOptionProc\fR, \fBTcl_ChannelGetOptionProc\fR, \fBTcl_ChannelWatchProc\fR, \fBTcl_ChannelGetHandleProc\fR, \fBTcl_ChannelFlushProc\fR, or \fBTcl_ChannelHandlerProc\fR. .PP @@ -362,22 +382,31 @@ This value can be retrieved with \fBTcl_ChannelName\fR, which returns a pointer to the string. .SH VERSION .PP -The \fIversion\fR field should be set to \fBTCL_CHANNEL_VERSION_2\fR. -If it is not set to this value \fBTCL_CHANNEL_VERSION_3\fR, then this -\fBTcl_ChannelType\fR is assumed to have the older structure. See + +The \fIversion\fR field should be set to the version of the structure +that you require. \fBTCL_CHANNEL_VERSION_2\fR is the minimum recommended. +.VS 8.4 +\fBTCL_CHANNEL_VERSION_3\fR must be set to specifiy the \fIwideSeekProc\fR member. +.VE 8.4 +.VS 8.4 +\fBTCL_CHANNEL_VERSION_4\fR must be set to specifiy the +\fIthreadActionProc\fR member (includes \fIwideSeekProc\fR). +.VE 8.4 +If it is not set to any of these, then this +\fBTcl_ChannelType\fR is assumed to have the original structure. See \fBOLD CHANNEL TYPES\fR for more details. While Tcl will recognize -and function with either structure, stacked channels must be of at +and function with either structures, stacked channels must be of at least \fBTCL_CHANNEL_VERSION_2\fR to function correctly. .PP This value can be retrieved with \fBTcl_ChannelVersion\fR, which returns .VS 8.4 -one of \fBTCL_CHANNEL_VERSION_3\fR, +one of \fBTCL_CHANNEL_VERSION_4\fR, \fBTCL_CHANNEL_VERSION_3\fR, .VE 8.4 -\fBTCL_CHANNEL_VERSION_2\fR or \fBTCL_CHANNEL_VERSION_1\fR. +\fBTCL_CHANNEL_VERSION_2\fR, or \fBTCL_CHANNEL_VERSION_1\fR. .SH BLOCKMODEPROC .PP The \fIblockModeProc\fR field contains the address of a function called by the generic layer to set blocking and nonblocking mode on the device. @@ -403,10 +432,18 @@ implemented by the underlying operating system; for other device types, the behavior must be emulated in the channel driver. .PP This value can be retrieved with \fBTcl_ChannelBlockModeProc\fR, which returns a pointer to the function. +.PP +A channel driver \fBnot\fR supplying a \fIblockModeProc\fR has to be +very, very careful. It has to tell the generic layer exactly which +blocking mode is acceptable to it, and should this also document for +the user so that the blocking mode of the channel is not changed to an +inacceptable value. Any confusion here may lead the interpreter into a +(spurious and difficult to find) deadlock. + .SH "CLOSEPROC AND CLOSE2PROC" .PP The \fIcloseProc\fR field contains the address of a function called by the generic layer to clean up driver-related information when the channel is @@ -776,10 +813,39 @@ combination of \fBTCL_READABLE\fR or \fBTCL_WRITABLE\fR; it indicates what type of event occurred on this channel. .PP This value can be retrieved with \fBTcl_ChannelHandlerProc\fR, which returns a pointer to the function. + +.VS 8.4 +.SH "THREADACTIONPROC" +.PP +The \fIthreadActionProc\fR field contains the address of the function +called by the generic layer when a channel is created, closed, or +going to move to a different thread, i.e. whenever thread-specific +driver state might have to initialized or updated. It can be NULL. +The action \fITCL_CHANNEL_THREAD_REMOVE\fR is used to notify the +driver that it should update or remove any thread-specific data it +might be maintaining for the channel. +.PP +The action \fITCL_CHANNEL_THREAD_INSERT\fR is used to notify the +driver that it should update or initialize any thread-specific data it +might be maintaining using the calling thread as the associate. See +\fBTcl_CutChannel\fR and \fBTcl_SpliceChannel\fR for more detail. +.PP +.CS +typedef void Tcl_DriverThreadActionProc( + ClientData \fIinstanceData\fR, + int \fIaction\fR); +.CE +.PP +\fIInstanceData\fR is the same as the value passed to +\fBTcl_CreateChannel\fR when this channel was created. +.PP +These values can be retrieved with \fBTcl_ChannelThreadActionProc\fR, +which returns a pointer to the function. +.VE 8.4 .SH TCL_BADCHANNELOPTION .PP This procedure generates a "bad option" error message in an (optional) interpreter. It is used by channel drivers when Index: doc/CrtCommand.3 ================================================================== --- doc/CrtCommand.3 +++ doc/CrtCommand.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: CrtCommand.3,v 1.5 2002/08/05 03:24:39 dgp Exp $ +'\" RCS: @(#) $Id: CrtCommand.3,v 1.5.2.1 2004/07/16 20:46:52 andreas_kupries Exp $ '\" .so man.macros .TH Tcl_CreateCommand 3 "" Tcl "Tcl Library Procedures" .BS .SH NAME @@ -100,10 +100,15 @@ .VS Note that the argument strings should not be modified as they may point to constant strings or may be shared with other parts of the interpreter. .VE +.PP +.VS +Note that the argument strings are encoded in normalized UTF-8 since +version 8.1 of Tcl. +.VE .PP \fIProc\fR must return an integer code that is either \fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR. See the Tcl overview man page for details on what these codes mean. Most normal commands will only return \fBTCL_OK\fR or \fBTCL_ERROR\fR. In addition, \fIproc\fR must set Index: doc/CrtMathFnc.3 ================================================================== --- doc/CrtMathFnc.3 +++ doc/CrtMathFnc.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: CrtMathFnc.3,v 1.5 2001/05/30 08:57:05 dkf Exp $ +'\" RCS: @(#) $Id: CrtMathFnc.3,v 1.5.14.2 2003/04/16 22:26:16 dkf Exp $ '\" .so man.macros .TH Tcl_CreateMathFunc 3 8.4 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -44,15 +44,15 @@ .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR when it is invoked. .AP int *numArgsPtr out Points to a variable that will be set to contain the number of arguments to the function. -.AP Tcl_ValueType *argTypesPtr out +.AP Tcl_ValueType **argTypesPtr out Points to a variable that will be set to contain a pointer to an array giving the permissible types for each argument to the function which will need to be freed up using \fITcl_Free\fR. -.AP Tcl_MathProc *procPtr out +.AP Tcl_MathProc **procPtr out Points to a variable that will be set to contain a pointer to the implementation code for the function (or NULL if the function is implemented directly in bytecode.) .AP ClientData *clientDataPtr out Points to a variable that will be set to contain the clientData @@ -71,13 +71,17 @@ to those already provided by Tcl or to replace existing functions. \fIName\fR is the name of the function as it will appear in expressions. If \fIname\fR doesn't already exist as a function then a new function is created. If it does exist, then the existing function is replaced. \fINumArgs\fR and \fIargTypes\fR describe the arguments to the function. -Each entry in the \fIargTypes\fR array must be either TCL_INT, TCL_DOUBLE, +Each entry in the \fIargTypes\fR array must be +.VS 8.4 +one of TCL_INT, TCL_DOUBLE, TCL_WIDE_INT, or TCL_EITHER to indicate whether the corresponding argument must be an -integer, a double-precision floating value, or either, respectively. +integer, a double-precision floating value, a wide (64-bit) integer, +or any, respectively. +.VE 8.4 .PP Whenever the function is invoked in an expression Tcl will invoke \fIproc\fR. \fIProc\fR should have arguments and result that match the type \fBTcl_MathProc\fR: .CS @@ -90,31 +94,40 @@ .PP When \fIproc\fR is invoked the \fIclientData\fR and \fIinterp\fR arguments will be the same as those passed to \fBTcl_CreateMathFunc\fR. \fIArgs\fR will point to an array of \fInumArgs\fR Tcl_Value structures, which describe the actual arguments to the function: +.VS 8.4 .CS typedef struct Tcl_Value { Tcl_ValueType \fItype\fR; long \fIintValue\fR; double \fIdoubleValue\fR; + Tcl_WideInt \fIwideValue\fR; } Tcl_Value; .CE .PP The \fItype\fR field indicates the type of the argument and is -either TCL_INT or TCL_DOUBLE. +one of TCL_INT, TCL_DOUBLE or TCL_WIDE_INT. +.VE 8.4 It will match the \fIargTypes\fR value specified for the function unless the \fIargTypes\fR value was TCL_EITHER. Tcl converts the argument supplied in the expression to the type requested in \fIargTypes\fR, if that is necessary. -Depending on the value of the \fItype\fR field, the \fIintValue\fR -or \fIdoubleValue\fR field will contain the actual value of the argument. +Depending on the value of the \fItype\fR field, the \fIintValue\fR, +.VS 8.4 +\fIdoubleValue\fR or \fIwideValue\fR +.VE 8.4 +field will contain the actual value of the argument. .PP \fIProc\fR should compute its result and store it either as an integer in \fIresultPtr->intValue\fR or as a floating value in \fIresultPtr->doubleValue\fR. -It should set also \fIresultPtr->type\fR to either TCL_INT or TCL_DOUBLE +It should set also \fIresultPtr->type\fR to one of +.VS 8.4 +TCL_INT, TCL_DOUBLE or TCL_WIDE_INT +.VE 8.4 to indicate which value was set. Under normal circumstances \fIproc\fR should return TCL_OK. If an error occurs while executing the function, \fIproc\fR should return TCL_ERROR and leave an error message in the interpreter's result. .PP Index: doc/CrtObjCmd.3 ================================================================== --- doc/CrtObjCmd.3 +++ doc/CrtObjCmd.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: CrtObjCmd.3,v 1.7 2002/05/17 00:26:53 jenglish Exp $ +'\" RCS: @(#) $Id: CrtObjCmd.3,v 1.7.2.1 2004/05/05 20:54:47 dkf Exp $ '\" .so man.macros .TH Tcl_CreateObjCommand 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -273,11 +273,11 @@ command's deletion procedure to be given a different value than the ClientData for its command procedure. .PP Note that neither \fBTcl_SetCommandInfo\fR nor \fBTcl_SetCommandInfoFromToken\fR will change a command's namespace. -You must use \fBTcl_RenameCommand\fR to do that. +Use \fBTcl_Eval\fR to call the \fBrename\fR command to do that. .PP \fBTcl_GetCommandName\fR provides a mechanism for tracking commands that have been renamed. Given a token returned by \fBTcl_CreateObjCommand\fR when the command was created, \fBTcl_GetCommandName\fR returns the Index: doc/CrtSlave.3 ================================================================== --- doc/CrtSlave.3 +++ doc/CrtSlave.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: CrtSlave.3,v 1.8 2002/08/05 03:24:39 dgp Exp $ +'\" RCS: @(#) $Id: CrtSlave.3,v 1.8.2.2 2003/07/18 15:20:51 dgp Exp $ '\" .so man.macros .TH Tcl_CreateSlave 3 7.6 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -138,14 +138,19 @@ .PP \fBTcl_IsSafe\fR returns \fB1\fR if \fIinterp\fR is ``safe'' (was created with the \fBTCL_SAFE_INTERPRETER\fR flag specified), \fB0\fR otherwise. .PP -\fBTcl_MakeSafe\fR makes \fIinterp\fR ``safe'' by removing all -non-core and core unsafe functionality. Note that if you call this after -adding some extension to an interpreter, all traces of that extension will -be removed from the interpreter. +\fBTcl_MakeSafe\fR marks \fIinterp\fR as ``safe'', so that future +calls to \fBTcl_IsSafe\fR will return 1. It also removes all known +potentially-unsafe core functionality (both commands and variables) +from \fIinterp\fR. However, it cannot know what parts of an extension +or application are safe and does not make any attempt to remove those +parts, so safety is not guaranteed after calling \fBTcl_MakeSafe\fR. +Callers will want to take care with their use of \fBTcl_MakeSafe\fR +to avoid false claims of safety. For many situations, \fBTcl_CreateSlave\fR +may be a better choice, since it creates interpreters in a known-safe state. .PP \fBTcl_GetSlave\fR returns a pointer to a slave interpreter of \fIinterp\fR. The slave interpreter is identified by \fIslaveName\fR. If no such slave interpreter exists, \fBNULL\fR is returned. .PP Index: doc/CrtTrace.3 ================================================================== --- doc/CrtTrace.3 +++ doc/CrtTrace.3 @@ -4,11 +4,11 @@ '\" Copyright (c) 2002 by Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: CrtTrace.3,v 1.6 2002/08/05 03:24:39 dgp Exp $ +'\" RCS: @(#) $Id: CrtTrace.3,v 1.6.2.1 2003/07/18 15:20:51 dgp Exp $ '\" .so man.macros .TH Tcl_CreateTrace 3 "" Tcl "Tcl Library Procedures" .BS .SH NAME @@ -45,11 +45,11 @@ details on the calling sequence. .AP ClientData clientData in Arbitrary one-word value to pass to \fIobjProc\fR or \fIproc\fR. .AP Tcl_CmdObjTraceDeleteProc *deleteProc Procedure to call when the trace is deleted. See below for details of -the calling sequence. A null pointer is permissible and results in no +the calling sequence. A NULL pointer is permissible and results in no callback when the trace is deleted. .AP Tcl_Trace trace in Token for trace to be removed (return value from previous call to \fBTcl_CreateTrace\fR). .BE Index: doc/Encoding.3 ================================================================== --- doc/Encoding.3 +++ doc/Encoding.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1997-1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: Encoding.3,v 1.11 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: Encoding.3,v 1.11.2.1 2003/07/18 16:56:24 dgp Exp $ '\" .so man.macros .TH Tcl_GetEncoding 3 "8.1" Tcl "Tcl Library Procedures" .BS .SH NAME @@ -172,11 +172,11 @@ \fBTcl_FreeEncoding\fR will release all storage the encoding was using and delete it from the database. .PP \fBTcl_ExternalToUtfDString\fR converts a source buffer \fIsrc\fR from the specified \fIencoding\fR into UTF-8. The converted bytes are stored in -\fIdstPtr\fR, which is then NULL terminated. The caller should eventually +\fIdstPtr\fR, which is then null-terminated. The caller should eventually call \fBTcl_DStringFree\fR to free any information stored in \fIdstPtr\fR. When converting, if any of the characters in the source buffer cannot be represented in the target encoding, a default fallback character will be used. The return value is a pointer to the value stored in the DString. .PP @@ -210,11 +210,11 @@ .RE .LP \fBTcl_UtfToExternalDString\fR converts a source buffer \fIsrc\fR from UTF-8 into the specified \fIencoding\fR. The converted bytes are stored in \fIdstPtr\fR, which is then terminated with the appropriate encoding-specific -NULL. The caller should eventually call \fBTcl_DStringFree\fR to free any +null. The caller should eventually call \fBTcl_DStringFree\fR to free any information stored in \fIdstPtr\fR. When converting, if any of the characters in the source buffer cannot be represented in the target encoding, a default fallback character will be used. The return value is a pointer to the value stored in the DString. .PP Index: doc/Environment.3 ================================================================== --- doc/Environment.3 +++ doc/Environment.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1997-1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: Environment.3,v 1.1 2001/04/04 21:32:18 andreas_kupries Exp $ +'\" RCS: @(#) $Id: Environment.3,v 1.1.18.1 2005/05/03 17:53:41 dgp Exp $ '\" .so man.macros .TH Tcl_PutEnv 3 "7.5" Tcl "Tcl Library Procedures" .BS .SH NAME @@ -17,12 +17,12 @@ .sp int \fBTcl_PutEnv\fR(\fIstring\fR) .SH ARGUMENTS .AP "CONST char" *string in -Info about environment variable in the form NAME=value. The string is -in native format. +Info about environment variable in the form NAME=value. +The \fIstring\fR argument is in the system encoding. .BE .SH DESCRIPTION .PP \fBTcl_PutEnv\fR sets an environment variable. The information is Index: doc/Eval.3 ================================================================== --- doc/Eval.3 +++ doc/Eval.3 @@ -4,11 +4,11 @@ '\" Copyright (c) 2000 Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: Eval.3,v 1.12 2002/08/05 03:24:39 dgp Exp $ +'\" RCS: @(#) $Id: Eval.3,v 1.12.2.3 2003/07/18 16:56:24 dgp Exp $ '\" .so man.macros .TH Tcl_Eval 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -35,11 +35,11 @@ .sp int \fBTcl_GlobalEval\fR(\fIinterp, script\fR) .sp int -\fBTcl_GlobalEvalObj\fR(\fIinterp, objPtr, flags\fR) +\fBTcl_GlobalEvalObj\fR(\fIinterp, objPtr\fR) .sp int \fBTcl_VarEval\fR(\fIinterp, string, string, ... \fB(char *) NULL\fR) .sp int @@ -65,11 +65,11 @@ .AP int numBytes in The number of bytes in \fIscript\fR, not including any null terminating character. If \-1, then all characters up to the first null byte are used. .AP "CONST char" *script in -Points to first byte of script to execute (NULL terminated and UTF-8). +Points to first byte of script to execute (null-terminated and UTF-8). .AP char *string in String forming part of a Tcl script. .AP va_list argList in An argument list which must have been initialised using \fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. @@ -89,11 +89,12 @@ can be skipped if the object 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 one of the values \fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, -\fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR. +\fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR, or possibly some other +integer value originating in an extension. In addition, a result value or error message is left in \fIinterp\fR's result; it can be retrieved using \fBTcl_GetObjResult\fR. .PP \fBTcl_EvalFile\fR reads the file given by \fIfileName\fR and evaluates its contents as a Tcl script. It returns the same information as Index: doc/ExprLong.3 ================================================================== --- doc/ExprLong.3 +++ doc/ExprLong.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: ExprLong.3,v 1.6 2002/08/05 03:24:39 dgp Exp $ +'\" RCS: @(#) $Id: ExprLong.3,v 1.6.2.1 2005/05/03 17:53:41 dgp Exp $ '\" .so man.macros .TH Tcl_ExprLong 3 7.0 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -28,11 +28,11 @@ int \fBTcl_ExprString\fR(\fIinterp, string\fR) .SH ARGUMENTS .AS Tcl_Interp *booleanPtr .AP Tcl_Interp *interp in -Interpreter in whose context to evaluate \fIstring\fR or \fIobjPtr\fR. +Interpreter in whose context to evaluate \fIstring\fR. .VS 8.4 .AP "CONST char" *string in .VE Expression to be evaluated. .AP long *longPtr out @@ -96,17 +96,11 @@ it must be one of the values accepted by \fBTcl_GetBoolean\fR such as ``yes'' or ``no'', or else an error occurs. .PP \fBTcl_ExprString\fR returns the value of the expression as a string stored in the interpreter's result. -If the expression's actual value is an integer -then \fBTcl_ExprString\fR converts it to a string using \fBsprintf\fR -with a ``%d'' converter. -If the expression's actual value is a floating-point -number, then \fBTcl_ExprString\fR calls \fBTcl_PrintDouble\fR -to convert it to a string. .SH "SEE ALSO" Tcl_ExprLongObj, Tcl_ExprDoubleObj, Tcl_ExprBooleanObj, Tcl_ExprObj .SH KEYWORDS boolean, double, evaluate, expression, integer, object, string Index: doc/ExprLongObj.3 ================================================================== --- doc/ExprLongObj.3 +++ doc/ExprLongObj.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: ExprLongObj.3,v 1.3 2001/09/03 09:38:50 dkf Exp $ +'\" RCS: @(#) $Id: ExprLongObj.3,v 1.3.12.1 2005/05/03 17:53:41 dgp Exp $ '\" .so man.macros .TH Tcl_ExprLongObj 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -27,11 +27,11 @@ int \fBTcl_ExprObj\fR(\fIinterp, objPtr, resultPtrPtr\fR) .SH ARGUMENTS .AS Tcl_Interp **resultPtrPtr out .AP Tcl_Interp *interp in -Interpreter in whose context to evaluate \fIstring\fR or \fIobjPtr\fR. +Interpreter in whose context to evaluate \fIobjPtr\fR. .AP Tcl_Obj *objPtr in Pointer to an object containing the expression to evaluate. .AP long *longPtr out Pointer to location in which to store the integer value of the expression. Index: doc/FileSystem.3 ================================================================== --- doc/FileSystem.3 +++ doc/FileSystem.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 2001 Vincent Darley '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: FileSystem.3,v 1.32 2003/02/10 12:50:31 vincentdarley Exp $ +'\" RCS: @(#) $Id: FileSystem.3,v 1.32.2.4 2005/06/20 16:57:43 dgp Exp $ '\" .so man.macros .TH Filesystem 3 8.4 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -56,11 +56,12 @@ .sp int \fBTcl_FSEvalFile\fR(\fIinterp, pathPtr\fR) .sp int -\fBTcl_FSLoadFile\fR(\fIinterp, pathPtr, sym1, sym2, proc1Ptr, proc2Ptr, handlePtr, unloadProcPtr\fR) +\fBTcl_FSLoadFile\fR(\fIinterp, pathPtr, sym1, sym2, proc1Ptr, proc2Ptr, + handlePtr, unloadProcPtr\fR) .sp int \fBTcl_FSMatchInDirectory\fR(\fIinterp, result, pathPtr, pattern, types\fR) .sp Tcl_Obj* @@ -198,10 +199,12 @@ Name of a procedure to look up in the file's symbol table .AP Tcl_PackageInitProc **proc1Ptr out Filled with the init function for this code. .AP Tcl_PackageInitProc **proc2Ptr out Filled with the safe-init function for this code. +.AP Tcl_LoadHandle *handlePtr out +Filled with an abstract token representing the loaded file. .AP ClientData *clientDataPtr out Filled with the clientData value to pass to this code's unload function when it is called. .AP TclfsUnloadFileProc_ **unloadProcPtr out Filled with the function to use to unload this piece of code. @@ -544,18 +547,26 @@ not require additional conversions. .PP \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 returned. Otherwise NULL will be returned, and an error message may -be left in the interpreter. A "translated" path is one which -contains no "~" or "~user" sequences (these have been expanded to -their current representation in the filesystem). +If the translation succeeds (i.e. the object is a valid path), then it is +returned. Otherwise NULL will be returned, and an error message may be +left in the interpreter. A "translated" path is one which contains no +"~" or "~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 +freed. This function is of little practical use, and +\fBTcl_FSGetNormalizedPath\fR or \fBTcl_GetNativePath\fR are usually +better functions to use for most purposes. .PP -\fBTcl_FSGetTranslatedStringPath\fR does the same as +\fBTcl_FSGetTranslatedStringPath\fR does the same as \fBTcl_FSGetTranslatedPath\fR, but returns a character string or NULL. +The string returned is dynamically allocated and owned by the caller, +which must store it or call ckfree to ensure it is freed. Again, +\fBTcl_FSGetNormalizedPath\fR or \fBTcl_GetNativePath\fR are usually +better functions to use for most purposes. .PP \fBTcl_FSNewNativePath\fR performs something like that reverse of the usual obj->path->nativerep conversions. If some code retrieves a path in native form (from, e.g. readlink or a native dialog), and that path is to be used at the Tcl level, then calling this function is an @@ -777,22 +788,22 @@ handling of path representations, for example copying and freeing such representations. .SH 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 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, \fBTCL_ERROR\fR should be -returned. If \fBTCL_OK\fR is returned, then the optional -\fBclientDataPtr\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 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 Tcl's internal list of -known filesystems. +which is called to determine whether a given path object 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 behaviour of Tcl +for any other return value is not defined). If \fBTCL_OK\fR is returned, +then the optional \fBclientDataPtr\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 +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 +Tcl's internal list of known filesystems. .PP .CS typedef int Tcl_FSPathInFilesystemProc( Tcl_Obj *\fIpathPtr\fR, ClientData *\fIclientDataPtr\fR); @@ -1014,19 +1025,47 @@ assumed to be both non-NULL and non-empty. It is not currently documented whether \fIpathPtr\fR will have a file separator at its end of not, so code should be flexible to both possibilities. .PP The return value is a standard Tcl result indicating whether an error -occurred in the matching process. Error messages are placed in interp, -but on a TCL_OK result, the interpreter should not be modified, but -rather results should be added to the \fIresult\fR object given -(which can be assumed to be a valid Tcl list). The matches added +occurred in the matching process. Error messages are placed in +\fIinterp\fR; on a \fBTCL_OK\fR result, results should be added to the +\fIresult\fR object given (which can be assumed to be a valid +unshared Tcl list). The matches added to \fIresult\fR should include any path prefix given in \fIpathPtr\fR (this usually means they will be absolute path specifications). Note that if no matches are found, that simply leads to an empty -result --- errors are only signaled for actual file or filesystem +result; errors are only signaled for actual file or filesystem problems which may occur during the matching process. +.PP +The \fBTcl_GlobTypeData\fR structure passed in the \fItypes\fR +parameter contains the following fields: +.CS +typedef struct Tcl_GlobTypeData { + /* Corresponds to bcdpfls as in 'find -t' */ + int \fItype\fR; + /* Corresponds to file permissions */ + int \fIperm\fR; + /* Acceptable mac type */ + Tcl_Obj *\fImacType\fR; + /* Acceptable mac creator */ + Tcl_Obj *\fImacCreator\fR; +} Tcl_GlobTypeData; +.CE +.PP +There are two specific cases which it is important to handle correctly, +both when \fItypes\fR is non-NULL. The two cases are when \fItypes->types +& TCL_GLOB_TYPE_DIR\fR or \fItypes->types & TCL_GLOB_TYPE_MOUNT\fR are +true (and in particular when the other flags are false). In the first of +these cases, the function must list the contained directories. Tcl uses +this to implement recursive globbing, so it is critical that filesystems +implement directory matching correctly. In the second of these cases, +with \fBTCL_GLOB_TYPE_MOUNT\fR, the filesystem must list the mount points +which lie within the given \fIpathPtr\fR (and in this case, \fIpathPtr\fR +need not lie within the same filesystem - different to all other cases in +which this function is called). Support for this is critical if Tcl is +to have seamless transitions between from one filesystem to another. .SH UTIMEPROC .PP Function to process a \fBTcl_FSUtime()\fR call. Required to allow setting (not reading) of times with 'file mtime', 'file atime' and the open-r/open-w/fcopy implementation of 'file copy'. Index: doc/GetIndex.3 ================================================================== --- doc/GetIndex.3 +++ doc/GetIndex.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: GetIndex.3,v 1.10 2002/02/28 05:11:25 dgp Exp $ +'\" RCS: @(#) $Id: GetIndex.3,v 1.10.2.2 2006/04/06 18:57:24 dgp Exp $ '\" .so man.macros .TH Tcl_GetIndexFromObj 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -32,15 +32,15 @@ .AP Tcl_Obj *objPtr in/out The string value of this object is used to search through \fItablePtr\fR. The internal representation is modified to hold the index of the matching table entry. .AP "CONST char" **tablePtr in -An array of null-terminated ASCII strings. The end of the array is marked +An array of null-terminated strings. The end of the array is marked by a NULL string pointer. .AP "CONST VOID" *structTablePtr in An array of arbitrary type, typically some \fBstruct\fP type. -The first member of the structure must be a null-terminated ASCII string. +The first member of the structure must be a null-terminated string. The size of the structure is given by \fIoffset\fP. .VS .AP int offset in The offset to add to structTablePtr to get to the next entry. The end of the array is marked by a NULL string pointer. @@ -62,11 +62,11 @@ switch names, option names, and similar things where the value of an object must be one of a predefined set of values. \fIObjPtr\fR is compared 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 -\fItablePtr\fR, or if it is a unique abbreviation +\fItablePtr\fR, or if it is a non-empty unique abbreviation for exactly one of the strings in \fItablePtr\fR and the \fBTCL_EXACT\fR flag was not specified; in either case the index of the matching entry is stored at \fI*indexPtr\fR and TCL_OK is returned. .PP Index: doc/GetStdChan.3 ================================================================== --- doc/GetStdChan.3 +++ doc/GetStdChan.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1996 by Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: GetStdChan.3,v 1.4 2001/12/10 15:50:46 dgp Exp $ +'\" RCS: @(#) $Id: GetStdChan.3,v 1.4.4.1 2006/06/06 20:07:36 dgp Exp $ '\" .so man.macros .TH Tcl_GetStdChannel 3 7.5 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -50,10 +50,20 @@ A new channel can be set for the standard channel specified by \fItype\fR by calling \fBTcl_SetStdChannel\fR with a new channel or NULL in the \fIchannel\fR argument. If the specified channel is closed by a later call to \fBTcl_Close\fR, then the corresponding standard channel will automatically be set to NULL. +.PP +If a non-NULL value for \fIchannel\fR is passed to \fBTcl_SetStdChannel\fR, +then that same value should be passed to \fBTcl_RegisterChannel\fR, like so: +.CS +Tcl_RegisterChannel(NULL, channel); +.CE +This is a workaround for a misfeature in \fBTcl_SetStdChannel\fR that it +fails to do some reference counting housekeeping. This misfeature cannot +be corrected without contradicting the assumptions of some existing +code that calls \fBTcl_SetStdChannel\fR. .PP If \fBTcl_GetStdChannel\fR is called before \fBTcl_SetStdChannel\fR, Tcl will construct a new channel to wrap the appropriate platform-specific standard file handle. If \fBTcl_SetStdChannel\fR is called before \fBTcl_GetStdChannel\fR, then the default channel will not be created. Index: doc/Hash.3 ================================================================== --- doc/Hash.3 +++ doc/Hash.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: Hash.3,v 1.10 2002/07/11 15:40:19 dgp Exp $ +'\" RCS: @(#) $Id: Hash.3,v 1.10.2.1 2003/07/18 16:56:24 dgp Exp $ '\" .so man.macros .TH Tcl_Hash 3 "" Tcl "Tcl Library Procedures" .BS .SH NAME @@ -117,11 +117,11 @@ new hash table. The space for the structure is provided by the caller, not by the hash module. The value of \fIkeyType\fR indicates what kinds of keys will be used for all entries in the table. \fIKeyType\fR must have one of the following values: .IP \fBTCL_STRING_KEYS\fR 25 -Keys are null-terminated ASCII strings. +Keys are null-terminated strings. They are passed to hashing routines using the address of the first character of the string. .IP \fBTCL_ONE_WORD_KEYS\fR 25 Keys are single-word values; they are passed to hashing routines and stored in hash table entries as ``char *'' values. Index: doc/LinkVar.3 ================================================================== --- doc/LinkVar.3 +++ doc/LinkVar.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: LinkVar.3,v 1.6 2002/08/05 03:24:39 dgp Exp $ +'\" RCS: @(#) $Id: LinkVar.3,v 1.6.2.1 2003/07/18 16:56:24 dgp Exp $ '\" .so man.macros .TH Tcl_LinkVar 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -93,17 +93,17 @@ Tcl errors. .TP \fBTCL_LINK_STRING\fR The C variable is of type \fBchar *\fR. .VS -If its value is not null then it must be a pointer to a string +If its value is not NULL then it must be a pointer to a string allocated with \fBTcl_Alloc\fR or \fBckalloc\fR. .VE Whenever the Tcl variable is modified the current C string will be freed and new memory will be allocated to hold a copy of the variable's new value. -If the C variable contains a null pointer then the Tcl variable +If the C variable contains a NULL pointer then the Tcl variable will read as ``NULL''. .PP If the TCL_LINK_READ_ONLY flag is present in \fItype\fR then the variable will be read-only from Tcl, so that its value can only be changed by modifying the C variable. Index: doc/Macintosh.3 ================================================================== --- doc/Macintosh.3 +++ doc/Macintosh.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1997-1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: Macintosh.3,v 1.4 2002/01/25 20:40:55 dgp Exp $ +'\" RCS: @(#) $Id: Macintosh.3,v 1.4.2.1 2003/07/18 16:56:24 dgp Exp $ '\" .so man.macros .TH Tcl_MacSetEventProc 3 "8.1" Tcl "Tcl Library Procedures" .BS .SH NAME @@ -77,11 +77,11 @@ Currently only sources the resource by name, file IDs may be supported at a later date. .PP \fBTcl_MacConvertTextResource\fR converts a TEXT resource into a Tcl suitable string. It mallocs the returned memory, converts ``\\r'' to -``\\n'', and appends a NULL. The caller has the responsibility for +``\\n'', and appends a null. The caller has the responsibility for freeing the memory. .PP \fBTcl_MacFindResource\fR provides a higher level interface for loading resources. It is used by \fBresource read\fR. .PP Index: doc/Notifier.3 ================================================================== --- doc/Notifier.3 +++ doc/Notifier.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1995-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: Notifier.3,v 1.9 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: Notifier.3,v 1.9.2.1 2004/11/25 15:28:37 vasiljevic Exp $ '\" .so man.macros .TH Notifier 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -31,11 +31,11 @@ .sp void \fBTcl_ThreadQueueEvent\fR(\fIthreadId, evPtr, position\fR) .sp void -\fBTcl_ThreadAlert\fR(\fIthreadId, clientData\fR) +\fBTcl_ThreadAlert\fR(\fIthreadId\fR) .sp Tcl_ThreadId \fBTcl_GetCurrentThread\fR() .sp void Index: doc/OpenFileChnl.3 ================================================================== --- doc/OpenFileChnl.3 +++ doc/OpenFileChnl.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: OpenFileChnl.3,v 1.20 2002/07/23 18:17:12 jenglish Exp $ +'\" RCS: @(#) $Id: OpenFileChnl.3,v 1.20.2.4 2004/07/16 22:22:15 andreas_kupries Exp $ .so man.macros .TH Tcl_OpenFileChannel 3 8.3 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME @@ -99,15 +99,17 @@ .sp int \fBTcl_OutputBuffered\fR(\fIchannel\fR) .VE .sp -int +.VS 8.4 +Tcl_WideInt \fBTcl_Seek\fR(\fIchannel, offset, seekMode\fR) .sp -int +Tcl_WideInt \fBTcl_Tell\fR(\fIchannel\fR) +.VE 8.4 .sp int \fBTcl_GetChannelOption\fR(\fIinterp, channel, optionName, optionValue\fR) .sp int @@ -200,11 +202,11 @@ A buffer containing the bytes to output to the channel. .AP int bytesToWrite in The number of bytes to consume from \fIcharBuf\fR or \fIbyteBuf\fR and output to the channel. .VE -.AP int offset in +.AP Tcl_WideInt offset in How far to move the access point in the channel at which the next input or output operation will be applied, measured in bytes from the position given by \fIseekMode\fR. May be either positive or negative. .AP int seekMode in Relative to which point to seek; used with \fIoffset\fR to calculate the new @@ -430,10 +432,14 @@ \fIreadObjPtr\fR's string representation. The return value of \fBTcl_ReadChars\fR is the number of characters, up to \fIcharsToRead\fR, that were stored in \fIreadObjPtr\fR. If an error occurs while reading, the return value is \-1 and \fBTcl_ReadChars\fR records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. +.PP +Setting \fIcharsToRead\fR to \fB-1\fR will cause the command to read +all characters currently available (non-blocking) or everything until +eof (blocking mode). .PP The return value may be smaller than the value to read, indicating that less data than requested was available. This is called a \fIshort read\fR. In blocking mode, this can only happen on an end-of-file. In nonblocking mode, a short read can also occur if there is not enough input currently @@ -466,11 +472,11 @@ encoding conversions, regardless of the channel's encoding. It is deprecated and exists for backwards compatibility with non-internationalized Tcl extensions. It consumes bytes from \fIchannel\fR and stores them in \fIreadBuf\fR, performing end-of-line translations on the way. The return value of \fBTcl_Read\fR is the number of bytes, up to \fIbytesToRead\fR, written in -\fIreadBuf\fR. The buffer produced by \fBTcl_Read\fR is not NULL terminated. +\fIreadBuf\fR. The buffer produced by \fBTcl_Read\fR is not null-terminated. Its contents are valid from the zeroth position up to and excluding the position indicated by the return value. .PP \fBTcl_ReadRaw\fR is the same as \fBTcl_Read\fR but does not compensate for stacking. While \fBTcl_Read\fR (and the other functions @@ -522,11 +528,11 @@ .PP \fBTcl_WriteChars\fR accepts \fIbytesToWrite\fR bytes of character data at \fIcharBuf\fR. The UTF-8 characters in the buffer are converted to the channel's encoding and queued for output to \fIchannel\fR. If \fIbytesToWrite\fR is negative, \fBTcl_WriteChars\fR expects \fIcharBuf\fR -to be NULL terminated and it outputs everything up to the NULL. +to be null-terminated and it outputs everything up to the null. .PP Data queued for output may not appear on the output device immediately, due to internal buffering. If the data should appear immediately, call \fBTcl_Flush\fR after the call to \fBTcl_WriteChars\fR, or set the \fB\-buffering\fR option on the channel to \fBnone\fR. If you wish the data @@ -560,11 +566,11 @@ encoding conversions, regardless of the channel's encoding. It is deprecated and exists for backwards compatibility with non-internationalized Tcl extensions. It accepts \fIbytesToWrite\fR bytes of data at \fIbyteBuf\fR and queues them for output to \fIchannel\fR. If \fIbytesToWrite\fR is negative, \fBTcl_Write\fR expects \fIbyteBuf\fR to be -NULL terminated and it outputs everything up to the NULL. +null-terminated and it outputs everything up to the null. .PP \fBTcl_WriteRaw\fR is the same as \fBTcl_Write\fR but does not compensate for stacking. While \fBTcl_Write\fR (and the other functions in the API) always feed their input to the topmost channel in the stack the supplied channel is part of, \fBTcl_WriteRaw\fR does Index: doc/ParseCmd.3 ================================================================== --- doc/ParseCmd.3 +++ doc/ParseCmd.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: ParseCmd.3,v 1.10 2002/08/05 03:24:39 dgp Exp $ +'\" RCS: @(#) $Id: ParseCmd.3,v 1.10.2.2 2005/09/15 23:21:37 msofer Exp $ '\" .so man.macros .TH Tcl_ParseCommand 3 8.3 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -36,11 +36,11 @@ \fBTcl_FreeParse\fR(\fIusedParsePtr\fR) .sp Tcl_Obj * \fBTcl_EvalTokens\fR(\fIinterp, tokenPtr, numTokens\fR) .sp -Tcl_Obj * +int \fBTcl_EvalTokensStandard\fR(\fIinterp, tokenPtr, numTokens\fR) .SH ARGUMENTS .AS Tcl_Interp *usedParsePtr .AP Tcl_Interp *interp out For procedures other than \fBTcl_FreeParse\fR, \fBTcl_EvalTokens\fR @@ -106,11 +106,11 @@ \fBTCL_ERROR\fR is returned, an error message is left in \fIinterp\fR's result, and no information is left at \fI*parsePtr\fR. .PP \fBTcl_ParseExpr\fR parses Tcl expressions. Given a pointer to a script containing an expression, -\fBTcl_ParseCommand\fR parses the expression. +\fBTcl_ParseExpr\fR parses the expression. If the expression was parsed successfully, \fBTcl_ParseExpr\fR returns \fBTCL_OK\fR and fills in the structure pointed to by \fIparsePtr\fR with information about the structure of the expression (see below for details). If an error occurred in parsing the command then @@ -188,11 +188,12 @@ a reference to an array variable. \fBTcl_EvalTokensStandard\fR performs the substitutions requested by the tokens and concatenates the resulting values. The return value from \fBTcl_EvalTokensStandard\fR is a Tcl completion code with one of the values \fBTCL_OK\fR, \fBTCL_ERROR\fR, -\fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR. +\fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR, or possibly +some other integer value originating in an extension. In addition, a result value or error message is left in \fIinterp\fR's 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. @@ -209,23 +210,23 @@ \fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseBraces\fR, \fBTcl_ParseQuotedString\fR, and \fBTcl_ParseVarName\fR return parse information in two data structures, Tcl_Parse and Tcl_Token: .CS typedef struct Tcl_Parse { - char *\fIcommentStart\fR; + CONST char *\fIcommentStart\fR; int \fIcommentSize\fR; - char *\fIcommandStart\fR; + CONST char *\fIcommandStart\fR; int \fIcommandSize\fR; int \fInumWords\fR; Tcl_Token *\fItokenPtr\fR; int \fInumTokens\fR; ... } Tcl_Parse; typedef struct Tcl_Token { int \fItype\fR; - char *\fIstart\fR; + CONST char *\fIstart\fR; int \fIsize\fR; int \fInumComponents\fR; } Tcl_Token; .CE .PP Index: doc/PkgRequire.3 ================================================================== --- doc/PkgRequire.3 +++ doc/PkgRequire.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: PkgRequire.3,v 1.6 2002/02/26 02:22:20 hobbs Exp $ +'\" RCS: @(#) $Id: PkgRequire.3,v 1.6.2.1 2006/09/22 01:26:22 andreas_kupries Exp $ '\" .so man.macros .TH Tcl_PkgRequire 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -52,11 +52,10 @@ .AP ClientData *clientDataPtr out Pointer to place to store the value associated with the matching package. It is only changed if the pointer is not NULL and the function completed successfully. .BE - .SH DESCRIPTION .PP These procedures provide C-level interfaces to Tcl's package and version management facilities. .PP @@ -80,8 +79,7 @@ .PP \fBTcl_PkgProvideEx\fR, \fBTcl_PkgPresentEx\fR and \fBTcl_PkgRequireEx\fR allow the setting and retrieving of the client data associated with the package. In all other respects they are equivalent to the matching functions. - .SH KEYWORDS package, present, provide, require, version Index: doc/SetVar.3 ================================================================== --- doc/SetVar.3 +++ doc/SetVar.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: SetVar.3,v 1.7 2002/08/05 03:24:39 dgp Exp $ +'\" RCS: @(#) $Id: SetVar.3,v 1.7.2.2 2004/08/16 14:18:25 msofer Exp $ '\" .so man.macros .TH Tcl_SetVar 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -74,11 +74,11 @@ May include \fB::\fR namespace qualifiers to specify a variable in a particular namespace. May refer to a scalar variable or an element of an array. .AP "CONST char" *newValue in -New value for variable, specified as a NULL-terminated string. +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. The name may include a series of \fB::\fR namespace qualifiers to specify a variable in a particular namespace. @@ -219,10 +219,13 @@ Tcl list element before setting (or appending to) the variable. A separator space is appended before the new list element unless the list element is going to be the first element in a list or sublist (i.e. the variable's current value is empty, or contains the single character ``{'', or ends in `` }''). +When appending, the original value of the variable must also be +a valid list, so that the operation is the appending of a new +list element onto a list. .PP \fBTcl_GetVar\fR and \fBTcl_GetVar2\fR return the current value of a variable. The arguments to these procedures are treated in the same way as the arguments to \fBTcl_SetVar\fR and \fBTcl_SetVar2\fR. Index: doc/StringObj.3 ================================================================== --- doc/StringObj.3 +++ doc/StringObj.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: StringObj.3,v 1.13 2002/10/22 12:16:53 dkf Exp $ +'\" RCS: @(#) $Id: StringObj.3,v 1.13.2.1 2003/07/18 16:56:24 dgp Exp $ '\" .so man.macros .TH Tcl_StringObj 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME @@ -116,11 +116,11 @@ .AP va_list argList in An argument list which must have been initialised using \fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. .AP int newLength in New length for the string value of \fIobjPtr\fR, not including the -final NULL character. +final null character. .AP int objc in The number of elements to concatenate. .AP Tcl_Obj *objv[] in The array of objects to concatenate. .BE Index: doc/Tcl.n ================================================================== --- doc/Tcl.n +++ doc/Tcl.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: Tcl.n,v 1.9 2003/02/01 19:48:23 kennykb Exp $ +'\" RCS: @(#) $Id: Tcl.n,v 1.9.2.1 2005/12/19 10:09:50 dkf Exp $ '\" .so man.macros .TH Tcl n "8.1" Tcl "Tcl Built-In Commands" .BS .SH NAME @@ -74,11 +74,12 @@ substituted into the word in place of the brackets and all of the characters between them. There may be any number of command substitutions in a single word. Command substitution is not performed on words enclosed in braces. .IP "[7] \fBVariable substitution.\fR" -If a word contains a dollar-sign (``$'') then Tcl performs \fIvariable +If a word contains a dollar-sign (``$'') followed by one of the forms +described below, then Tcl performs \fIvariable substitution\fR: the dollar-sign and the following characters are replaced in the word by the value of a variable. Variable substitution may take any of the following forms: .RS .TP 15 Index: doc/Thread.3 ================================================================== --- doc/Thread.3 +++ doc/Thread.3 @@ -3,11 +3,11 @@ '\" Copyright (c) 1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: Thread.3,v 1.14 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: Thread.3,v 1.14.2.2 2004/11/25 15:48:52 vasiljevic Exp $ '\" .so man.macros .TH Threads 3 "8.1" Tcl "Tcl Library Procedures" .BS .SH NAME @@ -44,11 +44,11 @@ \fBTcl_JoinThread\fR(\fIid, result\fR) .SH ARGUMENTS .AS Tcl_ThreadDataKey *keyPtr .AP Tcl_Condition *condPtr in A condition variable, which must be associated with a mutex lock. -.AP Tcl_Condition *mutexPtr in +.AP Tcl_Mutex *mutexPtr in A mutex lock. .AP Tcl_Time *timePtr in A time limit on the condition wait. NULL to wait forever. Note that a polling value of 0 seconds doesn't make much sense. .AP Tcl_ThreadDataKey *keyPtr in @@ -138,12 +138,13 @@ In this release, the Tcl language itself provides no support for creating multithreaded scripts (for example, scripts that could spawn a Tcl interpreter in a separate thread). If you need to add this feature at this time, see the \fItclThreadTest.c\fR file in the Tcl source distribution for an experimental implementation -of a Tcl "Thread" package implementing thread creation and management -commands at the script level. +or use the Tcl "Threading Extension" package implementing thread creation +and management commands at the script level. + .SH DESCRIPTION A mutex is a lock that is used to serialize all threads through a piece of code by calling \fBTcl_MutexLock\fR and \fBTcl_MutexUnlock\fR. If one thread holds a mutex, any other thread calling \fBTcl_MutexLock\fR will @@ -153,10 +154,13 @@ The result of locking a mutex twice from the same thread is undefined. On some platforms it will result in a deadlock. .VE The \fBTcl_MutexLock\fR, \fBTcl_MutexUnlock\fR and \fBTcl_MutexFinalize\fR procedures are defined as empty macros if not compiling with threads enabled. +For declaration of mutexes the \fBTCL_DECLARE_MUTEX\fR macro should be used. +This macro assures correct mutex handling even when the core is compiled +without threads enabled. .PP A condition variable is used as a signaling mechanism: a thread can lock a mutex and then wait on a condition variable with \fBTcl_ConditionWait\fR. This atomically releases the mutex lock and blocks the waiting thread until another thread calls Index: doc/Utf.3 ================================================================== --- doc/Utf.3 +++ doc/Utf.3 @@ -2,11 +2,11 @@ '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: Utf.3,v 1.13 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: Utf.3,v 1.13.2.2 2003/07/18 22:15:45 dkf Exp $ '\" .so man.macros .TH Utf 3 "8.1" Tcl "Tcl Library Procedures" .BS .SH NAME @@ -91,13 +91,13 @@ .AP Tcl_UniChar *chPtr out Filled with the Tcl_UniChar represented by the head of the UTF-8 string. .AP "CONST char" *src in Pointer to a UTF-8 string. .AP "CONST Tcl_UniChar" *uniStr in -A NULL-terminated Unicode string. +A null-terminated Unicode string. .AP "CONST Tcl_UniChar" *uniPattern in -A NULL-terminated Unicode string. +A null-terminated Unicode string. .AP int len in The length of the UTF-8 string in bytes (not UTF-8 characters). If negative, all bytes up to the first null byte are used. .AP int numChars in The length of the Unicode string in characters. Must be greater than or @@ -141,11 +141,11 @@ \fBTcl_UtfToUniChar\fR reads one UTF-8 character starting at \fIsrc\fR and stores it as a Tcl_UniChar in \fI*chPtr\fR. The return value is the number of bytes read from \fIsrc\fR.. The caller must ensure that the source buffer is long enough such that this routine does not run off the end and dereference non-existent or random memory; if the source buffer -is known to be null terminated, this will not happen. If the input is +is known to be null-terminated, this will not happen. If the input is not in proper UTF-8 format, \fBTcl_UtfToUniChar\fR will store the first byte of \fIsrc\fR in \fI*chPtr\fR as a Tcl_UniChar between 0x0000 and 0x00ff and return 1. .PP \fBTcl_UniCharToUtfDString\fR converts the given Unicode string @@ -160,35 +160,35 @@ you may either specify the length of the given UTF-8 string or "-1", in which case \fBTcl_UtfToUniCharDString\fR uses \fBstrlen\fR to calculate the length. The return value is a pointer to the Unicode representation of the UTF-8 string. Storage for the return value is appended to the end of the \fBTcl_DString\fR. The Unicode string -is terminated with a Unicode NULL character. +is terminated with a Unicode null character. .PP \fBTcl_UniCharLen\fR corresponds to \fBstrlen\fR for Unicode -characters. It accepts a NULL-terminated Unicode string and returns +characters. It accepts a null-terminated Unicode string and returns the number of Unicode characters (not bytes) in that string. .PP \fBTcl_UniCharNcmp\fR and \fBTcl_UniCharNcasecmp\fR correspond to \fBstrncmp\fR and \fBstrncasecmp\fR, respectively, for Unicode characters. -They accepts two NULL-terminated Unicode strings and the number of characters +They accepts two null-terminated Unicode strings and the number of characters to compare. Both strings are assumed to be at least \fIlen\fR characters long. \fBTcl_UniCharNcmp\fR compares the two strings character-by-character according to the Unicode character ordering. It returns an integer greater than, equal to, or less than 0 if the first string is greater than, equal to, or less than the second string respectively. \fBTcl_UniCharNcasecmp\fR is the Unicode case insensitive version. .PP .VS 8.4 \fBTcl_UniCharCaseMatch\fR is the Unicode equivalent to -\fBTcl_StringCaseMatch\fR. It accepts a NULL-terminated Unicode string, +\fBTcl_StringCaseMatch\fR. It accepts a null-terminated Unicode string, a Unicode pattern, and a boolean value specifying whether the match should be case sensitive and returns whether the string matches the pattern. .VE 8.4 .PP \fBTcl_UtfNcmp\fR corresponds to \fBstrncmp\fR for UTF-8 strings. It -accepts two NULL-terminated UTF-8 strings and the number of characters +accepts two null-terminated UTF-8 strings and the number of characters to compare. (Both strings are assumed to be at least \fIlen\fR characters long.) \fBTcl_UtfNcmp\fR compares the two strings character-by-character according to the Unicode character ordering. It returns an integer greater than, equal to, or less than 0 if the first string is greater than, equal to, or less than the second string @@ -207,30 +207,33 @@ full Tcl_UniChar has been seen. .PP \fBTcl_NumUtfChars\fR corresponds to \fBstrlen\fR for UTF-8 strings. It returns the number of Tcl_UniChars that are represented by the UTF-8 string \fIsrc\fR. The length of the source string is \fIlen\fR bytes. If the -length is negative, all bytes up to the first NULL byte are used. +length is negative, all bytes up to the first null byte are used. .PP \fBTcl_UtfFindFirst\fR corresponds to \fBstrchr\fR for UTF-8 strings. It returns a pointer to the first occurrence of the Tcl_UniChar \fIch\fR -in the NULL-terminated UTF-8 string \fIsrc\fR. The NULL terminator is +in the null-terminated UTF-8 string \fIsrc\fR. The null terminator is considered part of the UTF-8 string. .PP \fBTcl_UtfFindLast\fR corresponds to \fBstrrchr\fR for UTF-8 strings. It returns a pointer to the last occurrence of the Tcl_UniChar \fIch\fR -in the NULL terminated UTF-8 string \fIsrc\fR. The NULL terminator is +in the null-terminated UTF-8 string \fIsrc\fR. The null terminator is considered part of the UTF-8 string. .PP Given \fIsrc\fR, a pointer to some location in a UTF-8 string, \fBTcl_UtfNext\fR returns a pointer to the next UTF-8 character in the string. The caller must not ask for the next character after the last -character in the string. +character in the string if the string is not terminated by a null +character. .PP -Given \fIsrc\fR, a pointer to some location in a UTF-8 string, -\fBTcl_UtfPrev\fR returns a pointer to the previous UTF-8 character in the -string. This function will not back up to a position before \fIstart\fR, +Given \fIsrc\fR, a pointer to some location in a UTF-8 string (or to a +null byte immediately following such a string), \fBTcl_UtfPrev\fR +returns a pointer to the closest preceding byte that starts a UTF-8 +character. +This function will not back up to a position before \fIstart\fR, the start of the UTF-8 string. If \fIsrc\fR was already at \fIstart\fR, the return value will be \fIstart\fR. .PP \fBTcl_UniCharAtIndex\fR corresponds to a C string array dereference or the Pascal Ord() function. It returns the Tcl_UniChar represented at the Index: doc/after.n ================================================================== --- doc/after.n +++ doc/after.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: after.n,v 1.3 2000/09/07 14:27:45 poenitz Exp $ +'\" RCS: @(#) $Id: after.n,v 1.3.18.2 2004/10/27 14:23:41 dkf Exp $ '\" .so man.macros .TH after n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -99,11 +99,44 @@ assume that the application is event driven: the delayed commands will not be executed unless the application enters the event loop. In applications that are not normally event-driven, such as \fBtclsh\fR, the event loop can be entered with the \fBvwait\fR and \fBupdate\fR commands. +.SH "EXAMPLES" +This defines a command to make Tcl do nothing at all for \fIN\fR +seconds: +.CS +proc sleep {N} { + \fBafter\fR [expr {int($N * 1000)}] +} +.CE +.PP +This arranges for the command \fIwake_up\fR to be run in eight hours +(providing the event loop is active at that time): +.CS +\fBafter\fR [expr {1000 * 60 * 60 * 8}] wake_up +.CE +.PP +The following command can be used to do long-running calculations (as +represented here by \fI::my_calc::one_step\fR, which is assumed to +return a boolean indicating whether another step should be performed) +in a step-by-step fashion, though the calculation itself needs to be +arranged so it can work step-wise. This technique is extra careful to +ensure that the event loop is not starved by the rescheduling of +processing steps (arranging for the next step to be done using an +already-triggered timer event only when the event queue has been +drained) and is useful when you want to ensure that a Tk GUI remains +responsive during a slow task. +.CS +proc doOneStep {} { + if {[::my_calc::one_step]} { + \fBafter idle\fR [list \fBafter\fR 0 doOneStep] + } +} +doOneStep +.CE .SH "SEE ALSO" bgerror(n), concat(n), update(n), vwait(n) .SH KEYWORDS cancel, delay, idle callback, sleep, time Index: doc/append.n ================================================================== --- doc/append.n +++ doc/append.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: append.n,v 1.4 2003/02/10 13:32:22 dkf Exp $ +'\" RCS: @(#) $Id: append.n,v 1.4.2.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH append n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -27,11 +27,21 @@ \fIvarName\fR. This command provides an efficient way to build up long variables incrementally. For example, ``\fBappend a $b\fR'' is much more efficient than ``\fBset a $a$b\fR'' if \fB$a\fR is long. +.SH EXAMPLE +Building a string of comma-separated numbers piecemeal using a loop. +.CS +set var 0 +for {set i 1} {$i<=10} {incr i} { + \fBappend\fR var "," $i +} +puts $var +# Prints 0,1,2,3,4,5,6,7,8,9,10 +.CE .SH "SEE ALSO" concat(n), lappend(n) .SH KEYWORDS append, variable Index: doc/array.n ================================================================== --- doc/array.n +++ doc/array.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: array.n,v 1.8 2000/09/07 14:27:45 poenitz Exp $ +'\" RCS: @(#) $Id: array.n,v 1.8.18.3 2004/10/27 14:23:41 dkf Exp $ '\" .so man.macros .TH array n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -113,10 +113,14 @@ command should be invoked. The return value is a search identifier that must be used in \fBarray nextelement\fR and \fBarray donesearch\fR commands; it allows multiple searches to be underway simultaneously for the same array. +It is currently more efficient and easier to use either the \fBarray +get\fR or \fBarray names\fR, together with \fBforeach\fR, to iterate +over all but very large arrays. See the examples below for how to do +this. .VS 8.4 .TP \fBarray statistics \fIarrayName\fR Returns statistics about the distribution of data within the hashtable that represents the array. This information includes the number of @@ -131,11 +135,59 @@ of an array variable or there are no matching elements in the array, no error will be raised. If \fIpattern\fR is omitted and \fIarrayName\fR is an array variable, then the command unsets the entire array. The command always returns an empty string. .VE 8.3 +.SH EXAMPLES +.CS +\fBarray set\fR colorcount { + red 1 + green 5 + blue 4 + white 9 +} + +foreach {color count} [\fBarray get\fR colorcount] { + puts "Color: $color Count: $count" +} + => Color: blue Count: 4 + Color: white Count: 9 + Color: green Count: 5 + Color: red Count: 1 + +foreach color [\fBarray names\fR colorcount] { + puts "Color: $color Count: $colorcount($color)" +} + => Color: blue Count: 4 + Color: white Count: 9 + Color: green Count: 5 + Color: red Count: 1 + +foreach color [lsort [array names colorcount]] { + puts "Color: $color Count: $colorcount($color)" +} + => Color: blue Count: 4 + Color: green Count: 5 + Color: red Count: 1 + Color: white Count: 9 + +\fBarray statistics\fR colorcount + => 4 entries in table, 4 buckets + number of buckets with 0 entries: 1 + number of buckets with 1 entries: 2 + number of buckets with 2 entries: 1 + number of buckets with 3 entries: 0 + number of buckets with 4 entries: 0 + number of buckets with 5 entries: 0 + number of buckets with 6 entries: 0 + number of buckets with 7 entries: 0 + number of buckets with 8 entries: 0 + number of buckets with 9 entries: 0 + number of buckets with 10 or more entries: 0 + average search distance for entry: 1.2 +.CE .SH "SEE ALSO" -list(n), string(n), variable(n), trace(n) +list(n), string(n), variable(n), trace(n), foreach(n) .SH KEYWORDS array, element names, search Index: doc/bgerror.n ================================================================== --- doc/bgerror.n +++ doc/bgerror.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: bgerror.n,v 1.4 2000/09/07 14:27:45 poenitz Exp $ +'\" RCS: @(#) $Id: bgerror.n,v 1.4.18.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH bgerror n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -69,11 +69,27 @@ function button, and \fB*ErrorDialog.function.command\fR, to specify the command to be run. The text of the stack trace is appended to the command when it is evaluated. If either of these options is set to the empty string, then the additional button will not be displayed in the dialog. +.PP +If you are writing code that will be used by others as part of a +package or other kind of library, consider avoiding \fBbgerror\fR. +The reason for this is that the application programmer may also want +to define a \fBbgerror\fR, or use other code that does and thus will +have trouble integrating your code. +.SH "EXAMPLE" +This \fBbgerror\fR procedure appends errors to a file, with a timestamp. +.CS +proc bgerror {message} { + set timestamp [clock format [clock seconds]] + set fl [open mylog.txt {WRONLY CREAT APPEND}] + puts $fl "$timestamp: bgerror in $::argv '$message'" + close $fl +} +.CE .SH "SEE ALSO" after(n), tclvars(n) .SH KEYWORDS background error, reporting Index: doc/binary.n ================================================================== --- doc/binary.n +++ doc/binary.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1997 by Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: binary.n,v 1.11 2002/10/09 14:07:43 dkf Exp $ +'\" RCS: @(#) $Id: binary.n,v 1.11.2.8 2005/02/10 10:28:21 dkf Exp $ '\" .so man.macros .TH binary n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -53,20 +53,26 @@ .CE .PP The first argument is a list of four numbers, but because of the count of 3 for the associated field specifier, only the first three will be used. The second argument is associated with the second field -specifier. The resulting binary string contains the four numbers 10, +specifier. The resulting binary string contains the four numbers 1.0, 2.0, 3.0 and 0.1. .PP Each type-count pair moves an imaginary cursor through the binary data, storing bytes at the current position and advancing the cursor to just after the last byte stored. The cursor is initially at position 0 at the beginning of the data. The type may be any one of the following characters: .IP \fBa\fR 5 Stores a character string of length \fIcount\fR in the output string. +Every character is taken as modulo 256 (i.e. the low byte of every +character is used, and the high byte discarded) so when storing +character strings not wholly expressible using the characters \\u0000-\\u00ff, +the \fBencoding convertto\fR command should be used +first if this truncation is not desired (i.e. if the characters are +not part of the ISO 8859-1 character set.) If \fIarg\fR has fewer than \fIcount\fR bytes, then additional zero bytes are used to pad out the field. If \fIarg\fR is longer than the specified length, the extra characters will be ignored. If \fIcount\fR is \fB*\fR, then all of the bytes in \fIarg\fR will be formatted. If \fIcount\fR is omitted, then one character will be @@ -211,11 +217,11 @@ will return a string equivalent to \fB\\x00\\x00\\x00\\x03\\xff\\xff\\xff\\xfd\\x00\\x01\\x00\\x00\fR .RE .IP \fBw\fR 5 .VS 8.4 -This form is the same as \fBw\fR except that it stores one or more +This form is the same as \fBc\fR except that it stores one or more 64-bit integers in little-endian byte order in the output string. The low-order 64-bits of each integer are stored as an eight-byte value at the cursor position with the least significant byte stored first. For example, .RS @@ -228,11 +234,11 @@ This form is the same as \fBw\fR except that it stores one or more one or more 64-bit integers in big-endian byte order in the output string. For example, .RS .CS -\fBbinary format W 4785469626960341345\fR +\fBbinary format Wc 4785469626960341345 110\fR .CE will return the string \fBBigEndian\fR .VE .RE .IP \fBf\fR 5 @@ -381,11 +387,15 @@ the following characters: .IP \fBa\fR 5 The data is a character string of length \fIcount\fR. If \fIcount\fR is \fB*\fR, then all of the remaining bytes in \fIstring\fR will be scanned into the variable. If \fIcount\fR is omitted, then one -character will be scanned. For example, +character will be scanned. +All characters scanned will be interpreted as being in the +range \\u0000-\\u00ff so the \fBencoding convertfrom\fR command might be +needed if the string is not an ISO 8859\-1 string. +For example, .RS .CS \fBbinary scan abcde\\000fghi a6a10 var1 var2\fR .CE will return \fB1\fR with the string equivalent to \fBabcde\\000\fR @@ -464,11 +474,11 @@ will return \fB2\fR with \fB7 -122\fR stored in \fBvar1\fR and \fB5\fR stored in \fBvar2\fR. Note that the integers returned are signed, but they can be converted to unsigned 8-bit quantities using an expression like: .CS -\fBexpr ( $num + 0x100 ) % 0x100\fR +\fBexpr { $num & 0xff }\fR .CE .RE .IP \fBs\fR 5 The data is interpreted as \fIcount\fR 16-bit signed integers represented in little-endian byte order. The integers are stored in @@ -483,11 +493,11 @@ will return \fB2\fR with \fB5 7\fR stored in \fBvar1\fR and \fB-16\fR stored in \fBvar2\fR. Note that the integers returned are signed, but they can be converted to unsigned 16-bit quantities using an expression like: .CS -\fBexpr ( $num + 0x10000 ) % 0x10000\fR +\fBexpr { $num & 0xffff }\fR .CE .RE .IP \fBS\fR 5 This form is the same as \fBs\fR except that the data is interpreted as \fIcount\fR 16-bit signed integers represented in big-endian byte @@ -509,12 +519,16 @@ .RS .CS \fBbinary scan \\x05\\x00\\x00\\x00\\x07\\x00\\x00\\x00\\xf0\\xff\\xff\\xff i2i* var1 var2\fR .CE will return \fB2\fR with \fB5 7\fR stored in \fBvar1\fR and \fB-16\fR -stored in \fBvar2\fR. Note that the integers returned are signed and -cannot be represented by Tcl as unsigned values. +stored in \fBvar2\fR. Note that the integers returned are signed, but +they can be converted to unsigned 32-bit quantities using an expression +like: +.CS +\fBexpr { $num & 0xffffffff }\fR +.CE .RE .IP \fBI\fR 5 This form is the same as \fBI\fR except that the data is interpreted as \fIcount\fR 32-bit signed integers represented in big-endian byte order. For example, @@ -622,17 +636,38 @@ \fBbinary scan \\x01\\x02\\x03\\x04 c2@1H* var1 var2\fR .CE will return \fB2\fR with \fB1 2\fR stored in \fBvar1\fR and \fB020304\fR stored in \fBvar2\fR. .RE - .SH "PLATFORM ISSUES" Sometimes it is desirable to format or scan integer values in the native byte order for the machine. Refer to the \fBbyteOrder\fR element of the \fBtcl_platform\fR array to decide which type character to use when formatting or scanning integers. +.SH EXAMPLES +This is a procedure to write a Tcl string to a binary-encoded channel as +UTF-8 data preceded by a length word: +.CS +proc writeString {channel string} { + set data [encoding convertto utf-8 $string] + puts -nonewline [\fBbinary format\fR Ia* \e + [string length $data] $data] +} +.CE +.PP +This procedure reads a string from a channel that was written by the +previously presented \fBwriteString\fR procedure: +.CS +proc readString {channel} { + if {![\fBbinary scan\fR [read $channel 4] I length]} { + error "missing length" + } + set data [read $channel $length] + return [encoding convertfrom utf-8 $data] +} +.CE .SH "SEE ALSO" format(n), scan(n), tclvars(n) .SH KEYWORDS binary, format, scan Index: doc/break.n ================================================================== --- doc/break.n +++ doc/break.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: break.n,v 1.3 2000/09/07 14:27:46 poenitz Exp $ +'\" RCS: @(#) $Id: break.n,v 1.3.18.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH break n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -19,19 +19,29 @@ .SH DESCRIPTION .PP This command is typically invoked inside the body of a looping command such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR. -It returns a TCL_BREAK code, which causes a break exception +It returns a \fBTCL_BREAK\fR code, which causes a break exception to occur. The exception causes the current script to be aborted out to the innermost containing loop command, which then aborts its execution and returns normally. Break exceptions are also handled in a few other situations, such as the \fBcatch\fR command, Tk event bindings, and the outermost scripts of procedure bodies. +.SH EXAMPLE +Print a line for each of the integers from 0 to 5: +.CS +for {set x 0} {$x<10} {incr x} { + if {$x > 5} { + \fBbreak\fR + } + puts "x is $x" +} +.CE .SH "SEE ALSO" -catch(n), continue(n), for(n), foreach(n), while(n) +catch(n), continue(n), for(n), foreach(n), return(n), while(n) .SH KEYWORDS abort, break, loop Index: doc/catch.n ================================================================== --- doc/catch.n +++ doc/catch.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: catch.n,v 1.5 2000/09/07 14:27:46 poenitz Exp $ +'\" RCS: @(#) $Id: catch.n,v 1.5.18.2 2004/11/09 10:25:23 dkf Exp $ '\" .so man.macros .TH catch n "8.0" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -18,22 +18,35 @@ .BE .SH DESCRIPTION .PP The \fBcatch\fR command may be used to prevent errors from aborting command -interpretation. \fBCatch\fR calls the Tcl interpreter recursively to +interpretation. The \fBcatch\fR command calls the Tcl interpreter recursively to execute \fIscript\fR, and always returns without raising an error, regardless of any errors that might occur while executing \fIscript\fR. .PP If \fIscript\fR raises an error, \fBcatch\fR will return a non-zero integer -value corresponding to one of the exceptional return codes (see tcl.h -for the definitions of code values). If the \fIvarName\fR argument is -given, then the variable it names is set to the error message from -interpreting \fIscript\fR. +value corresponding to the exceptional return code returned by evaluation +of \fIscript\fR. Tcl defines the normal return code from script +evaluation to be zero (0), or \fBTCL_OK\fR. Tcl also defines four exceptional +return codes: 1 (\fBTCL_ERROR\fR), 2 (\fBTCL_RETURN\fR), 3 (\fBTCL_BREAK\fR), +and 4 (\fBTCL_CONTINUE\fR). Errors during evaluation of a script are indicated +by a return code of \fBTCL_ERROR\fR. The other exceptional return codes are +returned by the \fBreturn\fR, \fBbreak\fR, and \fBcontinue\fR commands +and in other special situations as documented. Tcl packages can define +new commands that return other integer values as return codes as well, +and scripts that make use of the \fBreturn -code\fR command can also +have return codes other than the five defined by Tcl. +.PP +If the \fIvarName\fR argument is given, then the variable it names is +set to the result of the script evaluation. When the return code from +the script is 1 (\fBTCL_ERROR\fR), the value stored in \fIvarName\fR is an error +message. When the return code from the script is 0 (\fBTCL_OK\fR), the value +stored in \fIresultVarName\fR is the value returned from \fIscript\fR. .PP If \fIscript\fR does not raise an error, \fBcatch\fR will return 0 -(TCL_OK) and set the variable to the value returned from \fIscript\fR. +(\fBTCL_OK\fR) and set the variable to the value returned from \fIscript\fR. .PP Note that \fBcatch\fR catches all exceptions, including those generated by \fBbreak\fR and \fBcontinue\fR as well as errors. The only errors that are not caught are syntax errors found when the script is compiled. This is because the catch command only catches @@ -40,30 +53,28 @@ errors during runtime. When the catch statement is compiled, the script is compiled as well and any syntax errors will generate a Tcl error. .SH EXAMPLES - The \fBcatch\fR command may be used in an \fBif\fR to branch based on the success of a script. - .CS -if { [catch {open $someFile w} fid] } { +if { [\fBcatch\fR {open $someFile w} fid] } { puts stderr "Could not open $someFile for writing\\n$fid" exit 1 } .CE +.PP The \fBcatch\fR command will not catch compiled syntax errors. The first time proc \fBfoo\fR is called, the body will be compiled and a Tcl error will be generated. - .CS proc foo {} { - catch {expr {1 +- }} + \fBcatch\fR {expr {1 +- }} } .CE .SH "SEE ALSO" -error(n), break(n), continue(n) +break(n), continue(n), error(n), return(n), tclvars(n) .SH KEYWORDS catch, error Index: doc/cd.n ================================================================== --- doc/cd.n +++ doc/cd.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: cd.n,v 1.3 2000/09/07 14:27:46 poenitz Exp $ +'\" RCS: @(#) $Id: cd.n,v 1.3.18.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH cd n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -21,11 +21,25 @@ .PP Change the current working directory to \fIdirName\fR, or to the home directory (as specified in the HOME environment variable) if \fIdirName\fR is not given. Returns an empty string. +Note that the current working directory is a per-process resource; the +\fBcd\fR command changes the working directory for all interpreters +and (in a threaded environment) all threads. +.SH EXAMPLES +Change to the home directory of the user \fBfred\fR: +.CS +\fBcd\fR ~fred +.CE +.PP +Change to the directory \fBlib\fR that is a sibling directory of the +current one: +.CS +\fBcd\fR ../lib +.CE .SH "SEE ALSO" filename(n), glob(n), pwd(n) .SH KEYWORDS working directory Index: doc/clock.n ================================================================== --- doc/clock.n +++ doc/clock.n @@ -8,11 +8,11 @@ '\" TclX, by Mark Diekhans and Karl Lehenbauer. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: clock.n,v 1.11 2002/04/22 22:41:46 hobbs Exp $ +'\" RCS: @(#) $Id: clock.n,v 1.11.2.6 2004/12/13 15:52:21 kennykb Exp $ '\" .so man.macros .TH clock n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -27,12 +27,12 @@ This command performs one of several operations that may obtain or manipulate strings or values that represent some notion of time. The \fIoption\fR argument determines what action is carried out by the command. The legal \fIoptions\fR (which may be abbreviated) are: -.TP .VS 8.3 +.TP \fBclock clicks\fR ?\fB\-milliseconds\fR? Return a high-resolution time value as a system-dependent integer value. The unit of the value is system-dependent but should be the highest resolution clock available on the system such as a CPU cycle counter. If \fB\-milliseconds\fR is specified, then the value is @@ -41,12 +41,12 @@ of elapsed time. .VE 8.3 .TP \fBclock format \fIclockValue\fR ?\fB\-format \fIstring\fR? ?\fB\-gmt \fIboolean\fR? Converts an integer time value, typically returned by -\fBclock seconds\fR, \fBclock scan\fR, or the \fBatime\fR, \fBmtime\fR, -or \fBctime\fR options of the \fBfile\fR command, to human-readable +\fBclock seconds\fR, \fBclock scan\fR, or the \fBatime\fR or \fBmtime\fR +options of the \fBfile\fR command, to human-readable form. If the \fB\-format\fR argument is present the next argument is a string that describes how the date and time are to be formatted. Field descriptors consist of a \fB%\fR followed by a field descriptor character. All other characters are copied into the result. Valid field descriptors are: @@ -77,10 +77,16 @@ '\" platforms. .IP \fB%D\fR Date as %m/%d/%y. .IP \fB%e\fR Day of month (1 - 31), no leading zeros. +.IP \fB%g\fR +The ISO8601 year number corresponding to the ISO8601 week (%V), expressed +as a two-digit year-of-the-century, with leading zero if necessary. +.IP \fB%G\fR +The ISO8601 year number corresponding to the ISO8601 week (%V), expressed +as a four-digit number. .IP \fB%h\fR Abbreviated month name. .VE 8.4 .IP \fB%H\fR Hour in 24-hour format (00 - 23). @@ -230,11 +236,15 @@ .VE .TP \fIISO 8601 point-in-time\fR An ISO 8601 point-in-time specification, such as \fICCyymmddThhmmss\fR, where T is the literal T, \fICCyymmdd hhmmss\fR, or -\fICCyymmddThh:mm:ss\fR. +\fICCyymmddThh:mm:ss\fR. Note that only these three formats are accepted. +The command does \fInot\fR accept the full range of point-in-time +specifications specified in ISO8601. Other formats can be recognized by +using commands such as \fBregexp\fR to extract their fields and reorganize +them into a form accepted by the \fBclock scan\fR command. .TP \fIrelative time\fR A specification relative to the current time. The format is \fInumber unit\fR acceptable units are \fByear\fR, \fBfortnight\fR, \fBmonth\fR, \fBweek\fR, \fBday\fR, \fBhour\fR, \fBminute\fR (or \fBmin\fR), and \fBsecond\fR (or \fBsec\fR). The @@ -260,14 +270,14 @@ years. This means that when crossing the daylight savings time boundary, different results will be given for \fBclock scan "1 day"\fR and \fBclock scan "24 hours"\fR: .CS .ta 6c -\fB% clock scan "1 day" -base [clock scan 1999-10-31] +% \fBclock scan\fR "1 day" -base [\fBclock scan\fR 1999-10-31] 941443200 -% clock scan "24 hours" -base [clock scan 1999-10-31] -941439600\fR +% \fBclock scan\fR "24 hours" -base [\fBclock scan\fR 1999-10-31] +941439600 .CE .RE .TP \fBclock seconds\fR Return the current date and time as a system-dependent integer value. The Index: doc/close.n ================================================================== --- doc/close.n +++ doc/close.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: close.n,v 1.4 2001/09/14 19:20:40 andreas_kupries Exp $ +'\" RCS: @(#) $Id: close.n,v 1.4.8.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH close n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -57,12 +57,29 @@ when the process exits. Channels are switched to blocking mode, to ensure that all output is correctly flushed before the process exits. .VE .PP The command returns an empty string, and may generate an error if -an error occurs while flushing output. +an error occurs while flushing output. If a command in a command +pipeline created with \fBopen\fR returns an error, \fBclose\fR +generates an error (similar to the \fBexec\fR command.) +.SH EXAMPLE +This illustrates how you can use Tcl to ensure that files get closed +even when errors happen by combining \fBcatch\fR, \fBclose\fR and +\fBreturn\fR: +.CS +proc withOpenFile {filename channelVar script} { + upvar 1 $channelVar chan + set chan [open $filename] + catch { + uplevel 1 $script + } result options + \fBclose\fR $chan + return -options $options $result +} +.CE .SH "SEE ALSO" file(n), open(n), socket(n), eof(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, channel, close, nonblocking Index: doc/concat.n ================================================================== --- doc/concat.n +++ doc/concat.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: concat.n,v 1.4 2002/07/01 10:50:21 dkf Exp $ +'\" RCS: @(#) $Id: concat.n,v 1.4.2.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH concat n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -18,33 +18,35 @@ .BE .SH DESCRIPTION .PP This command joins each of its arguments together with spaces after -trimming leading and trailing spaces from each of them. If all the +trimming leading and trailing white-space from each of them. If all the arguments are lists, this has the same effect as concatenating them into a single list. -It permits any number of arguments. For example, the command -.CS -\fBconcat a b {c d e} {f {g h}}\fR -.CE -will return -.CS -\fBa b c d e f {g h}\fR -.CE -as its result, and -.CS -\fBconcat " a b {c " d " e} f"\fR -.CE -will return -.CS -\fBa b {c d e} f\fR -.CE -as its result. -.PP -If no \fIarg\fRs are supplied, the result is an empty string. +It permits any number of arguments; +if no \fIarg\fRs are supplied, the result is an empty string. +.SH EXAMPLES +Although \fBconcat\fR will concatenate lists (so the command: +.CS +\fBconcat\fR a b {c d e} {f {g h}} +.CE +will return "\fBa b c d e f {g h}\fR" as its result), it will also +concatenate things that are not lists, and hence the command: +.CS +\fBconcat\fR " a b {c " d " e} f" +.CE +will return "\fBa b {c d e} f\fR" as its result. +.PP +Note that the concatenation does not remove spaces from the middle of +its arguments, so the command: +.CS +\fBconcat\fR "a b c" { d e f } +.CE +will return "\fBa b c d e f\fR" (i.e. with three spaces between +the \fBa\fR, the \fBb\fR and the \fBc\fR). .SH "SEE ALSO" append(n), eval(n) .SH KEYWORDS concatenate, join, lists Index: doc/continue.n ================================================================== --- doc/continue.n +++ doc/continue.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: continue.n,v 1.3 2000/09/07 14:27:46 poenitz Exp $ +'\" RCS: @(#) $Id: continue.n,v 1.3.18.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH continue n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -19,19 +19,29 @@ .SH DESCRIPTION .PP This command is typically invoked inside the body of a looping command such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR. -It returns a TCL_CONTINUE code, which causes a continue exception +It returns a \fBTCL_CONTINUE\fR code, which causes a continue exception to occur. The exception causes the current script to be aborted out to the innermost containing loop command, which then continues with the next iteration of the loop. Catch exceptions are also handled in a few other situations, such as the \fBcatch\fR command and the outermost scripts of procedure bodies. +.SH EXAMPLE +Print a line for each of the integers from 0 to 10 \fIexcept\fR 5: +.CS +for {set x 0} {$x<10} {incr x} { + if {$x == 5} { + \fBcontinue\fR + } + puts "x is $x" +} +.CE .SH "SEE ALSO" -break(n), for(n), foreach(n), while(n) +break(n), for(n), foreach(n), return(n), while(n) .SH KEYWORDS continue, iteration, loop Index: doc/dde.n ================================================================== --- doc/dde.n +++ doc/dde.n @@ -3,11 +3,11 @@ '\" Copyright (c) 2001 ActiveState Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: dde.n,v 1.8 2002/06/27 22:29:08 dgp Exp $ +'\" RCS: @(#) $Id: dde.n,v 1.8.2.4 2004/12/03 00:37:21 hobbs Exp $ '\" .so man.macros .TH dde n 1.2 dde "Tcl Bundled Packages" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -15,21 +15,21 @@ dde \- Execute a Dynamic Data Exchange command .SH SYNOPSIS .sp \fBpackage require dde 1.2\fR .sp -\fBdde \fIservername\fR ?\fItopic\fR? -.sp -\fBdde \fIexecute\fR ?\fI\-async\fR? \fIservice topic \fR?\fIdata\fR? -.sp -\fBdde \fIpoke\fR \fIservice topic item data\fR -.sp -\fBdde \fIrequest\fR ?\fI\-binary\fR? \fIservice topic \fR?\fIdata\fR? -.sp -\fBdde \fIservices\fR \fIservice topic \fR?\fIdata\fR? -.sp -\fBdde \fIeval\fR ?\fI\-async\fR? \fIservice topic \fR?\fIdata\fR? +\fBdde eval\fR ?\fB\-async\fR? \fIservice cmd\fR ?\fIarg ...\fR? +.sp +\fBdde execute\fR ?\fB\-async\fR? \fIservice topic data\fR +.sp +\fBdde poke \fIservice topic item data\fR +.sp +\fBdde request\fR ?\fB\-binary\fR? \fIservice topic data\fR +.sp +\fBdde servername\fR ?\fItopic\fR? +.sp +\fBdde services \fIservice topic\fR .BE .SH DESCRIPTION .PP This command allows an application to send Dynamic Data Exchange (DDE) @@ -37,15 +37,14 @@ a mechanism where applications can exchange raw data. Each DDE transaction needs a \fIservice name\fR and a \fItopic\fR. Both the \fIservice name\fR and \fItopic\fR are application defined; Tcl uses the service name \fBTclEval\fR, while the topic name is the name of the interpreter given by \fBdde servername\fR. Other applications have their -own \fIservice names\fR and \fItopics\fR. For instance, Microsoft Excel +own \fIservice name\fRs and \fItopic\fRs. For instance, Microsoft Excel has the service name \fBExcel\fR. .PP The \fBeval\fR and \fBexecute\fR commands accept the option \fB\-async\fR: -.TP .SH "DDE COMMANDS" .PP The following commands are a subset of the full Dynamic Data Exchange set of commands. @@ -54,17 +53,17 @@ \fBdde servername\fR registers the interpreter as a DDE server with the service name \fBTclEval\fR and the topic name specified by \fItopic\fR. If no \fItopic\fR is given, \fBdde servername\fR returns the name of the current topic or the empty string if it is not registered as a service. .TP -\fBdde execute\fR ?\fI\-async\fR? \fIservice topic data\fR +\fBdde execute\fR ?\fB\-async\fR? \fIservice topic data\fR \fBdde execute\fR takes the \fIdata\fR and sends it to the server indicated by \fIservice\fR with the topic indicated by \fItopic\fR. Typically, \fIservice\fR is the name of an application, and \fItopic\fR is a file to work on. The \fIdata\fR field is given to the remote application. Typically, the application treats the \fIdata\fR field as a script, and the -script is run in the application. The \fI\-async\fR option requests +script is run in the application. The \fB\-async\fR option requests 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. .TP \fBdde poke \fIservice topic item data\fR @@ -74,18 +73,18 @@ specific but can be a command to the server or the name of a file to work 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. .TP -\fBdde request\fR ?\fI\-binary\fR? \fIservice topic item\fR +\fBdde request\fR ?\fB\-binary\fR? \fIservice topic item\fR \fBdde request\fR is typically used to get the value of something; the value of a cell in Microsoft Excel or the text of a selection in Microsoft Word. \fIservice\fR is typically the name of an application, \fItopic\fR is typically the name of the file, and \fIitem\fR is application-specific. The command returns the value of \fIitem\fR as defined in the application. Normally this is interpreted to be a -string with terminating null. If \fI\-binary\fR is specified, the +string with terminating null. If \fB\-binary\fR is specified, the result is returned as a byte array. .TP \fBdde services \fIservice topic\fR \fBdde services\fR returns a list of service-topic pairs that currently exist on the machine. If \fIservice\fR and \fItopic\fR are @@ -95,17 +94,17 @@ returned. If \fIservice\fR is not null and \fItopic\fR is, all topics for a given service are returned. If both are not null, if that service-topic pair currently exists, it is returned; otherwise, null is returned. .TP -\fBdde eval\fR ?\fI\-async\fR? \fItopic cmd \fR?\fIarg arg ...\fR? +\fBdde eval\fR ?\fB\-async\fR? \fItopic cmd \fR?\fIarg arg ...\fR? \fBdde eval\fR evaluates a command and its arguments using the interpreter specified by \fItopic\fR. The DDE service must be the \fBTclEval\fR -service. The \fI\-async\fR option requests asynchronous invocation. The +service. The \fB\-async\fR option requests 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. This command can be used to replace send on Windows. +with no error. This command can be used to replace \fBsend\fR on Windows. .SH "DDE AND TCL" A Tcl interpreter always has a service name of \fBTclEval\fR. Each different interpreter of all running Tcl applications must be given a unique @@ -135,11 +134,19 @@ when using \fBwish\fR unless a blocking command is called (such as \fBexec\fR without adding the \fB&\fR to place the process in the background). If for any reason the event queue is not flushed, DDE commands may hang until the event queue is flushed. This can create a deadlock situation. + +.SH EXAMPLE +This asks Internet Explorer (which must already be running) to go to a +particularly important website: +.CS +package require dde +\fBdde execute\fR iexplore WWW_OpenURL http://www.tcl.tk/ +.CE .SH "SEE ALSO" tk(n), winfo(n), send(n) .SH KEYWORDS application, dde, name, remote execution Index: doc/encoding.n ================================================================== --- doc/encoding.n +++ doc/encoding.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1998 by Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: encoding.n,v 1.3 2000/09/07 14:27:47 poenitz Exp $ +'\" RCS: @(#) $Id: encoding.n,v 1.3.18.3 2004/10/27 14:23:56 dkf Exp $ '\" .so man.macros .TH encoding n "8.1" Tcl "Tcl Built-In Commands" .BS .SH NAME @@ -19,25 +19,24 @@ .PP Strings in Tcl are encoded using 16-bit Unicode characters. Different operating system interfaces or applications may generate strings in other encodings such as Shift-JIS. The \fBencoding\fR command helps to bridge the gap between Unicode and these other formats. - .SH DESCRIPTION .PP Performs one of several encoding related operations, depending on \fIoption\fR. The legal \fIoption\fRs are: .TP -\fBencoding convertfrom ?\fIencoding\fR? \fIdata\fR +\fBencoding convertfrom\fR ?\fIencoding\fR? \fIdata\fR Convert \fIdata\fR to Unicode from the specified \fIencoding\fR. The characters in \fIdata\fR are treated as binary data where the lower 8-bits of each character is taken as a single byte. The resulting sequence of bytes is treated as a string in the specified \fIencoding\fR. If \fIencoding\fR is not specified, the current system encoding is used. .TP -\fBencoding convertto ?\fIencoding\fR? \fIstring\fR +\fBencoding convertto\fR ?\fIencoding\fR? \fIstring\fR Convert \fIstring\fR from Unicode to the specified \fIencoding\fR. The result is a sequence of bytes that represents the converted string. Each byte is stored in the lower 8-bits of a Unicode character. If \fIencoding\fR is not specified, the current system encoding is used. @@ -48,32 +47,35 @@ .TP \fBencoding system\fR ?\fIencoding\fR? Set the system encoding to \fIencoding\fR. If \fIencoding\fR is omitted then the command returns the current system encoding. The system encoding is used whenever Tcl passes strings to system calls. - .SH EXAMPLE .PP It is common practice to write script files using a text editor that produces output in the euc-jp encoding, which represents the ASCII characters as singe bytes and Japanese characters as two bytes. This makes it easy to embed literal strings that correspond to non-ASCII characters by simply typing the strings in place in the script. However, because the \fBsource\fR command always reads files using the -ISO8859-1 encoding, Tcl will treat each byte in the file as a separate -character that maps to the 00 page in Unicode. The -resulting Tcl strings will not contain the expected Japanese -characters. Instead, they will contain a sequence of Latin-1 -characters that correspond to the bytes of the original string. The -\fBencoding\fR command can be used to convert this string to the -expected Japanese Unicode characters. For example, +current system encoding, Tcl will only source such files correctly +when the encoding used to write the file is the same. This tends not +to be true in an internationalized setting. For example, if such a +file was sourced in North America (where the ISO8859-1 is normally +used), each byte in the file would be treated as a separate character +that maps to the 00 page in Unicode. The resulting Tcl strings will +not contain the expected Japanese characters. Instead, they will +contain a sequence of Latin-1 characters that correspond to the bytes +of the original string. The \fBencoding\fR command can be used to +convert this string to the expected Japanese Unicode characters. For +example, .CS - set s [encoding convertfrom euc-jp "\\xA4\\xCF"] +set s [\fBencoding convertfrom\fR euc-jp "\\xA4\\xCF"] .CE would return the Unicode string "\\u306F", which is the Hiragana letter HA. .SH "SEE ALSO" Tcl_GetEncoding(3) .SH KEYWORDS encoding Index: doc/eof.n ================================================================== --- doc/eof.n +++ doc/eof.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: eof.n,v 1.4 2001/09/14 19:20:40 andreas_kupries Exp $ +'\" RCS: @(#) $Id: eof.n,v 1.4.8.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH eof n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -21,17 +21,43 @@ .PP Returns 1 if an end of file condition occurred during the most recent input operation on \fIchannelId\fR (such as \fBgets\fR), 0 otherwise. .PP -.VS \fIChannelId\fR must be an identifier for an open channel such as a Tcl standard channel (\fBstdin\fR, \fBstdout\fR, or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. -.VE +.SH EXAMPLES +Read and print out the contents of a file line-by-line: +.CS +set f [open somefile.txt] +while {1} { + set line [gets $f] + if {[\fBeof\fR $f]} { + close $f + break + } + puts "Read line: $line" +} +.CE +.PP +Read and print out the contents of a file by fixed-size records: +.CS +set f [open somefile.dat] +fconfigure $f -translation binary +set recordSize 40 +while {1} { + set record [read $f $recordSize] + if {[\fBeof\fR $f]} { + close $f + break + } + puts "Read record: $record" +} +.CE .SH "SEE ALSO" file(n), open(n), close(n), fblocked(n), Tcl_StandardChannels(3) .SH KEYWORDS channel, end of file Index: doc/error.n ================================================================== --- doc/error.n +++ doc/error.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: error.n,v 1.3 2000/09/07 14:27:47 poenitz Exp $ +'\" RCS: @(#) $Id: error.n,v 1.3.18.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH error n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -17,11 +17,11 @@ \fBerror \fImessage\fR ?\fIinfo\fR? ?\fIcode\fR? .BE .SH DESCRIPTION .PP -Returns a TCL_ERROR code, which causes command interpretation to be +Returns a \fBTCL_ERROR\fR code, which causes command interpretation to be unwound. \fIMessage\fR is a string that is returned to the application to indicate what went wrong. .PP If the \fIinfo\fR argument is provided and is non-empty, it is used to initialize the global variable \fBerrorInfo\fR. @@ -51,11 +51,18 @@ page for information on the proper format for the variable. If the \fIcode\fR argument is not present, then \fBerrorCode\fR is automatically reset to ``NONE'' by the Tcl interpreter as part of processing the error generated by the command. +.SH EXAMPLE +Generate an error if a basic mathematical operation fails: +.CS +if {1+2 != 3} { + \fBerror\fR "something is very wrong with addition" +} +.CE .SH "SEE ALSO" -catch(n), tclvars(n) +catch(n), return(n), tclvars(n) .SH KEYWORDS error, errorCode, errorInfo Index: doc/eval.n ================================================================== --- doc/eval.n +++ doc/eval.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: eval.n,v 1.4 2002/08/28 14:46:50 dkf Exp $ +'\" RCS: @(#) $Id: eval.n,v 1.4.2.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH eval n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -25,11 +25,24 @@ fashion as the \fBconcat\fR command, passes the concatenated string to the Tcl interpreter recursively, and returns the result of that evaluation (or any error generated by it). Note that the \fBlist\fR command quotes sequences of words in such a way that they are not further expanded by the \fBeval\fR command. +.SH EXAMPLE +This procedure acts in a way that is analogous to the \fBlappend\fR +command, except it inserts the argument values at the start of the +list in the variable: +.CS +proc lprepend {varName args} { + upvar 1 $varName var + # Ensure that the variable exists and contains a list + lappend var + # Now we insert all the arguments in one go + set var [\fBeval\fR [list linsert $var 0] $args] +} +.CE .SH KEYWORDS concatenate, evaluate, script .SH "SEE ALSO" catch(n), concat(n), error(n), list(n), subst(n), tclvars(n) Index: doc/exec.n ================================================================== --- doc/exec.n +++ doc/exec.n @@ -3,18 +3,18 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: exec.n,v 1.6 2002/04/23 19:06:10 hobbs Exp $ +'\" RCS: @(#) $Id: exec.n,v 1.6.2.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH exec n 7.6 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME -exec \- Invoke subprocess(es) +exec \- Invoke subprocesses .SH SYNOPSIS \fBexec \fR?\fIswitches\fR? \fIarg \fR?\fIarg ...\fR? .BE .SH DESCRIPTION @@ -36,11 +36,11 @@ .TP 13 \fB\-\|\-\fR Marks the end of switches. The argument following this one will be treated as the first \fIarg\fR even if it starts with a \fB\-\fR. .PP -If an \fIarg\fR (or pair of \fIarg\fR's) has one of the forms +If an \fIarg\fR (or pair of \fIarg\fRs) has one of the forms described below then it is used by \fBexec\fR to control the flow of input and output among the subprocess(es). Such arguments will not be passed to the subprocess(es). In forms such as ``< \fIfileName\fR'' \fIfileName\fR may either be in a separate argument from ``<'' or in the same argument with no @@ -215,20 +215,19 @@ 1) CLI -- CommandLine Interface, simple stdio exchange. \fBnetstat.exe\fR for example. .br 2) TUI -- Textmode User Interface, any application that accesses the console API for doing such things as cursor movement, setting text color, detecting -key presses and mouse movement, etc... An example would be \fBtelnet.exe\fR +key presses and mouse movement, etc. An example would be \fBtelnet.exe\fR from Windows 2000. These types of applications are not common in a windows environment, but do exist. .RE \fBexec\fR will not work well with TUI applications when a console is not present, as is done when launching applications under wish. It is desirable to have console applications hidden and detached. This is a designed-in limitation as \fBexec\fR wants to communicate over pipes. The Expect -extension addresses this issue when communication between a TUI application -is desired. +extension addresses this issue when communicating with a TUI application. .sp .RE .TP \fBWindows NT\fR . @@ -252,16 +251,17 @@ The Windows NT home directory. .br The directories listed in the path. .RE .sp -In order to execute the shell builtin commands like \fBdir\fR and \fBcopy\fR, -the caller must prepend ``\fBcmd.exe /c\0\fR'' to the desired command. +In order to execute shell built-in commands like \fBdir\fR and \fBcopy\fR, +the caller must prepend the desired command with ``\fBcmd.exe /c\0\fR'' +because built-in commands are not implemented using executables. .sp .RE .TP -\fBWindows 95\fR +\fBWindows 9x\fR . When attempting to execute an application, \fBexec\fR first searches for the name as it was specified. Then, in order, \fB.com\fR, \fB.exe\fR, and \fB.bat\fR are appended to the end of the specified name and it searches for the longer name. If a directory name was not specified as part of the @@ -272,19 +272,20 @@ .RS The directory from which the Tcl executable was loaded. .br The current directory. .br -The Windows 95 system directory. +The Windows 9x system directory. .br -The Windows 95 home directory. +The Windows 9x home directory. .br The directories listed in the path. .RE .sp -In order to execute the shell builtin commands like \fBdir\fR and \fBcopy\fR, -the caller must prepend ``\fBcommand.com /c\0\fR'' to the desired command. +In order to execute shell built-in commands like \fBdir\fR and \fBcopy\fR, +the caller must prepend the desired command with ``\fBcommand.com /c\0\fR'' +because built-in commands are not implemented using executables. .sp Once a 16-bit DOS application has read standard input from a console and then quit, all subsequently run 16-bit DOS applications will see the standard input as already closed. 32-bit applications do not have this problem and will run correctly, even after a 16-bit DOS application thinks @@ -319,11 +320,92 @@ \fBMacintosh\fR The \fBexec\fR command is not implemented and does not exist under Macintosh. .TP \fBUnix\fR\0\0\0\0\0\0\0 The \fBexec\fR command is fully functional and works as described. + +.SH "UNIX EXAMPLES" +Here are some examples of the use of the \fBexec\fR command on Unix. +.PP +To execute a simple program and get its result: +.CS +\fBexec\fR uname -a +.CE +.PP +To execute a program that can return a non-zero result, you should +wrap the call to \fBexec\fR in \fBcatch\fR and check what the contents +of the global \fBerrorCode\fR variable is if you have an error: +.CS +set status 0 +if {[catch {\fBexec\fR grep foo bar.txt} results]} { + if {[lindex $::errorCode 0] eq "CHILDSTATUS"} { + set status [lindex $::errorCode 2] + } else { + # Some kind of unexpected failure + } +} +.CE +.PP +When translating a command from a Unix shell invocation, care should +be taken over the fact that single quote characters have no special +significance to Tcl. Thus: +.CS +awk '{sum += $1} END {print sum}' numbers.list +.CE +would be translated into something like: +.CS +\fBexec\fR awk {{sum += $1} END {print sum}} numbers.list +.CE +.PP +If you are converting invocations involving shell globbing, you should +remember that Tcl does not handle globbing or expand things into +multiple arguments by default. Instead you should write things like +this: +.CS +eval [list \fBexec\fR ls -l] [glob *.tcl] +.CE +.PP +.SH "WINDOWS EXAMPLES" +Here are some examples of the use of the \fBexec\fR command on Windows. +.PP +To start an instance of \fInotepad\fR editing a file without waiting +for the user to finish editing the file: +.CS +\fBexec\fR notepad myfile.txt & +.CE +.PP +To print a text file using \fInotepad\fR: +.CS +\fBexec\fR notepad /p myfile.txt +.CE +.PP +If a program calls other programs, such as is common with compilers, +then you may need to resort to batch files to hide the console windows +that sometimes pop up: +.CS +\fBexec\fR cmp.bat somefile.c -o somefile +.CE +With the file \fIcmp.bat\fR looking something like: +.CS +@gcc %1 %2 %3 %4 %5 %6 %7 %8 %9 +.CE +.PP +Sometimes you need to be careful, as different programs may have the +same name and be in the path. It can then happen that typing a command +at the DOS prompt finds \fIa different program\fR than the same +command run via \fBexec\fR. This is because of the (documented) +differences in behaviour between \fBexec\fR and DOS batch files. +.PP +When in doubt, use the command \fBauto_execok\fR: it will return the +complete path to the program as seen by the \fBexec\fR command. This +applies especially when you want to run "internal" commands like +\fIdir\fR from a Tcl script (if you just want to list filenames, use +the \fBglob\fR command.) To do that, use this: +.CS +eval [list \fBexec\fR] [auto_execok dir] [list *.tcl] +.CE .SH "SEE ALSO" error(n), open(n) .SH KEYWORDS execute, pipeline, redirection, subprocess Index: doc/exit.n ================================================================== --- doc/exit.n +++ doc/exit.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: exit.n,v 1.3 2000/09/07 14:27:47 poenitz Exp $ +'\" RCS: @(#) $Id: exit.n,v 1.3.18.1 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH exit n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -21,11 +21,33 @@ .PP Terminate the process, returning \fIreturnCode\fR to the system as the exit status. If \fIreturnCode\fR isn't specified then it defaults to 0. +.SH EXAMPLE +Since non-zero exit codes are usually interpreted as error cases by +the calling process, the \fBexit\fR command is an important part of +signalling that something fatal has gone wrong. This code fragment is +useful in scripts to act as a general problem trap: +.CS +proc main {} { + # ... put the real main code in here ... +} + +if {[catch {main} msg]} { + puts stderr "unexpected script error: $msg" + if {[info exist env(DEBUG)]} { + puts stderr "---- BEGIN TRACE ----" + puts stderr $errorInfo + puts stderr "---- END TRACE ----" + } + + # Reserve code 1 for "expected" error exits... + \fBexit\fR 2 +} +.CE .SH "SEE ALSO" exec(n), tclvars(n) .SH KEYWORDS exit, process Index: doc/expr.n ================================================================== --- doc/expr.n +++ doc/expr.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-2000 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: expr.n,v 1.10 2003/01/03 23:03:22 dgp Exp $ +'\" RCS: @(#) $Id: expr.n,v 1.10.2.2 2004/10/27 09:35:38 dkf Exp $ '\" .so man.macros .TH expr n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -17,11 +17,11 @@ \fBexpr \fIarg \fR?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP -Concatenates \fIarg\fR's (adding separator spaces between them), +Concatenates \fIarg\fRs (adding separator spaces between them), evaluates the result as a Tcl expression, and returns the value. The operators permitted in Tcl expressions are a subset of the operators permitted in C expressions, and they have the same meaning and precedence as the corresponding C operators. Expressions almost always yield numeric results @@ -49,13 +49,14 @@ possible. Floating-point numbers may be specified in any of the ways accepted by an ANSI-compliant C compiler (except that the \fBf\fR, \fBF\fR, \fBl\fR, and \fBL\fR suffixes will not be permitted in most installations). For example, all of the following are valid floating-point numbers: 2.1, 3., 6e4, 7.91e+16. -If no numeric interpretation is possible, then an operand is left -as a string (and only a limited set of operators may be applied to -it). +If no numeric interpretation is possible (note that all literal +operands that are not numeric or boolean must be quoted with either +braces or with double quotes), then an operand is left as a string +(and only a limited set of operators may be applied to it). .PP .VS 8.4 On 32-bit systems, integer values MAX_INT (0x7FFFFFFF) and MIN_INT (-0x80000000) will be represented as 32-bit values, and integer values outside that range will be represented as 64-bit values (if that is @@ -62,37 +63,38 @@ possible at all.) .VE 8.4 .PP Operands may be specified in any of the following ways: .IP [1] -As an numeric value, either integer or floating-point. +As a numeric value, either integer or floating-point. .IP [2] +As a boolean value, using any form understood by \fBstring is boolean\fR. +.IP [3] As a Tcl variable, using standard \fB$\fR notation. The variable's value will be used as the operand. -.IP [3] +.IP [4] As a string enclosed in double-quotes. The expression parser will perform backslash, variable, and command substitutions on the information between the quotes, and use the resulting value as the operand -.IP [4] +.IP [5] As a string enclosed in braces. The characters between the open brace and matching close brace will be used as the operand without any substitutions. -.IP [5] +.IP [6] As a Tcl command enclosed in brackets. The command will be executed and its result will be used as the operand. -.IP [6] +.IP [7] As a mathematical function whose arguments have any of the above forms for operands, such as \fBsin($x)\fR. See below for a list of defined functions. .LP -Where substitutions occur above (e.g. inside quoted strings), they +Where the above substitutions occur (e.g. inside quoted strings), they are performed by the expression's instructions. -However, an additional layer of substitution may already have -been performed by the command parser before the expression -processor was called. +However, the command parser may already have performed one round of +substitution before the expression processor was called. As discussed below, it is usually best to enclose expressions in braces to prevent the command parser from performing substitutions on the contents. .PP For some examples of simple expressions, suppose the variable @@ -111,16 +113,16 @@ .PP The valid operators are listed below, grouped in decreasing order of precedence: .TP 20 \fB\-\0\0+\0\0~\0\0!\fR -Unary minus, unary plus, bit-wise NOT, logical NOT. None of these operands +Unary minus, unary plus, bit-wise NOT, logical NOT. None of these operators may be applied to string operands, and bit-wise NOT may be applied only to integers. .TP 20 \fB*\0\0/\0\0%\fR -Multiply, divide, remainder. None of these operands may be +Multiply, divide, remainder. None of these operators may be applied to string operands, and remainder may be applied only to integers. The remainder will always have the same sign as the divisor and an absolute value smaller than the divisor. .TP 20 @@ -167,11 +169,11 @@ .TP 20 \fIx\fB?\fIy\fB:\fIz\fR If-then-else, as in C. If \fIx\fR evaluates to non-zero, then the result is the value of \fIy\fR. Otherwise the result is the value of \fIz\fR. -The \fIx\fR operand must have a numeric value. +The \fIx\fR operand must have a boolean or numeric value. .LP See the C manual for more details on the results produced by each operator. All of the binary operators group left-to-right within the same precedence level. For example, the command @@ -192,18 +194,19 @@ only true if the entire expression is enclosed in braces; otherwise the Tcl parser will evaluate both \fB[a]\fR and \fB[b]\fR before invoking the \fBexpr\fR command. .SH "MATH FUNCTIONS" .PP -Tcl supports the following mathematical functions in expressions: +Tcl supports the following mathematical functions in expressions, all +of which work solely with floating-point numbers unless otherwise noted: .DS .ta 3c 6c 9c \fBabs\fR \fBcosh\fR \fBlog\fR \fBsqrt\fR \fBacos\fR \fBdouble\fR \fBlog10\fR \fBsrand\fR \fBasin\fR \fBexp\fR \fBpow\fR \fBtan\fR \fBatan\fR \fBfloor\fR \fBrand\fR \fBtanh\fR -\fBatan2\fR \fBfmod\fR \fBround\fR +\fBatan2\fR \fBfmod\fR \fBround\fR \fBwide\fR \fBceil\fR \fBhypot\fR \fBsin\fR \fBcos\fR \fBint\fR \fBsinh\fR .DE .PP .TP @@ -227,11 +230,11 @@ Returns the arc tangent of \fIy\fR/\fIx\fR, in the range [\fI-pi\fR,\fIpi\fR] radians. \fIx\fR and \fIy\fR cannot both be 0. If \fIx\fR is greater than \fI0\fR, this is equivalent to \fBatan(\fIy/x\fB)\fR. .TP \fBceil(\fIarg\fB)\fR -Returns the smallest integral floating point value (i.e. with a zero +Returns the smallest integral floating-point value (i.e. with a zero fractional part) not less than \fIarg\fR. .TP \fBcos(\fIarg\fB)\fR Returns the cosine of \fIarg\fR, measured in radians. .TP @@ -238,19 +241,19 @@ \fBcosh(\fIarg\fB)\fR Returns the hyperbolic cosine of \fIarg\fR. If the result would cause an overflow, an error is returned. .TP \fBdouble(\fIarg\fB)\fR -If \fIarg\fR is a floating value, returns \fIarg\fR, otherwise converts -\fIarg\fR to floating and returns the converted value. +If \fIarg\fR is a floating-point value, returns \fIarg\fR, otherwise converts +\fIarg\fR to floating-point and returns the converted value. .TP \fBexp(\fIarg\fB)\fR Returns the exponential of \fIarg\fR, defined as \fIe\fR**\fIarg\fR. If the result would cause an overflow, an error is returned. .TP \fBfloor(\fIarg\fB)\fR -Returns the largest integral floating point value (i.e. with a zero +Returns the largest integral floating-point value (i.e. with a zero fractional part) not greater than \fIarg\fR. .TP \fBfmod(\fIx, y\fB)\fR Returns the floating-point remainder of the division of \fIx\fR by \fIy\fR. If \fIy\fR is 0, an error is returned. @@ -259,11 +262,12 @@ Computes the length of the hypotenuse of a right-angled triangle \fBsqrt(\fIx\fR*\fIx\fR+\fIy\fR*\fIy\fB)\fR. .TP \fBint(\fIarg\fB)\fR .VS 8.4 -If \fIarg\fR is an integer value, returns \fIarg\fR, otherwise +If \fIarg\fR is an integer value of the same width as the machine +word, returns \fIarg\fR, otherwise converts \fIarg\fR to an integer (of the same size as a machine word, i.e. 32-bits on 32-bit systems, and 64-bits on 64-bit systems) by truncation and returns the converted value. .VE 8.4 .TP @@ -278,11 +282,11 @@ \fBpow(\fIx, y\fB)\fR Computes the value of \fIx\fR raised to the power \fIy\fR. If \fIx\fR is negative, \fIy\fR must be an integer value. .TP \fBrand()\fR -Returns a pseudo-random floating point value in the range (\fI0\fR,\fI1\fR). +Returns a pseudo-random floating-point value in the range (\fI0\fR,\fI1\fR). The generator algorithm is a simple linear congruential generator that is not cryptographically secure. Each result from \fBrand\fR completely determines all future results from subsequent calls to \fBrand\fR, so \fBrand\fR should not be used to generate a sequence of secrets, such as one-time passwords. The seed of the generator is initialized from the @@ -303,22 +307,22 @@ Returns the square root of \fIarg\fR. \fIArg\fR must be non-negative. .TP \fBsrand(\fIarg\fB)\fR The \fIarg\fR, which must be an integer, is used to reset the seed for the random number generator of \fBrand\fR. Returns the first random -number from that seed. Each interpreter has its own seed. +number (see \fBrand()\fR) from that seed. Each interpreter has its own seed. .TP \fBtan(\fIarg\fB)\fR Returns the tangent of \fIarg\fR, measured in radians. .TP \fBtanh(\fIarg\fB)\fR Returns the hyperbolic tangent of \fIarg\fR. .TP \fBwide(\fIarg\fB)\fR .VS 8.4 -Converts \fIarg\fR to a value at least 64-bits wide (by sign-extension -if \fIarg\fR is a 32-bit number.) +Converts \fIarg\fR to an integer value at least 64-bits wide (by sign-extension +if \fIarg\fR is a 32-bit number) if it is not one already. .VE 8.4 .PP In addition to these predefined functions, applications may define additional functions using \fBTcl_CreateMathFunc\fR(). .SH "TYPES, OVERFLOW, AND PRECISION" @@ -355,11 +359,10 @@ example, .CS \fBexpr 20.0/5.0\fR .CE returns \fB4.0\fR, not \fB4\fR. - .SH "STRING OPERATIONS" .PP String values may be used as operands of the comparison operators, although the expression evaluator tries to do comparisons as integer or floating-point when it can, @@ -416,11 +419,53 @@ additional instructions to handle this situation. The most expensive code is required for unbraced expressions that contain command substitutions. These expressions must be implemented by generating new code each time the expression is executed. +.SH EXAMPLES +Define a procedure that computes an "interesting" mathematical +function: +.CS +proc calc {x y} { + \fBexpr\fR { ($x*$x - $y*$y) / exp($x*$x + $y*$y) } +} +.CE +.PP +Convert polar coordinates into cartesian coordinates: +.CS +# convert from ($radius,$angle) +set x [\fBexpr\fR { $radius * cos($angle) }] +set y [\fBexpr\fR { $radius * sin($angle) }] +.CE +.PP +Convert cartesian coordinates into polar coordinates: +.CS +# convert from ($x,$y) +set radius [\fBexpr\fR { hypot($y, $x) }] +set angle [\fBexpr\fR { atan2($y, $x) }] +.CE +.PP +Print a message describing the relationship of two string values to +each other: +.CS +puts "a and b are [\fBexpr\fR {$a eq $b ? {equal} : {different}}]" +.CE +.PP +Set a variable to whether an environment variable is both defined at +all and also set to a true boolean value: +.CS +set isTrue [\fBexpr\fR { + [info exists ::env(SOME_ENV_VAR)] && + [string is true -strict $::env(SOME_ENV_VAR)] +}] +.CE +.PP +Generate a random integer in the range 0..99 inclusive: +.CS +set randNum [\fBexpr\fR { int(100 * rand()) }] +.CE .SH "SEE ALSO" -array(n), string(n), Tcl(n) +array(n), for(n), if(n), string(n), Tcl(n), while(n) .SH KEYWORDS arithmetic, boolean, compare, expression, fuzzy comparison Index: doc/fblocked.n ================================================================== --- doc/fblocked.n +++ doc/fblocked.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: fblocked.n,v 1.4 2001/09/14 19:20:40 andreas_kupries Exp $ +'\" RCS: @(#) $Id: fblocked.n,v 1.4.8.1 2004/10/27 12:52:39 dkf Exp $ .so man.macros .TH fblocked n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME @@ -29,11 +29,45 @@ \fIChannelId\fR must be an identifier for an open channel such as a Tcl standard channel (\fBstdin\fR, \fBstdout\fR, or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. .VE +.SH EXAMPLE +The \fBfblocked\fR command is particularly useful when writing network +servers, as it allows you to write your code in a line-by-line style +without preventing the servicing of other connections. This can be +seen in this simple echo-service: +.PP +.CS +# This is called whenever a new client connects to the server +proc connect {chan host port} { + set clientName [format <%s:%d> $host $port] + puts "connection from $clientName" + fconfigure $chan -blocking 0 -buffering line + fileevent $chan readable [list echoLine $chan $clientName] +} + +# This is called whenever either at least one byte of input +# data is available, or the channel was closed by the client. +proc echoLine {chan clientName} { + gets $chan line + if {[eof $chan]} { + puts "finishing connection from $clientName" + close $chan + } elseif {![\fBfblocked\fR $chan]} { + # Didn't block waiting for end-of-line + puts "$clientName - $line" + puts $chan $line + } +} + +# Create the server socket and enter the event-loop to wait +# for incoming connections... +socket -server connect 12345 +vwait forever +.CE .SH "SEE ALSO" -gets(n), open(n), read(n), Tcl_StandardChannels(3) +gets(n), open(n), read(n), socket(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, nonblocking Index: doc/fconfigure.n ================================================================== --- doc/fconfigure.n +++ doc/fconfigure.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: fconfigure.n,v 1.7 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: fconfigure.n,v 1.7.2.3 2006/03/14 22:51:13 andreas_kupries Exp $ '\" .so man.macros .TH fconfigure n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -163,10 +163,17 @@ No end-of-line translations are performed. This is nearly identical to \fBlf\fP mode, except that in addition \fBbinary\fP mode also sets the end-of-file character to the empty string (which disables it) and sets the encoding to \fBbinary\fR (which disables encoding filtering). See the description of \fB\-eofchar\fR and \fB\-encoding\fR for more information. +.PP +.RS +Internally, i.e. when it comes to the actual behaviour of the +translator this value \fBis\fR identical to \fBlf\fR and is therefore +reported as such when queried. Even if \fBbinary\fR was used to set +the translation. +.RE .TP \fBcr\fR . The end of a line in the underlying file or device is represented by a single carriage return character. As the input translation mode, @@ -190,218 +197,83 @@ single newline (linefeed) character. In this mode no translations occur during either input or output. This mode is typically used on UNIX platforms. .RE .PP - .SH "STANDARD CHANNELS" .PP The Tcl standard channels (\fBstdin\fR, \fBstdout\fR, and \fBstderr\fR) can be configured through this command like every other channel opened by the Tcl library. Beyond the standard options described above they will also support any special option according to their current type. If, for example, a Tcl application is started by the \fBinet\fR super-server common on Unix system its Tcl standard channels will be sockets and thus support the socket options. - -.VS 8.4 -.SH "SERIAL PORT CONFIGURATION OPTIONS" -.PP -If \fIchannelId\fR refers to a serial port, then the following -additional configuration options are available on Windows and -Unix systems with a POSIX serial interface: - -.TP -\fB\-mode\fR \fIbaud\fB,\fIparity\fB,\fIdata\fB,\fIstop\fR -. -This option is a set of 4 comma-separated values: the baud rate, parity, -number of data bits, and number of stop bits for this serial port. The -\fIbaud\fR rate is a simple integer that specifies the connection speed. -\fIParity\fR is one of the following letters: \fBn\fR, \fBo\fR, \fBe\fR, -\fBm\fR, \fBs\fR; respectively signifying the parity options of ``none'', -``odd'', ``even'', ``mark'', or ``space''. \fIData\fR is the number of -data bits and should be an integer from 5 to 8, while \fIstop\fR is the -number of stop bits and should be the integer 1 or 2. - -.TP -\fB\-handshake\fR \fItype\fR -. -(Windows and Unix). This option is used to setup automatic handshake -control. Note that not all handshake types maybe supported by your operating -system. The \fItype\fR parameter is case-independent. - -If \fItype\fR is \fBnone\fR then any handshake is switched off. -\fBrtscts\fR activates hardware handshake. Hardware handshake signals -are described below. -For software handshake \fBxonxoff\fR the handshake characters can be redefined -with \fB-xchar\fR. -An additional hardware handshake \fBdtrdsr\fR is available only under Windows. -There is no default handshake configuration, the initial value depends -on your operating system settings. -The \fB-handshake\fR option cannot be queried. - -.TP -\fB\-queue\fR -. -(Windows and Unix). The \fB-queue\fR option can only be queried. -It returns a list of two integers representing the current number -of bytes in the input and output queue respectively. - -.TP -\fB\-timeout\fR \fImsec\fR -. -(Windows and Unix). This option is used to set the timeout for blocking -read operations. It specifies the maximum interval between the -reception of two bytes in milliseconds. -For Unix systems the granularity is 100 milliseconds. -The \fB-timeout\fR option does not affect write operations or -nonblocking reads. -This option cannot be queried. - -.TP -\fB\-ttycontrol\fR \fI{signal boolean signal boolean ...}\fR -. -(Windows and Unix). This option is used to setup the handshake -output lines (see below) permanently or to send a BREAK over the serial line. -The \fIsignal\fR names are case-independent. -\fB{RTS 1 DTR 0}\fR sets the RTS output to high and the DTR output to low. -The BREAK condition (see below) is enabled and disabled with \fB{BREAK 1}\fR and -\fB{BREAK 0}\fR respectively. -It's not a good idea to change the \fBRTS\fR (or \fBDTR\fR) signal -with active hardware handshake \fBrtscts\fR (or \fBdtrdsr\fR). -The result is unpredictable. -The \fB-ttycontrol\fR option cannot be queried. - -.TP -\fB\-ttystatus\fR -. -(Windows and Unix). The \fB-ttystatus\fR option can only be -queried. It returns the current modem status and handshake input signals -(see below). -The result is a list of signal,value pairs with a fixed order, -e.g. \fB{CTS 1 DSR 0 RING 1 DCD 0}\fR. -The \fIsignal\fR names are returned upper case. - -.TP -\fB\-xchar\fR \fI{xonChar xoffChar}\fR -. -(Windows and Unix). This option is used to query or change the software -handshake characters. Normally the operating system default should be -DC1 (0x11) and DC3 (0x13) representing the ASCII standard -XON and XOFF characters. - -.TP -\fB\-pollinterval\fR \fImsec\fR -. -(Windows only). This option is used to set the maximum time between -polling for fileevents. -This affects the time interval between checking for events throughout the Tcl -interpreter (the smallest value always wins). Use this option only if -you want to poll the serial port more or less often than 10 msec -(the default). - -.TP -\fB\-sysbuffer\fR \fIinSize\fR -.TP -\fB\-sysbuffer\fR \fI{inSize outSize}\fR -. -(Windows only). This option is used to change the size of Windows -system buffers for a serial channel. Especially at higher communication -rates the default input buffer size of 4096 bytes can overrun -for latent systems. The first form specifies the input buffer size, -in the second form both input and output buffers are defined. - -.TP -\fB\-lasterror\fR -. -(Windows only). This option is query only. -In case of a serial communication error, \fBread\fR or \fBputs\fR -returns a general Tcl file I/O error. -\fBfconfigure -lasterror\fR can be called to get a list of error details. -See below for an explanation of the various error codes. - -.SH "SERIAL PORT SIGNALS" -.PP -RS-232 is the most commonly used standard electrical interface for serial -communications. A negative voltage (-3V..-12V) define a mark (on=1) bit and -a positive voltage (+3..+12V) define a space (off=0) bit (RS-232C). The -following signals are specified for incoming and outgoing data, status -lines and handshaking. Here we are using the terms \fIworkstation\fR for -your computer and \fImodem\fR for the external device, because some signal -names (DCD, RI) come from modems. Of course your external device may use -these signal lines for other purposes. -.RS -.IP \fBTXD(output)\fR -\fBTransmitted Data:\fR Outgoing serial data. -.IP \fBRXD(input)\fR -\fBReceived Data:\fRIncoming serial data. -.IP \fBRTS(output)\fR -\fBRequest To Send:\fR This hardware handshake line informs the modem that -your workstation is ready to receive data. Your workstation may -automatically reset this signal to indicate that the input buffer is full. -.IP \fBCTS(input)\fR -\fBClear To Send:\fR The complement to RTS. Indicates that the modem is -ready to receive data. -.IP \fBDTR(output)\fR -\fBData Terminal Ready:\fR This signal tells the modem that the workstation -is ready to establish a link. DTR is often enabled automatically whenever a -serial port is opened. -.IP \fBDSR(input)\fR -\fBData Set Ready:\fR The complement to DTR. Tells the workstation that the -modem is ready to establish a link. -.IP \fBDCD(input)\fR -\fBData Carrier Detect:\fR This line becomes active when a modem detects -a "Carrier" signal. -.IP \fBRI(input)\fR -\fBRing Indicator:\fR Goes active when the modem detects an incoming call. -.IP \fBBREAK\fR -A BREAK condition is not a hardware signal line, but a logical zero on the -TXD or RXD lines for a long period of time, usually 250 to 500 -milliseconds. Normally a receive or transmit data signal stays at the mark -(on=1) voltage until the next character is transferred. A BREAK is sometimes -used to reset the communications line or change the operating mode of -communications hardware. -.RE - -.SH "ERROR CODES (Windows only)" -.PP -A lot of different errors may occur during serial read operations or during -event polling in background. The external device may have been switched -off, the data lines may be noisy, system buffers may overrun or your mode -settings may be wrong. That's why a reliable software should always -\fBcatch\fR serial read operations. In cases of an error Tcl returns a -general file I/O error. Then \fBfconfigure -lasterror\fR may help to -locate the problem. The following error codes may be returned. -.RS -.IP \fBRXOVER:\fR -Windows input buffer overrun. The data comes faster than your scripts reads -it or your system is overloaded. Use \fBfconfigure -sysbuffer\fR to avoid a -temporary bottleneck and/or make your script faster. -.IP \fBTXFULL\fR -Windows output buffer overrun. Complement to RXOVER. This error should -practically not happen, because Tcl cares about the output buffer status. -.IP \fBOVERRUN\fR -UART buffer overrun (hardware) with data lost. -The data comes faster than the system driver receives it. -Check your advanced serial port settings to enable the FIFO (16550) buffer -and/or setup a lower(1) interrupt threshold value. -.IP \fBRXPARITY\fR -A parity error has been detected by your UART. -Wrong parity settings with \fBfconfigure -mode\fR or a noisy data line (RXD) -may cause this error. -.IP \fBFRAME\fR -A stop-bit error has been detected by your UART. -Wrong mode settings with \fBfconfigure -mode\fR or a noisy data line (RXD) -may cause this error. -.IP \fBBREAK\fR -A BREAK condition has been detected by your UART (see above). -.RE -.VE +.SH EXAMPLES +Instruct Tcl to always send output to \fBstdout\fR immediately, +whether or not it is to a terminal: +.CS +\fBfconfigure\fR stdout -buffering none +.CE +.PP +Open a socket and read lines from it without ever blocking the +processing of other events: +.CS +set s [socket some.where.com 12345] +\fBfconfigure\fR $s -blocking 0 +fileevent $s readable "readMe $s" +proc readMe chan { + if {[gets $chan line] < 0} { + if {[eof $chan]} { + close $chan + return + } + # Could not read a complete line this time; Tcl's + # internal buffering will hold the partial line for us + # until some more data is available over the socket. + } else { + puts stdout $line + } +} +.CE +.PP +Read a PPM-format image from a file: +.CS +# Open the file and put it into Unix ASCII mode +set f [open teapot.ppm] +\fBfconfigure\fR $f \-encoding ascii \-translation lf + +# Get the header +if {[gets $f] ne "P6"} { + error "not a raw\-bits PPM" +} + +# Read lines until we have got non-comment lines +# that supply us with three decimal values. +set words {} +while {[llength $words] < 3} { + gets $f line + if {[string match "#*" $line]} continue + lappend words [eval concat [scan $line %d%d%d]] +} + +# Those words supply the size of the image and its +# overall depth per channel. Assign to variables. +foreach {xSize ySize depth} $words {break} + +# Now switch to binary mode to pull in the data, +# one byte per channel (red,green,blue) per pixel. +\fBfconfigure\fR $f \-translation binary +set numDataBytes [expr {3 * $xSize * $ySize}] +set data [read $f $numDataBytes] + +close $f +.CE .SH "SEE ALSO" -close(n), flush(n), gets(n), puts(n), read(n), socket(n), +close(n), flush(n), gets(n), open(n), puts(n), read(n), socket(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, buffering, carriage return, end of line, flushing, linemode, newline, nonblocking, platform, translation, encoding, filter, byte array, binary Index: doc/fcopy.n ================================================================== --- doc/fcopy.n +++ doc/fcopy.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: fcopy.n,v 1.3 2001/05/19 16:59:04 andreas_kupries Exp $ +'\" RCS: @(#) $Id: fcopy.n,v 1.3.14.1 2007/01/29 16:50:35 dgp Exp $ '\" .so man.macros .TH fcopy n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -113,11 +113,11 @@ in the command callback .DS proc CopyMore {in out chunk bytes {error {}}} { global total done incr total $bytes - if {([string length $error] != 0) || [eof $in] { + if {([string length $error] != 0) || [eof $in]} { set done $total close $in close $out } else { fcopy $in $out -command [list CopyMore $in $out $chunk] \\ Index: doc/file.n ================================================================== --- doc/file.n +++ doc/file.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: file.n,v 1.23 2003/02/28 12:11:49 vincentdarley Exp $ +'\" RCS: @(#) $Id: file.n,v 1.23.2.3 2006/12/04 09:12:02 dkf Exp $ '\" .so man.macros .TH file n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -99,11 +99,11 @@ recursively copied into \fItargetDir\fR. Existing files will not be overwritten unless the \fB\-force\fR option is specified. When copying within a single filesystem, \fIfile copy\fR will copy soft links (i.e. the links themselves are copied, not the things they point to). Trying to overwrite a non-empty directory, overwrite a directory with a file, -or a file with a directory will all result in errors even if +or overwrite a file with a directory will all result in errors even if \fI\-force\fR was specified. Arguments are processed in the order specified, halting at the first error, if any. A \fB\-\|\-\fR marks the end of switches; the argument following the \fB\-\|\-\fR will be treated as a \fIsource\fR even if it starts with a \fB\-\fR. .RE @@ -198,12 +198,12 @@ \fIlinkName\fR (i.e. the name of the file it points to). If \fIlinkName\fR isn't a link or its value cannot be read (as, for example, seems to be the case with hard links, which look just like ordinary files), then an error is returned. . -If 2 arguments are given, then these are assumed to be \fIlinkName\fR and -\fItarget\fR. If \fIlinkName\fR already exists, or if \fItarget\fR +If 2 arguments are given, then these are assumed to be \fIlinkName\fR +and \fItarget\fR. If \fIlinkName\fR already exists, or if \fItarget\fR doesn't exist, an error will be returned. Otherwise, Tcl creates a new link called \fIlinkName\fR which points to the existing filesystem object at \fItarget\fR, where the type of the link is platform-specific (on Unix a symbolic link will be the default). This is useful for the case where the user wishes to create a link in a cross-platform way, and doesn't @@ -256,18 +256,18 @@ under Windows or AppleScript on the Macintosh. .TP \fBfile normalize \fIname\fR . .RS -Returns a unique normalised path representation for the file-system +Returns a unique normalized path representation for the file-system object (file, directory, link, etc), whose string value can be used as a unique identifier for it. A normalized path is an absolute path which has all '../', './' removed. Also it is one which is in the ``standard'' format for the native platform. On MacOS, Unix, this means the segments leading up to the path must be free of symbolic links/aliases (but the very last path component may be a symbolic link), and on Windows it also -means means we want the long form with that form's case-dependence (which +means we want the long form with that form's case-dependence (which gives us a unique, case-dependent path). The one exception concerning the last link in the path is necessary, because Tcl or the user may wish to operate on the actual symbolic link itself (for example 'file delete', 'file rename', 'file copy' are defined to operate on symbolic links, not on the things that they point to). @@ -284,11 +284,11 @@ \fIname\fR refers to a specific file on a specific volume, the path type will be \fBabsolute\fR. If \fIname\fR refers to a file relative to the current working directory, then the path type will be \fBrelative\fR. If \fIname\fR refers to a file relative to the current working directory on a specified volume, or to a specific file on the current working volume, then -the file type is \fBvolumerelative\fR. +the path type is \fBvolumerelative\fR. .TP \fBfile readable \fIname\fR . Returns \fB1\fR if file \fIname\fR is readable by the current user, \fB0\fR otherwise. @@ -416,12 +416,49 @@ .TP \fBUnix\fR\0\0\0\0\0\0\0 . These commands always operate using the real user and group identifiers, not the effective ones. +.SH EXAMPLES +This procedure shows how to search for C files in a given directory +that have a correspondingly-named object file in the current +directory: +.CS +proc findMatchingCFiles {dir} { + set files {} + switch $::tcl_platform(platform) { + windows { + set ext .obj + } + unix { + set ext .o + } + } + foreach file [glob -nocomplain -directory $dir *.c] { + set objectFile [\fBfile tail\fR [\fBfile rootname\fR $file]]$ext + if {[\fBfile exists\fR $objectFile]} { + lappend files $file + } + } + return $files +} +.CE +.PP +Rename a file and leave a symbolic link pointing from the old location +to the new place: +.CS +set oldName foobar.txt +set newName foo/bar.txt +# Make sure that where we're going to move to exists... +if {![\fBfile isdirectory\fR [\fBfile dirname\fR $newName]]} { + \fBfile mkdir\fR [\fBfile dirname\fR $newName] +} +\fBfile rename\fR $oldName $newName +\fBfile link\fR -symbolic $oldName $newName +.CE .SH "SEE ALSO" filename(n), open(n), close(n), eof(n), gets(n), tell(n), seek(n), fblocked(n), flush(n) .SH KEYWORDS attributes, copy files, delete files, directory, file, move files, name, rename files, stat Index: doc/fileevent.n ================================================================== --- doc/fileevent.n +++ doc/fileevent.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: fileevent.n,v 1.5 2001/09/27 05:50:56 andreas_kupries Exp $ +'\" RCS: @(#) $Id: fileevent.n,v 1.5.6.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH fileevent n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -98,25 +98,22 @@ If an error occurs while executing the script then the \fBbgerror\fR mechanism is used to report the error. In addition, the file event handler is deleted if it ever returns an error; this is done in order to prevent infinite loops due to buggy handlers. - .SH EXAMPLE -.PP +In this setup \fBGetData\fR will be called with the channel as an +argument whenever $chan becomes readable. .CS - proc GetData {chan} { +proc GetData {chan} { if {![eof $chan]} { puts [gets $chan] } - } +} - fileevent $chan readable [list GetData $chan] - +\fBfileevent\fR $chan readable [list GetData $chan] .CE -In this setup \fBGetData\fR will be called with the channel as an -argument whenever $chan becomes readable. .SH CREDITS .PP \fBfileevent\fR is based on the \fBaddinput\fR command created by Mark Diekhans. Index: doc/filename.n ================================================================== --- doc/filename.n +++ doc/filename.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: filename.n,v 1.7 2001/09/04 18:06:34 vincentdarley Exp $ +'\" RCS: @(#) $Id: filename.n,v 1.7.12.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH filename n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -206,12 +206,19 @@ more than 3 characters. .PP On Windows platforms there are file and path length restrictions. Complete paths or filenames longer than about 260 characters will lead to errors in most file operations. - +.PP +Another Windows peculiarity is that any number of trailing dots '.' in +filenames are totally ignored, so, for example, attempts to create a +file or directory with a name "foo." will result in the creation of a +file/directory with name "foo". This fact is reflected in the +results of 'file normalize'. Furthermore, a file name consisting only +of dots '.........' or dots with trailing characters '.....abc' is +illegal. .SH KEYWORDS current directory, absolute file name, relative file name, volume-relative file name, portability .SH "SEE ALSO" file(n), glob(n) Index: doc/flush.n ================================================================== --- doc/flush.n +++ doc/flush.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: flush.n,v 1.4 2001/09/14 19:20:40 andreas_kupries Exp $ +'\" RCS: @(#) $Id: flush.n,v 1.4.8.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH flush n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -32,11 +32,19 @@ If the channel is in blocking mode the command does not return until all the buffered output has been flushed to the channel. If the channel is in nonblocking mode, the command may return before all buffered output has been flushed; the remainder will be flushed in the background as fast as the underlying file or device is able to absorb it. +.SH EXAMPLE +Prompt for the user to type some information in on the console: +.CS +puts -nonewline "Please type your name: " +\fBflush\fR stdout +gets stdin name +puts "Hello there, $name!" +.CE .SH "SEE ALSO" file(n), open(n), socket(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, buffer, channel, flush, nonblocking, output Index: doc/for.n ================================================================== --- doc/for.n +++ doc/for.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: for.n,v 1.3 2000/09/07 14:27:48 poenitz Exp $ +'\" RCS: @(#) $Id: for.n,v 1.3.18.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH for n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -46,18 +46,39 @@ made by the loop body will not be considered in the expression. This is likely to result in an infinite loop. If \fItest\fR is enclosed in braces, variable substitutions are delayed until the expression is evaluated (before each loop iteration), so changes in the variables will be visible. -For an example, try the following script with and without the braces -around \fB$x<10\fR: +See below for an example: +.SH EXAMPLES +Print a line for each of the integers from 0 to 10: .CS for {set x 0} {$x<10} {incr x} { - puts "x is $x" + puts "x is $x" +} +.CE +.PP +Either loop infinitely or not at all because the expression being +evaluated is actually the constant, or even generate an error! The +actual behaviour will depend on whether the variable \fIx\fR exists +before the \fBfor\fR command is run and whether its value is a value +that is less than or greater than/equal to ten, and this is because +the expression will be substituted before the \fBfor\fR command is +executed. +.CS +for {set x 0} $x<10 {incr x} { + puts "x is $x" +} +.CE +.PP +Print out the powers of two from 1 to 1024: +.CS +for {set x 1} {$x<=1024} {set x [expr {$x * 2}]} { + puts "x is $x" } .CE .SH "SEE ALSO" break, continue, foreach, while .SH KEYWORDS for, iteration, looping Index: doc/foreach.n ================================================================== --- doc/foreach.n +++ doc/foreach.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: foreach.n,v 1.3 2000/09/07 14:27:48 poenitz Exp $ +'\" RCS: @(#) $Id: foreach.n,v 1.3.18.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH foreach n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -54,31 +54,31 @@ .PP The following loop uses i and j as loop variables to iterate over pairs of elements of a single list. .DS set x {} -foreach {i j} {a b c d e f} { +\fBforeach\fR {i j} {a b c d e f} { lappend x $j $i } # The value of x is "b a d c f e" # There are 3 iterations of the loop. .DE .PP The next loop uses i and j to iterate over two lists in parallel. .DS set x {} -foreach i {a b c} j {d e f g} { +\fBforeach\fR i {a b c} j {d e f g} { lappend x $i $j } # The value of x is "a d b e c f {} g" # There are 4 iterations of the loop. .DE .PP The two forms are combined in the following example. .DS set x {} -foreach i {a b c} {j k} {d e f g} { +\fBforeach\fR i {a b c} {j k} {d e f g} { lappend x $i $j $k } # The value of x is "a d e b f g c {} {}" # There are 3 iterations of the loop. .DE Index: doc/format.n ================================================================== --- doc/format.n +++ doc/format.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: format.n,v 1.7 2002/02/19 10:26:24 dkf Exp $ +'\" RCS: @(#) $Id: format.n,v 1.7.2.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH format n 8.1 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -24,11 +24,10 @@ implementation). \fIFormatString\fR indicates how to format the result, using \fB%\fR conversion specifiers as in \fBsprintf\fR, and the additional arguments, if any, provide values to be substituted into the result. The return value from \fBformat\fR is the formatted string. - .SH "DETAILS ON FORMATTING" .PP The command operates by scanning \fIformatString\fR from left to right. Each character from the format string is appended to the result string unless it is a percent sign. @@ -131,11 +130,11 @@ If it is \fBh\fR it specifies that the numeric value should be truncated to a 16-bit value before converting. This option is rarely useful. .VS 8.4 If it is \fBl\fR it specifies that the numeric value should be (at -least) a 64-bit value. If neither \fBh\fR or \fBl\fR are present, +least) a 64-bit value. If neither \fBh\fR nor \fBl\fR are present, numeric values are interpreted as being values of the width of the native machine word, as described by \fBtcl_platform(wordSize)\fR. .VE .PP The last thing in a conversion specifier is an alphabetic character @@ -194,11 +193,10 @@ .LP For the numerical conversions the argument being converted must be an integer or floating-point string; format converts the argument to binary and then converts it back to a string according to the conversion specifier. - .SH "DIFFERENCES FROM ANSI SPRINTF" .PP The behavior of the format command is the same as the ANSI C \fBsprintf\fR procedure except for the following differences: @@ -216,11 +214,58 @@ of real and integer values, respectively). .VE 8.4 If the \fBh\fR modifier is specified then integer values are truncated to \fBshort\fR before conversion. Both \fBh\fR and \fBl\fR modifiers are ignored on all other conversions. +.SH EXAMPLES +Convert the output of \fBtime\fR into seconds to an accuracy of +hundredths of a second: +.CS +set us [lindex [time $someTclCode] 0] +puts [\fBformat\fR "%.2f seconds to execute" [expr {$us / 1e6}]] +.CE +.PP +Create a packed X11 literal color specification: +.CS +# Each color-component should be in range (0..255) +set color [\fBformat\fR "#%02x%02x%02x" $r $g $b] +.CE +.PP +Use XPG3 format codes to allow reordering of fields (a technique that +is often used in localized message catalogs; see \fBmsgcat\fR) without +reordering the data values passed to \fBformat\fR: +.CS +set fmt1 "Today, %d shares in %s were bought at $%.2f each" +puts [\fBformat\fR $fmt1 123 "Global BigCorp" 19.37] + +set fmt2 "Bought %2\\$s equity ($%3$.2f x %1\\$d) today" +puts [\fBformat\fR $fmt2 123 "Global BigCorp" 19.37] +.CE +.PP +Print a small table of powers of three: +.CS +# Set up the column widths +set w1 5 +set w2 10 + +# Make a nice header (with separator) for the table first +set sep +-[string repeat - $w1]-+-[string repeat - $w2]-+ +puts $sep +puts [\fBformat\fR "| %-*s | %-*s |" $w1 "Index" $w2 "Power"] +puts $sep + +# Print the contents of the table +set p 1 +for {set i 0} {$i<=20} {incr i} { + puts [\fBformat\fR "| %*d | %*ld |" $w1 $i $w2 $p] + set p [expr {wide($p) * 3}] +} + +# Finish off by printing the separator again +puts $sep +.CE .SH "SEE ALSO" -sprintf(3), string(n) +scan(n), sprintf(3), string(n) .SH KEYWORDS conversion specifier, format, sprintf, string, substitution Index: doc/gets.n ================================================================== --- doc/gets.n +++ doc/gets.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: gets.n,v 1.4 2001/09/14 19:20:40 andreas_kupries Exp $ +'\" RCS: @(#) $Id: gets.n,v 1.4.8.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH gets n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -49,11 +49,23 @@ and no-full-line-available cases can produce the same results as if there were an input line consisting only of the end-of-line character(s). The \fBeof\fR and \fBfblocked\fR commands can be used to distinguish these three cases. +.SH "EXAMPLE" +This example reads a file one line at a time and prints it out with +the current line number attached to the start of each line. +.PP +.CS +set chan [open "some.file.txt"] +set lineNumber 0 +while {[\fBgets\fR $chan line] >= 0} { + puts "[incr lineNumber]: $line" +} +close $chan +.CE .SH "SEE ALSO" file(n), eof(n), fblocked(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, channel, end of file, end of line, line, nonblocking, read Index: doc/glob.n ================================================================== --- doc/glob.n +++ doc/glob.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: glob.n,v 1.12 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: glob.n,v 1.12.2.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH glob n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -76,10 +76,13 @@ \fIf\fR (plain file), \fIl\fR (symbolic link), \fIp\fR (named pipe), or \fIs\fR (socket), where multiple types may be specified in the list. \fBGlob\fR will return all files which match at least one of the types given. +Note that symbolic links will be returned both if \fB\-types l\fR is given, +or if the target of a link matches the requested type. So, a link to +a directory will be returned if \fB\-types d\fR was specified. .RS .PP The second form specifies types where all the types given must match. These are \fIr\fR, \fIw\fR, \fIx\fR as file permissions, and \fIreadonly\fR, \fIhidden\fR as special permission cases. On the @@ -147,11 +150,17 @@ First, it does not sort its result list (use the \fBlsort\fR command if you want the list sorted). Second, \fBglob\fR only returns the names of files that actually exist; in csh no check for existence is made unless a pattern contains a ?, *, or [] construct. - +.LP +When the \fBglob\fR command returns relative paths whose filenames +start with a tilde ``~'' (for example through \fBglob *\fR or +\fBglob -tails\fR, the returned list will not quote the tilde with +``./''. This means care must be taken if those names are later to +be used with \fBfile join\fR, to avoid them being interpreted as +absolute paths pointing to a given user's home directory. .SH "PORTABILITY ISSUES" .PP Unlike other Tcl commands that will accept both network and native style names (see the \fBfilename\fR manual entry for details on how native and network names are specified), the \fBglob\fR command only @@ -182,11 +191,32 @@ . When using the options, \fB\-directory\fR, \fB\-join\fR or \fB\-path\fR, glob assumes the directory separator for the entire pattern is the standard ``:''. When not using these options, glob examines each pattern argument and uses ``/'' unless the pattern contains a ``:''. +.SH EXAMPLES +Find all the Tcl files in the current directory: +.CS +\fBglob\fR *.tcl +.CE +.PP +Find all the Tcl files in the user's home directory, irrespective of +what the current directory is: +.CS +\fBglob\fR \-directory ~ *.tcl +.CE +.PP +Find all subdirectories of the current directory: +.CS +\fBglob\fR \-type d * +.CE +.PP +Find all files whose name contains an "a", a "b" or the sequence "cde": +.CS +\fBglob\fR \-type f *{a,b,cde}* +.CE .SH "SEE ALSO" file(n) .SH KEYWORDS exist, file, glob, pattern Index: doc/global.n ================================================================== --- doc/global.n +++ doc/global.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: global.n,v 1.4 2002/06/11 13:22:35 msofer Exp $ +'\" RCS: @(#) $Id: global.n,v 1.4.2.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH global n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -17,20 +17,39 @@ \fBglobal \fIvarname \fR?\fIvarname ...\fR? .BE .SH DESCRIPTION .PP -This command is ignored unless a Tcl procedure is being interpreted. -If so then it declares the given \fIvarname\fR's to be global variables -rather than local ones. -Global variables are variables in the global namespace. -For the duration of the current procedure -(and only while executing in the current procedure), -any reference to any of the \fIvarname\fRs -will refer to the global variable by the same name. +This command has no effect unless executed in the context of a proc body. +If the \fBglobal\fR command is executed in the context of a proc body, it +creates local variables linked to the corresponding global variables (and +therefore these variables are listed by info locals). +.PP +If \fIvarname\fR contains namespace qualifiers, the local variable's name is +the unqualified name of the global variable, as determined by the +\fBnamespace tail\fR command. +.SH EXAMPLES +This procedure sets the namespace variable \fI::a::x\fR +.CS +proc reset {} { + \fBglobal\fR a::x + set x 0 +} +.CE .PP +This procedure accumulates the strings passed to it in a global +buffer, separated by newlines. It is useful for situations when you +want to build a message piece-by-piece (as if with \fBputs\fR) but +send that full message in a single piece (e.g. over a connection +opened with \fBsocket\fR or as part of a counted HTTP response). +.CS +proc accum {string} { + \fBglobal\fR accumulator + append accumulator $string \\n +} +.CE .SH "SEE ALSO" namespace(n), upvar(n), variable(n) .SH KEYWORDS global, namespace, procedure, variable Index: doc/history.n ================================================================== --- doc/history.n +++ doc/history.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: history.n,v 1.2 1998/09/14 18:39:53 stanton Exp $ +'\" RCS: @(#) $Id: history.n,v 1.2.40.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH history n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -80,11 +80,11 @@ Returns the number of the next event to be recorded in the history list. It is useful for things like printing the event number in command-line prompts. .TP \fBhistory redo \fR?\fIevent\fR? -Re-executes the command indicated by \fIevent\fR and return its result. +Re-executes the command indicated by \fIevent\fR and returns its result. \fIEvent\fR defaults to \fB\-1\fR. This command results in history revision: see below for details. .SH "HISTORY REVISION" .PP Pre-8.0 Tcl had a complex history revision mechanism. Index: doc/http.n ================================================================== --- doc/http.n +++ doc/http.n @@ -1,30 +1,31 @@ '\" '\" Copyright (c) 1995-1997 Sun Microsystems, Inc. '\" Copyright (c) 1998-2000 by Ajuba Solutions. +'\" Copyright (c) 2004 ActiveState Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: http.n,v 1.18 2002/07/23 18:17:12 jenglish Exp $ +'\" RCS: @(#) $Id: http.n,v 1.18.2.3 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros -.TH "http" n 2.4 http "Tcl Bundled Packages" +.TH "http" n 2.5 http "Tcl Bundled Packages" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME http \- Client-side implementation of the HTTP/1.0 protocol. .SH SYNOPSIS -\fBpackage require http ?2.4?\fR +\fBpackage require http ?2.5?\fR .sp \fB::http::config \fI?options?\fR .sp \fB::http::geturl \fIurl ?options?\fR .sp -\fB::http::formatQuery \fIlist\fR +\fB::http::formatQuery\fP \fIkey value\fP ?\fIkey value\fP ...? .sp -\fB::http::reset \fItoken\fR +\fB::http::reset\fP \fItoken\fP ?\fIwhy\fP? .sp \fB::http::wait \fItoken\fR .sp \fB::http::status \fItoken\fR .sp @@ -52,11 +53,11 @@ of HTTP/1.0. It allows configuration of a proxy host to get through firewalls. The package is compatible with the \fBSafesock\fR security policy, so it can be used by untrusted applets to do URL fetching from a restricted set of hosts. This package can be extended to support additional HTTP transport protocols, such as HTTPS, by providing -a custom \fBsocket\fR command, via \fBhttp::register\fR. +a custom \fBsocket\fR command, via \fB::http::register\fR. .PP The \fB::http::geturl\fR procedure does a HTTP transaction. Its \fIoptions \fR determine whether a GET, POST, or HEAD transaction is performed. The return value of \fB::http::geturl\fR is a token for the transaction. @@ -85,11 +86,11 @@ .RS .TP \fB\-accept\fP \fImimetypes\fP The Accept header of the request. The default is */*, which means that all types of documents are accepted. Otherwise you can supply a -comma separated list of mime type patterns that you are +comma-separated list of mime type patterns that you are willing to receive. For example, "image/gif, image/jpeg, text/*". .TP \fB\-proxyhost\fP \fIhostname\fP The name of the proxy host, if any. If this value is the empty string, the URL host is contacted directly. @@ -100,15 +101,24 @@ \fB\-proxyfilter\fP \fIcommand\fP The command is a callback that is made during \fB::http::geturl\fR to determine if a proxy is required for a given host. One argument, a host name, is added to \fIcommand\fR when it is invoked. If a proxy -is required, the callback should return a two element list containing +is required, the callback should return a two-element list containing the proxy server and proxy port. Otherwise the filter should return an empty list. The default filter returns the values of the \fB\-proxyhost\fR and \fB\-proxyport\fR settings if they are non-empty. +.TP +\fB\-urlencoding\fP \fIencoding\fP +The \fIencoding\fR used for creating the x-url-encoded URLs with +\fB::http::formatQuery\fR. The default is \fButf-8\fR, as specified by RFC +2718. Prior to http 2.5 this was unspecified, and that behavior can be +returned by specifying the empty string (\fB{}\fR), although +\fIiso8859-1\fR is recommended to restore similar behavior but without the +\fB::http::formatQuery\fR throwing an error processing non-latin-1 +characters. .TP \fB\-useragent\fP \fIstring\fP The value of the User-Agent header in the HTTP request. The default is \fB"Tcl http client package 2.4."\fR .RE @@ -125,17 +135,17 @@ that is invoked when the HTTP transaction completes. \fB::http::geturl\fR takes several options: .RS .TP \fB\-binary\fP \fIboolean\fP -Specifies whether to force interpreting the url data as binary. Normally +Specifies whether to force interpreting the URL data as binary. Normally this is auto-detected (anything not beginning with a \fBtext\fR content type or whose content encoding is \fBgzip\fR or \fBcompress\fR is considered binary data). .TP \fB\-blocksize\fP \fIsize\fP -The blocksize used when reading the URL. +The block size used when reading the URL. At most \fIsize\fR bytes are read at once. After each block, a call to the \fB\-progress\fR callback is made (if that option is specified). .TP \fB\-channel\fP \fIname\fP Copy the URL contents to channel \fIname\fR instead of saving it in @@ -205,25 +215,26 @@ .CE .RE .TP \fB\-query\fP \fIquery\fP This flag causes \fB::http::geturl\fR to do a POST request that passes the -\fIquery\fR to the server. The \fIquery\fR must be a x-url-encoding +\fIquery\fR to the server. The \fIquery\fR must be an x-url-encoding formatted query. The \fB::http::formatQuery\fR procedure can be used to do the formatting. .TP \fB\-queryblocksize\fP \fIsize\fP -The blocksize used when posting query data to the URL. +The block size used when posting query data to the URL. At most \fIsize\fR bytes are written at once. After each block, a call to the \fB\-queryprogress\fR callback is made (if that option is specified). .TP \fB\-querychannel\fP \fIchannelID\fP This flag causes \fB::http::geturl\fR to do a POST request that passes the -data contained in \fIchannelID\fR to the server. The data contained in \fIchannelID\fR must be a x-url-encoding +data contained in \fIchannelID\fR to the server. The data contained in +\fIchannelID\fR must be an x-url-encoding formatted query unless the \fB\-type\fP option below is used. If a Content-Length header is not specified via the \fB\-headers\fR options, \fB::http::geturl\fR attempts to determine the size of the post data in order to create that header. If it is unable to determine the size, it returns an error. @@ -316,22 +327,22 @@ .RS .CS package require http package require tls -http::register https 443 ::tls::socket +::http::register https 443 ::tls::socket -set token [http::geturl https://my.secure.site/] +set token [::http::geturl https://my.secure.site/] .CE .RE .TP \fB::http::unregister\fP \fIproto\fP This procedure unregisters a protocol handler that was previously -registered via \fBhttp::register\fR. +registered via \fB::http::register\fR. .SH "ERRORS" -The \fBhttp::geturl\fP procedure will raise errors in the following cases: +The \fB::http::geturl\fP procedure will raise errors in the following cases: invalid command line options, an invalid URL, a URL on a non-existent host, or a URL at a bad port on an existing host. These errors mean that it @@ -359,21 +370,21 @@ to know the result of the asynchronous HTTP request, it can call \fB::http::wait\fP and then check status and error, just as the callback does. .PP In any case, you must still call -\fBhttp::cleanup\fP to delete the state array when you're done. +\fB::http::cleanup\fP to delete the state array when you're done. .PP There are other possible results of the HTTP transaction -determined by examining the status from \fBhttp::status\fP. +determined by examining the status from \fB::http::status\fP. These are described below. .TP ok If the HTTP transaction completes entirely, then status will be \fBok\fP. -However, you should still check the \fBhttp::code\fP value to get -the HTTP status. The \fBhttp::ncode\fP procedure provides just -the numeric error (e.g., 200, 404 or 500) while the \fBhttp::code\fP +However, you should still check the \fB::http::code\fP value to get +the HTTP status. The \fB::http::ncode\fP procedure provides just +the numeric error (e.g., 200, 404 or 500) while the \fB::http::code\fP procedure returns a value like "HTTP 404 File not found". .TP eof If the server closes the socket without replying, then no error is raised, but the status of the transaction will be \fBeof\fP. @@ -380,15 +391,15 @@ .TP error The error message will also be stored in the \fBerror\fP status array element, accessible via \fB::http::error\fP. .PP -Another error possibility is that \fBhttp::geturl\fP is unable to +Another error possibility is that \fB::http::geturl\fP is unable to write all the post query data to the server before the server responds and closes the socket. The error message is saved in the \fBposterror\fP status array -element and then \fBhttp::geturl\fP attempts to complete the +element and then \fB::http::geturl\fP attempts to complete the transaction. If it can read the server's response it will end up with an \fBok\fP status, otherwise it will have an \fBeof\fP status. @@ -397,13 +408,13 @@ get to the state of the HTTP transaction in the form of a Tcl array. Use this construct to create an easy-to-use array variable: .CS upvar #0 $token state .CE -Once the data associated with the url is no longer needed, the state +Once the data associated with the URL is no longer needed, the state array should be unset to free up storage. -The \fBhttp::cleanup\fP procedure is provided for that purpose. +The \fB::http::cleanup\fP procedure is provided for that purpose. The following elements of the array are supported: .RS .TP \fBbody\fR @@ -484,43 +495,46 @@ .TP \fBurl\fR The requested URL. .RE .SH EXAMPLE -.DS -# Copy a URL to a file and print meta-data -proc ::http::copy { url file {chunk 4096} } { - set out [open $file w] - set token [geturl $url -channel $out -progress ::http::Progress \\ - -blocksize $chunk] - close $out - # This ends the line started by http::Progress - puts stderr "" - upvar #0 $token state - set max 0 - foreach {name value} $state(meta) { - if {[string length $name] > $max} { - set max [string length $name] - } - if {[regexp -nocase ^location$ $name]} { - # Handle URL redirects - puts stderr "Location:$value" - return [copy [string trim $value] $file $chunk] - } - } - incr max - foreach {name value} $state(meta) { - puts [format "%-*s %s" $max $name: $value] - } - - return $token -} -proc ::http::Progress {args} { - puts -nonewline stderr . ; flush stderr -} -.DE +.CS +# Copy a URL to a file and print meta-data +proc httpcopy { url file {chunk 4096} } { + set out [open $file w] + set token [\fB::http::geturl\fR $url -channel $out \\ + -progress httpCopyProgress -blocksize $chunk] + close $out + + # This ends the line started by httpCopyProgress + puts stderr "" + + upvar #0 $token state + set max 0 + foreach {name value} $state(meta) { + if {[string length $name] > $max} { + set max [string length $name] + } + if {[regexp -nocase ^location$ $name]} { + # Handle URL redirects + puts stderr "Location:$value" + return [httpcopy [string trim $value] $file $chunk] + } + } + incr max + foreach {name value} $state(meta) { + puts [format "%-*s %s" $max $name: $value] + } + + return $token +} +proc httpCopyProgress {args} { + puts -nonewline stderr . + flush stderr +} +.CE .SH "SEE ALSO" safe(n), socket(n), safesock(n) .SH KEYWORDS security policy, socket Index: doc/if.n ================================================================== --- doc/if.n +++ doc/if.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: if.n,v 1.3 2000/09/07 14:27:48 poenitz Exp $ +'\" RCS: @(#) $Id: if.n,v 1.3.18.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH if n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -36,11 +36,46 @@ There may be any number of \fBelseif\fR clauses, including zero. \fIBodyN\fR may also be omitted as long as \fBelse\fR is omitted too. The return value from the command is the result of the body script that was executed, or an empty string if none of the expressions was non-zero and there was no \fIbodyN\fR. +.SH EXAMPLES +A simple conditional: +.CS +\fBif\fR {$vbl == 1} { puts "vbl is one" } +.CE +.PP +With an \fBelse\fR-clause: +.CS +\fBif\fR {$vbl == 1} { + puts "vbl is one" +} \fBelse\fR { + puts "vbl is not one" +} +.CE +.PP +With an \fBelseif\fR-clause too: +.CS +\fBif\fR {$vbl == 1} { + puts "vbl is one" +} \fBelseif\fR {$vbl == 2} { + puts "vbl is two" +} \fBelse\fR { + puts "vbl is not one or two" +} +.CE +.PP +Remember, expressions can be multi-line, but in that case it can be a +good idea to use the optional \fBthen\fR keyword for clarity: +.CS +\fBif\fR { + $vbl == 1 || $vbl == 2 || $vbl == 3 +} \fBthen\fR { + puts "vbl is one, two or three" +} +.CE .SH "SEE ALSO" expr(n), for(n), foreach(n) .SH KEYWORDS boolean, conditional, else, false, if, true Index: doc/incr.n ================================================================== --- doc/incr.n +++ doc/incr.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: incr.n,v 1.3 2000/09/07 14:27:48 poenitz Exp $ +'\" RCS: @(#) $Id: incr.n,v 1.3.18.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH incr n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -24,11 +24,34 @@ If \fIincrement\fR is supplied then its value (which must be an integer) is added to the value of variable \fIvarName\fR; otherwise 1 is added to \fIvarName\fR. The new value is stored as a decimal string in variable \fIvarName\fR and also returned as result. +.SH EXAMPLES +Add one to the contents of the variable \fIx\fR: +.CS +\fBincr\fR x +.CE +.PP +Add 42 to the contents of the variable \fIx\fR: +.CS +\fBincr\fR x 42 +.CE +.PP +Add the contents of the variable \fIy\fR to the contents of the +variable \fIx\fR: +.CS +\fBincr\fR x $y +.CE +.PP +Add nothing at all to the variable \fIx\fR (often useful for checking +whether an argument to a procedure is actually numeric and generating +an error if it is not): +.CS +\fBincr\fR x 0 +.CE .SH "SEE ALSO" expr(n) .SH KEYWORDS add, increment, variable, value Index: doc/info.n ================================================================== --- doc/info.n +++ doc/info.n @@ -5,11 +5,11 @@ '\" Copyright (c) 1998-2000 Ajuba Solutions '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: info.n,v 1.8 2002/06/11 13:22:35 msofer Exp $ +'\" RCS: @(#) $Id: info.n,v 1.8.2.3 2004/10/27 14:23:56 dkf Exp $ '\" .so man.macros .TH info n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -46,20 +46,20 @@ If \fIpattern\fR is specified, only those names matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring match\fR. \fIpattern\fR can be a qualified name like \fBFoo::print*\fR. That is, it may specify a particular namespace -using a sequence of namespace names separated by \fB::\fRs, +using a sequence of namespace names separated by double colons (\fB::\fR), and may have pattern matching special characters at the end to specify a set of commands in that namespace. If \fIpattern\fR is a qualified name, the resulting list of command names has each one qualified with the name of the specified namespace. .TP \fBinfo complete \fIcommand\fR Returns 1 if \fIcommand\fR is a complete Tcl command in the sense of -having no unclosed quotes, braces, brackets or array element names, +having no unclosed quotes, braces, brackets or array element names. If the command doesn't appear to be complete then 0 is returned. This command is typically used in line-oriented input environments to allow users to type in commands that span multiple lines; if the command isn't complete, the script can delay evaluating it until additional lines have been typed to complete the command. @@ -161,10 +161,15 @@ If \fIpattern\fR is specified, only those procedure names in the current namespace matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring match\fR. +If \fIpattern\fR contains any namespace separators, they are used to +select a namespace relative to the current namespace (or relative to +the global namespace if \fIpattern\fR starts with \fB::\fR) to match +within; the matching pattern is taken to be the part after the last +namespace separator. .TP \fBinfo script\fR ?\fIfilename\fR? If a Tcl script file is currently being evaluated (i.e. there is a call to \fBTcl_EvalFile\fR active or there is an active invocation of the \fBsource\fR command), then this command returns the name @@ -191,17 +196,38 @@ If \fIpattern\fR is specified, only those names matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring match\fR. \fIpattern\fR can be a qualified name like \fBFoo::option*\fR. That is, it may specify a particular namespace -using a sequence of namespace names separated by \fB::\fRs, +using a sequence of namespace names separated by double colons (\fB::\fR), and may have pattern matching special characters at the end to specify a set of variables in that namespace. If \fIpattern\fR is a qualified name, the resulting list of variable names has each matching namespace variable qualified with the name of its namespace. +Note that a currently-visible variable may not yet "exist" if it has not +been set (e.g. a variable declared but not set by \fBvariable\fR). +.SH EXAMPLE +This command prints out a procedure suitable for saving in a Tcl +script: +.CS +proc printProc {procName} { + set result [list proc $procName] + set formals {} + foreach var [\fBinfo args\fR $procName] { + if {[\fBinfo default\fR $procName $var def]} { + lappend formals [list $var $def] + } else { + # Still need the list-quoting because variable + # names may properly contain spaces. + lappend formals [list $var] + } + } + puts [lappend result $formals [\fBinfo body\fR $procName]] +} +.CE .SH "SEE ALSO" global(n), proc(n) .SH KEYWORDS Index: doc/interp.n ================================================================== --- doc/interp.n +++ doc/interp.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: interp.n,v 1.9 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: interp.n,v 1.9.2.2 2004/10/27 14:23:56 dkf Exp $ '\" .so man.macros .TH interp n 7.6 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -46,19 +46,20 @@ scripts without fear of them damaging other interpreters or the application's environment. For example, all IO channel creation commands and subprocess creation commands are made inaccessible to safe interpreters. .VS -See SAFE INTERPRETERS below for more information on +See \fBSAFE INTERPRETERS\fR below for more information on what features are present in a safe interpreter. The dangerous functionality is not removed from the safe interpreter; instead, it is \fIhidden\fR, so that only trusted interpreters can obtain access to it. For a detailed explanation of hidden commands, see -HIDDEN COMMANDS, below. +\fBHIDDEN COMMANDS\fR, below. The alias mechanism can be used for protected communication (analogous to a -kernel call) between a slave interpreter and its master. See ALIAS -INVOCATION, below, for more details on how the alias mechanism works. +kernel call) between a slave interpreter and its master. +See \fBALIAS INVOCATION\fR, below, for more details +on how the alias mechanism works. .VE .PP A qualified interpreter name is a proper Tcl lists containing a subset of its ancestors in the interpreter hierarchy, terminated by the string naming the interpreter in its immediate master. Interpreter names are relative to the @@ -72,31 +73,28 @@ can always be referred to as \fB{}\fR (the empty list or string). Note that it is impossible to refer to a master (ancestor) interpreter by name in a slave interpreter except through aliases. Also, there is no global name by which one can refer to the first interpreter created in an application. Both restrictions are motivated by safety concerns. - -.VS .SH "THE INTERP COMMAND" .PP -.VE The \fBinterp\fR command is used to create, delete, and manipulate slave interpreters, and to share or transfer channels between interpreters. It can have any of several forms, depending on the \fIoption\fR argument: .TP -\fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcCmd\fR +\fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcToken\fR Returns a Tcl list whose elements are the \fItargetCmd\fR and -\fIarg\fRs associated with the alias named \fIsrcCmd\fR -(all of these are the values specified when the alias was -created; it is possible that the actual source command in the -slave is different from \fIsrcCmd\fR if it was renamed). +\fIarg\fRs associated with the alias represented by \fIsrcToken\fR +(this is the value returned when the alias was +created; it is possible that the name of the source command in the +slave is different from \fIsrcToken\fR). .TP -\fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcCmd\fR \fB{}\fR -Deletes the alias for \fIsrcCmd\fR in the slave interpreter identified by +\fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcToken\fR \fB{}\fR +Deletes the alias for \fIsrcToken\fR in the slave interpreter identified by \fIsrcPath\fR. -\fIsrcCmd\fR refers to the name under which the alias +\fIsrcToken\fR refers to the value returned when the alias was created; if the source command has been renamed, the renamed command will be deleted. .TP \fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcCmd\fR \fItargetPath\fR \fItargetCmd \fR?\fIarg arg ...\fR? This command creates an alias between one slave and another (see the @@ -117,16 +115,22 @@ in the invocation of \fIsrcCmd\fR. \fITargetCmd\fR may be undefined at the time of this call, or it may already exist; it is not created by this command. The alias arranges for the given target command to be invoked in the target interpreter whenever the given source command is -invoked in the source interpreter. See ALIAS INVOCATION below for -more details. +invoked in the source interpreter. See \fBALIAS INVOCATION\fR below for +more details. +The command returns a token that uniquely identifies the command created +\fIsrcCmd\fR, even if the command is renamed afterwards. The token may but +does not have to be equal to \fIsrcCmd\fR. .TP \fBinterp\fR \fBaliases \fR?\fIpath\fR? -This command returns a Tcl list of the names of all the source commands for -aliases defined in the interpreter identified by \fIpath\fR. +This command returns a Tcl list of the tokens of all the source commands for +aliases defined in the interpreter identified by \fIpath\fR. The tokens +correspond to the values returned when +the aliases were created (which may not be the same +as the current names of the commands). .TP \fBinterp\fR \fBcreate \fR?\fB\-safe\fR? ?\fB\-\|\-\fR? ?\fIpath\fR? Creates a slave interpreter identified by \fIpath\fR and a new command, called a \fIslave command\fR. The name of the slave command is the last component of \fIpath\fR. The new slave interpreter and the slave command @@ -162,10 +166,15 @@ fashion as the \fBconcat\fR command, then evaluates the resulting string as a Tcl script in the slave interpreter identified by \fIpath\fR. The result of this evaluation (including error information such as the \fBerrorInfo\fR and \fBerrorCode\fR variables, if an error occurs) is returned to the invoking interpreter. +Note that the script will be executed in the current context stack frame of the +\fIpath\fR interpreter; this is so that the implementations (in a master +interpreter) of aliases in a slave interpreter can execute scripts in +the slave that find out information about the slave's current state +and stack frame. .TP \fBinterp exists \fIpath\fR Returns \fB1\fR if a slave interpreter by the specified \fIpath\fR exists in this master, \fB0\fR otherwise. If \fIpath\fR is omitted, the invoking interpreter is used. @@ -177,11 +186,11 @@ accepted only if it is a valid global name space name without any ::), in the interpreter denoted by \fIpath\fR. If an exposed command with the targeted name already exists, this command fails. -Hidden commands are explained in more detail in HIDDEN COMMANDS, below. +Hidden commands are explained in more detail in \fBHIDDEN COMMANDS\fR, below. .TP \fBinterp\fR \fBhide\fR \fIpath\fR \fIexposedCmdName\fR ?\fIhiddenCmdName\fR? Makes the exposed command \fIexposedCmdName\fR hidden, renaming it to the hidden command \fIhiddenCmdName\fR, or keeping the same name if \fIhiddenCmdName\fR is not given, in the interpreter denoted @@ -192,11 +201,11 @@ not contain namespace qualifiers, or an error is raised. Commands to be hidden by \fBinterp hide\fR are looked up in the global namespace even if the current namespace is not the global one. This prevents slaves from fooling a master interpreter into hiding the wrong command, by making the current namespace be different from the global one. -Hidden commands are explained in more detail in HIDDEN COMMANDS, below. +Hidden commands are explained in more detail in \fBHIDDEN COMMANDS\fR, below. .TP \fBinterp\fR \fBhidden\fR \fIpath\fR Returns a list of the names of all hidden commands in the interpreter identified by \fIpath\fR. .TP @@ -206,11 +215,11 @@ are applied to the arguments. If the \fB-global\fR flag is present, the hidden command is invoked at the global level in the target interpreter; otherwise it is invoked at the current call frame and can access local variables in that and outer call frames. -Hidden commands are explained in more detail in HIDDEN COMMANDS, below. +Hidden commands are explained in more detail in \fBHIDDEN COMMANDS\fR, below. .VE .TP \fBinterp issafe\fR ?\fIpath\fR? Returns \fB1\fR if the interpreter identified by the specified \fIpath\fR is safe, \fB0\fR otherwise. @@ -267,11 +276,10 @@ .TP \fBinterp\fR \fBtransfer\fR \fIsrcPath channelId destPath\fR Causes the IO channel identified by \fIchannelId\fR to become available in the interpreter identified by \fIdestPath\fR and unavailable in the interpreter identified by \fIsrcPath\fR. - .SH "SLAVE COMMAND" .PP For each slave interpreter created with the \fBinterp\fR command, a new Tcl command is created in the master interpreter with the same name as the new interpreter. This command may be used to invoke @@ -283,68 +291,75 @@ \fISlave\fR is the name of the interpreter, and \fIcommand\fR and the \fIarg\fRs determine the exact behavior of the command. The valid forms of this command are: .TP \fIslave \fBaliases\fR -Returns a Tcl list whose elements are the names of all the -aliases in \fIslave\fR. The names returned are the \fIsrcCmd\fR -values used when the aliases were created (which may not be the same -as the current names of the commands, if they have been -renamed). +Returns a Tcl list whose elements are the tokens of all the +aliases in \fIslave\fR. The tokens correspond to the values returned when +the aliases were created (which may not be the same +as the current names of the commands). .TP -\fIslave \fBalias \fIsrcCmd\fR +\fIslave \fBalias \fIsrcToken\fR Returns a Tcl list whose elements are the \fItargetCmd\fR and -\fIarg\fRs associated with the alias named \fIsrcCmd\fR -(all of these are the values specified when the alias was +\fIarg\fRs associated with the alias represented by \fIsrcToken\fR +(this is the value returned when the alias was created; it is possible that the actual source command in the -slave is different from \fIsrcCmd\fR if it was renamed). +slave is different from \fIsrcToken\fR). .TP -\fIslave \fBalias \fIsrcCmd \fB{}\fR -Deletes the alias for \fIsrcCmd\fR in the slave interpreter. -\fIsrcCmd\fR refers to the name under which the alias +\fIslave \fBalias \fIsrcToken \fB{}\fR +Deletes the alias for \fIsrcToken\fR in the slave interpreter. +\fIsrcToken\fR refers to the value returned when the alias was created; if the source command has been renamed, the renamed command will be deleted. .TP \fIslave \fBalias \fIsrcCmd targetCmd \fR?\fIarg ..\fR? Creates an alias such that whenever \fIsrcCmd\fR is invoked in \fIslave\fR, \fItargetCmd\fR is invoked in the master. The \fIarg\fR arguments will be passed to \fItargetCmd\fR as additional arguments, prepended before any arguments passed in the invocation of \fIsrcCmd\fR. -See ALIAS INVOCATION below for details. +See \fBALIAS INVOCATION\fR below for details. +The command returns a token that uniquely identifies the command created +\fIsrcCmd\fR, even if the command is renamed afterwards. The token may but +does not have to be equal to \fIsrcCmd\fR. .TP \fIslave \fBeval \fIarg \fR?\fIarg ..\fR? This command concatenates all of the \fIarg\fR arguments in the same fashion as the \fBconcat\fR command, then evaluates the resulting string as a Tcl script in \fIslave\fR. The result of this evaluation (including error information such as the \fBerrorInfo\fR and \fBerrorCode\fR variables, if an error occurs) is returned to the invoking interpreter. +Note that the script will be executed in the current context stack frame +of \fIslave\fR; this is so that the implementations (in a master +interpreter) of aliases in a slave interpreter can execute scripts in +the slave that find out information about the slave's current state +and stack frame. .VS "" BR .TP \fIslave \fBexpose \fIhiddenName \fR?\fIexposedCmdName\fR? This command exposes the hidden command \fIhiddenName\fR, eventually bringing it back under a new \fIexposedCmdName\fR name (this name is currently accepted only if it is a valid global name space name without any ::), in \fIslave\fR. If an exposed command with the targeted name already exists, this command fails. -For more details on hidden commands, see HIDDEN COMMANDS, below. +For more details on hidden commands, see \fBHIDDEN COMMANDS\fR, below. .TP \fIslave \fBhide \fIexposedCmdName\fR ?\fIhiddenCmdName\fR? This command hides the exposed command \fIexposedCmdName\fR, renaming it to the hidden command \fIhiddenCmdName\fR, or keeping the same name if the -the argument is not given, in the \fIslave\fR interpreter. +argument is not given, in the \fIslave\fR interpreter. If a hidden command with the targeted name already exists, this command fails. Currently both \fIexposedCmdName\fR and \fIhiddenCmdName\fR can not contain namespace qualifiers, or an error is raised. Commands to be hidden are looked up in the global namespace even if the current namespace is not the global one. This prevents slaves from fooling a master interpreter into hiding the wrong command, by making the current namespace be different from the global one. -For more details on hidden commands, see HIDDEN COMMANDS, below. +For more details on hidden commands, see \fBHIDDEN COMMANDS\fR, below. .TP \fIslave \fBhidden\fR Returns a list of the names of all hidden commands in \fIslave\fR. .TP \fIslave \fBinvokehidden\fR ?\fB-global\fR \fIhiddenName \fR?\fIarg ..\fR? @@ -352,12 +367,12 @@ supplied arguments, in \fIslave\fR. No substitutions or evaluations are applied to the arguments. If the \fB-global\fR flag is given, the command is invoked at the global level in the slave; otherwise it is invoked at the current call frame and can access local variables in that or outer call frames. -For more details on hidden commands, see HIDDEN -COMMANDS, below. +For more details on hidden commands, +see \fBHIDDEN COMMANDS\fR, below. .VE .TP \fIslave \fBissafe\fR Returns \fB1\fR if the slave interpreter is safe, \fB0\fR otherwise. .VS "" BR @@ -431,11 +446,11 @@ The following commands are hidden by \fBinterp create\fR when it creates a safe interpreter: .DS .ta 1.2i 2.4i 3.6i \fBcd encoding exec exit -fconfigure file glob load +fconfigure file glob load open pwd socket source\fR .DE These commands can be recreated later as Tcl procedures or aliases, or re-exposed by \fBinterp expose\fR. .PP @@ -485,11 +500,10 @@ management of extensions for safety see the manual entries for \fBSafe\-Tcl\fR and the \fBload\fR Tcl command. .PP A safe interpreter may not alter the recursion limit of any interpreter, including itself. - .SH "ALIAS INVOCATION" .PP The alias mechanism has been carefully designed so that it can be used safely when an untrusted script is executing in a safe slave and the target of the alias is a trusted @@ -526,11 +540,10 @@ it is very important that the arguments to that command never be evaluated or substituted, since this would provide an escape mechanism whereby the slave interpreter could execute arbitrary code in the master. This in turn would compromise the security of the system. - .VS .SH "HIDDEN COMMANDS" .PP Safe interpreters greatly restrict the functionality available to Tcl programs executing within them. @@ -569,11 +582,11 @@ Because a master interpreter may invoke a hidden command as part of handling an alias invocation, great care must be taken to avoid evaluating any arguments passed in through the alias invocation. Otherwise, malicious slave interpreters could cause a trusted master interpreter to execute dangerous commands on their behalf. See the section -on ALIAS INVOCATION for a more complete discussion of this topic. +on \fBALIAS INVOCATION\fR for a more complete discussion of this topic. To help avoid this problem, no substitutions or evaluations are applied to arguments of \fBinterp invokehidden\fR. .PP Safe interpreters are not allowed to invoke hidden commands in themselves or in their descendants. This prevents safe slaves from gaining access to @@ -600,11 +613,32 @@ .VE .SH CREDITS .PP This mechanism is based on the Safe-Tcl prototype implemented by Nathaniel Borenstein and Marshall Rose. +.SH EXAMPLES +Creating and using an alias for a command in the current interpreter: +.CS +\fBinterp alias\fR {} getIndex {} lsearch {alpha beta gamma delta} +set idx [getIndex delta] +.CE +.PP +Executing an arbitrary command in a safe interpreter where every +invokation of \fBlappend\fR is logged: +.CS +set i [\fBinterp create\fR -safe] +\fBinterp hide\fR $i lappend +\fBinterp alias\fR $i lappend {} loggedLappend $i +proc loggedLappend {i args} { + puts "logged invokation of lappend $args" + # Be extremely careful about command construction + eval [linsert $args 0 \\ + \fBinterp invokehidden\fR $i lappend] +} +\fBinterp eval\fR $i $someUntrustedScript +.CE .SH "SEE ALSO" load(n), safe(n), Tcl_CreateSlave(3) .SH KEYWORDS alias, master interpreter, safe interpreter, slave interpreter Index: doc/join.n ================================================================== --- doc/join.n +++ doc/join.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: join.n,v 1.3 2000/09/07 14:27:48 poenitz Exp $ +'\" RCS: @(#) $Id: join.n,v 1.3.18.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH join n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -22,11 +22,25 @@ The \fIlist\fR argument must be a valid Tcl list. This command returns the string formed by joining all of the elements of \fIlist\fR together with \fIjoinString\fR separating each adjacent pair of elements. The \fIjoinString\fR argument defaults to a space character. +.SH EXAMPLES +Making a comma-separated list: +.CS +set data {1 2 3 4 5} +\fBjoin\fR $data ", " + \fB=> 1, 2, 3, 4, 5\fR +.CE +.PP +Using \fBjoin\fR to flatten a list by a single level: +.CS +set data {1 {2 3} 4 {5 {6 7} 8}} +\fBjoin\fR $data + \fB=> 1 2 3 4 5 {6 7} 8\fR +.CE .SH "SEE ALSO" -list(n), lappend(n) +list(n), lappend(n), split(n) .SH KEYWORDS element, join, list, separator Index: doc/lappend.n ================================================================== --- doc/lappend.n +++ doc/lappend.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: lappend.n,v 1.6 2001/11/14 23:38:39 hobbs Exp $ +'\" RCS: @(#) $Id: lappend.n,v 1.6.4.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH lappend n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -29,10 +29,20 @@ are appended as list elements rather than raw text. This command provides a relatively efficient way to build up large lists. For example, ``\fBlappend a $b\fR'' is much more efficient than ``\fBset a [concat $a [list $b]]\fR'' when \fB$a\fR is long. +.SH EXAMPLE +Using \fBlappend\fR to build up a list of numbers. +.CS +% set var 1 +1 +% \fBlappend\fR var 2 +1 2 +% \fBlappend\fR var 3 4 5 +1 2 3 4 5 +.CE .SH "SEE ALSO" list(n), lindex(n), linsert(n), llength(n), .VS 8.4 lset(n) Index: doc/lindex.n ================================================================== --- doc/lindex.n +++ doc/lindex.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: lindex.n,v 1.7 2001/11/14 23:15:33 hobbs Exp $ +'\" RCS: @(#) $Id: lindex.n,v 1.7.4.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH lindex n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -67,20 +67,20 @@ .CS lindex [lindex [lindex $a 1] 2] 3 .CE .SH EXAMPLES .CS -lindex {a b c} => a b c -lindex {a b c} {} => a b c -lindex {a b c} 0 => a -lindex {a b c} 2 => c -lindex {a b c} end => c -lindex {a b c} end-1 => b -lindex {{a b c} {d e f} {g h i}} 2 1 => h -lindex {{a b c} {d e f} {g h i}} {2 1} => h -lindex {{{a b} {c d}} {{e f} {g h}}} 1 1 0 => g -lindex {{{a b} {c d}} {{e f} {g h}}} {1 1 0} => g +\fBlindex\fR {a b c} \fI=> a b c\fR +\fBlindex\fR {a b c} {} \fI=> a b c\fR +\fBlindex\fR {a b c} 0 \fI=> a\fR +\fBlindex\fR {a b c} 2 \fI=> c\fR +\fBlindex\fR {a b c} end \fI=> c\fR +\fBlindex\fR {a b c} end-1 \fI=> b\fR +\fBlindex\fR {{a b c} {d e f} {g h i}} 2 1 \fI=> h\fR +\fBlindex\fR {{a b c} {d e f} {g h i}} {2 1} \fI=> h\fR +\fBlindex\fR {{{a b} {c d}} {{e f} {g h}}} 1 1 0 \fI=> g\fR +\fBlindex\fR {{{a b} {c d}} {{e f} {g h}}} {1 1 0} \fI=> g\fR .CE .VE .SH "SEE ALSO" list(n), lappend(n), linsert(n), llength(n), lsearch(n), .VS 8.4 Index: doc/linsert.n ================================================================== --- doc/linsert.n +++ doc/linsert.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: linsert.n,v 1.7 2001/11/14 23:38:39 hobbs Exp $ +'\" RCS: @(#) $Id: linsert.n,v 1.7.4.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH linsert n 8.2 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -19,23 +19,32 @@ .BE .SH DESCRIPTION .PP This command produces a new list from \fIlist\fR by inserting all of the -\fIelement\fR arguments just before the \fIindex\fRth element of +\fIelement\fR arguments just before the \fIindex\fR'th element of \fIlist\fR. Each \fIelement\fR argument will become a separate element of the new list. If \fIindex\fR is less than or equal to zero, then the new elements are inserted at the beginning of the list. If \fIindex\fR has the value \fBend\fR, or if it is greater than or equal to the number of elements in the list, then the new elements are appended to the list. \fBend\-\fIinteger\fR refers to the last element in the list minus the specified integer offset. - +.SH EXAMPLE +Putting some values into a list, first indexing from the start and +then indexing from the end, and then chaining them together: +.CS +set oldList {the fox jumps over the dog} +set midList [\fBlinsert\fR $oldList 1 quick] +set newList [\fBlinsert\fR $midList end-1 lazy] +# The old lists still exist though... +set newerList [\fBlinsert\fR [\fBlinsert\fR $oldList end-1 quick] 1 lazy] +.CE .SH "SEE ALSO" .VS 8.4 list(n), lappend(n), lindex(n), llength(n), lsearch(n), lset(n), lsort(n), lrange(n), lreplace(n) .VE .SH KEYWORDS element, insert, list Index: doc/list.n ================================================================== --- doc/list.n +++ doc/list.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: list.n,v 1.7 2001/12/05 22:26:43 dgp Exp $ +'\" RCS: @(#) $Id: list.n,v 1.7.4.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH list n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -27,28 +27,29 @@ so that \fBeval\fR may be used to execute the resulting list, with \fIarg1\fR comprising the command's name and the other \fIarg\fRs comprising its arguments. \fBList\fR produces slightly different results than \fBconcat\fR: \fBconcat\fR removes one level of grouping before forming the list, while \fBlist\fR works directly from the original arguments. -For example, the command +.SH EXAMPLE +The command .CS -\fBlist a b {c d e} {f {g h}}\fR +\fBlist\fR a b "c d e " " f {g h}" .CE will return .CS -\fBa b {c d e} {f {g h}}\fR +\fBa b {c d e } { f {g h}}\fR .CE while \fBconcat\fR with the same arguments will return .CS \fBa b c d e f {g h}\fR .CE .SH "SEE ALSO" -lappend(n), lindex(n), linsert(n), llength(n), lsearch(n), +lappend(n), lindex(n), linsert(n), llength(n), lrange(n), +lreplace(n), lsearch(n), .VS 8.4 lset(n), -.VE -lsort(n), -lrange(n), lreplace(n) +.VE 8.4 +lsort(n) .SH KEYWORDS element, list Index: doc/llength.n ================================================================== --- doc/llength.n +++ doc/llength.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: llength.n,v 1.6 2001/11/14 23:38:39 hobbs Exp $ +'\" RCS: @(#) $Id: llength.n,v 1.6.4.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH llength n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -20,14 +20,40 @@ .SH DESCRIPTION .PP Treats \fIlist\fR as a list and returns a decimal string giving the number of elements in it. + +.SH EXAMPLES +The result is the number of elements: +.CS +% \fBllength\fR {a b c d e} +5 +% \fBllength\fR {a b c} +3 +% \fBllength\fR {} +0 +.CE +.PP +Elements are not guaranteed to be exactly words in a dictionary sense +of course, especially when quoting is used: +.CS +% \fBllength\fR {a b {c d} e} +4 +% \fBllength\fR {a b { } c d e} +6 +.CE +.PP +An empty list is not necessarily an empty string: +.CS +% set var { }; puts "[string length $var],[\fBllength\fR $var]" +1,0 +.CE .SH "SEE ALSO" .VS 8.4 list(n), lappend(n), lindex(n), linsert(n), lsearch(n), lset(n), lsort(n), lrange(n), lreplace(n) .VE .SH KEYWORDS element, list, length Index: doc/load.n ================================================================== --- doc/load.n +++ doc/load.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: load.n,v 1.7 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: load.n,v 1.7.2.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH load n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -103,11 +103,10 @@ 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. .VE - .SH "PORTABILITY ISSUES" .TP \fBWindows\fR\0\0\0\0\0 . When a load fails with "library not found" error, it is also possible @@ -114,22 +113,60 @@ that a dependent library was not found. To see the dependent libraries, type ``dumpbin -imports '' in a DOS console to see what the library must import. When loading a DLL in the current directory, Windows will ignore ``./'' as a path specifier and use a search heuristic to find the DLL instead. -To avoid this, load the DLL with +To avoid this, load the DLL with: .CS - load [file join [pwd] mylib.DLL] +\fBload\fR [file join [pwd] mylib.DLL] .CE - .SH BUGS .PP If the same file is \fBload\fRed by different \fIfileName\fRs, it will be loaded into the process's address space multiple times. The behavior of this varies from system to system (some systems may detect the redundant loads, others may not). +.SH EXAMPLE +The following is a minimal extension: +.PP +.CS +#include +#include +static int fooCmd(ClientData clientData, + Tcl_Interp *interp, int objc, char * CONST objv[]) { + printf("called with %d arguments\\n", objc); + return TCL_OK; +} +int Foo_Init(Tcl_Interp *interp) { + if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { + return TCL_ERROR; + } + printf("creating foo command"); + Tcl_CreateObjCommand(interp, "foo", fooCmd, NULL, NULL); + return TCL_OK; +} +.CE +.PP +When built into a shared/dynamic library with a suitable name +(e.g. \fBfoo.dll\fR on Windows, \fBlibfoo.so\fR on Solaris and Linux) +it can then be loaded into Tcl with the following: +.PP +.CS +# Load the extension +switch $tcl_platform(platform) { + windows { + \fBload\fR ./foo.dll + } + unix { + \fBload\fR ./libfoo[info sharedlibextension] + } +} + +# Now execute the command defined by the extension +foo +.CE .SH "SEE ALSO" info sharedlibextension, Tcl_StaticPackage(3), safe(n) .SH KEYWORDS binary code, loading, safe interpreter, shared library Index: doc/lrange.n ================================================================== --- doc/lrange.n +++ doc/lrange.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: lrange.n,v 1.6 2001/11/14 23:38:39 hobbs Exp $ +'\" RCS: @(#) $Id: lrange.n,v 1.6.4.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH lrange n 7.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -33,14 +33,43 @@ is returned. Note: ``\fBlrange \fIlist first first\fR'' does not always produce the same result as ``\fBlindex \fIlist first\fR'' (although it often does for simple fields that aren't enclosed in braces); it does, however, produce exactly the same results as ``\fBlist [lindex \fIlist first\fB]\fR'' +.SH EXAMPLES +Selecting the first two elements: +.CS +% \fBlrange\fR {a b c d e} 0 1 +a b +.CE +.PP +Selecting the last three elements: +.CS +% \fBlrange\fR {a b c d e} end-2 end +c d e +.CE +.PP +Selecting everything except the first and last element: +.CS +% \fBlrange\fR {a b c d e} 1 end-1 +b c d +.CE +.PP +Selecting a single element with \fBlrange\fR is not the same as doing +so with \fBlindex\fR: +.CS +% set var {some {elements to} select} +some {elements to} select +% lindex $var 1 +elements to +% \fBlrange\fR $var 1 1 +{elements to} +.CE .SH "SEE ALSO" .VS 8.4 list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n), lset(n), lreplace(n), lsort(n) .VE .SH KEYWORDS element, list, range, sublist Index: doc/lreplace.n ================================================================== --- doc/lreplace.n +++ doc/lreplace.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: lreplace.n,v 1.8 2001/11/14 23:38:39 hobbs Exp $ +'\" RCS: @(#) $Id: lreplace.n,v 1.8.4.1 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH lreplace n 7.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -41,14 +41,34 @@ be added to the list in place of those that were deleted. Each \fIelement\fR argument will become a separate element of the list. If no \fIelement\fR arguments are specified, then the elements between \fIfirst\fR and \fIlast\fR are simply deleted. If \fIlist\fR is empty, any \fIelement\fR arguments are added to the end of the list. +.SH EXAMPLES +Replacing an element of a list with another: +.CS +% \fBlreplace\fR {a b c d e} 1 1 foo +a foo c d e +.CE +.PP +Replacing two elements of a list with three: +.CS +% \fBlreplace\fR {a b c d e} 1 2 three more elements +a three more elements d e +.CE +.PP +Deleting the last element from a list in a variable: +.CS +% set var {a b c d e} +a b c d e +% set var [\fBlreplace\fR $var end end] +a b c d +.CE .SH "SEE ALSO" .VS 8.4 list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n), lset(n), lrange(n), lsort(n) .VE .SH KEYWORDS element, list, replace Index: doc/lsearch.n ================================================================== --- doc/lsearch.n +++ doc/lsearch.n @@ -1,14 +1,14 @@ -'\" +'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: lsearch.n,v 1.13 2002/10/03 13:08:55 dkf Exp $ +'\" RCS: @(#) $Id: lsearch.n,v 1.13.2.4 2005/01/05 21:53:30 dkf Exp $ '\" .so man.macros .TH lsearch n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -35,21 +35,25 @@ Changes the result to be the list of all matching indices (or all matching values if \fB\-inline\fR is specified as well.) .VE 8.4 .TP \fB\-ascii\fR -The list elements are to be examined as ASCII strings. This option is only -meaningful when used with \fB\-exact\fR or \fB\-sorted\fR. +The list elements are to be examined as Unicode strings (the name is +for backward-compatability reasons.) This option is only meaningful +when used with \fB\-exact\fR or \fB\-sorted\fR. .TP \fB\-decreasing\fR The list elements are sorted in decreasing order. This option is only meaningful when used with \fB\-sorted\fR. .TP \fB\-dictionary\fR The list elements are to be compared using dictionary-style -comparisons. This option is only meaningful when used with -\fB\-exact\fR or \fB\-sorted\fR. +comparisons (see \fBlsort\fR for a fuller description). This option +is only meaningful when used with \fB\-exact\fR or \fB\-sorted\fR, and +it is only distinguishable from the \fB\-ascii\fR option when +the \fB\-sorted\fR option is given, because values are only +dictionary-equal when exactly equal. .TP \fB\-exact\fR The list element must contain exactly the same string as \fIpattern\fR. .TP \fB\-glob\fR @@ -113,17 +117,17 @@ precedence. .VS 8.4 .SH EXAMPLES .CS -lsearch {a b c d e} c => 2 -lsearch -all {a b c a b c} c => 2 5 -lsearch -inline {a20 b35 c47} b* => b35 -lsearch -inline -not {a20 b35 c47} b* => a20 -lsearch -all -inline -not {a20 b35 c47} b* => a20 c47 -lsearch -all -not {a20 b35 c47} b* => 0 2 -lsearch -start 3 {a b c a b c} c => 5 +\fBlsearch\fR {a b c d e} c \fI=> 2\fR +\fBlsearch\fR -all {a b c a b c} c \fI=> 2 5\fR +\fBlsearch\fR -inline {a20 b35 c47} b* \fI=> b35\fR +\fBlsearch\fR -inline -not {a20 b35 c47} b* \fI=> a20\fR +\fBlsearch\fR -all -inline -not {a20 b35 c47} b* \fI=> a20 c47\fR +\fBlsearch\fR -all -not {a20 b35 c47} b* \fI=> 0 2\fR +\fBlsearch\fR -start 3 {a b c a b c} c \fI=> 5\fR .CE .VE 8.4 .SH "SEE ALSO" .VS 8.4 @@ -131,5 +135,9 @@ lset(n), lsort(n), lrange(n), lreplace(n) .VE .SH KEYWORDS list, match, pattern, regular expression, search, string + +'\" Local Variables: +'\" mode: nroff +'\" End: Index: doc/lset.n ================================================================== --- doc/lset.n +++ doc/lset.n @@ -2,11 +2,11 @@ '\" Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: lset.n,v 1.6 2003/01/23 14:18:33 dkf Exp $ +'\" RCS: @(#) $Id: lset.n,v 1.6.2.1 2003/12/01 21:29:34 msofer Exp $ '\" .so man.macros .TH lset n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -35,11 +35,11 @@ .CE In this case, \fInewValue\fR replaces the old value of the variable \fIvarName\fR. .PP When presented with a single index, the \fBlset\fR command -treats the content of the \fIvarBane\fR variable as a Tcl list. +treats the content of the \fIvarName\fR variable as a Tcl list. It addresses the \fIindex\fR'th element in it (0 refers to the first element of the list). When interpreting the list, \fBlset\fR observes the same rules concerning braces and quotes and backslashes as the Tcl command interpreter; however, variable Index: doc/lsort.n ================================================================== --- doc/lsort.n +++ doc/lsort.n @@ -5,11 +5,11 @@ '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: lsort.n,v 1.12 2001/11/14 23:38:39 hobbs Exp $ +'\" RCS: @(#) $Id: lsort.n,v 1.12.4.2 2004/10/27 12:52:40 dkf Exp $ '\" .so man.macros .TH lsort n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -30,11 +30,12 @@ increasing order. However, any of the following options may be specified before \fIlist\fR to control the sorting process (unique abbreviations are accepted): .TP 20 \fB\-ascii\fR -Use string comparison with ASCII collation order. This is the default. +Use string comparison with Unicode code-point collation order (the +name is for backward-compatibility reasons.) This is the default. .TP 20 \fB\-dictionary\fR Use dictionary-style comparison. This is the same as \fB\-ascii\fR except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, @@ -99,11 +100,10 @@ elements found in the list will be retained. Note that duplicates are determined relative to the comparison used in the sort. Thus if \fI-index 0\fR is used, \fB{1 a}\fR and \fB{1 b}\fR would be considered duplicates and only the second element, \fB{1 b}\fR, would be retained. - .SH "NOTES" .PP The options to \fBlsort\fR only control what sort of comparison is used, and do not necessarily constrain what the values themselves actually are. This distinction is only noticeable when the list to be @@ -110,64 +110,56 @@ sorted has fewer than two elements. .PP The \fBlsort\fR command is reentrant, meaning it is safe to use as part of the implementation of a command used in the \fB\-command\fR option. - .SH "EXAMPLES" - .PP Sorting a list using ASCII sorting: .CS -% lsort {a10 B2 b1 a1 a2} +% \fBlsort\fR {a10 B2 b1 a1 a2} B2 a1 a10 a2 b1 .CE - .PP Sorting a list using Dictionary sorting: .CS -% lsort -dictionary {a10 B2 b1 a1 a2} +% \fBlsort\fR -dictionary {a10 B2 b1 a1 a2} a1 a2 a10 b1 B2 .CE - .PP Sorting lists of integers: .CS -% lsort -integer {5 3 1 2 11 4} +% \fBlsort\fR -integer {5 3 1 2 11 4} 1 2 3 4 5 11 -% lsort -integer {1 2 0x5 7 0 4 -1} +% \fBlsort\fR -integer {1 2 0x5 7 0 4 -1} -1 0 1 2 4 0x5 7 .CE - .PP Sorting lists of floating-point numbers: .CS -% lsort -real {5 3 1 2 11 4} +% \fBlsort\fR -real {5 3 1 2 11 4} 1 2 3 4 5 11 -% lsort -real {.5 0.07e1 0.4 6e-1} +% \fBlsort\fR -real {.5 0.07e1 0.4 6e-1} 0.4 .5 6e-1 0.07e1 .CE - .PP Sorting using indices: .CS % # Note the space character before the c -% lsort {{a 5} { c 3} {b 4} {e 1} {d 2}} +% \fBlsort\fR {{a 5} { c 3} {b 4} {e 1} {d 2}} { c 3} {a 5} {b 4} {d 2} {e 1} -% lsort -index 0 {{a 5} { c 3} {b 4} {e 1} {d 2}} +% \fBlsort\fR -index 0 {{a 5} { c 3} {b 4} {e 1} {d 2}} {a 5} {b 4} { c 3} {d 2} {e 1} -% lsort -index 1 {{a 5} { c 3} {b 4} {e 1} {d 2}} +% \fBlsort\fR -index 1 {{a 5} { c 3} {b 4} {e 1} {d 2}} {e 1} {d 2} { c 3} {b 4} {a 5} .CE - .PP Stripping duplicate values using sorting: .CS -% lsort -unique {a b c a b c a b c} +% \fBlsort\fR -unique {a b c a b c a b c} a b c .CE - .PP More complex sorting using a comparison function: .CS % proc compare {a b} { set a0 [lindex $a 0] @@ -177,11 +169,11 @@ } elseif {$a0 > $b0} { return 1 } return [string compare [lindex $a 1] [lindex $b 1]] } -% lsort -command compare \\ +% \fBlsort\fR -command compare \\ {{3 apple} {0x2 carrot} {1 dingo} {2 banana}} {1 dingo} {2 banana} {0x2 carrot} {3 apple} .CE .SH "SEE ALSO" Index: doc/msgcat.n ================================================================== --- doc/msgcat.n +++ doc/msgcat.n @@ -13,11 +13,11 @@ .SH NAME msgcat \- Tcl message catalog .SH SYNOPSIS \fBpackage require Tcl 8.2\fR .sp -\fBpackage require msgcat 1.3\fR +\fBpackage require msgcat 1.3.4\fR .sp \fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR? .sp \fB::msgcat::mcmax ?\fIsrc-string src-string ...\fR? .sp @@ -46,19 +46,18 @@ the message catalog. .PP Use of the message catalog is optional by any application or package, but is encouraged if the application or package wishes to be enabled for multi-lingual applications. - .SH COMMANDS .TP \fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR? Returns a translation of \fIsrc-string\fR according to the user's current locale. If additional arguments past \fIsrc-string\fR are given, the \fBformat\fR command is used to substitute the additional arguments in the translation of \fIsrc-string\fR. - +.PP \fB::msgcat::mc\fR will search the messages defined in the current namespace for a translation of \fIsrc-string\fR; if none is found, it will search in the parent of the current namespace, and so on until it reaches the global namespace. If no translation string exists, \fB::msgcat::mcunknown\fR is called and the string @@ -89,22 +88,22 @@ \fB::msgcat::mcpreferences\fR Returns an ordered list of the locales preferred by the user, based on the user's language specification. The list is ordered from most specific to least preference. The list is derived from the current -locale set in msgcat by \fBmsgcat::mclocale\fR, and +locale set in msgcat by \fB::msgcat::mclocale\fR, and cannot be set independently. For example, if the -current locale is en_US_funky, then \fBmsgcat::mcpreferences\fR -returns {en_US_funky en_US en}. +current locale is en_US_funky, then \fB::msgcat::mcpreferences\fR +returns \fB{en_US_funky en_US en}\fR. .TP \fB::msgcat::mcload \fIdirname\fR Searches the specified directory for files that match the language specifications returned by \fB::msgcat::mcpreferences\fR (note that these are all lowercase), extended by the file extension ``.msg''. Each matching file is read in order, assuming a UTF-8 encoding. The file contents are -then evaluated as a Tcl script. This means that non-Latin characters +then evaluated as a Tcl script. This means that Unicode characters may be present in the message file either directly in their UTF-8 encoded form, or by use of the backslash-u quoting recognized by Tcl evaluation. The number of message files which matched the specification and were loaded is returned. .TP @@ -118,12 +117,12 @@ Sets the translation for multiple source strings in \fIsrc-trans-list\fR in the specified \fIlocale\fR and the current namespace. \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?} \fBmsgcat::mcmset\fR can be significantly -faster than multiple invocations of \fBmsgcat::mcset\fR. The function +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::mcunknown \fIlocale src-string\fR This routine is called by \fB::msgcat::mc\fR in the case when a translation for \fIsrc-string\fR is not defined in the @@ -132,11 +131,10 @@ application, for example to log error messages for each unknown string. The \fB::msgcat::mcunknown\fR procedure is invoked at the same stack context as the call to \fB::msgcat::mc\fR. The return value of \fB::msgcat::mcunknown\fR is used as the return value for the call to \fB::msgcat::mc\fR. - .SH "LOCALE SPECIFICATION" .PP The locale is specified to \fBmsgcat\fR by a locale string passed to \fB::msgcat::mclocale\fR. The locale string consists of @@ -153,11 +151,11 @@ initial locale. The value is parsed according to the XPG4 pattern .CS language[_country][.codeset][@modifier] .CE to extract its parts. The initial locale is then set by calling -\fBmsgcat::mclocale\fR with the argument +\fB::msgcat::mclocale\fR with the argument .CS language[_country][_modifier] .CE On Windows, if none of those environment variables is set, msgcat will attempt to extract locale information from the @@ -167,13 +165,12 @@ .PP When a locale is specified by the user, a ``best match'' search is performed during string translation. For example, if a user specifies en_GB_Funky, the locales ``en_GB_Funky'', ``en_GB'', and ``en'' are searched in order until a matching translation string is found. If no -translation string is available, then \fB::msgcat::unknown\fR is +translation string is available, then \fB::msgcat::mcunknown\fR is called. - .SH "NAMESPACES AND MESSAGE CATALOGS" .PP Strings stored in the message catalog are stored relative to the namespace from which they were added. This allows multiple packages to use the same strings without fear @@ -181,14 +178,16 @@ source string to be shorter and less prone to typographical error. .PP For example, executing the code .CS -mcset en hello "hello from ::" -namespace eval foo {mcset en hello "hello from ::foo"} -puts [mc hello] -namespace eval foo {puts [mc hello]} +\fB::msgcat::mcset\fR en hello "hello from ::" +namespace eval foo { + \fB::msgcat::mcset\fR en hello "hello from ::foo" +} +puts [\fB::msgcat::mc\fR hello] +namespace eval foo {puts [\fB::msgcat::mc\fR hello]} .CE will print .CS hello from :: hello from ::foo @@ -200,31 +199,31 @@ the global namespace is reached. This allows child namespaces to "inherit" messages from their parent namespace. .PP For example, executing (in the ``en'' locale) the code .CS -mcset en m1 ":: message1" -mcset en m2 ":: message2" -mcset en m3 ":: message3" +\fB::msgcat::mcset\fR en m1 ":: message1" +\fB::msgcat::mcset\fR en m2 ":: message2" +\fB::msgcat::mcset\fR en m3 ":: message3" namespace eval ::foo { - mcset en m2 "::foo message2" - mcset en m3 "::foo message3" + \fB::msgcat::mcset\fR en m2 "::foo message2" + \fB::msgcat::mcset\fR en m3 "::foo message3" } namespace eval ::foo::bar { - mcset en m3 "::foo::bar message3" + \fB::msgcat::mcset\fR en m3 "::foo::bar message3" } -puts "[mc m1]; [mc m2]; [mc m3]" -namespace eval ::foo {puts "[mc m1]; [mc m2]; [mc m3]"} -namespace eval ::foo::bar {puts "[mc m1]; [mc m2]; [mc m3]"} +namespace import \fB::msgcat::mc\fR +puts "[\fBmc\fR m1]; [\fBmc\fR m2]; [\fBmc\fR m3]" +namespace eval ::foo {puts "[\fBmc\fR m1]; [\fBmc\fR m2]; [\fBmc\fR m3]"} +namespace eval ::foo::bar {puts "[\fBmc\fR m1]; [\fBmc\fR m2]; [\fBmc\fR m3]"} .CE will print .CS :: message1; :: message2; :: message3 :: message1; ::foo message2; ::foo message3 :: message1; ::foo message2; ::foo::bar message3 .CE - .SH "LOCATION AND FORMAT OF MESSAGE FILES" .PP Message files can be located in any directory, subject to the following conditions: .IP [1] @@ -242,14 +241,13 @@ 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: .CS namespace eval ::mypackage { - ::msgcat::mcset es "Free Beer!" "Cerveza Gracias!" + \fB::msgcat::mcset\fR es "Free Beer!" "Cerveza Gracias!" } .CE - .SH "RECOMMENDED MESSAGE SETUP FOR PACKAGES" .PP If a package is installed into a subdirectory of the \fBtcl_pkgPath\fR and loaded via \fBpackage require\fR, the following procedure is recommended. @@ -261,13 +259,12 @@ .IP [3] Add the following command to your package initialization script: .CS # load language files, stored in msgs subdirectory -::msgcat::mcload [file join [file dirname [info script]] msgs] +\fB::msgcat::mcload\fR [file join [file dirname [info script]] msgs] .CE - .SH "POSITIONAL CODES FOR FORMAT AND SCAN COMMANDS" .PP It is possible that a message string used as an argument to \fBformat\fR might have positionally dependent parameters that might need to be repositioned. For example, it might be @@ -285,15 +282,14 @@ format "In location %2\\$s we produced %1\\$d units" $num $city .CE .PP Similarly, positional parameters can be used with \fBscan\fR to extract values from internationalized strings. - .SH CREDITS .PP The message catalog code was developed by Mark Harrison. .SH "SEE ALSO" format(n), scan(n), namespace(n), package(n) .SH KEYWORDS internationalization, i18n, localization, l10n, message, text, translation Index: doc/namespace.n ================================================================== --- doc/namespace.n +++ doc/namespace.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2000 Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: namespace.n,v 1.9 2003/01/21 20:06:11 jenglish Exp $ +'\" RCS: @(#) $Id: namespace.n,v 1.9.2.2 2005/05/12 16:23:11 dgp Exp $ '\" .so man.macros .TH namespace n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -22,27 +22,27 @@ .PP The \fBnamespace\fR command lets you create, access, and destroy separate contexts for commands and variables. See the section \fBWHAT IS A NAMESPACE?\fR below for a brief overview of namespaces. -The legal \fIoption\fR's are listed below. -Note that you can abbreviate the \fIoption\fR's. +The legal values of \fIoption\fR are listed below. +Note that you can abbreviate the \fIoption\fRs. .TP \fBnamespace children \fR?\fInamespace\fR? ?\fIpattern\fR? Returns a list of all child namespaces that belong to the namespace \fInamespace\fR. If \fInamespace\fR is not specified, then the children are returned for the current namespace. This command returns fully-qualified names, -which start with \fB::\fR. +which start with a double colon (\fB::\fR). If the optional \fIpattern\fR is given, then this command returns only the names that match the glob-style pattern. The actual pattern used is determined as follows: -a pattern that starts with \fB::\fR is used directly, +a pattern that starts with double colon (\fB::\fR) is used directly, otherwise the namespace \fInamespace\fR (or the fully-qualified name of the current namespace) -is prepended onto the the pattern. +is prepended onto the pattern. .TP \fBnamespace code \fIscript\fR Captures the current namespace context for later execution of the script \fIscript\fR. It returns a new script in which \fIscript\fR has been wrapped @@ -64,11 +64,11 @@ This command is needed because extensions like Tk normally execute callback scripts in the global namespace. A scoped command captures a command together with its namespace context in a way that allows it to be executed properly later. -See the section \fBSCOPED VALUES\fR for some examples +See the section \fBSCOPED SCRIPTS\fR for some examples of how this is used to create callback scripts. .TP \fBnamespace current\fR Returns the fully-qualified name for the current namespace. The actual name of the global namespace is ``'' @@ -127,11 +127,11 @@ .TP \fBnamespace forget \fR?\fIpattern pattern ...\fR? Removes previously imported commands from a namespace. Each \fIpattern\fR is a simple or qualified name such as \fBx\fR, \fBfoo::x\fR or \fBa::b::p*\fR. -Qualified names contain \fB::\fRs and qualify a name +Qualified names contain double colons (\fB::\fR) and qualify a name with the name of one or more namespaces. Each \fIqualified pattern\fR is qualified with the name of an exporting namespace and may have glob-style special characters in the command name at the end of the qualified name. @@ -209,11 +209,11 @@ If \fInamespace\fR is not specified, the fully-qualified name of the current namespace's parent is returned. .TP \fBnamespace qualifiers\fR \fIstring\fR Returns any leading namespace qualifiers for \fIstring\fR. -Qualifiers are namespace names separated by \fB::\fRs. +Qualifiers are namespace names separated by double colons (\fB::\fR). For the \fIstring\fR \fB::foo::bar::x\fR, this command returns \fB::foo::bar\fR, and for \fB::\fR it returns an empty string. This command is the complement of the \fBnamespace tail\fR command. Note that it does not check whether the @@ -220,11 +220,11 @@ namespace names are, in fact, the names of currently defined namespaces. .TP \fBnamespace tail\fR \fIstring\fR Returns the simple name at the end of a qualified string. -Qualifiers are namespace names separated by \fB::\fRs. +Qualifiers are namespace names separated by double colons (\fB::\fR). For the \fIstring\fR \fB::foo::bar::x\fR, this command returns \fBx\fR, and for \fB::\fR it returns an empty string. This command is the complement of the \fBnamespace qualifiers\fR command. It does not check whether the namespace names are, in fact, @@ -242,11 +242,10 @@ or through a \fBtrace\fR on the variable, this command will return the fully-qualified name of the variable. If no flag is given, \fIname\fR is treated as a command name. See the section \fBNAME RESOLUTION\fR below for an explanation of the rules regarding name resolution. - .SH "WHAT IS A NAMESPACE?" .PP A namespace is a collection of commands and variables. It encapsulates the commands and variables to ensure that they won't interfere with the commands and variables of other namespaces. @@ -254,19 +253,19 @@ which we refer to as the \fIglobal namespace\fR. The global namespace holds all global variables and commands. The \fBnamespace eval\fR command lets you create new namespaces. For example, .CS -\fBnamespace eval Counter { - namespace export bump - variable num 0 - - proc bump {} { - variable num - incr num - } -}\fR +\fBnamespace eval\fR Counter { + \fBnamespace export\fR bump + variable num 0 + + proc bump {} { + variable num + incr num + } +} .CE creates a new namespace containing the variable \fBnum\fR and the procedure \fBbump\fR. The commands and variables in this namespace are separate from other commands and variables in the same program. @@ -284,34 +283,33 @@ so you can build up the contents of a namespace over time using a series of \fBnamespace eval\fR commands. For example, the following series of commands has the same effect as the namespace definition shown above: .CS -\fBnamespace eval Counter { - variable num 0 - proc bump {} { - variable num - return [incr num] - } -} -namespace eval Counter { - proc test {args} { - return $args - } -} -namespace eval Counter { +\fBnamespace eval\fR Counter { + variable num 0 + proc bump {} { + variable num + return [incr num] + } +} +\fBnamespace eval\fR Counter { + proc test {args} { + return $args + } +} +\fBnamespace eval\fR Counter { rename test "" -}\fR +} .CE Note that the \fBtest\fR procedure is added to the \fBCounter\fR namespace, and later removed via the \fBrename\fR command. .PP Namespaces can have other namespaces within them, so they nest hierarchically. A nested namespace is encapsulated inside its parent namespace and can not interfere with other namespaces. - .SH "QUALIFIED NAMES" .PP Each namespace has a textual name such as \fBhistory\fR or \fB::safe::interp\fR. Since namespaces may nest, @@ -323,57 +321,56 @@ instead of \fB/\fR or \fB.\fR. The topmost or global namespace has the name ``'' (i.e., an empty string), although \fB::\fR is a synonym. As an example, the name \fB::safe::interp::create\fR refers to the command \fBcreate\fR in the namespace \fBinterp\fR -that is a child of of namespace \fB::safe\fR, -which in turn is a child of the global namespace \fB::\fR. +that is a child of namespace \fB::safe\fR, +which in turn is a child of the global namespace, \fB::\fR. .PP If you want to access commands and variables from another namespace, you must use some extra syntax. Names must be qualified by the namespace that contains them. From the global namespace, we might access the \fBCounter\fR procedures like this: .CS -\fBCounter::bump 5 -Counter::Reset\fR +Counter::bump 5 +Counter::Reset .CE We could access the current count like this: .CS -\fBputs "count = $Counter::num"\fR +puts "count = $Counter::num" .CE When one namespace contains another, you may need more than one qualifier to reach its elements. If we had a namespace \fBFoo\fR that contained the namespace \fBCounter\fR, you could invoke its \fBbump\fR procedure from the global namespace like this: .CS -\fBFoo::Counter::bump 3\fR +Foo::Counter::bump 3 .CE .PP You can also use qualified names when you create and rename commands. For example, you could add a procedure to the \fBFoo\fR namespace like this: .CS -\fBproc Foo::Test {args} {return $args}\fR +proc Foo::Test {args} {return $args} .CE And you could move the same procedure to another namespace like this: .CS -\fBrename Foo::Test Bar::Test\fR +rename Foo::Test Bar::Test .CE .PP There are a few remaining points about qualified names that we should cover. Namespaces have nonempty names except for the global namespace. \fB::\fR is disallowed in simple command, variable, and namespace names except as a namespace separator. -Extra \fB:\fRs in a qualified name are ignored; -that is, two or more \fB:\fRs are treated as a namespace separator. +Extra colons in any separator part of a qualified name are ignored; +i.e. two or more colons are treated as a namespace separator. A trailing \fB::\fR in a qualified variable or command name refers to the variable or command named {}. However, a trailing \fB::\fR in a qualified namespace name is ignored. - .SH "NAME RESOLUTION" .PP In general, all Tcl commands that take variable and command names support qualified names. This means you can give qualified names to such commands as @@ -390,30 +387,30 @@ Namespace names, on the other hand, are always resolved by looking in only the current namespace. .PP In the following example, .CS -\fBset traceLevel 0 -namespace eval Debug { - printTrace $traceLevel -}\fR +set traceLevel 0 +\fBnamespace eval\fR Debug { + printTrace $traceLevel +} .CE Tcl looks for \fBtraceLevel\fR in the namespace \fBDebug\fR and then in the global namespace. It looks up the command \fBprintTrace\fR in the same way. If a variable or command name is not found in either context, the name is undefined. To make this point absolutely clear, consider the following example: .CS -\fBset traceLevel 0 -namespace eval Foo { - variable traceLevel 3 - - namespace eval Debug { - printTrace $traceLevel - } -}\fR +set traceLevel 0 +\fBnamespace eval\fR Foo { + variable traceLevel 3 + + \fBnamespace eval\fR Debug { + printTrace $traceLevel + } +} .CE Here Tcl looks for \fBtraceLevel\fR first in the namespace \fBFoo::Debug\fR. Since it is not found there, Tcl then looks for it in the global namespace. The variable \fBFoo::traceLevel\fR is completely ignored @@ -421,16 +418,16 @@ .PP You can use the \fBnamespace which\fR command to clear up any question about name resolution. For example, the command: .CS -\fBnamespace eval Foo::Debug {namespace which \-variable traceLevel}\fR +\fBnamespace eval\fR Foo::Debug {\fBnamespace which\fR \-variable traceLevel} .CE returns \fB::traceLevel\fR. On the other hand, the command, .CS -\fBnamespace eval Foo {namespace which \-variable traceLevel}\fR +\fBnamespace eval\fR Foo {\fBnamespace which\fR \-variable traceLevel} .CE returns \fB::Foo::traceLevel\fR. .PP As mentioned above, namespace names are looked up differently @@ -437,11 +434,11 @@ than the names of variables and commands. Namespace names are always resolved in the current namespace. This means, for example, that a \fBnamespace eval\fR command that creates a new namespace always creates a child of the current namespace -unless the new namespace name begins with a \fB::\fR. +unless the new namespace name begins with \fB::\fR. .PP Tcl has no access control to limit what variables, commands, or namespaces you can reference. If you provide a qualified name that resolves to an element by the name resolution rule above, @@ -457,35 +454,34 @@ Note that the \fBglobal\fR command only creates links to variables in the global namespace. It is not necessary to use a \fBvariable\fR command if you always refer to the namespace variable using an appropriate qualified name. - .SH "IMPORTING COMMANDS" .PP Namespaces are often used to represent libraries. Some library commands are used so frequently that it is a nuisance to type their qualified names. For example, suppose that all of the commands in a package like BLT are contained in a namespace called \fBBlt\fR. Then you might access these commands like this: .CS -\fBBlt::graph .g \-background red -Blt::table . .g 0,0\fR +Blt::graph .g \-background red +Blt::table . .g 0,0 .CE If you use the \fBgraph\fR and \fBtable\fR commands frequently, you may want to access them without the \fBBlt::\fR prefix. You can do this by importing the commands into the current namespace, like this: .CS -\fBnamespace import Blt::*\fR +\fBnamespace import\fR Blt::* .CE This adds all exported commands from the \fBBlt\fR namespace into the current namespace context, so you can write code like this: .CS -\fBgraph .g \-background red -table . .g 0,0\fR +graph .g \-background red +table . .g 0,0 .CE The \fBnamespace import\fR command only imports commands from a namespace that that namespace exported with a \fBnamespace export\fR command. .PP @@ -492,11 +488,11 @@ Importing \fIevery\fR command from a namespace is generally a bad idea since you don't know what you will get. It is better to import just the specific commands you need. For example, the command .CS -\fBnamespace import Blt::graph Blt::table\fR +\fBnamespace import\fR Blt::graph Blt::table .CE imports only the \fBgraph\fR and \fBtable\fR commands into the current context. .PP If you try to import a command that already exists, you will get an @@ -505,60 +501,59 @@ you may want to get around this restriction. You may want to reissue the \fBnamespace import\fR command to pick up new commands that have appeared in a namespace. In that case, you can use the \fB\-force\fR option, and existing commands will be silently overwritten: .CS -\fBnamespace import \-force Blt::graph Blt::table\fR +\fBnamespace import\fR \-force Blt::graph Blt::table .CE If for some reason, you want to stop using the imported commands, -you can remove them with an \fBnamespace forget\fR command, like this: +you can remove them with a \fBnamespace forget\fR command, like this: .CS -\fBnamespace forget Blt::*\fR +\fBnamespace forget\fR Blt::* .CE This searches the current namespace for any commands imported from \fBBlt\fR. If it finds any, it removes them. Otherwise, it does nothing. After this, the \fBBlt\fR commands must be accessed with the \fBBlt::\fR prefix. .PP When you delete a command from the exporting namespace like this: .CS -\fBrename Blt::graph ""\fR +rename Blt::graph "" .CE the command is automatically removed from all namespaces that import it. - .SH "EXPORTING COMMANDS" You can export commands from a namespace like this: .CS -\fBnamespace eval Counter { - namespace export bump reset - variable Num 0 - variable Max 100 - - proc bump {{by 1}} { - variable Num - incr Num $by - Check - return $Num - } - proc reset {} { - variable Num - set Num 0 - } - proc Check {} { - variable Num - variable Max - if {$Num > $Max} { - error "too high!" - } - } -}\fR +\fBnamespace eval\fR Counter { + \fBnamespace export\fR bump reset + variable Num 0 + variable Max 100 + + proc bump {{by 1}} { + variable Num + incr Num $by + Check + return $Num + } + proc reset {} { + variable Num + set Num 0 + } + proc Check {} { + variable Num + variable Max + if {$Num > $Max} { + error "too high!" + } + } +} .CE The procedures \fBbump\fR and \fBreset\fR are exported, so they are included when you import from the \fBCounter\fR namespace, like this: .CS -\fBnamespace import Counter::*\fR +\fBnamespace import\fR Counter::* .CE However, the \fBCheck\fR procedure is not exported, so it is ignored by the import operation. .PP The \fBnamespace import\fR command only imports commands @@ -565,11 +560,61 @@ that were declared as exported by their namespace. The \fBnamespace export\fR command specifies what commands may be imported by other namespaces. If a \fBnamespace import\fR command specifies a command that is not exported, the command is not imported. +.SH "SCOPED SCRIPTS" +The \fBnamespace code\fR command is the means by which a script may be +packaged for evaluation in a namespace other than the one in which it +was created. It is used most often to create event handlers, Tk bindings, +and traces for evaluation in the global context. For instance, the following +code indicates how to direct a variable trace callback into the current +namespace: +.CS +\fBnamespace eval\fR a { + variable b + proc theTraceCallback { n1 n2 op } { + upvar 1 $n1 var + puts "the value of $n1 has changed to $var" + return + } + trace variable b w [\fBnamespace code\fR theTraceCallback] +} +set a::b c +.CE +When executed, it prints the message: +.CS +the value of a::b has changed to c +.CE +.SH EXAMPLES +Create a namespace containing a variable and an exported command: +.CS +\fBnamespace eval\fR foo { + variable bar 0 + proc grill {} { + variable bar + puts "called [incr bar] times" + } + \fBnamespace export\fR grill +} +.CE +.PP +Call the command defined in the previous example in various ways. +.CS +# Direct call +foo::grill + +# Import into current namespace, then call local alias +namespace import foo::grill +grill +.CE +.PP +Look up where the command imported in the previous example came from: +.CS +puts "grill came from [\fBnamespace origin\fR grill]" +.CE .SH "SEE ALSO" variable(n) .SH KEYWORDS exported, internal, variable Index: doc/open.n ================================================================== --- doc/open.n +++ doc/open.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: open.n,v 1.16 2002/07/23 18:17:12 jenglish Exp $ +'\" RCS: @(#) $Id: open.n,v 1.16.2.4 2006/03/16 21:11:57 andreas_kupries Exp $ '\" .so man.macros .TH open n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -53,11 +53,11 @@ If it doesn't exist, create a new file. .TP 15 \fBa\fR Open the file for writing only. If the file doesn't exist, create a new empty file. -Set the initial access position to the end of the file. +Set the file pointer to the end of the file prior to each write. .TP 15 \fBa+\fR Open the file for reading and writing. If the file doesn't exist, create a new empty file. Set the initial access position to the end of the file. @@ -130,27 +130,205 @@ If read-only access is used (e.g. \fIaccess\fR is \fBr\fR), standard input for the pipeline is taken from the current standard input unless overridden by the command. The id of the spawned process is accessible through the \fBpid\fR command, using the channel id returned by \fBopen\fR as argument. - +.PP +If the command (or one of the commands) executed in the command +pipeline returns an error (according to the definition in \fBexec\fR), +a Tcl error is generated when \fBclose\fR is called on the channel +unless the pipeline is in non-blocking mode then no exit status is +returned (a silent \fBclose\fR with -blocking 0). +.PP +It is often useful to use the \fBfileevent\fR command with pipelines +so other processing may happen at the same time as running the command +in the background. .VS 8.4 .SH "SERIAL COMMUNICATIONS" .PP If \fIfileName\fR refers to a serial port, then the specified serial port is opened and initialized in a platform-dependent manner. Acceptable values for the \fIfileName\fR to use to open a serial port are described in the PORTABILITY ISSUES section. .PP The \fBfconfigure\fR command can be used to query and set additional -configuration options specific to serial ports. +configuration options specific to serial ports (where supported): +.TP +\fB\-mode\fR \fIbaud\fB,\fIparity\fB,\fIdata\fB,\fIstop\fR +This option is a set of 4 comma-separated values: the baud rate, parity, +number of data bits, and number of stop bits for this serial port. The +\fIbaud\fR rate is a simple integer that specifies the connection speed. +\fIParity\fR is one of the following letters: \fBn\fR, \fBo\fR, \fBe\fR, +\fBm\fR, \fBs\fR; respectively signifying the parity options of ``none'', +``odd'', ``even'', ``mark'', or ``space''. \fIData\fR is the number of +data bits and should be an integer from 5 to 8, while \fIstop\fR is the +number of stop bits and should be the integer 1 or 2. +.TP +\fB\-handshake\fR \fItype\fR +(Windows and Unix). This option is used to setup automatic handshake +control. Note that not all handshake types maybe supported by your operating +system. The \fItype\fR parameter is case-independent. +.sp +If \fItype\fR is \fBnone\fR then any handshake is switched off. +\fBrtscts\fR activates hardware handshake. Hardware handshake signals +are described below. +For software handshake \fBxonxoff\fR the handshake characters can be redefined +with \fB-xchar\fR. +An additional hardware handshake \fBdtrdsr\fR is available only under Windows. +There is no default handshake configuration, the initial value depends +on your operating system settings. +The \fB-handshake\fR option cannot be queried. +.TP +\fB\-queue\fR +(Windows and Unix). The \fB-queue\fR option can only be queried. +It returns a list of two integers representing the current number +of bytes in the input and output queue respectively. +.TP +\fB\-timeout\fR \fImsec\fR +(Windows and Unix). This option is used to set the timeout for blocking +read operations. It specifies the maximum interval between the +reception of two bytes in milliseconds. +For Unix systems the granularity is 100 milliseconds. +The \fB-timeout\fR option does not affect write operations or +nonblocking reads. +This option cannot be queried. +.TP +\fB\-ttycontrol\fR \fI{signal boolean signal boolean ...}\fR +(Windows and Unix). This option is used to setup the handshake +output lines (see below) permanently or to send a BREAK over the serial line. +The \fIsignal\fR names are case-independent. +\fB{RTS 1 DTR 0}\fR sets the RTS output to high and the DTR output to low. +The BREAK condition (see below) is enabled and disabled with \fB{BREAK 1}\fR and +\fB{BREAK 0}\fR respectively. +It's not a good idea to change the \fBRTS\fR (or \fBDTR\fR) signal +with active hardware handshake \fBrtscts\fR (or \fBdtrdsr\fR). +The result is unpredictable. +The \fB-ttycontrol\fR option cannot be queried. +.TP +\fB\-ttystatus\fR +(Windows and Unix). The \fB-ttystatus\fR option can only be +queried. It returns the current modem status and handshake input signals +(see below). +The result is a list of signal,value pairs with a fixed order, +e.g. \fB{CTS 1 DSR 0 RING 1 DCD 0}\fR. +The \fIsignal\fR names are returned upper case. +.TP +\fB\-xchar\fR \fI{xonChar xoffChar}\fR +(Windows and Unix). This option is used to query or change the software +handshake characters. Normally the operating system default should be +DC1 (0x11) and DC3 (0x13) representing the ASCII standard +XON and XOFF characters. +.TP +\fB\-pollinterval\fR \fImsec\fR +(Windows only). This option is used to set the maximum time between +polling for fileevents. +This affects the time interval between checking for events throughout the Tcl +interpreter (the smallest value always wins). Use this option only if +you want to poll the serial port more or less often than 10 msec +(the default). +.TP +\fB\-sysbuffer\fR \fIinSize\fR +.TP +\fB\-sysbuffer\fR \fI{inSize outSize}\fR +(Windows only). This option is used to change the size of Windows +system buffers for a serial channel. Especially at higher communication +rates the default input buffer size of 4096 bytes can overrun +for latent systems. The first form specifies the input buffer size, +in the second form both input and output buffers are defined. +.TP +\fB\-lasterror\fR +(Windows only). This option is query only. +In case of a serial communication error, \fBread\fR or \fBputs\fR +returns a general Tcl file I/O error. +\fBfconfigure -lasterror\fR can be called to get a list of error details. +See below for an explanation of the various error codes. + +.SH "SERIAL PORT SIGNALS" +.PP +RS-232 is the most commonly used standard electrical interface for serial +communications. A negative voltage (-3V..-12V) define a mark (on=1) bit and +a positive voltage (+3..+12V) define a space (off=0) bit (RS-232C). The +following signals are specified for incoming and outgoing data, status +lines and handshaking. Here we are using the terms \fIworkstation\fR for +your computer and \fImodem\fR for the external device, because some signal +names (DCD, RI) come from modems. Of course your external device may use +these signal lines for other purposes. + +.IP \fBTXD(output)\fR +\fBTransmitted Data:\fR Outgoing serial data. +.IP \fBRXD(input)\fR +\fBReceived Data:\fRIncoming serial data. +.IP \fBRTS(output)\fR +\fBRequest To Send:\fR This hardware handshake line informs the modem that +your workstation is ready to receive data. Your workstation may +automatically reset this signal to indicate that the input buffer is full. +.IP \fBCTS(input)\fR +\fBClear To Send:\fR The complement to RTS. Indicates that the modem is +ready to receive data. +.IP \fBDTR(output)\fR +\fBData Terminal Ready:\fR This signal tells the modem that the workstation +is ready to establish a link. DTR is often enabled automatically whenever a +serial port is opened. +.IP \fBDSR(input)\fR +\fBData Set Ready:\fR The complement to DTR. Tells the workstation that the +modem is ready to establish a link. +.IP \fBDCD(input)\fR +\fBData Carrier Detect:\fR This line becomes active when a modem detects +a "Carrier" signal. +.IP \fBRI(input)\fR +\fBRing Indicator:\fR Goes active when the modem detects an incoming call. +.IP \fBBREAK\fR +A BREAK condition is not a hardware signal line, but a logical zero on the +TXD or RXD lines for a long period of time, usually 250 to 500 +milliseconds. Normally a receive or transmit data signal stays at the mark +(on=1) voltage until the next character is transferred. A BREAK is sometimes +used to reset the communications line or change the operating mode of +communications hardware. + +.SH "ERROR CODES (Windows only)" +.PP +A lot of different errors may occur during serial read operations or during +event polling in background. The external device may have been switched +off, the data lines may be noisy, system buffers may overrun or your mode +settings may be wrong. That's why a reliable software should always +\fBcatch\fR serial read operations. In cases of an error Tcl returns a +general file I/O error. Then \fBfconfigure -lasterror\fR may help to +locate the problem. The following error codes may be returned. + +.TP 10 +\fBRXOVER\fR +Windows input buffer overrun. The data comes faster than your scripts reads +it or your system is overloaded. Use \fBfconfigure -sysbuffer\fR to avoid a +temporary bottleneck and/or make your script faster. +.TP 10 +\fBTXFULL\fR +Windows output buffer overrun. Complement to RXOVER. This error should +practically not happen, because Tcl cares about the output buffer status. +.TP 10 +\fBOVERRUN\fR +UART buffer overrun (hardware) with data lost. +The data comes faster than the system driver receives it. +Check your advanced serial port settings to enable the FIFO (16550) buffer +and/or setup a lower(1) interrupt threshold value. +.TP 10 +\fBRXPARITY\fR +A parity error has been detected by your UART. +Wrong parity settings with \fBfconfigure -mode\fR or a noisy data line (RXD) +may cause this error. +.TP 10 +\fBFRAME\fR +A stop-bit error has been detected by your UART. +Wrong mode settings with \fBfconfigure -mode\fR or a noisy data line (RXD) +may cause this error. +.TP 10 +\fBBREAK\fR +A BREAK condition has been detected by your UART (see above). .VE .SH "PORTABILITY ISSUES" .TP \fBWindows \fR(all versions) -. Valid values for \fIfileName\fR to open a serial port are of the form \fBcom\fIX\fB:\fR, where \fIX\fR is a number, generally from 1 to 4. This notation only works for serial ports from 1 to 9, if the system happens to have more than four. An attempt to open a serial port that does not exist or has a number greater than 9 will fail. An alternate @@ -157,27 +335,25 @@ form of opening serial ports is to use the filename \fB\e\e.\ecomX\fR, where X is any number that corresponds to a serial port; please note that this method is considerably slower on Windows 95 and Windows 98. .TP \fBWindows NT\fR -. When running Tcl interactively, there may be some strange interactions between the real console, if one is present, and a command pipeline that uses standard input or output. If a command pipeline is opened for reading, some of the lines entered at the console will be sent to the command pipeline and some will be sent to the Tcl evaluator. If a command pipeline is opened for -writing, keystrokes entered into the console are not visible until the the +writing, keystrokes entered into the console are not visible until the pipe is closed. This behavior occurs whether the command pipeline is executing 16-bit or 32-bit applications. These problems only occur because both Tcl and the child application are competing for the console at the same time. If the command pipeline is started from a script, so that Tcl is not accessing the console, or if the command pipeline does not use standard input or output, but is redirected from or to a file, then the above problems do not occur. .TP \fBWindows 95\fR -. A command pipeline that executes a 16-bit DOS application cannot be opened for both reading and writing, since 16-bit DOS applications that receive standard input from a pipe and send standard output to a pipe run synchronously. Command pipelines that do not execute 16-bit DOS applications run asynchronously and can be opened for both reading and @@ -187,11 +363,11 @@ between the real console, if one is present, and a command pipeline that uses standard input or output. If a command pipeline is opened for reading from a 32-bit application, some of the keystrokes entered at the console will be sent to the command pipeline and some will be sent to the Tcl evaluator. If a command pipeline is opened for writing to a 32-bit application, no output -is visible on the console until the the pipe is closed. These problems only +is visible on the console until the pipe is closed. These problems only occur because both Tcl and the child application are competing for the console at the same time. If the command pipeline is started from a script, so that Tcl is not accessing the console, or if the command pipeline does not use standard input or output, but is redirected from or to a file, then the above problems do not occur. @@ -203,21 +379,23 @@ application, no data will be sent to the command pipeline's standard output until the pipe is actually closed. This problem occurs because 16-bit DOS applications are run synchronously, as described above. .TP \fBMacintosh\fR -. Opening a serial port is not currently implemented under Macintosh. .sp Opening a command pipeline is not supported under Macintosh, since applications do not support the concept of standard input or output. .TP \fBUnix\fR\0\0\0\0\0\0\0 -. Valid values for \fIfileName\fR to open a serial port are generally of the form \fB/dev/tty\fIX\fR, where \fIX\fR is \fBa\fR or \fBb\fR, but the name of any pseudo-file that maps to a serial port may be used. +.VS 8.4 +Advanced configuration options are only supported for serial ports +when Tcl is built to use the POSIX serial interface. +.VE 8.4 .sp When running Tcl interactively, there may be some strange interactions between the console, if one is present, and a command pipeline that uses standard input. If a command pipeline is opened for reading, some of the lines entered at the console will be sent to the command pipeline and @@ -228,13 +406,22 @@ input, but is redirected from a file, then the above problem does not occur. .LP See the PORTABILITY ISSUES section of the \fBexec\fR command for additional information not specific to command pipelines about executing applications on the various platforms +.SH "EXAMPLE" +Open a command pipeline and catch any errors: +.CS +set fl [\fBopen\fR "| ls this_file_does_not_exist"] +set data [read $fl] +if {[catch {close $fl} err]} { + puts "ls command failed: $err" +} +.CE .SH "SEE ALSO" file(n), close(n), filename(n), fconfigure(n), gets(n), read(n), puts(n), exec(n), pid(n), fopen(3) .SH KEYWORDS access mode, append, create, file, non-blocking, open, permissions, pipeline, process, serial Index: doc/package.n ================================================================== --- doc/package.n +++ doc/package.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: package.n,v 1.6 2002/01/27 17:35:06 dgp Exp $ +'\" RCS: @(#) $Id: package.n,v 1.6.2.3 2006/09/04 19:35:49 hobbs Exp $ '\" .so man.macros .TH package n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -88,11 +88,11 @@ An error occurs if a different version of \fIpackage\fR has been provided by a previous \fBpackage provide\fR command. If the \fIversion\fR argument is omitted, then the command returns the version number that is currently provided, or an empty string if no \fBpackage provide\fR command has been -invoked for \fIpackage\fR in this interpreter. +invoked for \fIpackage\fR in this interpreter. .TP \fBpackage require \fR?\fB\-exact\fR? \fIpackage \fR?\fIversion\fR? This command is typically invoked by Tcl code that wishes to use a particular version of a particular package. The arguments indicate which package is wanted, and the command ensures that @@ -159,11 +159,10 @@ \fBpackage vsatisfies \fIversion1 version2\fR Returns 1 if scripts written for \fIversion2\fR will work unchanged with \fIversion1\fR (i.e. \fIversion1\fR is equal to or greater than \fIversion2\fR and they both have the same major version number), 0 otherwise. - .SH "VERSION NUMBERS" .PP Version numbers consist of one or more decimal numbers separated by dots, such as 2 or 1.162 or 3.1.13.1. The first number is called the major version number. @@ -179,20 +178,38 @@ For example, Tcl scripts written for version 2.3 of a package should work unchanged under versions 2.3.2, 2.4, and 2.5.1. Changes in the major version number signify incompatible changes: if code is written to use version 2.1 of a package, it is not guaranteed to work unmodified with either version 1.7.3 or version 3.1. - .SH "PACKAGE INDICES" .PP The recommended way to use packages in Tcl is to invoke \fBpackage require\fR and \fBpackage provide\fR commands in scripts, and use the procedure \fBpkg_mkIndex\fR to create package index files. Once you've done this, packages will be loaded automatically in response to \fBpackage require\fR commands. See the documentation for \fBpkg_mkIndex\fR for details. +.SH EXAMPLES +To state that a Tcl script requires the Tk and http packages, put this +at the top of the script: +.CS +\fBpackage require\fR Tk +\fBpackage require\fR http +.CE +.PP +To test to see if the Snack package is available and load if it is +(often useful for optional enhancements to programs where the loss of +the functionality is not critical) do this: +.CS +if {[catch {\fBpackage require\fR Snack}]} { + # Error thrown - package not found. + # Set up a dummy interface to work around the absence +} else { + # We have the package, configure the app to use it +} +.CE .SH "SEE ALSO" msgcat(n), packagens(n), pkgMkIndex(n) .SH KEYWORDS package, version Index: doc/pid.n ================================================================== --- doc/pid.n +++ doc/pid.n @@ -3,18 +3,18 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: pid.n,v 1.3 2000/09/07 14:27:50 poenitz Exp $ +'\" RCS: @(#) $Id: pid.n,v 1.3.18.1 2004/10/27 14:23:57 dkf Exp $ '\" .so man.macros .TH pid n 7.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME -pid \- Retrieve process id(s) +pid \- Retrieve process identifiers .SH SYNOPSIS \fBpid \fR?\fIfileId\fR? .BE .SH DESCRIPTION @@ -27,11 +27,24 @@ The list will be empty if \fIfileId\fR refers to an open file that isn't a process pipeline. If no \fIfileId\fR argument is given then \fBpid\fR returns the process identifier of the current process. All process identifiers are returned as decimal strings. +.SH EXAMPLE +Print process information about the processes in a pipeline using the +SysV \fBps\fR program before reading the output of that pipeline: +.PP +.CS +set pipeline [open "| zcat somefile.gz | grep foobar | sort -u"] +# Print process information +exec ps -fp [\fBpid\fR $pipeline] >@stdout +# Print a separator and then the output of the pipeline +puts [string repeat - 70] +puts [read $pipeline] +close $pipeline +.CE .SH "SEE ALSO" exec(n), open(n) .SH KEYWORDS file, pipeline, process identifier Index: doc/proc.n ================================================================== --- doc/proc.n +++ doc/proc.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: proc.n,v 1.3 2000/09/07 14:27:50 poenitz Exp $ +'\" RCS: @(#) $Id: proc.n,v 1.3.18.1 2004/10/27 14:23:57 dkf Exp $ '\" .so man.macros .TH proc n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -67,11 +67,31 @@ \fBreturn\fR command. If the procedure doesn't execute an explicit \fBreturn\fR, then its return value is the value of the last command executed in the procedure's body. If an error occurs while executing the procedure body, then the procedure-as-a-whole will return that same error. +.SH EXAMPLES +This is a procedure that accepts arbitrarily many arguments and prints +them out, one by one. +.CS +\fBproc\fR printArguments args { + foreach arg $args { + puts $arg + } +} +.CE +.PP +This procedure is a bit like the \fBincr\fR command, except it +multiplies the contents of the named variable by the value, which +defaults to \fB2\fR: +.CS +\fBproc\fR mult {varName {multiplier 2}} { + upvar 1 $varName var + set var [expr {$var * $multiplier}] +} +.CE .SH "SEE ALSO" info(n), unknown(n) .SH KEYWORDS argument, procedure Index: doc/puts.n ================================================================== --- doc/puts.n +++ doc/puts.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: puts.n,v 1.5 2001/09/14 19:20:40 andreas_kupries Exp $ +'\" RCS: @(#) $Id: puts.n,v 1.5.8.1 2004/10/27 14:23:57 dkf Exp $ '\" .so man.macros .TH puts n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -66,11 +66,36 @@ large amount of memory. To avoid wasting memory, nonblocking I/O should normally be used in an event-driven fashion with the \fBfileevent\fR command (don't invoke \fBputs\fR unless you have recently been notified via a file event that the channel is ready for more output data). +.SH EXAMPLES +Write a short message to the console (or wherever \fBstdout\fR is +directed): +.CS +\fBputs\fR "Hello, World!" +.CE +.PP +Print a message in several parts: +.CS +\fBputs\fR -nonewline "Hello, " +\fBputs\fR "World!" +.CE +.PP +Print a message to the standard error channel: +.CS +\fBputs\fR stderr "Hello, World!" +.CE +.PP +Append a log message to a file: +.CS +set chan [open my.log a] +set timestamp [clock format [clock seconds]] +\fBputs\fR $chan "$timestamp - Hello, World!" +close $chan +.CE .SH "SEE ALSO" file(n), fileevent(n), Tcl_StandardChannels(3) .SH KEYWORDS channel, newline, output, write Index: doc/pwd.n ================================================================== --- doc/pwd.n +++ doc/pwd.n @@ -3,25 +3,39 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: pwd.n,v 1.3 2000/09/07 14:27:50 poenitz Exp $ +'\" RCS: @(#) $Id: pwd.n,v 1.3.18.1 2004/10/27 14:23:57 dkf Exp $ '\" .so man.macros .TH pwd n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME -pwd \- Return the current working directory +pwd \- Return the absolute path of the current working directory .SH SYNOPSIS \fBpwd\fR .BE .SH DESCRIPTION .PP -Returns the path name of the current working directory. +Returns the absolute path name of the current working directory. +.SH EXAMPLE +Sometimes it is useful to change to a known directory when running +some external command using \fBexec\fR, but it is important to keep +the application usually running in the directory that it was started +in (unless the user specifies otherwise) since that minimises user +confusion. The way to do this is to save the current directory while +the external command is being run: +.CS +set tarFile [file normalize somefile.tar] +set savedDir [\fBpwd\fR] +cd /tmp +exec tar -xf $tarFile +cd $savedDir +.CE .SH "SEE ALSO" file(n), cd(n), glob(n), filename(n) .SH KEYWORDS Index: doc/re_syntax.n ================================================================== --- doc/re_syntax.n +++ doc/re_syntax.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1999 Scriptics Corporation '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: re_syntax.n,v 1.3 1999/07/14 19:09:36 jpeek Exp $ +'\" RCS: @(#) $Id: re_syntax.n,v 1.3.32.1 2006/04/12 02:19:53 das Exp $ '\" .so man.macros .TH re_syntax n "8.1" Tcl "Tcl Built-In Commands" .BS .SH NAME @@ -277,12 +277,12 @@ class. Standard character classes are: .PP .RS .ne 5 -.nf .ta 3c +.nf \fBalpha\fR A letter. \fBupper\fR An upper-case letter. \fBlower\fR A lower-case letter. \fBdigit\fR A decimal digit. \fBxdigit\fR A hexadecimal digit. Index: doc/read.n ================================================================== --- doc/read.n +++ doc/read.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: read.n,v 1.7 2001/09/14 19:20:40 andreas_kupries Exp $ +'\" RCS: @(#) $Id: read.n,v 1.7.8.1 2004/10/27 14:23:57 dkf Exp $ '\" .so man.macros .TH read n 8.1 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -71,12 +71,20 @@ \fBread \fIchannelId\fR In this form \fBread\fR blocks until the reception of the end-of-file character, see \fBfconfigure -eofchar\fR. If there no end-of-file character has been configured for the channel, then \fBread\fR will block forever. - +.SH "EXAMPLE" +This example code reads a file all at once, and splits it into a list, +with each line in the file corresponding to an element in the list: +.CS +set fl [open /proc/meminfo] +set data [\fBread\fR $fl] +close $fl +set lines [split $data \\n] +.CE .SH "SEE ALSO" file(n), eof(n), fblocked(n), fconfigure(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, channel, end of line, end of file, nonblocking, read, translation, encoding Index: doc/regexp.n ================================================================== --- doc/regexp.n +++ doc/regexp.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: regexp.n,v 1.12 2002/10/10 14:46:57 dgp Exp $ +'\" RCS: @(#) $Id: regexp.n,v 1.12.2.1 2004/10/27 14:23:57 dkf Exp $ '\" .so man.macros .TH regexp n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -124,11 +124,38 @@ subexpressions within \fIexp\fR, or if a particular subexpression in \fIexp\fR doesn't match the string (e.g. because it was in a portion of the expression that wasn't matched), then the corresponding \fIsubMatchVar\fR will be set to ``\fB\-1 \-1\fR'' if \fB\-indices\fR has been specified or to an empty string otherwise. +.SH EXAMPLES +Find the first occurrence of a word starting with \fBfoo\fR in a +string that is not actually an instance of \fBfoobar\fR, and get the +letters following it up to the end of the word into a variable: +.CS +\fBregexp\fR {\\)(\\w*)} $string \-> restOfWord +.CE +Note that the whole matched substring has been placed in the variable +\fB\->\fR which is a name chosen to look nice given that we are not +actually interested in its contents. +.PP +Find the index of the word \fBbadger\fR (in any case) within a string +and store that in the variable \fBlocation\fR: +.CS +\fBregexp\fR \-indices {(?i)\\} $string location +.CE +.PP +Count the number of octal digits in a string: +.CS +\fBregexp\fR \-all {[0\-7]} $string +.CE +.PP +List all words (consisting of all sequences of non-whitespace +characters) in a string: +.CS +\fBregexp\fR \-all \-inline {\\S+} $string +.CE .SH "SEE ALSO" re_syntax(n), regsub(n) .SH KEYWORDS match, regular expression, string Index: doc/registry.n ================================================================== --- doc/registry.n +++ doc/registry.n @@ -3,11 +3,11 @@ '\" Copyright (c) 2002 ActiveState Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: registry.n,v 1.8 2002/10/19 01:48:46 hobbs Exp $ +'\" RCS: @(#) $Id: registry.n,v 1.8.2.2 2004/11/12 09:02:30 das Exp $ '\" .so man.macros .TH registry n 1.1 registry "Tcl Bundled Packages" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -48,21 +48,21 @@ registry key names separated by backslash (\fB\e\fR) characters. .PP \fIOption\fR indicates what to do with the registry key name. Any unique abbreviation for \fIoption\fR is acceptable. The valid options are: -.TP .VS 8.4 +.TP \fBregistry broadcast \fIkeyName\fR ?\fI-timeout milliseconds\fR? . Sends a broadcast message to the system and running programs to notify them of certain updates. This is necessary to propagate changes to key registry keys like Environment. The timeout specifies the amount of time, in milliseconds, to wait for applications to respond to the broadcast message. It defaults to 3000. The following example demonstrates how to add a path to the global Environment and notify applications of the change without -reguiring a logoff/logon step (assumes admin privileges): +requiring a logoff/logon step (assumes admin privileges): .CS set regPath {HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment} set curPath [registry get $regPath "Path"] registry set $regPath "Path" "$curPath;$addPath" registry broadcast "Environment" @@ -177,11 +177,26 @@ .PP In addition to the symbolically named types listed above, unknown types are identified using a 32-bit integer that corresponds to the type code returned by the system interfaces. In this case, the data is represented exactly in Tcl, including any embedded nulls. - .SH "PORTABILITY ISSUES" The registry command is only available on Windows. +.SH EXAMPLE +Print out how double-clicking on a Tcl script file will invoke a Tcl +interpreter: +.CS +package require registry +set ext .tcl + +# Read the type name +set type [\fBregistry get\fR HKEY_CLASSES_ROOT\e\e$ext {}] +# Work out where to look for the command +set path HKEY_CLASSES_ROOT\e\e$type\e\eShell\e\eOpen\e\ecommand +# Read the command! +set command [\fBregistry get\fR $path {}] + +puts "$ext opens with $command" +.CE .SH KEYWORDS registry Index: doc/regsub.n ================================================================== --- doc/regsub.n +++ doc/regsub.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2000 Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: regsub.n,v 1.9 2003/02/20 15:33:02 dkf Exp $ +'\" RCS: @(#) $Id: regsub.n,v 1.9.2.1 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH regsub n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -112,11 +112,37 @@ number of matching ranges that were found and replaced, otherwise the string after replacement is returned. .VE 8.4 See the manual entry for \fBregexp\fR for details on the interpretation of regular expressions. +.SH EXAMPLES +Replace (in the string in variable \fIstring\fR) every instance of +\fBfoo\fR which is a word by itself with \fBbar\fR: +.CS +\fBregsub\fR -all {\e} $string bar string +.CE +.PP +Insert double-quotes around the first instance of the word +\fBinteresting\fR, however it is capitalised. +.CS +\fBregsub\fR -nocase {\e} $string {"&"} string +.CE +.PP +Convert all non-ASCII and Tcl-significant characters into \eu escape +sequences by using \fBregsub\fR and \fBsubst\fR in combination: +.CS +# This RE is just a character class for everything "bad" +set RE {[][{}\e$\es\eu0100-\euffff]} + +# We will substitute with a fragment of Tcl script in brackets +set substitution {[format \e\e\e\eu%04x [scan "\e\e&" %c]]} + +# Now we apply the substitution to get a subst-string that +# will perform the computational parts of the conversion. +set quoted [subst [\fBregsub\fR -all $RE $string $substitution]] +.CE .SH "SEE ALSO" -regexp(n), re_syntax(n) +regexp(n), re_syntax(n), subst(n) .SH KEYWORDS match, pattern, regular expression, substitute Index: doc/rename.n ================================================================== --- doc/rename.n +++ doc/rename.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: rename.n,v 1.3 2000/09/07 14:27:51 poenitz Exp $ +'\" RCS: @(#) $Id: rename.n,v 1.3.18.1 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH rename n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -25,11 +25,24 @@ \fIoldName\fR and \fInewName\fR may include namespace qualifiers (names of containing namespaces). If a command is renamed into a different namespace, future invocations of it will execute in the new namespace. The \fBrename\fR command returns an empty string as result. +.SH EXAMPLE +The \fBrename\fR command can be used to wrap the standard Tcl commands +with your own monitoring machinery. For example, you might wish to +count how often the \fBsource\fR command is called: +.CS +\fBrename\fR ::source ::theRealSource +set sourceCount 0 +proc ::source args { + global sourceCount + puts "called source for the [incr sourceCount]'th time" + uplevel 1 ::theRealSource $args +} +.CE .SH "SEE ALSO" namespace(n), proc(n) .SH KEYWORDS command, delete, namespace, rename Index: doc/return.n ================================================================== --- doc/return.n +++ doc/return.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: return.n,v 1.3 2000/09/07 14:27:51 poenitz Exp $ +'\" RCS: @(#) $Id: return.n,v 1.3.18.1 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH return n 7.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -21,47 +21,49 @@ .PP Return immediately from the current procedure (or top-level command or \fBsource\fR command), with \fIstring\fR as the return value. If \fIstring\fR is not specified then an empty string will be returned as result. - -.SH "EXCEPTIONAL RETURNS" +.SH "EXCEPTIONAL RETURN CODES" .PP +In addition to the result of a procedure, the return +code of a procedure may also be set by \fBreturn\fR +through use of the \fB-code\fR option. In the usual case where the \fB\-code\fR option isn't -specified the procedure will return normally (its completion -code will be TCL_OK). +specified the procedure will return normally. However, the \fB\-code\fR option may be used to generate an exceptional return from the procedure. \fICode\fR may have any of the following values: -.TP 10 -\fBok\fR -Normal return: same as if the option is omitted. -.TP 10 -\fBerror\fR -Error return: same as if the \fBerror\fR command were used to -terminate the procedure, except for handling of \fBerrorInfo\fR -and \fBerrorCode\fR variables (see below). -.TP 10 -\fBreturn\fR -The current procedure will return with a completion code of -TCL_RETURN, so that the procedure that invoked it will return -also. -.TP 10 -\fBbreak\fR -The current procedure will return with a completion code of -TCL_BREAK, which will terminate the innermost nested loop in -the code that invoked the current procedure. -.TP 10 -\fBcontinue\fR -The current procedure will return with a completion code of -TCL_CONTINUE, which will terminate the current iteration of -the innermost nested loop in the code that invoked the current -procedure. -.TP 10 +.TP 13 +\fBok (or 0)\fR +Normal return: same as if the option is omitted. The return code +of the procedure is 0 (\fBTCL_OK\fR). +.TP 13 +\fBerror (1)\fR +Error return: the return code of the procedure is 1 (\fBTCL_ERROR\fR). +The procedure command behaves in its calling context as if it +were the command \fBerror \fIresult\fR. See below for additional +options. +.TP 13 +\fBreturn (2)\fR +The return code of the procedure is 2 (\fBTCL_RETURN\fR). The +procedure command behaves in its calling context as if it +were the command \fBreturn\fR (with no arguments). +.TP 13 +\fBbreak (3)\fR +The return code of the procedure is 3 (\fBTCL_BREAK\fR). The +procedure command behaves in its calling context as if it +were the command \fBbreak\fR. +.TP 13 +\fBcontinue (4)\fR +The return code of the procedure is 4 (\fBTCL_CONTINUE\fR). The +procedure command behaves in its calling context as if it +were the command \fBcontinue\fR. +.TP 13 \fIvalue\fR \fIValue\fR must be an integer; it will be returned as the -completion code for the current procedure. +return code for the current procedure. .LP The \fB\-code\fR option is rarely used. It is provided so that procedures that implement new control structures can reflect exceptional conditions back to their callers. @@ -82,11 +84,61 @@ .PP If the \fB\-errorcode\fR option is specified then \fIcode\fR provides a value for the \fBerrorCode\fR variable. If the option is not specified then \fBerrorCode\fR will default to \fBNONE\fR. +.SH EXAMPLES +First, a simple example of using \fBreturn\fR to return from a +procedure, interrupting the procedure body. +.CS +proc printOneLine {} { + puts "line 1" ;# This line will be printed. + \fBreturn\fR + puts "line 2" ;# This line will not be printed. +} +.CE +.PP +Next, an example of using \fBreturn\fR to set the value +returned by the procedure. +.CS +proc returnX {} {\fBreturn\fR X} +puts [returnX] ;# prints "X" +.CE +.PP +Next, a more complete example, using \fBreturn -code error\fR +to report invalid arguments. +.CS +proc factorial {n} { + if {![string is integer $n] || ($n < 0)} { + \fBreturn\fR -code error \\ + "expected non-negative integer,\\ + but got \\"$n\\"" + } + if {$n < 2} { + \fBreturn\fR 1 + } + set m [expr {$n - 1}] + set code [catch {factorial $m} factor] + if {$code != 0} { + \fBreturn\fR -code $code $factor + } + set product [expr {$n * $factor}] + if {$product < 0} { + \fBreturn\fR -code error \\ + "overflow computing factorial of $n" + } + \fBreturn\fR $product +} +.CE +.PP +Next, a procedure replacement for \fBbreak\fR. +.CS +proc myBreak {} { + \fBreturn\fR -code break +} +.CE .SH "SEE ALSO" -break(n), continue(n), error(n), proc(n) +break(n), catch(n), continue(n), error(n), proc(n), source(n), tclvars(n) .SH KEYWORDS -break, continue, error, procedure, return +break, catch, continue, error, procedure, return Index: doc/safe.n ================================================================== --- doc/safe.n +++ doc/safe.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: safe.n,v 1.4 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: safe.n,v 1.4.2.1 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH "Safe Tcl" n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -207,11 +207,11 @@ This option is a convenience shortcut for \fB-nested true\fR and thus specifies the safe interpreter will be allowed to load packages into its own sub-interpreters. .TP \fB\-deleteHook\fR \fIscript\fR -When this option is given an non empty \fIscript\fR, it will be +When this option is given a non-empty \fIscript\fR, it will be evaluated in the master with the name of the safe interpreter as an additional argument just before actually deleting the safe interpreter. Giving an empty value removes any currently installed deletion hook script for that safe interpreter. @@ -286,11 +286,11 @@ structure of the file system of the host on which the interpreter is executing. The only valid file names arguments for the \fBsource\fR and \fBload\fR aliases provided to the slave are path in the form of -\fB[file join \fR\fItoken filename\fR\fB]\fR (ie, when using the +\fB[file join \fR\fItoken filename\fR\fB]\fR (i.e. when using the native file path formats: \fItoken\fR\fB/\fR\fIfilename\fR on Unix, \fItoken\fR\fB\\\fIfilename\fR on Windows, and \fItoken\fR\fB:\fR\fIfilename\fR on the Mac), where \fItoken\fR is representing one of the directories of the \fIaccessPath\fR list and \fIfilename\fR is @@ -336,15 +336,15 @@ restrictive path for which sub directories will never be searched by explicitly specifying your directory list with the \fB\-accessPath\fR flag instead of relying on this default mechanism. .PP When the \fIaccessPath\fR is changed after the first creation or -initialization (ie through \fBinterpConfigure -accessPath \fR\fIlist\fR), +initialization (i.e. through \fBinterpConfigure -accessPath \fR\fIlist\fR), an \fBauto_reset\fR is automatically evaluated in the safe interpreter to synchronize its \fBauto_index\fR with the new token list. .SH "SEE ALSO" interp(n), library(n), load(n), package(n), source(n), unknown(n) .SH KEYWORDS alias, auto\-loading, auto_mkindex, load, master interpreter, safe interpreter, slave interpreter, source Index: doc/scan.n ================================================================== --- doc/scan.n +++ doc/scan.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2000 Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: scan.n,v 1.9 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: scan.n,v 1.9.2.1 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH scan n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -31,11 +31,10 @@ If no \fIvarName\fR variables are specified, then \fBscan\fR works in an inline manner, returning the data that would otherwise be stored in the variables as a list. In the inline case, an empty string is returned when the end of the input string is reached before any conversions have been performed. - .SH "DETAILS ON SCANNING" .PP \fBScan\fR operates by scanning \fIstring\fR and \fIformat\fR together. If the next character in \fIformat\fR is a blank or tab then it matches any number of white space characters in \fIstring\fR (including @@ -186,11 +185,10 @@ The input field for a given conversion terminates either when a white-space character is encountered or when the maximum field width has been reached, whichever comes first. If a \fB*\fR is present in the conversion specifier then no variable is assigned and the next scan argument is not consumed. - .SH "DIFFERENCES FROM ANSI SSCANF" .PP The behavior of the \fBscan\fR command is the same as the behavior of the ANSI C \fBsscanf\fR procedure except for the following differences: .IP [1] @@ -207,11 +205,60 @@ \fBdouble\fR is used for the internal representation). .VE 8.4 .IP [4] If the end of the input string is reached before any conversions have been performed and no variables are given, an empty string is returned. +.SH EXAMPLES +Parse a simple color specification of the form \fI#RRGGBB\fR using +hexadecimal conversions with field sizes: +.CS +set string "#08D03F" +\fBscan\fR $string "#%2x%2x%2x" r g b +.CE +.PP +Parse a \fIHH:MM\fR time string, noting that this avoids problems with +octal numbers by forcing interpretation as decimals (if we did not +care, we would use the \fB%i\fR conversion instead): +.CS +set string "08:08" ;# *Not* octal! +if {[\fBscan\fR $string "%d:%d" hours minutes] != 2} { + error "not a valid time string" +} +# We have to understand numeric ranges ourselves... +if {$minutes < 0 || $minutes > 59} { + error "invalid number of minutes" +} +.CE +.PP +Break a string up into sequences of non-whitespace characters (note +the use of the \fB%n\fR conversion so that we get skipping over +leading whitespace correct): +.CS +set string " a string {with braced words} + leading space " +set words {} +while {[\fBscan\fR $string %s%n word length] == 2} { + lappend words $word + set string [string range $string $length end] +} +.CE +.PP +Parse a simple coordinate string, checking that it is complete by +looking for the terminating character explicitly: +.CS +set string "(5.2,-4e-2)" +# Note that the spaces before the literal parts of +# the scan pattern are significant, and that ")" is +# the Unicode character \\u0029 +if { + [\fBscan\fR $string " (%f ,%f %c" x y last] != 3 + || $last != 0x0029 +} then { + error "invalid coordinate string" +} +puts "X=$x, Y=$y" +.CE .SH "SEE ALSO" format(n), sscanf(3) .SH KEYWORDS conversion specifier, parse, scan Index: doc/seek.n ================================================================== --- doc/seek.n +++ doc/seek.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: seek.n,v 1.5 2001/09/14 19:20:40 andreas_kupries Exp $ +'\" RCS: @(#) $Id: seek.n,v 1.5.8.1 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH seek n 8.1 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -60,11 +60,32 @@ .VS 8.1 Note that \fIoffset\fR values are byte offsets, not character offsets. Both \fBseek\fR and \fBtell\fR operate in terms of bytes, not characters, unlike \fBread\fR. .VE 8.1 +.SH EXAMPLES +Read a file twice: +.CS +set f [open file.txt] +set data1 [read $f] +\fBseek\fR $f 0 +set data2 [read $f] +close $f +# $data1 == $data2 if the file wasn't updated +.CE +.PP +Read the last 10 bytes from a file: +.CS +set f [open file.data] +# This is guaranteed to work with binary data but +# may fail with other encodings... +fconfigure $f -translation binary +\fBseek\fR $f -10 end +set data [read $f 10] +close $f +.CE .SH "SEE ALSO" file(n), open(n), close(n), gets(n), tell(n), Tcl_StandardChannels(3) .SH KEYWORDS access position, file, seek Index: doc/set.n ================================================================== --- doc/set.n +++ doc/set.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: set.n,v 1.3 2000/09/07 14:27:51 poenitz Exp $ +'\" RCS: @(#) $Id: set.n,v 1.3.18.2 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH set n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -26,26 +26,50 @@ If \fIvarName\fR contains an open parenthesis and ends with a close parenthesis, then it refers to an array element: the characters before the first open parenthesis are the name of the array, and the characters between the parentheses are the index within the array. Otherwise \fIvarName\fR refers to a scalar variable. -Normally, \fIvarName\fR is unqualified -(does not include the names of any containing namespaces), -and the variable of that name in the current namespace is read or written. +.PP If \fIvarName\fR includes namespace qualifiers -(in the array name if it refers to an array element), -the variable in the specified namespace is read or written. +(in the array name if it refers to an array element), or if \fIvarName\fR +is unqualified (does not include the names of any containing namespaces) +but no procedure is active, +\fIvarName\fR refers to a namespace variable +resolved according to the rules described under \fBNAME RESOLUTION\fR in +the \fBnamespace\fR manual page. +.PP +If a procedure is active and \fIvarName\fR is unqualified, then +\fIvarName\fR refers to a parameter or local variable of the procedure, +unless \fIvarName\fR was declared to resolve differently through one of the +\fBglobal\fR, \fBvariable\fR or \fBupvar\fR commands. +.SH EXAMPLES +Store a random number in the variable \fIr\fR: +.CS +\fBset\fR r [expr rand()] +.CE +.PP +Store a short message in an array element: +.CS +\fBset\fR anAry(msg) "Hello, World!" +.CE +.PP +Store a short message in an array element specified by a variable: +.CS +\fBset\fR elemName "msg" +\fBset\fR anAry($elemName) "Hello, World!" +.CE .PP -If no procedure is active, -then \fIvarName\fR refers to a namespace variable -(global variable if the current namespace is the global namespace). -If a procedure is active, then \fIvarName\fR refers to a parameter -or local variable of the procedure unless the \fBglobal\fR command -was invoked to declare \fIvarName\fR to be global, -or unless a \fBvariable\fR command -was invoked to declare \fIvarName\fR to be a namespace variable. +Copy a value into the variable \fIout\fR from a variable whose name is +stored in the \fIvbl\fR (note that it is often easier to use arrays in +practice instead of doing double-dereferencing): +.CS +\fBset\fR in0 "small random" +\fBset\fR in1 "large random" +\fBset\fR vbl in[expr {rand() >= 0.5}] +\fBset\fR out [\fBset\fR $vbl] +.CE .SH "SEE ALSO" -expr(n), proc(n), trace(n), unset(n) +expr(n), global(n), namespace(n), proc(n), trace(n), unset(n), upvar(n), variable(n) .SH KEYWORDS read, write, variable Index: doc/socket.n ================================================================== --- doc/socket.n +++ doc/socket.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1998-1999 by Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: socket.n,v 1.7 2002/10/01 10:03:19 dkf Exp $ +'\" RCS: @(#) $Id: socket.n,v 1.7.2.3 2004/10/27 14:23:58 dkf Exp $ .so man.macros .TH socket n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME @@ -27,11 +27,17 @@ At present only the TCP network protocol is supported; future releases may include support for additional protocols. The \fBsocket\fR command may be used to open either the client or server side of a connection, depending on whether the \fB\-server\fR switch is specified. - +.PP +Note that the default encoding for \fIall\fR sockets is the system +encoding, as returned by \fBencoding system\fR. Most of the time, you +will need to use \fBfconfigure\fR to alter this to something else, +such as \fIutf\-8\fR (ideal for communicating with other Tcl +processes) or \fIiso8859\-1\fR (useful for many network protocols, +especially the older ones). .SH "CLIENT SOCKETS" .PP If the \fB\-server\fR option is not specified, then the client side of a connection is opened and the command returns a channel identifier that can be used for both reading and writing. @@ -38,11 +44,11 @@ \fIPort\fR and \fIhost\fR specify a port to connect to; there must be a server accepting connections on this port. \fIPort\fR is an integer port number (or service name, where supported and understood by the host operating system) and \fIhost\fR -is either a domain-style name such as \fBwww.sunlabs.com\fR or +is either a domain-style name such as \fBwww.tcl.tk\fR or a numerical IP address such as \fB127.0.0.1\fR. Use \fIlocalhost\fR to refer to the host on which the command is invoked. .PP The following options may also be present before \fIhost\fR to specify additional information about the connection: @@ -69,17 +75,18 @@ connection attempt succeeds or fails, if the socket is in blocking mode, the operation will wait until the connection is completed or fails. If the socket is in nonblocking mode and a \fBgets\fR or \fBflush\fR is done on the socket before the connection attempt succeeds or fails, the operation returns immediately and \fBfblocked\fR on the socket returns 1. - .SH "SERVER SOCKETS" .PP If the \fB\-server\fR option is specified then the new socket will be a server for the port given by \fIport\fR (either an integer or a service name, where supported and understood by the host -operating system). +operating system; if \fIport\fR is zero, the operating system will +allocate a free port to the server socket which may be discovered by +using \fBfconfigure\fR to read the \fB\-sockname\fR option). Tcl will automatically accept connections to the given port. For each connection Tcl will create a new channel that may be used to communicate with the client. Tcl then invokes \fIcommand\fR with three additional arguments: the name of the new channel, the address, in network address notation, of the client's host, and @@ -107,14 +114,13 @@ calling the C procedure \fBTcl_DoOneEvent\fR, then no connections will be accepted. .PP If \fIport\fR is specified as zero, the operating system will allocate an unused port for use as a server socket. The port number actually -allocated my be retrieved from the created server socket using the +allocated may be retrieved from the created server socket using the \fBfconfigure\fR command to retrieve the \fB\-sockname\fR option as described below. - .SH "CONFIGURATION OPTIONS" The \fBfconfigure\fR command can be used to query several readonly configuration options for socket channels: .TP \fB\-error\fR @@ -134,11 +140,32 @@ sockets, this option returns a list of three elements; these are the address, the host name and the port to which the peer socket is connected or bound. If the host name cannot be computed, the second element of the list is identical to the address, its first element. .PP +.SH "EXAMPLES" +Here is a very simple time server: +.CS +proc Server {channel clientaddr clientport} { + puts "Connection from $clientaddr registered" + puts $channel [clock format [clock seconds]] + close $channel +} + +\fBsocket\fR -server Server 9900 +vwait forever +.CE +.PP +And here is the corresponding client to talk to the server: +.CS +set server localhost +set sockChan [\fBsocket\fR $server 9900] +gets $sockChan line +close $sockChan +puts "The time on $server is $line" +.CE .SH "SEE ALSO" -flush(n), open(n), read(n) +fconfigure(n), flush(n), open(n), read(n) .SH KEYWORDS bind, channel, connection, domain name, host, network address, socket, tcp Index: doc/source.n ================================================================== --- doc/source.n +++ doc/source.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2000 Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: source.n,v 1.5 2000/09/07 14:27:51 poenitz Exp $ +'\" RCS: @(#) $Id: source.n,v 1.5.18.1 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH source n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -48,11 +48,24 @@ allow you to source a script from a \fBTEXT\fR resource. You may specify what \fBTEXT\fR resource to source by either name or id. By default Tcl searches all open resource files, which include the current application and any loaded C extensions. Alternatively, you may specify the \fIfileName\fR where the \fBTEXT\fR resource can be found. +.SH EXAMPLE +Run the script in the file \fBfoo.tcl\fR and then the script in the +file \fBbar.tcl\fR: +.CS +\fBsource\fR foo.tcl +\fBsource\fR bar.tcl +.CE +Alternatively: +.CS +foreach scriptFile {foo.tcl bar.tcl} { + \fBsource\fR $scriptFile +} +.CE .SH "SEE ALSO" -file(n), cd(n) +file(n), cd(n), info(n) .SH KEYWORDS file, script Index: doc/split.n ================================================================== --- doc/split.n +++ doc/split.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: split.n,v 1.3 2000/09/07 14:27:51 poenitz Exp $ +'\" RCS: @(#) $Id: split.n,v 1.3.18.1 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH split n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -28,20 +28,61 @@ adjacent characters in \fIsplitChars\fR, or if the first or last character of \fIstring\fR is in \fIsplitChars\fR. If \fIsplitChars\fR is an empty string then each character of \fIstring\fR becomes a separate element of the result list. \fISplitChars\fR defaults to the standard white-space characters. -For example, -.CS -\fBsplit "comp.unix.misc" .\fR -.CE -returns \fB"comp unix misc"\fR and -.CS -\fBsplit "Hello world" {}\fR -.CE -returns \fB"H e l l o { } w o r l d"\fR. +.SH EXAMPLES +Divide up a USENET group name into its hierarchical components: +.CS +\fBsplit\fR "comp.lang.tcl.announce" . + \fI=> comp lang tcl announce\fR +.CE +.PP +See how the \fBsplit\fR command splits on \fIevery\fR character in +\fIsplitChars\fR, which can result in information loss if you are not +careful: +.CS +\fBsplit\fR "alpha beta gamma" "temp" + \fI=> al {ha b} {} {a ga} {} a\fR +.CE +.PP +Extract the list words from a string that is not a well-formed list: +.CS +\fBsplit\fR "Example with {unbalanced brace character" + \fI=> Example with \\{unbalanced brace character\fR +.CE +.PP +Split a string into its constituent characters +.CS +\fBsplit\fR "Hello world" {} + \fI=> H e l l o { } w o r l d\fR +.CE +.SH "PARSING RECORD-ORIENTED FILES" +Parse a Unix /etc/passwd file, which consists of one entry per line, +with each line consisting of a colon-separated list of fields: +.CS +## Read the file +set fid [open /etc/passwd] +set content [read $fid] +close $fid + +## Split into records on newlines +set records [\fBsplit\fR $content "\\n"] + +## Iterate over the records +foreach rec $records { + + ## Split into fields on colons + set fields [\fBsplit\fR $rec ":"] + + ## Assign fields to variables and print some out... + lassign $fields \\ + userName password uid grp longName homeDir shell + puts "$longName uses [file tail $shell] for a login shell" +} +.CE .SH "SEE ALSO" join(n), list(n), string(n) .SH KEYWORDS list, split, string Index: doc/string.n ================================================================== --- doc/string.n +++ doc/string.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: string.n,v 1.17 2002/07/05 07:23:45 hobbs Exp $ +'\" RCS: @(#) $Id: string.n,v 1.17.2.4 2006/12/14 14:24:22 dkf Exp $ '\" .so man.macros .TH string n 8.1 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -93,54 +93,54 @@ returns 0, the index in the string where the class was no longer valid will be stored in the variable named \fIvarname\fR. The \fIvarname\fR will not be set if the function returns 1. The following character classes are recognized (the class name can be abbreviated): .RS -.IP \fBalnum\fR 10 +.IP \fBalnum\fR 12 Any Unicode alphabet or digit character. -.IP \fBalpha\fR 10 +.IP \fBalpha\fR 12 Any Unicode alphabet character. -.IP \fBascii\fR 10 +.IP \fBascii\fR 12 Any character with a value less than \\u0080 (those that are in the 7\-bit ascii range). -.IP \fBboolean\fR 10 +.IP \fBboolean\fR 12 Any of the forms allowed to \fBTcl_GetBoolean\fR. -.IP \fBcontrol\fR 10 +.IP \fBcontrol\fR 12 Any Unicode control character. -.IP \fBdigit\fR 10 +.IP \fBdigit\fR 12 Any Unicode digit character. Note that this includes characters outside of the [0\-9] range. -.IP \fBdouble\fR 10 +.IP \fBdouble\fR 12 Any of the valid forms for a double in Tcl, with optional surrounding whitespace. In case of under/overflow in the value, 0 is returned and the \fIvarname\fR will contain \-1. -.IP \fBfalse\fR 10 +.IP \fBfalse\fR 12 Any of the forms allowed to \fBTcl_GetBoolean\fR where the value is false. -.IP \fBgraph\fR 10 +.IP \fBgraph\fR 12 Any Unicode printing character, except space. -.IP \fBinteger\fR 10 -Any of the valid forms for an integer in Tcl, with optional +.IP \fBinteger\fR 12 +Any of the valid forms for an ordinary integer in Tcl, with optional surrounding whitespace. In case of under/overflow in the value, 0 is returned and the \fIvarname\fR will contain \-1. -.IP \fBlower\fR 10 +.IP \fBlower\fR 12 Any Unicode lower case alphabet character. -.IP \fBprint\fR 10 +.IP \fBprint\fR 12 Any Unicode printing character, including space. -.IP \fBpunct\fR 10 +.IP \fBpunct\fR 12 Any Unicode punctuation character. -.IP \fBspace\fR 10 +.IP \fBspace\fR 12 Any Unicode space character. -.IP \fBtrue\fR 10 +.IP \fBtrue\fR 12 Any of the forms allowed to \fBTcl_GetBoolean\fR where the value is true. -.IP \fBupper\fR 10 +.IP \fBupper\fR 12 Any upper case alphabet character in the Unicode character set. -.IP \fBwordchar\fR 10 +.IP \fBwordchar\fR 12 Any Unicode word character. That is any alphanumeric character, and any Unicode connector punctuation characters (e.g. underscore). -.IP \fBxdigit\fR 10 +.IP \fBxdigit\fR 12 Any hexadecimal digit character ([0\-9A\-Fa\-f]). .PP In the case of \fBboolean\fR, \fBtrue\fR and \fBfalse\fR, if the function will return 0, then the \fIvarname\fR will always be set to 0, due to the varied nature of a valid boolean value. @@ -170,13 +170,13 @@ \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. .TP -\fBstring map\fR ?\fB\-nocase\fR? \fIcharMap string\fR -Replaces characters in \fIstring\fR based on the key-value pairs in -\fIcharMap\fR. \fIcharMap\fR is a list of \fIkey value key value ...\fR +\fBstring map\fR ?\fB\-nocase\fR? \fImapping string\fR +Replaces substrings in \fIstring\fR based on the key-value pairs in +\fImapping\fR. \fImapping\fR is a list of \fIkey value key value ...\fR as in the form returned by \fBarray get\fR. Each instance of a key in the string will be replaced with its corresponding value. If \fB\-nocase\fR is specified, then matching is done without regard to case differences. Both \fIkey\fR and \fIvalue\fR may be multiple characters. Replacement is done in an ordered manner, so the key @@ -186,10 +186,18 @@ .RS .CS \fBstring map {abc 1 ab 2 a 3 1 0} 1abcaababcabababc\fR .CE will return the string \fB01321221\fR. +.PP +Note that if an earlier \fIkey\fR is a prefix of a later one, it will +completely mask the later one. So if the previous example is +reordered like this, +.CS +\fBstring map {1 0 ab 2 a 3 abc 1} 1abcaababcabababc\fR +.CE +it will return the string \fB02c322c222c\fR. .RE .TP \fBstring match\fR ?\fB\-nocase\fR? \fIpattern\fR \fIstring\fR See if \fIpattern\fR matches \fIstring\fR; return 1 if it does, 0 if it doesn't. If \fB\-nocase\fR is specified, then the pattern attempts @@ -301,11 +309,22 @@ character \fIcharIndex\fR of \fIstring\fR. \fIcharIndex\fR may be specified as for the \fBindex\fR method. A word is considered to be any contiguous range of alphanumeric (Unicode letters or decimal digits) or underscore (Unicode connector punctuation) characters, or any single character other than these. +.SH EXAMPLE +Test if the string in the variable \fIstring\fR is a proper non-empty +prefix of the string \fBfoobar\fR. +.CS +set length [\fBstring length\fR $string] +if {$length == 0} { + set isPrefix 0 +} else { + set isPrefix [\fBstring equal\fR -length $length $string "foobar"] +} +.CE .SH "SEE ALSO" expr(n), list(n) .SH KEYWORDS case conversion, compare, index, match, pattern, string, word, equal, ctype Index: doc/subst.n ================================================================== --- doc/subst.n +++ doc/subst.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2001 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: subst.n,v 1.5 2002/04/18 16:31:40 dgp Exp $ +'\" RCS: @(#) $Id: subst.n,v 1.5.2.1 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH subst n 7.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -64,62 +64,62 @@ .PP When it performs its substitutions, \fIsubst\fR does not give any special treatment to double quotes or curly braces (except within command substitutions) so the script .CS -\fBset a 44 -subst {xyz {$a}}\fR +set a 44 +\fBsubst\fR {xyz {$a}} .CE returns ``\fBxyz {44}\fR'', not ``\fBxyz {$a}\fR'' .VS 8.4 and the script .CS -\fBset a "p\\} q \\{r" -subst {xyz {$a}}\fR +set a "p\\} q \\{r" +\fBsubst\fR {xyz {$a}} .CE return ``\fBxyz {p} q {r}\fR'', not ``\fBxyz {p\\} q \\{r}\fR''. .PP When command substitution is performed, it includes any variable substitution necessary to evaluate the script. .CS -\fBset a 44 -subst -novariables {$a [format $a]}\fR +set a 44 +\fBsubst\fR -novariables {$a [format $a]} .CE returns ``\fB$a 44\fR'', not ``\fB$a $a\fR''. Similarly, when variable substitution is performed, it includes any command substitution necessary to retrieve the value of the variable. .CS -\fBproc b {} {return c} +proc b {} {return c} array set a {c c [b] tricky} -subst -nocommands {[b] $a([b])}\fR +\fBsubst\fR -nocommands {[b] $a([b])} .CE returns ``\fB[b] c\fR'', not ``\fB[b] tricky\fR''. .PP The continue and break exceptions allow command substitutions to prevent substitution of the rest of the command substitution and the rest of \fIstring\fR respectively, giving script authors more options when processing text using \fIsubst\fR. For example, the script .CS -\fBsubst {abc,[break],def}\fR +\fBsubst\fR {abc,[break],def} .CE returns ``\fBabc,\fR'', not ``\fBabc,,def\fR'' and the script .CS -\fBsubst {abc,[continue;expr 1+2],def}\fR +\fBsubst\fR {abc,[continue;expr 1+2],def} .CE returns ``\fBabc,,def\fR'', not ``\fBabc,3,def\fR''. .PP Other exceptional return codes substitute the returned value .CS -\fBsubst {abc,[return foo;expr 1+2],def}\fR +\fBsubst\fR {abc,[return foo;expr 1+2],def} .CE returns ``\fBabc,foo,def\fR'', not ``\fBabc,3,def\fR'' and .CS -\fBsubst {abc,[return -code 10 foo;expr 1+2],def}\fR +\fBsubst\fR {abc,[return -code 10 foo;expr 1+2],def} .CE also returns ``\fBabc,foo,def\fR'', not ``\fBabc,3,def\fR''. .VE .SH "SEE ALSO" Tcl(n), eval(n), break(n), continue(n) .SH KEYWORDS backslash substitution, command substitution, variable substitution Index: doc/switch.n ================================================================== --- doc/switch.n +++ doc/switch.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: switch.n,v 1.5 2000/09/07 14:27:51 poenitz Exp $ +'\" RCS: @(#) $Id: switch.n,v 1.5.18.1 2004/10/27 14:23:58 dkf Exp $ '\" .so man.macros .TH switch n 7.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -76,42 +76,48 @@ several patterns. .PP Beware of how you place comments in \fBswitch\fR commands. Comments should only be placed \fBinside\fR the execution body of one of the patterns, and not intermingled with the patterns. -.PP -Below are some examples of \fBswitch\fR commands: -.CS -\fBswitch\0abc\0a\0\-\0b\0{format 1}\0abc\0{format 2}\0default\0{format 3}\fR -.CE -will return \fB2\fR, -.CS -\fBswitch\0\-regexp\0aaab { - ^a.*b$\0\- - b\0{format 1} - a*\0{format 2} - default\0{format 3} -}\fR -.CE -will return \fB1\fR, and -.CS -\fBswitch\0xyz { - a - \- - b - { - # Correct Comment Placement - format 1 - } - a* - {format 2} - default - {format 3} -}\fR -.CE -will return \fB3\fR. +.SH "EXAMPLES" +The \fBswitch\fR command can match against variables and not just +literals, as shown here (the result is \fI2\fR): +.CS +set foo "abc" +\fBswitch\fR abc a \- b {expr 1} $foo {expr 2} default {expr 3} +.CE +.PP +Using glob matching and the fall-through body is an alternative to +writing regular expressions with alternations, as can be seen here +(this returns \fI1\fR): +.CS +\fBswitch\fR \-glob aaab { + a*b \- + b {expr 1} + a* {expr 2} + default {expr 3} +} +.CE +.PP +Whenever nothing matches, the \fBdefault\fR clause (which must be +last) is taken. This example has a result of \fI3\fR: +.CS +\fBswitch\fR xyz { + a \- + b { + # Correct Comment Placement + expr 1 + } + c { + expr 2 + } + default { + expr 3 + } +} +.CE .SH "SEE ALSO" for(n), if(n), regexp(n) .SH KEYWORDS switch, match, regular expression Index: doc/tcltest.n ================================================================== --- doc/tcltest.n +++ doc/tcltest.n @@ -6,21 +6,21 @@ '\" Contributions from Don Porter, NIST, 2002. (not subject to US copyright) '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: tcltest.n,v 1.38 2003/01/24 16:33:35 dgp Exp $ +'\" RCS: @(#) $Id: tcltest.n,v 1.38.2.6 2007/02/20 17:53:18 dgp Exp $ '\" .so man.macros .TH "tcltest" n 2.2 tcltest "Tcl Bundled Packages" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME tcltest \- Test harness support code and utilities .SH SYNOPSIS .nf -\fBpackage require tcltest ?2.2?\fR +\fBpackage require tcltest ?2.2.5?\fR .sp \fBtcltest::test \fIname description ?option value ...?\fR \fBtcltest::test \fIname description ?constraints? body result\fR .sp \fBtcltest::loadTestedCommands\fR @@ -30,16 +30,14 @@ \fBtcltest::removeFile \fIname ?directory?\fR \fBtcltest::viewFile \fIname ?directory?\fR \fBtcltest::cleanupTests \fI?runningMultipleTests?\fR \fBtcltest::runAllTests\fR .sp -.VS 2.1 \fBtcltest::configure\fR \fBtcltest::configure \fIoption\fR \fBtcltest::configure \fIoption value ?option value ...?\fR \fBtcltest::customMatch \fImode command\fR -.VE \fBtcltest::testConstraint \fIconstraint ?value?\fR \fBtcltest::outputChannel \fI?channelID?\fR \fBtcltest::errorChannel \fI?channelID?\fR \fBtcltest::interpreter \fI?interp?\fR .sp @@ -198,11 +196,10 @@ spanning multiple files and/or directories, as governed by the configurable options of \fBtcltest\fR. See \fBRUNNING ALL TESTS\fR below for a complete description of the many variations possible with [\fBrunAllTests\fR]. .SH "CONFIGURATION COMMANDS" -.VS .TP \fBconfigure\fR Returns the list of configurable options supported by \fBtcltest\fR. See \fBCONFIGURABLE OPTIONS\fR below for the full list of options, their valid values, and their effect on \fBtcltest\fR operations. @@ -236,11 +233,10 @@ words, the expected result, and the actual result, and the completed script is evaluated in the global namespace. The completed script is expected to return a boolean value indicating whether or not the results match. The built-in matching modes of [\fBtest\fR] are \fBexact\fR, \fBglob\fR, and \fBregexp\fR. -.VE .TP \fBtestConstraint \fIconstraint ?boolean?\fR Sets or returns the boolean value associated with the named \fIconstraint\fR. See \fBTEST CONSTRAINTS\fR below for more information. .TP @@ -380,11 +376,11 @@ also influence how [\fBtest\fR] operates. .PP The valid options for [\fBtest\fR] are summarized: .CS .ta 0.8i -test \fIname\fR \fIdescription\fR +\fBtest\fR \fIname\fR \fIdescription\fR ?-constraints \fIkeywordList|expression\fR? ?-setup \fIsetupScript\fR? ?-body \fItestScript\fR? ?-cleanup \fIcleanupScript\fR? ?-result \fIexpectedAnswer\fR? @@ -478,19 +474,19 @@ .TP \fB-output \fIexpectedValue\fR The \fB-output\fR attribute supplies the \fIexpectedValue\fR against which any output sent to \fBstdout\fR or [\fBoutputChannel\fR] during evaluation of the script(s) will be compared. Note that only output printed using -[\fBputs\fR] is used for comparison. If \fB-output\fR is not specified, +[\fB::puts\fR] is used for comparison. If \fB-output\fR is not specified, output sent to \fBstdout\fR and [\fBoutputChannel\fR] is not processed for comparison. .TP \fB-errorOutput \fIexpectedValue\fR The \fB-errorOutput\fR attribute supplies the \fIexpectedValue\fR against which any output sent to \fBstderr\fR or [\fBerrorChannel\fR] during evaluation of the script(s) will be compared. Note that only output -printed using [\fBputs\fR] is used for comparison. If \fB-errorOutput\fR +printed using [\fB::puts\fR] is used for comparison. If \fB-errorOutput\fR is not specified, output sent to \fBstderr\fR and [\fBerrorChannel\fR] is not processed for comparison. .TP \fB-returnCodes \fIexpectedCodeList\fR The optional \fB-returnCodes\fR attribute supplies \fIexpectedCodeList\fR, @@ -514,11 +510,11 @@ failures are instead reported as output written to [\fBoutputChannel\fR]. In default operation, a successful test produces no output. The output messages produced by [\fBtest\fR] are controlled by the [\fBconfigure -verbose\fR] option as described in \fBCONFIGURABLE OPTIONS\fR below. Any output produced by the test scripts themselves should be -produced using [\fBputs\fR] to [\fBoutputChannel\fR] or +produced using [\fB::puts\fR] to [\fBoutputChannel\fR] or [\fBerrorChannel\fR], so that users of the test suite may easily capture output with the [\fBconfigure -outfile\fR] and [\fBconfigure -errfile\fR] options, and so that the \fB-output\fR and \fB-errorOutput\fR attributes work properly. .SH "TEST CONSTRAINTS" @@ -665,11 +661,11 @@ [\fBconfigure -limitconstraints\fR] are in use, only those tests including only constraints from the [\fBconfigure -constraints\fR] list are run; all others are skipped. For example, one might set up a configuration with .CS -configure -constraints knownBug \e +\fBconfigure\fR -constraints knownBug \e -limitconstraints true \e -verbose pass .CE to run exactly those tests that exercise known bugs, and discover whether any of them pass, indicating the bug had been fixed. @@ -685,11 +681,11 @@ [\fBconfigure -testdir\fR]. The list of files in that directory that match any of the patterns in [\fBconfigure -file\fR] and match none of the patterns in [\fBconfigure -notfile\fR] is generated and sorted. Then each file will be evaluated in turn. If [\fBconfigure -singleproc\fR] is true, then each file will -be [\fBsource\fR]d in the caller's context. If if is false, +be [\fBsource\fR]d in the caller's context. If it is false, then a copy of [\fBinterpreter\fR] will be [\fBexec\fR]d to evaluate each file. The multi-process operation is useful when testing can cause errors so severe that a process terminates. Although such an error may terminate a child process evaluating one file, the master process can continue @@ -752,10 +748,11 @@ Display information regarding whether a test is skipped because it doesn't match any of the tests that were specified using by [\fBconfigure -match\fR] (userSpecifiedNonMatch) or matches any of the tests specified by [\fBconfigure -skip\fR] (userSpecifiedSkip). Also print warnings about possible lack of cleanup or balance in test files. +Also print warnings about any re-use of test names. .IP 2 Display the flag array parsed by the command line processor, the contents of the ::env array, and all user-defined variables that exist in the current namespace as they are used. .IP 3 @@ -764,11 +761,12 @@ .RE .TP \fB-verbose \fIlevel\fR Sets the type of output verbosity desired to \fIlevel\fR, a list of zero or more of the elements \fBbody\fR, \fBpass\fR, -\fBskip\fR, \fBstart\fR, and \fBerror\fR. Default value is \fBbody\fR. +\fBskip\fR, \fBstart\fR, and \fBerror\fR. Default value +is \fB{body error}\fR. Levels are defined as: .RS .IP "body (b)" Display the body of failed tests .IP "pass (p)" @@ -873,19 +871,19 @@ The fundamental element of a test suite is the individual [\fBtest\fR] command. We begin with several examples. .IP [1] Test of a script that returns normally. .CS -test example-1.0 {normal return} { +\fBtest\fR example-1.0 {normal return} { format %s value } value .CE .IP [2] Test of a script that requires context setup and cleanup. Note the bracing and indenting style that avoids any need for line continuation. .CS -test example-1.1 {test file existence} -setup { +\fBtest\fR example-1.1 {test file existence} -setup { set file [makeFile {} test] } -body { file exists $file } -cleanup { removeFile test @@ -892,18 +890,18 @@ } -result 1 .CE .IP [3] Test of a script that raises an error. .CS -test example-1.2 {error return} -body { +\fBtest\fR example-1.2 {error return} -body { error message } -returnCodes error -result message .CE .IP [4] Test with a constraint. .CS -test example-1.3 {user owns created files} -constraints { +\fBtest\fR example-1.3 {user owns created files} -constraints { unix } -setup { set file [makeFile {} test] } -body { file attributes $file -owner @@ -923,12 +921,12 @@ Most of the code in the test file should be the [\fBtest\fR] commands. Use constraints to skip tests, rather than conditional evaluation of [\fBtest\fR]. That is, do this: .IP [5] .CS -testConstraint X [expr $myRequirement] -test goodConditionalTest {} X { +\fBtestConstraint\fR X [expr $myRequirement] +\fBtest\fR goodConditionalTest {} X { # body } result .CE and do not do this: .IP [6] @@ -967,27 +965,27 @@ should be called. .IP [7] Here is a sketch of a sample test file illustrating those points: .CS package require tcltest 2.2 -eval tcltest::configure $argv +eval \fB::tcltest::configure\fR $argv package require example namespace eval ::example::test { namespace import ::tcltest::* - testConstraint X [expr {...}] + \fBtestConstraint\fR X [expr {...}] variable SETUP {#common setup code} variable CLEANUP {#common cleanup code} - test example-1 {} -setup $SETUP { + \fBtest\fR example-1 {} -setup $SETUP -body { # First test } -cleanup $CLEANUP -result {...} - test example-2 {} -constraints X -setup $SETUP { + \fBtest\fR example-2 {} -constraints X -setup $SETUP -body { # Second test; constrained } -cleanup $CLEANUP -result {...} - test example-3 {} { + \fBtest\fR example-3 {} { # Third test; no context required } {...} - cleanupTests + \fBcleanupTests\fR } namespace delete ::example::test .CE .PP The next level of organization is a full test suite, made up of several @@ -1000,14 +998,14 @@ Here is a sketch of a sample test suite master script: .CS package require Tcl 8.4 package require tcltest 2.2 package require example -tcltest::configure -testdir \ +\fB::tcltest::configure\fR -testdir \ [file dirname [file normalize [info script]]] -eval tcltest::configure $argv -tcltest::runAllTests +eval \fB::tcltest::configure\fR $argv +\fB::tcltest::runAllTests\fR .CE .SH COMPATIBILITY .PP A number of commands and variables in the \fB::tcltest\fR namespace provided by earlier releases of \fBtcltest\fR have not been documented @@ -1021,22 +1019,22 @@ from the variable \fB::argv\fR. This is to support test suites that depend on the old behavior that \fBtcltest\fR was automatically configured from command line arguments. New test files should not depend on this, but should explicitly include .CS -eval tcltest::configure $::argv +eval \fB::tcltest::configure\fR $::argv .CE to establish a configuration from command line arguments. .SH "KNOWN ISSUES" There are two known issues related to nested evaluations of [\fBtest\fR]. The first issue relates to the stack level in which test scripts are executed. Tests nested within other tests may be executed at the same stack level as the outermost test. For example, in the following code: .CS -test level-1.1 {level 1} { +\fBtest\fR level-1.1 {level 1} { -body { - test level-2.1 {level 2} { + \fBtest\fR level-2.1 {level 2} { } } } .CE any script executed in level-2.1 may be executed at the same stack @@ -1051,15 +1049,15 @@ been skipped, 'o' tests have passed and 'p' tests have failed, where 'm', 'n', 'o', and 'p' refer to tests that were run at the same test level as test level-1.1. .PP Implementation of output and error comparison in the test command -depends on usage of puts in your application code. Output is -intercepted by redefining the puts command while the defined test +depends on usage of ::puts in your application code. Output is +intercepted by redefining the ::puts command while the defined test script is being run. Errors thrown by C procedures or printed directly from C applications will not be caught by the test command. -Therefore, usage of the \fB-output\fR and \fB-errorOuput\fR +Therefore, usage of the \fB-output\fR and \fB-errorOutput\fR options to [\fBtest\fR] is useful only for pure Tcl applications -that use [\fBputs\fR] to produce output. +that use [\fB::puts\fR] to produce output. .SH KEYWORDS test, test harness, test suite Index: doc/tclvars.n ================================================================== --- doc/tclvars.n +++ doc/tclvars.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: tclvars.n,v 1.13 2002/07/01 18:24:39 jenglish Exp $ +'\" RCS: @(#) $Id: tclvars.n,v 1.13.2.3 2005/07/26 21:39:22 dgp Exp $ '\" .so man.macros .TH tclvars n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -108,13 +108,12 @@ applications needs. .RE .TP \fBerrorCode\fR After an error has occurred, this variable will be set to hold -additional information about the error in a form that is easy -to process with programs. -\fBerrorCode\fR consists of a Tcl list with one or more elements. +a list value representing additional information about the error +in a form that is easy to process with programs. The first element of the list identifies a general class of errors, and determines the format of the rest of the list. The following formats for \fBerrorCode\fR are used by the Tcl core; individual applications may define additional formats. .RS @@ -245,24 +244,24 @@ instruction set. The elements listed below will always be defined, but they may have empty strings as values if Tcl couldn't retrieve any relevant information. In addition, extensions and applications may add additional values to the array. The predefined elements are: - .RS .VS .TP \fBbyteOrder\fR The native byte order of this machine: either \fBlittleEndian\fR or \fBbigEndian\fR. .VE .TP \fBdebug\fR -If this variable exists, then the interpreter -was compiled with debugging symbols enabled. This variable will only -exist on Windows so extension writers can specify which package to load -depending on the C run-time library that is loaded. +If this variable exists, then the interpreter was compiled with and linked +to a debug-enabled C run-time. This variable will only exist on Windows, +so extension writers can specify which package to load depending on the +C run-time library that is in use. This is not an indication that this core +contains symbols. .TP \fBmachine\fR The instruction set executed by this machine, such as \fBintel\fR, \fBPPC\fR, \fB68k\fR, or \fBsun4m\fR. On UNIX machines, this is the value returned by \fBuname -m\fR. @@ -341,46 +340,46 @@ \fBtcl_traceCompile\fR The value of this variable can be set to control how much tracing information is displayed during bytecode compilation. By default, tcl_traceCompile is zero and no information is displayed. -Setting tcl_traceCompile to 1 generates a one line summary in stdout -whenever a procedure or top level command is compiled. +Setting tcl_traceCompile to 1 generates a one-line summary in stdout +whenever a procedure or top-level command is compiled. Setting it to 2 generates a detailed listing in stdout of the bytecode instructions emitted during every compilation. This variable is useful in tracking down suspected problems with the Tcl compiler. It is also occasionally useful when converting existing code to use Tcl8.0. - +.PP This variable and functionality only exist if -TCL_COMPILE_DEBUG was defined during Tcl's compilation. +\fBTCL_COMPILE_DEBUG\fR was defined during Tcl's compilation. .TP \fBtcl_traceExec\fR The value of this variable can be set to control how much tracing information is displayed during bytecode execution. By default, tcl_traceExec is zero and no information is displayed. -Setting tcl_traceExec to 1 generates a one line trace in stdout +Setting tcl_traceExec to 1 generates a one-line trace in stdout on each call to a Tcl procedure. Setting it to 2 generates a line of output whenever any Tcl command is invoked that contains the name of the command and its arguments. Setting it to 3 produces a detailed trace showing the result of executing each bytecode instruction. Note that when tcl_traceExec is 2 or 3, -commands such as set and incr +commands such as \fBset\fR and \fBincr\fR that have been entirely replaced by a sequence of bytecode instructions are not shown. Setting this variable is useful in tracking down suspected problems with the bytecode compiler and interpreter. It is also occasionally useful when converting code to use Tcl8.0. - +.PP This variable and functionality only exist if -TCL_COMPILE_DEBUG was defined during Tcl's compilation. +\fBTCL_COMPILE_DEBUG\fR was defined during Tcl's compilation. .TP \fBtcl_wordchars\fR The value of this variable is a regular expression that can be set to control what are considered ``word'' characters, for instances like selecting a word by double-clicking in text in Tk. It is platform @@ -402,11 +401,38 @@ Changes to \fIx\fR represent major changes with probable incompatibilities and changes to \fIy\fR represent small enhancements and bug fixes that retain backward compatibility. The value of this variable is returned by the \fBinfo tclversion\fR command. +.SH "OTHER GLOBAL VARIABLES" +The following variables are only guaranteed to exist in \fBtclsh\fR +and \fBwish\fR executables; the Tcl library does not define them +itself but many Tcl environments do. +.TP 6 +\fBargc\fR +The number of arguments to \fBtclsh\fR or \fBwish\fR. +.TP 6 +\fBargv\fR +Tcl list of arguments to \fBtclsh\fR or \fBwish\fR. +.TP 6 +\fBargv0\fR +The script that \fBtclsh\fR or \fBwish\fR started executing (if it was +specified) or otherwise the name by which \fBtclsh\fR or \fBwish\fR +was invoked. +.TP 6 +\fBtcl_interactive\fR +Contains 1 if \fBtclsh\fR or \fBwish\fR is running interactively (no +script was specified and standard input is a terminal-like device), 0 +otherwise. +.PP +The \fBwish\fR executably additionally specifies the following global +variable: +.TP 6 +\fBgeometry\fR +If set, contains the user-supplied geometry specification to use for +the main Tk window. .SH "SEE ALSO" -eval(n) +eval(n), tclsh(1), wish(1) .SH KEYWORDS arithmetic, bytecode, compiler, error, environment, POSIX, precision, subprocess, variables Index: doc/tell.n ================================================================== --- doc/tell.n +++ doc/tell.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: tell.n,v 1.5 2001/09/14 19:20:40 andreas_kupries Exp $ +'\" RCS: @(#) $Id: tell.n,v 1.5.8.1 2004/10/27 14:43:14 dkf Exp $ '\" .so man.macros .TH tell n 8.1 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -32,11 +32,24 @@ \fIChannelId\fR must be an identifier for an open channel such as a Tcl standard channel (\fBstdin\fR, \fBstdout\fR, or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. .VE +.SH EXAMPLE +Read a line from a file channel only if it starts with \fBfoobar\fR: +.CS +# Save the offset in case we need to undo the read... +set offset [\fBtell\fR $chan] +if {[read $chan 6] eq "foobar"} { + gets $chan line +} else { + set line {} + # Undo the read... + seek $chan $offset +} +.CE .SH "SEE ALSO" file(n), open(n), close(n), gets(n), seek(n), Tcl_StandardChannels(3) .SH KEYWORDS access position, channel, seeking Index: doc/time.n ================================================================== --- doc/time.n +++ doc/time.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: time.n,v 1.3 2000/09/07 14:27:52 poenitz Exp $ +'\" RCS: @(#) $Id: time.n,v 1.3.18.1 2004/10/27 14:43:14 dkf Exp $ '\" .so man.macros .TH time n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -26,11 +26,21 @@ \fB503 microseconds per iteration\fR .CE which indicates the average amount of time required per iteration, in microseconds. Time is measured in elapsed time, not CPU time. +.SH EXAMPLE +Estimate how long it takes for a simple Tcl \fBfor\fR loop to count to +a thousand: +.CS +time { + for {set i 0} {$i<1000} {incr i} { + # empty body + } +} +.CE .SH "SEE ALSO" clock(n) .SH KEYWORDS script, time Index: doc/trace.n ================================================================== --- doc/trace.n +++ doc/trace.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2000 Ajuba Solutions. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: trace.n,v 1.13 2003/02/04 00:56:20 hobbs Exp $ +'\" RCS: @(#) $Id: trace.n,v 1.13.2.2 2004/10/27 14:43:14 dkf Exp $ '\" .so man.macros .TH trace n "8.4" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -70,11 +70,12 @@ in which they appear. .RE .TP \fBtrace add execution\fR \fIname ops command\fR Arrange for \fIcommand\fR to be executed whenever command \fIname\fR -is modified in one of the ways given by the list \fIops\fR. \fIName\fR will be +is executed, with traces occurring at the points indicated by the list +\fIops\fR. \fIName\fR will be resolved using the usual namespace resolution rules used by procedures. If the command does not exist, an error will be thrown. .RS .PP \fIOps\fR indicates which operations are of interest, and is a list of @@ -87,20 +88,20 @@ \fBleave\fR Invoke \fIcommand\fR whenever the command \fIname\fR is executed, just after the actual execution takes place. .TP \fBenterstep\fR -Invoke \fIcommand\fR for every tcl command which is executed +Invoke \fIcommand\fR for every Tcl command which is executed inside the procedure \fIname\fR, just before the actual execution takes place. For example if we have 'proc foo {} { puts "hello" }', -then a \fIenterstep\fR trace would be +then an \fIenterstep\fR trace would be invoked just before \fIputs "hello"\fR is executed. -Setting a \fIenterstep\fR trace on a \fIcommand\fR +Setting an \fIenterstep\fR trace on a \fIcommand\fR will not result in an error and is simply ignored. .TP \fBleavestep\fR -Invoke \fIcommand\fR for every tcl command which is executed +Invoke \fIcommand\fR for every Tcl command which is executed inside the procedure \fIname\fR, just after the actual execution takes place. Setting a \fIleavestep\fR trace on a \fIcommand\fR will not result in an error and is simply ignored. .PP @@ -138,31 +139,31 @@ defined above. Note that the creation of many \fBenterstep\fR or \fBleavestep\fR traces can lead to unintuitive results, since the invoked commands from one trace can themselves lead to further command invocations for other traces. - +.PP \fICommand\fR executes in the same context as the code that invoked the traced operation: thus the \fIcommand\fR, if invoked from a procedure, will have access to the same local variables as code in the procedure. This context may be different than the context in which the trace was created. If \fIcommand\fR invokes a procedure (which it normally does) then the procedure will have to use upvar or uplevel commands if it wishes to access the local variables of the code which invoked the trace operation. - +.PP While \fIcommand\fR is executing during an execution trace, traces on \fIname\fR are temporarily disabled. This allows the \fIcommand\fR to execute \fIname\fR in its body without invoking any other traces again. If an error occurs while executing the \fIcommand\fR body, then the -\fIcommand\fR name as a whole will return that same error. - +command \fIname\fR as a whole will return that same error. +.PP When multiple traces are set on \fIname\fR, then for \fIenter\fR and \fIenterstep\fR operations, the traced commands are invoked in the reverse order of how the traces were originally created; and for \fIleave\fR and \fIleavestep\fR operations, the traced commands are invoked in the original order of creation. - +.PP The behavior of execution traces is currently undefined for a command \fIname\fR imported into another namespace. .RE .TP \fBtrace add variable\fI name ops command\fR @@ -351,11 +352,34 @@ future version of Tcl. They use an older syntax in which \fBarray\fR, \fBread\fR, \fBwrite\fR, \fBunset\fR are replaced by \fBa\fR, \fBr\fR, \fBw\fR and \fBu\fR respectively, and the \fIops\fR argument is not a list, but simply a string concatenation of the operations, such as \fBrwua\fR. +.SH EXAMPLES +Print a message whenever either of the global variables \fBfoo\fR and +\fBbar\fR are updated, even if they have a different local name at the +time (which can be done with the \fBupvar\fR command): +.CS +proc tracer {varname args} { + upvar #0 $varname var + puts "$varname was updated to be \e"$var\e"" +} +\fBtrace add\fR variable foo write "tracer foo" +\fBtrace add\fR variable bar write "tracer bar" +.CE +.PP +Ensure that the global variable \fBfoobar\fR always contains the +product of the global variables \fBfoo\fR and \fBbar\fR: +.CS +proc doMult args { + global foo bar foobar + set foobar [expr {$foo * $bar}] +} +\fBtrace add\fR variable foo write doMult +\fBtrace add\fR variable bar write doMult +.CE .SH "SEE ALSO" set(n), unset(n) .SH KEYWORDS read, command, rename, variable, write, trace, unset Index: doc/unknown.n ================================================================== --- doc/unknown.n +++ doc/unknown.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: unknown.n,v 1.4 2001/06/27 21:00:45 hobbs Exp $ +'\" RCS: @(#) $Id: unknown.n,v 1.4.12.1 2004/10/27 14:43:15 dkf Exp $ '\" .so man.macros .TH unknown n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -69,11 +69,25 @@ If the global variable \fBauto_noexec\fR is defined then the auto-exec step is skipped. Under normal circumstances the return value from \fBunknown\fR is the return value from the command that was eventually executed. +.SH EXAMPLE +Arrange for the \fBunknown\fR command to have its standard behavior +except for first logging the fact that a command was not found: +.PP +.CS +# Save the original one so we can chain to it +rename \fBunknown\fR _original_unknown + +# Provide our own implementation +proc \fBunknown\fR args { + puts stderr "WARNING: unknown command: $args" + uplevel 1 [list _original_unknown {expand}$args] +} +.CE .SH "SEE ALSO" info(n), proc(n), interp(n), library(n) .SH KEYWORDS error, non-existent command Index: doc/unset.n ================================================================== --- doc/unset.n +++ doc/unset.n @@ -4,11 +4,11 @@ '\" Copyright (c) 2000 Ajuba Solutions. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: unset.n,v 1.5 2001/03/06 14:45:03 dkf Exp $ +'\" RCS: @(#) $Id: unset.n,v 1.5.18.2 2004/10/27 14:43:15 dkf Exp $ '\" .so man.macros .TH unset n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -37,11 +37,32 @@ .VE 8.4 If an error occurs, any variables after the named one causing the error not deleted. An error can occur when the named variable doesn't exist, or the name refers to an array element but the variable is a scalar, or the name refers to a variable in a non-existent namespace. +.SH EXAMPLE +Create an array containing a mapping from some numbers to their +squares and remove the array elements for non-prime numbers: +.CS +array set squares { + 1 1 6 36 + 2 4 7 49 + 3 9 8 64 + 4 16 9 81 + 5 25 10 100 +} + +puts "The squares are:" +parray squares + +\fBunset\fR squares(1) squares(4) squares(6) +\fBunset\fR squares(8) squares(9) squares(10) + +puts "The prime squares are:" +parray squares +.CE .SH "SEE ALSO" -set(n), trace(n) +set(n), trace(n), upvar(n) .SH KEYWORDS remove, variable Index: doc/update.n ================================================================== --- doc/update.n +++ doc/update.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: update.n,v 1.4 2000/09/07 14:27:52 poenitz Exp $ +'\" RCS: @(#) $Id: update.n,v 1.4.18.1 2004/10/27 14:43:15 dkf Exp $ '\" .so man.macros .TH update n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -41,11 +41,27 @@ The \fBupdate\fR command with no options is useful in scripts where you are performing a long-running computation but you still want the application to respond to events such as user interactions; if you occasionally call \fBupdate\fR then user input will be processed during the next call to \fBupdate\fR. +.SH EXAMPLE +Run computations for about a second and then finish: +.CS +set x 1000 +set done 0 +after 1000 set done 1 +while {!$done} { + # A very silly example! + set x [expr {log($x) ** 2.8}] + + # Test to see if our time-limit has been hit. This would + # also give a chance for serving network sockets and, if + # the Tk package is loaded, updating a user interface. + \fBupdate\fR +} +.CE .SH "SEE ALSO" after(n), bgerror(n) .SH KEYWORDS event, flush, handler, idle, update Index: doc/uplevel.n ================================================================== --- doc/uplevel.n +++ doc/uplevel.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: uplevel.n,v 1.3 2000/09/07 14:27:52 poenitz Exp $ +'\" RCS: @(#) $Id: uplevel.n,v 1.3.18.1 2004/10/27 14:43:15 dkf Exp $ '\" .so man.macros .TH uplevel n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -42,18 +42,18 @@ .PP The \fBuplevel\fR command causes the invoking procedure to disappear from the procedure calling stack while the command is being executed. In the above example, suppose \fBc\fR invokes the command .CS -\fBuplevel 1 {set x 43; d}\fR +\fBuplevel\fR 1 {set x 43; d} .CE where \fBd\fR is another Tcl procedure. The \fBset\fR command will modify the variable \fBx\fR in \fBb\fR's context, and \fBd\fR will execute at level 3, as if called from \fBb\fR. If it in turn executes the command .CS -\fBuplevel {set x 42}\fR +\fBuplevel\fR {set x 42} .CE then the \fBset\fR command will modify the same variable \fBx\fR in \fBb\fR's context: the procedure \fBc\fR does not appear to be on the call stack when \fBd\fR is executing. The command ``\fBinfo level\fR'' may be used to obtain the level of the current procedure. @@ -70,11 +70,31 @@ For example, \fBinfo level 1\fR will return a list describing a command that is either the outermost procedure call or the outermost \fBnamespace eval\fR command. Also, \fBuplevel #0\fR evaluates a script at top-level in the outermost namespace (the global namespace). +.SH EXAMPLE +As stated above, the \fBuplevel\fR command is useful for creating new +control constructs. This example shows how (without error handling) +it can be used to create a \fBdo\fR command that is the counterpart of +\fBwhile\fR except for always performing the test after running the +loop body: +.CS +proc do {body while condition} { + if {$while ne "while"} { + error "required word missing" + } + set conditionCmd [list expr $condition] + while {1} { + \fBuplevel\fR 1 $body + if {![\fBuplevel\fR 1 $conditionCmd]} { + break + } + } +} +.CE .SH "SEE ALSO" namespace(n), upvar(n) .SH KEYWORDS context, level, namespace, stack frame, variables Index: doc/upvar.n ================================================================== --- doc/upvar.n +++ doc/upvar.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: upvar.n,v 1.5 2000/11/21 15:56:21 dkf Exp $ +'\" RCS: @(#) $Id: upvar.n,v 1.5.18.2 2004/11/12 09:02:30 das Exp $ '\" .so man.macros .TH upvar n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -44,16 +44,16 @@ The \fBupvar\fR command simplifies the implementation of call-by-name procedure calling and also makes it easier to build new control constructs as Tcl procedures. For example, consider the following procedure: .CS -\fBproc add2 name { - upvar $name x - set x [expr $x+2] -}\fR +proc add2 name { + \fBupvar\fR $name x + set x [expr $x+2] +} .CE -\fBAdd2\fR is invoked with an argument giving the name of a variable, +\fBadd2\fR is invoked with an argument giving the name of a variable, and it adds two to the value of that variable. Although \fBadd2\fR could have been implemented using \fBuplevel\fR instead of \fBupvar\fR, \fBupvar\fR makes it simpler for \fBadd2\fR to access the variable in the caller's procedure frame. .PP @@ -73,40 +73,48 @@ \fBunset\fR operation affects the variable it is linked to, not the upvar variable. There is no way to unset an upvar variable except by exiting the procedure in which it is defined. However, it is possible to retarget an upvar variable by executing another \fBupvar\fR command. - -.SH Traces and upvar +.SH "TRACES AND UPVAR" .PP Upvar interacts with traces in a straightforward but possibly unexpected manner. If a variable trace is defined on \fIotherVar\fR, that trace will be triggered by actions involving \fImyVar\fR. However, the trace procedure will be passed the name of \fImyVar\fR, rather than the name of \fIotherVar\fR. Thus, the output of the following code will be \fBlocalVar\fR rather than \fBoriginalVar\fR: .CS -\fBproc traceproc { name index op } { - puts $name +proc \fBtraceproc\fR { name index op } { + puts $name } -proc setByUpvar { name value } { - upvar $name localVar - set localVar $value +proc \fBsetByUpvar\fR { name value } { + \fBupvar\fR $name localVar + set localVar $value } set originalVar 1 -trace variable originalVar w traceproc -setByUpvar originalVar 2 -}\fR +trace variable originalVar w \fBtraceproc\fR +\fBsetByUpvar\fR originalVar 2 +} .CE - +.PP If \fIotherVar\fR refers to an element of an array, then variable traces set for the entire array will not be invoked when \fImyVar\fR is accessed (but traces on the particular element will still be invoked). In particular, if the array is \fBenv\fR, then changes made to \fImyVar\fR will not be passed to subprocesses correctly. .VE +.SH EXAMPLE +A \fBdecr\fR command that works like \fBincr\fR except it subtracts +the value from the variable instead of adding it: +.CS +proc decr {varName {decrement 1}} { + \fBupvar\fR 1 $varName var + incr var [expr {-$decrement}] +} +.CE .SH "SEE ALSO" global(n), namespace(n), uplevel(n), variable(n) .SH KEYWORDS context, frame, global, level, namespace, procedure, variable Index: doc/variable.n ================================================================== --- doc/variable.n +++ doc/variable.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: variable.n,v 1.4 2000/11/21 15:56:21 dkf Exp $ +'\" RCS: @(#) $Id: variable.n,v 1.4.18.2 2005/02/16 18:53:02 msofer Exp $ '\" .so man.macros .TH variable n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -41,11 +41,11 @@ command, but not to the \fBinfo exists\fR command. .PP If the \fBvariable\fR command is executed inside a Tcl procedure, it creates local variables linked to the corresponding namespace variables (and therefore these -variables are listed by \fBinfo locals\fR.) +variables are listed by \fBinfo vars\fR.) In this way the \fBvariable\fR command resembles the \fBglobal\fR command, although the \fBglobal\fR command only links to variables in the global namespace. If any \fIvalue\fRs are given, they are used to modify the values of the associated namespace variables. @@ -56,11 +56,44 @@ Instead, \fIname\fR should reference the entire array, and the initialization \fIvalue\fR should be left off. After the variable has been declared, elements within the array can be set using ordinary \fBset\fR or \fBarray\fR commands. +.SH EXAMPLES +Create a variable in a namespace: +.CS +namespace eval foo { + \fBvariable\fR bar 12345 +} +.CE +.PP +Create an array in a namespace: +.CS +namespace eval someNS { + \fBvariable\fR someAry + array set someAry { + someName someValue + otherName otherValue + } +} +.CE +.PP +Access variables in namespaces from a procedure: +.CS +namespace eval foo { + proc spong {} { + # Variable in this namespace + \fBvariable\fR bar + puts "bar is $bar" + + # Variable in another namespace + \fBvariable\fR ::someNS::someAry + parray someAry + } +} +.CE .SH "SEE ALSO" global(n), namespace(n), upvar(n) .SH KEYWORDS global, namespace, procedure, variable Index: doc/vwait.n ================================================================== --- doc/vwait.n +++ doc/vwait.n @@ -2,11 +2,11 @@ '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: vwait.n,v 1.4 2000/09/07 14:27:52 poenitz Exp $ +'\" RCS: @(#) $Id: vwait.n,v 1.4.18.1 2004/10/27 14:43:15 dkf Exp $ '\" .so man.macros .TH vwait n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -33,11 +33,49 @@ if an event handler sets \fIvarName\fR and then itself calls \fBvwait\fR to wait for a different variable, then it may not return for a long time. During this time the top-level \fBvwait\fR is blocked waiting for the event handler to complete, so it cannot return either. +.SH EXAMPLES +Run the event-loop continually until some event calls \fBexit\fR. +(You can use any variable not mentioned elsewhere, but the name +\fIforever\fR reminds you at a glance of the intent.) +.CS +\fBvwait\fR forever +.CE +.PP +Wait five seconds for a connection to a server socket, otherwise +close the socket and continue running the script: +.CS +# Initialise the state +after 5000 set state timeout +set server [socket -server accept 12345] +proc accept {args} { + global state connectionInfo + set state accepted + set connectionInfo $args +} + +# Wait for something to happen +\fBvwait\fR state + +# Clean up events that could have happened +close $server +after cancel set state timeout + +# Do something based on how the vwait finished... +switch $state { + timeout { + puts "no connection on port 12345" + } + accepted { + puts "connection: $connectionInfo" + puts [lindex $connectionInfo 0] "Hello there!" + } +} +.CE .SH "SEE ALSO" -global(n) +global(n), update(n) .SH KEYWORDS event, variable, wait Index: doc/while.n ================================================================== --- doc/while.n +++ doc/while.n @@ -3,11 +3,11 @@ '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: while.n,v 1.3 2000/09/07 14:27:52 poenitz Exp $ +'\" RCS: @(#) $Id: while.n,v 1.3.18.1 2004/10/27 14:43:15 dkf Exp $ '\" .so man.macros .TH while n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! @@ -43,16 +43,25 @@ each loop iteration), so changes in the variables will be visible. For an example, try the following script with and without the braces around \fB$x<10\fR: .CS set x 0 -while {$x<10} { - puts "x is $x" - incr x +\fBwhile\fR {$x<10} { + puts "x is $x" + incr x +} +.CE +.SH EXAMPLE +Read lines from a channel until we get to the end of the stream, and +print them out with a line-number prepended: +.CS +set lineCount 0 +\fBwhile\fR {[gets $chan line] >= 0} { + puts "[incr lineCount]: $line" } .CE .SH "SEE ALSO" break(n), continue(n), for(n), foreach(n) .SH KEYWORDS boolean value, loop, test, while Index: generic/README ================================================================== --- generic/README +++ generic/README @@ -1,5 +1,5 @@ This directory contains Tcl source files that work on all the platforms where Tcl runs (e.g. UNIX, PCs, and Macintoshes). Platform-specific -sources are in the directories ../unix, ../win, and ../mac. +sources are in the directories ../unix, ../win, ../macosx, and ../mac. -RCS: @(#) $Id: README,v 1.2 1998/09/14 18:39:56 stanton Exp $ +RCS: @(#) $Id: README,v 1.2.40.1 2005/12/02 21:13:26 dgp Exp $ Index: generic/regcomp.c ================================================================== --- generic/regcomp.c +++ generic/regcomp.c @@ -551,12 +551,16 @@ s = a->to; for (b = s->ins; b != NULL; b = b->inchain) if (b->from != pre) break; if (b != NULL) { /* must be split */ - s->tmp = slist; - slist = s; + if (s->tmp == NULL) { /* if not already in the list */ + /* (fixes bugs 505048, 230589, */ + /* 840258, 504785) */ + s->tmp = slist; + slist = s; + } } } /* do the splits */ for (s = slist; s != NULL; s = s2) { @@ -2157,19 +2161,19 @@ struct subre *t; char *buf; size_t bufsize; { /* big enough for hex int or decimal t->retry? */ - if (bufsize < sizeof(int)*2 + 3 || bufsize < sizeof(t->retry)*3 + 1) + if (bufsize < sizeof(void*)*2 + 3 || bufsize < sizeof(t->retry)*3 + 1) return "unable"; if (t->retry != 0) sprintf(buf, "%d", t->retry); else - sprintf(buf, "0x%x", (int)t); /* may lose bits, that's okay */ + sprintf(buf, "%p", t); return buf; } #include "regc_lex.c" #include "regc_color.c" #include "regc_nfa.c" #include "regc_cvec.c" #include "regc_locale.c" Index: generic/regcustom.h ================================================================== --- generic/regcustom.h +++ generic/regcustom.h @@ -89,13 +89,19 @@ typedef unsigned uchr; /* unsigned type that will hold a chr */ typedef int celt; /* type to hold chr, MCCE number, or NOCELT */ #define NOCELT (-1) /* celt value which is not valid chr or MCCE */ #define CHR(c) (UCHAR(c)) /* turn char literal into chr literal */ #define DIGITVAL(c) ((c)-'0') /* turn chr digit into its value */ +#if TCL_UTF_MAX > 3 +#define CHRBITS 32 /* bits in a chr; must not use sizeof */ +#define CHR_MIN 0x00000000 /* smallest and largest chr; the value */ +#define CHR_MAX 0xffffffff /* CHR_MAX-CHR_MIN+1 should fit in uchr */ +#else #define CHRBITS 16 /* bits in a chr; must not use sizeof */ #define CHR_MIN 0x0000 /* smallest and largest chr; the value */ #define CHR_MAX 0xffff /* CHR_MAX-CHR_MIN+1 should fit in uchr */ +#endif /* functions operating on chr */ #define iscalnum(x) Tcl_UniCharIsAlnum(x) #define iscalpha(x) Tcl_UniCharIsAlpha(x) #define iscdigit(x) Tcl_UniCharIsDigit(x) Index: generic/rege_dfa.c ================================================================== --- generic/rege_dfa.c +++ generic/rege_dfa.c @@ -559,11 +559,11 @@ { int i; struct sset *ss; struct sset *p; struct arcp ap; - struct arcp lastap; + struct arcp lastap = {NULL, 0}; /* silence gcc 4 warning */ color co; ss = pickss(v, d, cp, start); assert(!(ss->flags&LOCKED)); Index: generic/regerror.c ================================================================== --- generic/regerror.c +++ generic/regerror.c @@ -48,12 +48,12 @@ /* - regerror - the interface to error numbers */ /* ARGSUSED */ size_t /* actual space needed (including NUL) */ -regerror(errcode, preg, errbuf, errbuf_size) -int errcode; /* error code, or REG_ATOI or REG_ITOA */ +regerror(code, preg, errbuf, errbuf_size) +int code; /* error code, or REG_ATOI or REG_ITOA */ CONST regex_t *preg; /* associated regex_t (unused at present) */ char *errbuf; /* result buffer (unless errbuf_size==0) */ size_t errbuf_size; /* available space in errbuf, can be 0 */ { struct rerr *r; @@ -60,11 +60,11 @@ char *msg; char convbuf[sizeof(unk)+50]; /* 50 = plenty for int */ size_t len; int icode; - switch (errcode) { + switch (code) { case REG_ATOI: /* convert name to number */ for (r = rerrs; r->code >= 0; r++) if (strcmp(r->name, errbuf) == 0) break; sprintf(convbuf, "%d", r->code); /* -1 for unknown */ @@ -82,16 +82,16 @@ msg = convbuf; } break; default: /* a real, normal error code */ for (r = rerrs; r->code >= 0; r++) - if (r->code == errcode) + if (r->code == code) break; if (r->code >= 0) msg = r->explain; else { /* unknown; say so */ - sprintf(convbuf, unk, errcode); + sprintf(convbuf, unk, code); msg = convbuf; } break; } Index: generic/regexec.c ================================================================== --- generic/regexec.c +++ generic/regexec.c @@ -347,11 +347,11 @@ struct cnfa *cnfa; struct colormap *cm; { struct dfa *s; struct dfa *d; - chr *cold; + chr *cold = NULL; /* silence gcc 4 warning */ int ret; s = newdfa(v, &v->g->search, cm, &v->dfa1); NOERR(); d = newdfa(v, cnfa, cm, &v->dfa2); Index: generic/regguts.h ================================================================== --- generic/regguts.h +++ generic/regguts.h @@ -53,11 +53,13 @@ #endif /* assertions */ #ifndef assert # ifndef REG_DEBUG +# ifndef NDEBUG # define NDEBUG /* no assertions */ +# endif # endif #include #endif /* voids */ Index: generic/tcl.decls ================================================================== --- generic/tcl.decls +++ generic/tcl.decls @@ -9,11 +9,11 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2001, 2002 by Kevin B. Kenny. All rights reserved. # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: tcl.decls,v 1.94 2002/08/31 06:09:45 das Exp $ +# RCS: @(#) $Id: tcl.decls,v 1.94.2.4 2006/09/22 01:26:22 andreas_kupries Exp $ library tcl # Define the tcl interface with several sub interfaces: # tclPlat - platform specific public @@ -969,10 +969,14 @@ } declare 273 generic { int Tcl_PkgProvide(Tcl_Interp *interp, CONST char *name, CONST char *version) } + +# TIP #268: The internally used new Require function is in slot +# 573. Assuming TCL_TIP268 was activated. + declare 274 generic { CONST84_RETURN char * Tcl_PkgRequire(Tcl_Interp *interp, CONST char *name, CONST char *version, int exact) } declare 275 generic { @@ -1455,11 +1459,11 @@ *chanTypePtr) } # Introduced in 8.4a2 declare 412 generic { - int Tcl_JoinThread(Tcl_ThreadId id, int* result) + int Tcl_JoinThread(Tcl_ThreadId threadId, int* result) } declare 413 generic { int Tcl_IsChannelShared(Tcl_Channel channel) } declare 414 generic { @@ -1751,10 +1755,44 @@ # New export due to TIP#91 declare 493 generic { Tcl_DriverWideSeekProc * Tcl_ChannelWideSeekProc( Tcl_ChannelType *chanTypePtr) } + +# Slots 494 to 553 are taken already by 8.5 +# #111 - Dicts (494 ... 504) +# #59 - Config (505) +# #139 - Namespace API (506 ... 517) +# #137 - source -encoding (518) +# #121 - ExitProc (519) +# #121 - Resource Limits (520 ... 534) +# #226 - S/R Interp State (535 ... 537) +# #227 - S/G Return Opts (538 ... 539) +# #235 - Ensemble C API (540 ... 551) +# #233 - Virtualized Time (552 ... 553) + +# TIP#218 (Driver Thread Actions) davygrvy/akupries ChannelType ver 4 +# These slots are used by 8.5 as well. +declare 554 generic { + Tcl_DriverThreadActionProc *Tcl_ChannelThreadActionProc(Tcl_ChannelType *chanTypePtr) +} + +# Slots 555 to 572 are taken already by 8.5 +# TIP #237: Arbitrary-prec Integers (555 ... 559) +# TIP #208: 'chan' Command (560 ... 561) +# TIP #219: Channel Reflection (562 ... 565) +# TIP #237: Add. bignum support (566) +# TIP #181: 'namespace unknown' Cmd (567 ... 568) +# TIP #258: Enhanced Encodings API (569 ... 572) + +# TIP#268: Extended version numbers and requirements. +# The slot is present even if TCL_TIP268 is not activated. + +declare 573 generic { + int Tcl_PkgRequireProc(Tcl_Interp *interp, CONST char *name, + int objc, Tcl_Obj *CONST objv[], ClientData *clientDataPtr) +} ############################################################################## # Define the platform specific public Tcl interface. These functions are # only available on the designated platform. @@ -1831,5 +1869,13 @@ CONST char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath) } +declare 1 macosx { + int Tcl_MacOSXOpenVersionedBundleResources(Tcl_Interp *interp, + CONST char *bundleName, + CONST char *bundleVersion, + int hasResourceFile, + int maxPathLen, + char *libraryPath) +} Index: generic/tcl.h ================================================================== --- generic/tcl.h +++ generic/tcl.h @@ -11,11 +11,11 @@ * Copyright (c) 2002 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tcl.h,v 1.153 2003/02/15 02:16:29 hobbs Exp $ + * RCS: @(#) $Id: tcl.h,v 1.153.2.31 2007/05/30 14:05:18 dgp Exp $ */ #ifndef _TCL #define _TCL @@ -24,11 +24,11 @@ */ #ifdef __cplusplus extern "C" { #endif - + /* * The following defines are used to indicate the various release levels. */ #define TCL_ALPHA_RELEASE 0 @@ -44,12 +44,12 @@ * win/configure.in (as above) * win/tcl.m4 (not patchlevel) * win/makefile.vc (not patchlevel) 2 LOC * README (sections 0 and 2) * mac/README (2 LOC, not patchlevel) - * macosx/Tcl.pbproj/project.pbxproj - * (7 LOC total, 2 LOC patch) + * macosx/Tcl.pbproj/project.pbxproj (not patchlevel) 1 LOC + * macosx/Tcl.pbproj/default.pbxuser (not patchlevel) 1 LOC * win/README.binary (sections 0-4) * win/README (not patchlevel) (sections 0 and 2) * unix/tcl.spec (2 LOC Major/Minor, 1 LOC patch) * tests/basic.test (1 LOC M/M, not patchlevel) * tools/tcl.hpj.in (not patchlevel, for windows installer) @@ -57,17 +57,14 @@ * tools/tclSplash.bmp (not patchlevel) */ #define TCL_MAJOR_VERSION 8 #define TCL_MINOR_VERSION 4 #define TCL_RELEASE_LEVEL TCL_FINAL_RELEASE -#define TCL_RELEASE_SERIAL 2 - -#define TCL_PREFIX_IDENT "" -#define TCL_DEBUG_IDENT TCL_DBGX +#define TCL_RELEASE_SERIAL 16 #define TCL_VERSION "8.4" -#define TCL_PATCH_LEVEL "8.4.2" +#define TCL_PATCH_LEVEL "8.4.16" /* * The following definitions set up the proper options for Windows * compilers. We use this method because there is no autoconf equivalent. */ @@ -316,13 +313,10 @@ #endif /* * Miscellaneous declarations. */ -#ifndef NULL -# define NULL 0 -#endif #ifndef _CLIENTDATA # ifndef NO_VOID typedef void *ClientData; # else @@ -329,10 +323,26 @@ typedef int *ClientData; # endif # define _CLIENTDATA #endif +/* + * Darwin specifc configure overrides (to support fat compiles, where + * configure runs only once for multiple architectures): + */ + +#ifdef __APPLE__ +# ifdef __LP64__ +# undef TCL_WIDE_INT_TYPE +# define TCL_WIDE_INT_IS_LONG 1 +# else /* !__LP64__ */ +# define TCL_WIDE_INT_TYPE long long +# undef TCL_WIDE_INT_IS_LONG +# endif /* __LP64__ */ +# undef HAVE_STRUCT_STAT64 +#endif /* __APPLE__ */ + /* * Define Tcl_WideInt to be a type that is (at least) 64-bits wide, * and define Tcl_WideUInt to be the unsigned variant of that type * (assuming that where we have one, we can have the other.) * @@ -354,23 +364,32 @@ * Unix systems. It has to be split up like this to allow for the more * complex formats sometimes needed (e.g. in the format(n) command.) */ #if !defined(TCL_WIDE_INT_TYPE)&&!defined(TCL_WIDE_INT_IS_LONG) -# if defined(__CYGWIN__) +# if defined(__GNUC__) # define TCL_WIDE_INT_TYPE long long +# if defined(__WIN32__) && !defined(__CYGWIN__) +# define TCL_LL_MODIFIER "I64" +# define TCL_LL_MODIFIER_SIZE 3 +# else # define TCL_LL_MODIFIER "L" -typedef struct stat Tcl_StatBuf; # define TCL_LL_MODIFIER_SIZE 1 +# endif +typedef struct stat Tcl_StatBuf; # elif defined(__WIN32__) # define TCL_WIDE_INT_TYPE __int64 # ifdef __BORLANDC__ typedef struct stati64 Tcl_StatBuf; # define TCL_LL_MODIFIER "L" # define TCL_LL_MODIFIER_SIZE 1 # else /* __BORLANDC__ */ +# if _MSC_VER < 1400 || !defined(_M_IX86) typedef struct _stati64 Tcl_StatBuf; +# else +typedef struct _stat64 Tcl_StatBuf; +# endif /* _MSC_VER < 1400 */ # define TCL_LL_MODIFIER "I64" # define TCL_LL_MODIFIER_SIZE 3 # endif /* __BORLANDC__ */ # else /* __WIN32__ */ /* @@ -631,22 +650,17 @@ /* * Argument descriptors for math function callbacks in expressions: */ typedef enum { TCL_INT, TCL_DOUBLE, TCL_EITHER, TCL_WIDE_INT -#ifdef TCL_WIDE_INT_IS_LONG - = TCL_INT -#endif } Tcl_ValueType; typedef struct Tcl_Value { Tcl_ValueType type; /* Indicates intValue or doubleValue is * valid, or both. */ long intValue; /* Integer value. */ double doubleValue; /* Double-precision floating value. */ -#ifndef TCL_WIDE_INT_IS_LONG Tcl_WideInt wideValue; /* Wide (min. 64-bit) integer value. */ -#endif } Tcl_Value; /* * Forward declaration of Tcl_Obj to prevent an error when the forward * reference to Tcl_Obj is encountered in the procedure types declared @@ -810,12 +824,15 @@ # define Tcl_IsShared(objPtr) \ Tcl_DbIsShared(objPtr, __FILE__, __LINE__) #else # define Tcl_IncrRefCount(objPtr) \ ++(objPtr)->refCount + /* + * Use empty if ; else to handle use in unbraced outer if/else conditions + */ # define Tcl_DecrRefCount(objPtr) \ - if (--(objPtr)->refCount <= 0) TclFreeObj(objPtr) + if (--(objPtr)->refCount > 0) ; else TclFreeObj(objPtr) # define Tcl_IsShared(objPtr) \ ((objPtr)->refCount > 1) #endif /* @@ -1412,11 +1429,11 @@ /* * Bits passed to Tcl_DriverClose2Proc to indicate which side of a channel * should be closed. */ -#define TCL_CLOSE_READ (1<<1) +#define TCL_CLOSE_READ (1<<1) #define TCL_CLOSE_WRITE (1<<2) /* * Value to use as the closeProc for a channel that supports the * close2Proc interface. @@ -1427,10 +1444,18 @@ * Channel version tag. This was introduced in 8.3.2/8.4. */ #define TCL_CHANNEL_VERSION_1 ((Tcl_ChannelTypeVersion) 0x1) #define TCL_CHANNEL_VERSION_2 ((Tcl_ChannelTypeVersion) 0x2) #define TCL_CHANNEL_VERSION_3 ((Tcl_ChannelTypeVersion) 0x3) +#define TCL_CHANNEL_VERSION_4 ((Tcl_ChannelTypeVersion) 0x4) + +/* + * TIP #218: Channel Actions, Ids for Tcl_DriverThreadActionProc + */ + +#define TCL_CHANNEL_THREAD_INSERT (0) +#define TCL_CHANNEL_THREAD_REMOVE (1) /* * Typedefs for the various operations in a channel type: */ typedef int (Tcl_DriverBlockModeProc) _ANSI_ARGS_(( @@ -1462,10 +1487,13 @@ ClientData instanceData, int interestMask)); typedef Tcl_WideInt (Tcl_DriverWideSeekProc) _ANSI_ARGS_(( ClientData instanceData, Tcl_WideInt offset, int mode, int *errorCodePtr)); + /* TIP #218, Channel Thread Actions */ +typedef void (Tcl_DriverThreadActionProc) _ANSI_ARGS_ (( + ClientData instanceData, int action)); /* * The following declarations either map ckalloc and ckfree to * malloc and free, or they map them to procedures with all sorts * of debugging hooks defined in tclCkalloc.c. @@ -1552,19 +1580,29 @@ /* Procedure to call to seek * on the channel which can * handle 64-bit offsets. May be * NULL, and must be NULL if * seekProc is NULL. */ + + /* + * Only valid in TCL_CHANNEL_VERSION_4 channels or later + * TIP #218, Channel Thread Actions + */ + Tcl_DriverThreadActionProc *threadActionProc; + /* Procedure to call to notify + * the driver of thread specific + * activity for a channel. + * May be NULL. */ } Tcl_ChannelType; /* * The following flags determine whether the blockModeProc above should * set the channel into blocking or nonblocking mode. They are passed * as arguments to the blockModeProc procedure in the above structure. */ -#define TCL_MODE_BLOCKING 0 /* Put channel into blocking mode. */ -#define TCL_MODE_NONBLOCKING 1 /* Put channel into nonblocking +#define TCL_MODE_BLOCKING 0 /* Put channel into blocking mode. */ +#define TCL_MODE_NONBLOCKING 1 /* Put channel into nonblocking * mode. */ /* * Enum for different types of file paths. */ @@ -1598,10 +1636,11 @@ #define TCL_GLOB_TYPE_DIR (1<<2) #define TCL_GLOB_TYPE_PIPE (1<<3) #define TCL_GLOB_TYPE_FILE (1<<4) #define TCL_GLOB_TYPE_LINK (1<<5) #define TCL_GLOB_TYPE_SOCK (1<<6) +#define TCL_GLOB_TYPE_MOUNT (1<<7) #define TCL_GLOB_PERM_RONLY (1<<0) #define TCL_GLOB_PERM_HIDDEN (1<<1) #define TCL_GLOB_PERM_R (1<<2) #define TCL_GLOB_PERM_W (1<<3) @@ -2175,22 +2214,42 @@ #define TCL_CONVERT_MULTIBYTE -1 #define TCL_CONVERT_SYNTAX -2 #define TCL_CONVERT_UNKNOWN -3 #define TCL_CONVERT_NOSPACE -4 - /* * The maximum number of bytes that are necessary to represent a single - * Unicode character in UTF-8. + * Unicode character in UTF-8. The valid values should be 3 or 6 (or + * perhaps 1 if we want to support a non-unicode enabled core). + * If 3, then Tcl_UniChar must be 2-bytes in size (UCS-2). (default) + * If 6, then Tcl_UniChar must be 4-bytes in size (UCS-4). + * At this time UCS-2 mode is the default and recommended mode. + * UCS-4 is experimental and not recommended. It works for the core, + * but most extensions expect UCS-2. */ +#ifndef TCL_UTF_MAX #define TCL_UTF_MAX 3 +#endif /* * This represents a Unicode character. Any changes to this should * also be reflected in regcustom.h. */ +#if TCL_UTF_MAX > 3 + /* + * unsigned int isn't 100% accurate as it should be a strict 4-byte + * value (perhaps wchar_t). 64-bit systems may have troubles. The + * size of this value must be reflected correctly in regcustom.h and + * in tclEncoding.c. + * XXX: Tcl is currently UCS-2 and planning UTF-16 for the Unicode + * XXX: string rep that Tcl_UniChar represents. Changing the size + * XXX: of Tcl_UniChar is /not/ supported. + */ +typedef unsigned int Tcl_UniChar; +#else typedef unsigned short Tcl_UniChar; +#endif /* * Deprecated Tcl procedures: */ Index: generic/tclAlloc.c ================================================================== --- generic/tclAlloc.c +++ generic/tclAlloc.c @@ -13,19 +13,19 @@ * Portions contributed by Chris Kingsley, Jack Jansen and Ray Johnson. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclAlloc.c,v 1.16 2002/04/23 17:03:34 hobbs Exp $ + * RCS: @(#) $Id: tclAlloc.c,v 1.16.2.1 2004/10/28 21:12:37 andreas_kupries Exp $ */ /* * Windows and Unix use an alternative allocator when building with threads * that has significantly reduced lock contention. */ -#if !defined(TCL_THREADS) || !defined(USE_THREAD_ALLOC) +#if !defined(TCL_THREADS) || !defined(USE_THREAD_ALLOC) || defined(TCL_MEM_DEBUG) #include "tclInt.h" #include "tclPort.h" #if USE_TCLALLOC Index: generic/tclAsync.c ================================================================== --- generic/tclAsync.c +++ generic/tclAsync.c @@ -10,11 +10,11 @@ * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclAsync.c,v 1.6 2001/08/30 07:50:18 davygrvy Exp $ + * RCS: @(#) $Id: tclAsync.c,v 1.6.12.1 2006/07/11 13:18:10 vasiljevic Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -284,24 +284,33 @@ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); AsyncHandler *asyncPtr = (AsyncHandler *) async; AsyncHandler *prevPtr; + /* + * Conservatively check the existence of the linked list of + * registered handlers, as we may come at this point even + * when the TSD's for the current thread have been already + * garbage-collected. + */ + Tcl_MutexLock(&tsdPtr->asyncMutex); - if (tsdPtr->firstHandler == asyncPtr) { - tsdPtr->firstHandler = asyncPtr->nextPtr; - if (tsdPtr->firstHandler == NULL) { - tsdPtr->lastHandler = NULL; - } - } else { - prevPtr = tsdPtr->firstHandler; - while (prevPtr->nextPtr != asyncPtr) { - prevPtr = prevPtr->nextPtr; - } - prevPtr->nextPtr = asyncPtr->nextPtr; - if (tsdPtr->lastHandler == asyncPtr) { - tsdPtr->lastHandler = prevPtr; + if (tsdPtr->firstHandler != NULL ) { + if (tsdPtr->firstHandler == asyncPtr) { + tsdPtr->firstHandler = asyncPtr->nextPtr; + if (tsdPtr->firstHandler == NULL) { + tsdPtr->lastHandler = NULL; + } + } else { + prevPtr = tsdPtr->firstHandler; + while (prevPtr->nextPtr != asyncPtr) { + prevPtr = prevPtr->nextPtr; + } + prevPtr->nextPtr = asyncPtr->nextPtr; + if (tsdPtr->lastHandler == asyncPtr) { + tsdPtr->lastHandler = prevPtr; + } } } Tcl_MutexUnlock(&tsdPtr->asyncMutex); ckfree((char *) asyncPtr); } Index: generic/tclBasic.c ================================================================== --- generic/tclBasic.c +++ generic/tclBasic.c @@ -11,11 +11,11 @@ * Copyright (c) 2001, 2002 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclBasic.c,v 1.75 2003/02/18 02:37:52 msofer Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.75.2.26 2006/11/28 22:19:59 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclCompile.h" #ifndef TCL_GENERIC_ONLY @@ -38,10 +38,21 @@ CONST char* command, Tcl_Command commandInfo, int objc, Tcl_Obj *CONST objv[])); static void StringTraceDeleteProc _ANSI_ARGS_((ClientData clientData)); + +#ifdef TCL_TIP280 +/* TIP #280 - Modified token based evulation, with line information */ +static int EvalEx _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script, + int numBytes, int flags, int line)); + +static int EvalTokensStandard _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Token *tokenPtr, + int count, int line)); + +#endif extern TclStubs tclStubs; /* * The following structure defines the commands in the Tcl core. @@ -332,10 +343,23 @@ iPtr->numLevels = 0; iPtr->maxNestingDepth = MAX_NESTING_DEPTH; iPtr->framePtr = NULL; iPtr->varFramePtr = NULL; + +#ifdef TCL_TIP280 + /* + * TIP #280 - Initialize the arrays used to extend the ByteCode and + * Proc structures. + */ + iPtr->cmdFramePtr = NULL; + iPtr->linePBodyPtr = (Tcl_HashTable*) ckalloc (sizeof (Tcl_HashTable)); + iPtr->lineBCPtr = (Tcl_HashTable*) ckalloc (sizeof (Tcl_HashTable)); + Tcl_InitHashTable(iPtr->linePBodyPtr, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(iPtr->lineBCPtr, TCL_ONE_WORD_KEYS); +#endif + iPtr->activeVarTracePtr = NULL; iPtr->returnCode = TCL_OK; iPtr->errorInfo = NULL; iPtr->errorCode = NULL; @@ -343,10 +367,16 @@ iPtr->appendAvl = 0; iPtr->appendUsed = 0; Tcl_InitHashTable(&iPtr->packageTable, TCL_STRING_KEYS); iPtr->packageUnknown = NULL; +#ifdef TCL_TIP268 + /* TIP #268 */ + iPtr->packagePrefer = (getenv ("TCL_PKG_PREFER_LATEST") == NULL ? + PKG_PREFER_STABLE : + PKG_PREFER_LATEST); +#endif iPtr->cmdCount = 0; iPtr->termOffset = 0; TclInitLiteralTable(&(iPtr->literalTable)); iPtr->compileEpoch = 0; iPtr->compiledProcPtr = NULL; @@ -361,10 +391,11 @@ iPtr->assocData = (Tcl_HashTable *) NULL; iPtr->execEnvPtr = NULL; /* set after namespaces initialized */ iPtr->emptyObjPtr = Tcl_NewObj(); /* another empty object */ Tcl_IncrRefCount(iPtr->emptyObjPtr); iPtr->resultSpace[0] = 0; + iPtr->threadId = Tcl_GetCurrentThread(); iPtr->globalNsPtr = NULL; /* force creation of global ns below */ iPtr->globalNsPtr = (Namespace *) Tcl_CreateNamespace(interp, "", (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL); if (iPtr->globalNsPtr == NULL) { @@ -569,14 +600,25 @@ TCL_GLOBAL_ONLY); #endif /* * Register Tcl's version number. + * TIP#268: Expose information about its status, + * for runtime switches in the core library + * and tests. */ Tcl_PkgProvideEx(interp, "Tcl", TCL_VERSION, (ClientData) &tclStubs); - + +#ifdef TCL_TIP268 + Tcl_SetVar2(interp, "tcl_platform", "tip,268", "1", + TCL_GLOBAL_ONLY); +#endif +#ifdef TCL_TIP280 + Tcl_SetVar2(interp, "tcl_platform", "tip,280", "1", + TCL_GLOBAL_ONLY); +#endif #ifdef Tcl_InitStubs #undef Tcl_InitStubs #endif Tcl_InitStubs(interp, TCL_VERSION, 1); @@ -646,23 +688,20 @@ Tcl_InterpDeleteProc *proc; /* Procedure to call when interpreter * is about to be deleted. */ ClientData clientData; /* One-word value to pass to proc. */ { Interp *iPtr = (Interp *) interp; - static int assocDataCounter = 0; -#ifdef TCL_THREADS - static Tcl_Mutex assocMutex; -#endif + static Tcl_ThreadDataKey assocDataCounterKey; + int *assocDataCounterPtr = + Tcl_GetThreadData(&assocDataCounterKey, (int)sizeof(int)); int new; char buffer[32 + TCL_INTEGER_SPACE]; AssocData *dPtr = (AssocData *) ckalloc(sizeof(AssocData)); Tcl_HashEntry *hPtr; - Tcl_MutexLock(&assocMutex); - sprintf(buffer, "Assoc Data Key #%d", assocDataCounter); - assocDataCounter++; - Tcl_MutexUnlock(&assocMutex); + sprintf(buffer, "Assoc Data Key #%d", *assocDataCounterPtr); + (*assocDataCounterPtr)++; if (iPtr->assocData == (Tcl_HashTable *) NULL) { iPtr->assocData = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(iPtr->assocData, TCL_STRING_KEYS); } @@ -1095,10 +1134,66 @@ * Free up literal objects created for scripts compiled by the * interpreter. */ TclDeleteLiteralTable(interp, &(iPtr->literalTable)); + +#ifdef TCL_TIP280 + /* TIP #280 - Release the arrays for ByteCode/Proc extension, and contents. + */ + { + Tcl_HashEntry *hPtr; + Tcl_HashSearch hSearch; + CmdFrame* cfPtr; + ExtCmdLoc* eclPtr; + int i; + + for (hPtr = Tcl_FirstHashEntry(iPtr->linePBodyPtr, &hSearch); + hPtr != NULL; + hPtr = Tcl_NextHashEntry(&hSearch)) { + + cfPtr = (CmdFrame*) Tcl_GetHashValue (hPtr); + + if (cfPtr->type == TCL_LOCATION_SOURCE) { + Tcl_DecrRefCount (cfPtr->data.eval.path); + } + ckfree ((char*) cfPtr->line); + ckfree ((char*) cfPtr); + Tcl_DeleteHashEntry (hPtr); + + } + Tcl_DeleteHashTable (iPtr->linePBodyPtr); + ckfree ((char*) iPtr->linePBodyPtr); + iPtr->linePBodyPtr = NULL; + + /* See also tclCompile.c, TclCleanupByteCode */ + + for (hPtr = Tcl_FirstHashEntry(iPtr->lineBCPtr, &hSearch); + hPtr != NULL; + hPtr = Tcl_NextHashEntry(&hSearch)) { + + eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hPtr); + + if (eclPtr->type == TCL_LOCATION_SOURCE) { + Tcl_DecrRefCount (eclPtr->path); + } + for (i=0; i< eclPtr->nuloc; i++) { + ckfree ((char*) eclPtr->loc[i].line); + } + + if (eclPtr->loc != NULL) { + ckfree ((char*) eclPtr->loc); + } + + ckfree ((char*) eclPtr); + Tcl_DeleteHashEntry (hPtr); + } + Tcl_DeleteHashTable (iPtr->lineBCPtr); + ckfree((char*) iPtr->lineBCPtr); + iPtr->lineBCPtr = NULL; + } +#endif ckfree((char *) iPtr); } /* *--------------------------------------------------------------------------- @@ -1164,12 +1259,12 @@ * lets prevent "::" in the token too. --dl */ if (strstr(hiddenCmdToken, "::") != NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "cannot use namespace qualifiers as hidden command", - "token (rename)", (char *) NULL); + "cannot use namespace qualifiers in hidden command", + " token (rename)", (char *) NULL); return TCL_ERROR; } /* * Find the command to hide. An error is returned if cmdName can't @@ -1835,23 +1930,22 @@ * Create the object argument array "objv". Make sure objv is large * enough to hold the objc arguments plus 1 extra for the zero * end-of-objv word. */ - if ((argc + 1) > NUM_ARGS) { + if (argc > NUM_ARGS) { objv = (Tcl_Obj **) - ckalloc((unsigned)(argc + 1) * sizeof(Tcl_Obj *)); + ckalloc((unsigned)(argc * sizeof(Tcl_Obj *))); } for (i = 0; i < argc; i++) { length = strlen(argv[i]); TclNewObj(objPtr); TclInitStringRep(objPtr, argv[i], length); Tcl_IncrRefCount(objPtr); objv[i] = objPtr; } - objv[argc] = 0; /* * Invoke the command's object-based Tcl_ObjCmdProc. */ @@ -2432,10 +2526,17 @@ * themsevles. This flag declares that a delete is in progress * and that recursive deletes should be ignored. */ cmdPtr->flags |= CMD_IS_DELETED; + /* + * Bump the command epoch counter. This will invalidate all cached + * references that point to this command. + */ + + cmdPtr->cmdEpoch++; + /* * Call trace procedures for the command being deleted. Then delete * its traces. */ @@ -2486,17 +2587,10 @@ */ (*cmdPtr->deleteProc)(cmdPtr->deleteData); } - /* - * Bump the command epoch counter. This will invalidate all cached - * references that point to this command. - */ - - cmdPtr->cmdEpoch++; - /* * If this command was imported into other namespaces, then imported * commands were created that refer back to this command. Delete these * imported commands now. */ @@ -2549,20 +2643,21 @@ * invoked. */ CONST char *oldName; /* Command's old name, or NULL if we * must get the name from cmdPtr */ CONST char *newName; /* Command's new name, or NULL if * the command is not being renamed */ - int flags; /* Flags passed to trace procedures: - * indicates what's happening to command, - * plus other stuff like TCL_GLOBAL_ONLY, - * TCL_NAMESPACE_ONLY, and - * TCL_INTERP_DESTROYED. */ + int flags; /* Flags indicating the type of traces + * to trigger, either TCL_TRACE_DELETE + * or TCL_TRACE_RENAME. */ { register CommandTrace *tracePtr; ActiveCommandTrace active; char *result; Tcl_Obj *oldNamePtr = NULL; + int mask = (TCL_TRACE_DELETE | TCL_TRACE_RENAME); /* Safety */ + + flags &= mask; if (cmdPtr->flags & CMD_TRACE_ACTIVE) { /* * While a rename trace is active, we will not process any more * rename traces; while a delete trace is active we will never @@ -2583,10 +2678,11 @@ cmdPtr->flags |= CMD_TRACE_ACTIVE; cmdPtr->refCount++; result = NULL; active.nextPtr = iPtr->activeCmdTracePtr; + active.reverseScan = 0; iPtr->activeCmdTracePtr = &active; if (flags & TCL_TRACE_DELETE) { flags |= TCL_TRACE_DESTROYED; } @@ -2594,15 +2690,17 @@ Tcl_Preserve((ClientData) iPtr); for (tracePtr = cmdPtr->tracePtr; tracePtr != NULL; tracePtr = active.nextTracePtr) { + int traceFlags = (tracePtr->flags & mask); + active.nextTracePtr = tracePtr->nextPtr; - if (!(tracePtr->flags & flags)) { + if (!(traceFlags & flags)) { continue; } - cmdPtr->flags |= tracePtr->flags; + cmdPtr->flags |= traceFlags; if (oldName == NULL) { TclNewObj(oldNamePtr); Tcl_IncrRefCount(oldNamePtr); Tcl_GetCommandFullName((Tcl_Interp *) iPtr, (Tcl_Command) cmdPtr, oldNamePtr); @@ -2609,11 +2707,11 @@ oldName = TclGetString(oldNamePtr); } tracePtr->refCount++; (*tracePtr->traceProc)(tracePtr->clientData, (Tcl_Interp *) iPtr, oldName, newName, flags); - cmdPtr->flags &= ~tracePtr->flags; + cmdPtr->flags &= ~traceFlags; if ((--tracePtr->refCount) <= 0) { ckfree((char*)tracePtr); } } @@ -2918,11 +3016,11 @@ /* * Check depth of nested calls to Tcl_Eval: if this gets too large, * it's probably because of an infinite loop somewhere. */ - if (((iPtr->numLevels) >= iPtr->maxNestingDepth) + if (((iPtr->numLevels) > iPtr->maxNestingDepth) || (TclpCheckStackSpace() == 0)) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "too many nested evaluations (infinite loop?)", -1); return TCL_ERROR; } @@ -2935,13 +3033,11 @@ * * TclEvalObjvInternal -- * * This procedure evaluates a Tcl command that has already been * parsed into words, with one Tcl_Obj holding each word. The caller - * is responsible for checking that the interpreter is ready to - * evaluate (by calling TclInterpReady), and also to manage the - * iPtr->numLevels. + * is responsible for managing the iPtr->numLevels. * * Results: * The return value is a standard Tcl completion code such as * TCL_OK or TCL_ERROR. A result or error message is left in * interp's result. If an error occurs, this procedure does @@ -2984,36 +3080,45 @@ CallFrame *savedVarFramePtr; /* Saves old copy of iPtr->varFramePtr * in case TCL_EVAL_GLOBAL was set. */ int code = TCL_OK; int traceCode = TCL_OK; int checkTraces = 1; + Namespace *savedNsPtr = NULL; + + if (TclInterpReady(interp) == TCL_ERROR) { + return TCL_ERROR; + } if (objc == 0) { return TCL_OK; } + /* * If any execution traces rename or delete the current command, * we may need (at most) two passes here. */ + + savedVarFramePtr = iPtr->varFramePtr; while (1) { + /* Configure evaluation context to match the requested flags */ + if (flags & TCL_EVAL_GLOBAL) { + iPtr->varFramePtr = NULL; + } else if ((flags & TCL_EVAL_INVOKE) && iPtr->varFramePtr) { + savedNsPtr = iPtr->varFramePtr->nsPtr; + iPtr->varFramePtr->nsPtr = iPtr->globalNsPtr; + } + /* * Find the procedure to execute this command. If there isn't one, * then see if there is a command "unknown". If so, create a new * word array with "unknown" as the first word and the original * command words as arguments. Then call ourselves recursively * to execute it. */ - - savedVarFramePtr = iPtr->varFramePtr; - if (flags & TCL_EVAL_INVOKE) { - iPtr->varFramePtr = NULL; - } cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[0]); - iPtr->varFramePtr = savedVarFramePtr; - if (cmdPtr == NULL) { newObjv = (Tcl_Obj **) ckalloc((unsigned) ((objc + 1) * sizeof (Tcl_Obj *))); for (i = objc-1; i >= 0; i--) { newObjv[i+1] = objv[i]; @@ -3024,28 +3129,35 @@ if (cmdPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "invalid command name \"", Tcl_GetString(objv[0]), "\"", (char *) NULL); code = TCL_ERROR; - } else if (TclInterpReady(interp) == TCL_ERROR) { - code = TCL_ERROR; } else { iPtr->numLevels++; - code = TclEvalObjvInternal(interp, objc+1, newObjv, command, length, 0); + code = TclEvalObjvInternal(interp, objc+1, newObjv, + command, length, 0); iPtr->numLevels--; } Tcl_DecrRefCount(newObjv[0]); ckfree((char *) newObjv); + if (savedNsPtr) { + iPtr->varFramePtr->nsPtr = savedNsPtr; + } goto done; } + if (savedNsPtr) { + iPtr->varFramePtr->nsPtr = savedNsPtr; + } /* * Call trace procedures if needed. */ if ((checkTraces) && (command != NULL)) { int cmdEpoch = cmdPtr->cmdEpoch; - cmdPtr->refCount++; + int newEpoch; + + cmdPtr->refCount++; /* * If the first set of traces modifies/deletes the command or * any existing traces, then the set checkTraces to 0 and * go through this while loop one more time. */ @@ -3056,12 +3168,13 @@ if ((cmdPtr->flags & CMD_HAS_EXEC_TRACES) && (traceCode == TCL_OK)) { traceCode = TclCheckExecutionTraces(interp, command, length, cmdPtr, code, TCL_TRACE_ENTER_EXEC, objc, objv); } - cmdPtr->refCount--; - if (cmdEpoch != cmdPtr->cmdEpoch) { + newEpoch = cmdPtr->cmdEpoch; + TclCleanupCommand(cmdPtr); + if (cmdEpoch != newEpoch) { /* The command has been modified in some way */ checkTraces = 0; continue; } } @@ -3072,33 +3185,33 @@ * Finally, invoke the command's Tcl_ObjCmdProc. */ cmdPtr->refCount++; iPtr->cmdCount++; if ( code == TCL_OK && traceCode == TCL_OK) { - savedVarFramePtr = iPtr->varFramePtr; - if (flags & TCL_EVAL_GLOBAL) { - iPtr->varFramePtr = NULL; - } code = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv); - iPtr->varFramePtr = savedVarFramePtr; } if (Tcl_AsyncReady()) { code = Tcl_AsyncInvoke(interp, code); } /* * Call 'leave' command traces */ if (!(cmdPtr->flags & CMD_IS_DELETED)) { + int saveErrFlags = iPtr->flags + & (ERR_IN_PROGRESS | ERR_ALREADY_LOGGED | ERROR_CODE_SET); if ((cmdPtr->flags & CMD_HAS_EXEC_TRACES) && (traceCode == TCL_OK)) { traceCode = TclCheckExecutionTraces (interp, command, length, cmdPtr, code, TCL_TRACE_LEAVE_EXEC, objc, objv); } if (iPtr->tracePtr != NULL && traceCode == TCL_OK) { traceCode = TclCheckInterpTraces(interp, command, length, cmdPtr, code, TCL_TRACE_LEAVE_EXEC, objc, objv); } + if (traceCode == TCL_OK) { + iPtr->flags |= saveErrFlags; + } } TclCleanupCommand(cmdPtr); /* * If one of the trace invocation resulted in error, then @@ -3121,10 +3234,11 @@ if (*(iPtr->result) != 0) { (void) Tcl_GetObjResult(interp); } done: + iPtr->varFramePtr = savedVarFramePtr; return code; } /* *---------------------------------------------------------------------- @@ -3186,17 +3300,13 @@ cmdLen = Tcl_DStringLength(&cmdBuf); break; } } - code = TclInterpReady(interp); - if (code == TCL_OK) { - iPtr->numLevels++; - code = TclEvalObjvInternal(interp, objc, objv, cmdString, cmdLen, - flags); - iPtr->numLevels--; - } + iPtr->numLevels++; + code = TclEvalObjvInternal(interp, objc, objv, cmdString, cmdLen, flags); + iPtr->numLevels--; /* * If we are again at the top level, process any unusual * return code returned by the evaluated code. */ @@ -3302,10 +3412,18 @@ length = strlen(command); } if (length > 150) { length = 150; ellipsis = "..."; + } + while ( (command[length] & 0xC0) == 0x80 ) { + /* + * Back up truncation point so that we don't truncate in the + * middle of a multi-byte character (in UTF-8) + */ + length--; + ellipsis = "..."; } if (!(iPtr->flags & ERR_IN_PROGRESS)) { sprintf(buffer, "\n while executing\n\"%.*s%s\"", length, command, ellipsis); } else { @@ -3317,11 +3435,11 @@ } /* *---------------------------------------------------------------------- * - * Tcl_EvalTokensStandard -- + * Tcl_EvalTokensStandard, EvalTokensStandard -- * * Given an array of tokens parsed from a Tcl command (e.g., the * tokens that make up a word or the index for an array variable) * this procedure evaluates the tokens and concatenates their * values to form a single result value. @@ -3331,11 +3449,12 @@ * TCL_OK or TCL_ERROR. A result or error message is left in * interp's result. * * Side effects: * Depends on the array of tokens being evaled. - * + * + * TIP #280 : Keep public API, internally extended API. *---------------------------------------------------------------------- */ int Tcl_EvalTokensStandard(interp, tokenPtr, count) @@ -3345,10 +3464,26 @@ Tcl_Token *tokenPtr; /* Pointer to first in an array of tokens * to evaluate and concatenate. */ int count; /* Number of tokens to consider at tokenPtr. * Must be at least 1. */ { +#ifdef TCL_TIP280 + return EvalTokensStandard (interp, tokenPtr, count, 1); +} + +static int +EvalTokensStandard(interp, tokenPtr, count, line) + Tcl_Interp *interp; /* Interpreter in which to lookup + * variables, execute nested commands, + * and report errors. */ + Tcl_Token *tokenPtr; /* Pointer to first in an array of tokens + * to evaluate and concatenate. */ + int count; /* Number of tokens to consider at tokenPtr. + * Must be at least 1. */ + int line; /* The line the script starts on. */ +{ +#endif Tcl_Obj *resultPtr, *indexPtr, *valuePtr; char buffer[TCL_UTF_MAX]; #ifdef TCL_MEM_DEBUG # define MAX_VAR_CHARS 5 #else @@ -3388,26 +3523,45 @@ length = Tcl_UtfBackslash(tokenPtr->start, (int *) NULL, buffer); p = buffer; break; - case TCL_TOKEN_COMMAND: - code = Tcl_EvalEx(interp, tokenPtr->start+1, tokenPtr->size-2, - 0); + case TCL_TOKEN_COMMAND: { + Interp *iPtr = (Interp *) interp; + iPtr->numLevels++; + code = TclInterpReady(interp); + if (code == TCL_OK) { +#ifndef TCL_TIP280 + code = Tcl_EvalEx(interp, + tokenPtr->start+1, tokenPtr->size-2, 0); +#else + /* TIP #280: Transfer line information to nested command */ + code = EvalEx(interp, + tokenPtr->start+1, tokenPtr->size-2, 0, line); +#endif + } + iPtr->numLevels--; if (code != TCL_OK) { goto done; } valuePtr = Tcl_GetObjResult(interp); break; + } case TCL_TOKEN_VARIABLE: if (tokenPtr->numComponents == 1) { indexPtr = NULL; index = NULL; } else { +#ifndef TCL_TIP280 code = Tcl_EvalTokensStandard(interp, tokenPtr+2, tokenPtr->numComponents - 1); +#else + /* TIP #280: Transfer line information to nested command */ + code = EvalTokensStandard(interp, tokenPtr+2, + tokenPtr->numComponents - 1, line); +#endif if (code != TCL_OK) { goto done; } indexPtr = Tcl_GetObjResult(interp); Tcl_IncrRefCount(indexPtr); @@ -3483,12 +3637,11 @@ if (resultPtr != NULL) { Tcl_DecrRefCount(resultPtr); } return code; } - - + /* *---------------------------------------------------------------------- * * Tcl_EvalTokens -- * @@ -3540,11 +3693,11 @@ /* *---------------------------------------------------------------------- * - * Tcl_EvalEx -- + * Tcl_EvalEx, EvalEx -- * * This procedure evaluates a Tcl script without using the compiler * or byte-code interpreter. It just parses the script, creates * values for each word of each command, then calls EvalObjv * to execute each command. @@ -3555,10 +3708,11 @@ * interp's result. * * Side effects: * Depends on the script. * + * TIP #280 : Keep public API, internally extended API. *---------------------------------------------------------------------- */ int Tcl_EvalEx(interp, script, numBytes, flags) @@ -3571,17 +3725,37 @@ int flags; /* Collection of OR-ed bits that control * the evaluation of the script. Only * TCL_EVAL_GLOBAL is currently * supported. */ { +#ifdef TCL_TIP280 + return EvalEx (interp, script, numBytes, flags, 1); +} + +static int +EvalEx(interp, script, numBytes, flags, line) + Tcl_Interp *interp; /* Interpreter in which to evaluate the + * script. Also used for error reporting. */ + CONST char *script; /* First character of script to evaluate. */ + int numBytes; /* Number of bytes in script. If < 0, the + * script consists of all bytes up to the + * first null character. */ + int flags; /* Collection of OR-ed bits that control + * the evaluation of the script. Only + * TCL_EVAL_GLOBAL is currently + * supported. */ + int line; /* The line the script starts on. */ +{ +#endif Interp *iPtr = (Interp *) interp; CONST char *p, *next; Tcl_Parse parse; #define NUM_STATIC_OBJS 20 Tcl_Obj *staticObjArray[NUM_STATIC_OBJS], **objv; Tcl_Token *tokenPtr; - int i, code, commandLength, bytesLeft, nested; + int code = TCL_OK; + int i, commandLength, bytesLeft, nested; CallFrame *savedVarFramePtr; /* Saves old copy of iPtr->varFramePtr * in case TCL_EVAL_GLOBAL was set. */ int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS); /* @@ -3589,10 +3763,15 @@ * allocated while evaluating the script, so that it can be freed * properly if an error occurs. */ int gotParse = 0, objectsUsed = 0; + +#ifdef TCL_TIP280 + /* TIP #280 Structures for tracking of command locations. */ + CmdFrame eeFrame; +#endif if (numBytes < 0) { numBytes = strlen(script); } Tcl_ResetResult(interp); @@ -3613,10 +3792,66 @@ if (iPtr->evalFlags & TCL_BRACKET_TERM) { nested = 1; } else { nested = 0; } + +#ifdef TCL_TIP280 + /* TIP #280 Initialize tracking. Do not push on the frame stack yet. */ + /* + * We may cont. counting based on a specific context (CTX), or open a new + * context, either for a sourced script, or 'eval'. For sourced files we + * always have a path object, even if nothing was specified in the interp + * itself. That makes code using it simpler as NULL checks can be left + * out. Sourced file without path in the 'scriptFile' is possible during + * Tcl initialization. + */ + + if (iPtr->evalFlags & TCL_EVAL_CTX) { + /* Path information comes out of the context. */ + + eeFrame.type = TCL_LOCATION_SOURCE; + eeFrame.data.eval.path = iPtr->invokeCmdFramePtr->data.eval.path; + Tcl_IncrRefCount (eeFrame.data.eval.path); + } else if (iPtr->evalFlags & TCL_EVAL_FILE) { + /* Set up for a sourced file */ + + eeFrame.type = TCL_LOCATION_SOURCE; + + if (iPtr->scriptFile) { + /* Normalization here, to have the correct pwd. Should have + * negligible impact on performance, as the norm should have been + * done already by the 'source' invoking us, and it caches the + * result + */ + + Tcl_Obj* norm = Tcl_FSGetNormalizedPath (interp, iPtr->scriptFile); + if (!norm) { + /* Error message in the interp result */ + return TCL_ERROR; + } + eeFrame.data.eval.path = norm; + Tcl_IncrRefCount (eeFrame.data.eval.path); + } else { + eeFrame.data.eval.path = Tcl_NewStringObj ("",-1); + } + } else { + /* Set up for plain eval */ + + eeFrame.type = TCL_LOCATION_EVAL; + eeFrame.data.eval.path = NULL; + } + + eeFrame.level = (iPtr->cmdFramePtr == NULL + ? 1 + : iPtr->cmdFramePtr->level + 1); + eeFrame.framePtr = iPtr->framePtr; + eeFrame.nextPtr = iPtr->cmdFramePtr; + eeFrame.nline = 0; + eeFrame.line = NULL; +#endif + iPtr->evalFlags = 0; do { if (Tcl_ParseCommand(interp, p, bytesLeft, nested, &parse) != TCL_OK) { code = TCL_ERROR; @@ -3632,12 +3867,32 @@ */ code = TCL_ERROR; goto error; } + +#ifdef TCL_TIP280 + /* + * TIP #280 Track lines. The parser may have skipped text till it + * found the command we are now at. We have count the lines in this + * block. + */ + + TclAdvanceLines (&line, p, parse.commandStart); +#endif if (parse.numWords > 0) { +#ifdef TCL_TIP280 + /* + * TIP #280. Track lines within the words of the current + * command. + */ + + int wordLine = line; + CONST char* wordStart = parse.commandStart; +#endif + /* * Generate an array of objects for the words of the command. */ if (parse.numWords <= NUM_STATIC_OBJS) { @@ -3644,15 +3899,49 @@ objv = staticObjArray; } else { objv = (Tcl_Obj **) ckalloc((unsigned) (parse.numWords * sizeof (Tcl_Obj *))); } + +#ifdef TCL_TIP280 + eeFrame.nline = parse.numWords; + eeFrame.line = (int*) ckalloc((unsigned) + (parse.numWords * sizeof (int))); +#endif + for (objectsUsed = 0, tokenPtr = parse.tokenPtr; - objectsUsed < parse.numWords; - objectsUsed++, tokenPtr += (tokenPtr->numComponents + 1)) { + objectsUsed < parse.numWords; + objectsUsed++, tokenPtr += (tokenPtr->numComponents + 1)) { +#ifndef TCL_TIP280 code = Tcl_EvalTokensStandard(interp, tokenPtr+1, tokenPtr->numComponents); +#else + /* + * TIP #280. Track lines to current word. Save the + * information on a per-word basis, signaling dynamic words as + * needed. Make the information available to the recursively + * called evaluator as well, including the type of context + * (source vs. eval). + */ + + TclAdvanceLines (&wordLine, wordStart, tokenPtr->start); + wordStart = tokenPtr->start; + + eeFrame.line [objectsUsed] = (TclWordKnownAtCompileTime (tokenPtr) + ? wordLine + : -1); + + if (eeFrame.type == TCL_LOCATION_SOURCE) { + iPtr->evalFlags |= TCL_EVAL_FILE; + } + + code = EvalTokensStandard(interp, tokenPtr+1, + tokenPtr->numComponents, wordLine); + + iPtr->evalFlags = 0; +#endif + if (code == TCL_OK) { objv[objectsUsed] = Tcl_GetObjResult(interp); Tcl_IncrRefCount(objv[objectsUsed]); } else { goto error; @@ -3659,31 +3948,41 @@ } } /* * Execute the command and free the objects for its words. + * + * TIP #280: Remember the command itself for 'info frame'. We + * shorten the visible command by one char to exclude the + * termination character, if necessary. Here is where we put our + * frame on the stack of frames too. _After_ the nested commands + * have been executed. */ - if (TclInterpReady(interp) == TCL_ERROR) { - code = TCL_ERROR; - } else { - iPtr->numLevels++; - code = TclEvalObjvInternal(interp, objectsUsed, objv, p, - parse.commandStart + parse.commandSize - p, 0); - iPtr->numLevels--; - } - if (code != TCL_OK) { - if (iPtr->numLevels == 0) { - if (code == TCL_RETURN) { - code = TclUpdateReturnInfo(iPtr); - } - if ((code != TCL_OK) && (code != TCL_ERROR) - && !allowExceptions) { - ProcessUnexpectedResult(interp, code); - code = TCL_ERROR; - } - } +#ifdef TCL_TIP280 + eeFrame.cmd.str.cmd = parse.commandStart; + eeFrame.cmd.str.len = parse.commandSize; + + if (parse.term == parse.commandStart + parse.commandSize - 1) { + eeFrame.cmd.str.len --; + } + + iPtr->cmdFramePtr = &eeFrame; +#endif + iPtr->numLevels++; + code = TclEvalObjvInternal(interp, objectsUsed, objv, + parse.commandStart, parse.commandSize, 0); + iPtr->numLevels--; +#ifdef TCL_TIP280 + iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr; + + ckfree ((char*) eeFrame.line); + eeFrame.line = NULL; + eeFrame.nline = 0; +#endif + + if (code != TCL_OK) { goto error; } for (i = 0; i < objectsUsed; i++) { Tcl_DecrRefCount(objv[i]); } @@ -3694,15 +3993,21 @@ } } /* * Advance to the next command in the script. + * + * TIP #280 Track Lines. Now we track how many lines were in the + * executed command. */ next = parse.commandStart + parse.commandSize; bytesLeft -= next - p; p = next; +#ifdef TCL_TIP280 + TclAdvanceLines (&line, parse.commandStart, p); +#endif Tcl_FreeParse(&parse); gotParse = 0; if (nested && (*parse.term == ']')) { /* * We get here in the special case where the TCL_BRACKET_TERM @@ -3711,25 +4016,55 @@ * Return immediately. */ iPtr->termOffset = (p - 1) - script; iPtr->varFramePtr = savedVarFramePtr; +#ifndef TCL_TIP280 return TCL_OK; +#else + code = TCL_OK; + goto cleanup_return; +#endif } } while (bytesLeft > 0); + + if (nested) { + /* + * This nested script did not terminate in ']', it is an error. + */ + + code = TCL_ERROR; + goto error; + } + iPtr->termOffset = p - script; iPtr->varFramePtr = savedVarFramePtr; +#ifndef TCL_TIP280 return TCL_OK; +#else + code = TCL_OK; + goto cleanup_return; +#endif error: /* * Generate various pieces of error information, such as the line * number where the error occurred and information to add to the * errorInfo variable. Then free resources that had been allocated * to the command. */ + if (iPtr->numLevels == 0) { + if (code == TCL_RETURN) { + code = TclUpdateReturnInfo(iPtr); + } + if ((code != TCL_OK) && (code != TCL_ERROR) + && !allowExceptions) { + ProcessUnexpectedResult(interp, code); + code = TCL_ERROR; + } + } if ((code == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) { commandLength = parse.commandSize; if (parse.term == parse.commandStart + commandLength - 1) { /* * The terminator character (such as ; or ]) of the command where @@ -3763,11 +4098,15 @@ bytesLeft -= next - p; p = next; if (!nested) { iPtr->termOffset = p - script; +#ifndef TCL_TIP280 return code; +#else + goto cleanup_return; +#endif } /* * When we are nested (the TCL_BRACKET_TERM flag was set in the * interpreter), we must find the matching close-bracket to @@ -3791,11 +4130,15 @@ if (next == NULL) { iPtr->termOffset = (parse.commandStart - 1) - script; } else { iPtr->termOffset = (next - 1) - script; } +#ifndef TCL_TIP280 return code; +#else + goto cleanup_return; +#endif } next = parse.commandStart + parse.commandSize; bytesLeft -= next - p; p = next; next = parse.commandStart; @@ -3814,28 +4157,84 @@ */ iPtr->termOffset = parse.term - script; Tcl_SetObjResult(interp, Tcl_NewStringObj("missing close-bracket", -1)); +#ifndef TCL_TIP280 return TCL_ERROR; +#else + code = TCL_ERROR; + goto cleanup_return; +#endif } else if (*parse.term != ']') { /* * There was no close-bracket. Syntax error. */ iPtr->termOffset = (parse.term + 1) - script; Tcl_SetObjResult(interp, Tcl_NewStringObj("missing close-bracket", -1)); +#ifndef TCL_TIP280 return TCL_ERROR; +#else + code = TCL_ERROR; + goto cleanup_return; +#endif } else { /* * parse.term points to the close-bracket. */ iPtr->termOffset = parse.term - script; } + +#ifdef TCL_TIP280 + cleanup_return: + /* TIP #280. Release the local CmdFrame, and its contents. */ + + if (eeFrame.line != NULL) { + ckfree ((char*) eeFrame.line); + } + if (eeFrame.type == TCL_LOCATION_SOURCE) { + Tcl_DecrRefCount (eeFrame.data.eval.path); + } +#endif return code; } + +#ifdef TCL_TIP280 +/* + *---------------------------------------------------------------------- + * + * TclAdvanceLines -- + * + * This procedure is a helper which counts the number of lines + * in a block of text and advances an external counter. + * + * Results: + * None. + * + * Side effects: + * The specified counter is advanced per the number of lines found. + * + * TIP #280 + *---------------------------------------------------------------------- + */ + +void +TclAdvanceLines (line,start,end) + int* line; + CONST char* start; + CONST char* end; +{ + CONST char* p; + for (p = start; p < end; p++) { + if (*p == '\n') { + (*line) ++; + } + } +} +#endif /* *---------------------------------------------------------------------- * * Tcl_Eval -- @@ -3914,11 +4313,11 @@ } /* *---------------------------------------------------------------------- * - * Tcl_EvalObjEx -- + * Tcl_EvalObjEx, TclEvalObjEx -- * * Execute Tcl commands stored in a Tcl object. These commands are * compiled into bytecodes if necessary, unless TCL_EVAL_DIRECT * is specified. * @@ -3934,10 +4333,11 @@ * on those commands. * * Just as in Tcl_Eval, interp->termOffset is set to the offset of the * last character executed in the objPtr's string. * + * TIP #280 : Keep public API, internally extended API. *---------------------------------------------------------------------- */ int Tcl_EvalObjEx(interp, objPtr, flags) @@ -3950,10 +4350,30 @@ * control the evaluation of the * script. Supported values are * TCL_EVAL_GLOBAL and * TCL_EVAL_DIRECT. */ { +#ifdef TCL_TIP280 + return TclEvalObjEx (interp, objPtr, flags, NULL, 0); +} + +int +TclEvalObjEx(interp, objPtr, flags, invoker, word) + Tcl_Interp *interp; /* Token for command interpreter + * (returned by a previous call to + * Tcl_CreateInterp). */ + register Tcl_Obj *objPtr; /* Pointer to object containing + * commands to execute. */ + int flags; /* Collection of OR-ed bits that + * control the evaluation of the + * script. Supported values are + * TCL_EVAL_GLOBAL and + * TCL_EVAL_DIRECT. */ + CONST CmdFrame* invoker; /* Frame of the command doing the eval */ + int word; /* Index of the word which is in objPtr */ +{ +#endif register Interp *iPtr = (Interp *) interp; char *script; int numSrcBytes; int result; CallFrame *savedVarFramePtr; /* Saves old copy of iPtr->varFramePtr @@ -3980,27 +4400,188 @@ if (!(iPtr->flags & USE_EVAL_DIRECT) && (objPtr->typePtr == &tclListType) && /* is a list... */ (objPtr->bytes == NULL) /* ...without a string rep */) { register List *listRepPtr = (List *) objPtr->internalRep.twoPtrValue.ptr1; - result = Tcl_EvalObjv(interp, listRepPtr->elemCount, - listRepPtr->elements, flags); + int i, objc = listRepPtr->elemCount; + +#define TEOE_PREALLOC 10 + Tcl_Obj *staticObjv[TEOE_PREALLOC], **objv = staticObjv; + +#ifdef TCL_TIP280 + /* TIP #280 Structures for tracking lines. + * As we know that this is dynamic execution we ignore the + * invoker, even if known. + */ + int line; + CmdFrame eoFrame; + + eoFrame.type = TCL_LOCATION_EVAL_LIST; + eoFrame.level = (iPtr->cmdFramePtr == NULL ? + 1 : + iPtr->cmdFramePtr->level + 1); + eoFrame.framePtr = iPtr->framePtr; + eoFrame.nextPtr = iPtr->cmdFramePtr; + eoFrame.nline = objc; + eoFrame.line = (int*) ckalloc (objc * sizeof (int)); + + /* NOTE: Getting the string rep of the list to eval to fill the + * command information required by 'info frame' implies that + * further calls for the same list would not be optimized, as it + * would not be 'pure' anymore. It would also be a waste of time + * as most of the time this information is not needed at all. What + * we do instead is to keep the list obj itself around and have + * 'info frame' sort it out. + */ + + eoFrame.cmd.listPtr = objPtr; + Tcl_IncrRefCount (eoFrame.cmd.listPtr); + eoFrame.data.eval.path = NULL; +#endif + if (objc > TEOE_PREALLOC) { + objv = (Tcl_Obj **) ckalloc(objc*sizeof(Tcl_Obj *)); + } +#undef TEOE_PREALLOC + /* + * Copy the list elements here, to avoid a segfault if + * objPtr loses its List internal rep [Bug 1119369]. + * + * TIP #280 Computes all the line numbers for the + * words in the command. + */ + +#ifdef TCL_TIP280 + line = 1; +#endif + for (i=0; i < objc; i++) { + objv[i] = listRepPtr->elements[i]; + Tcl_IncrRefCount(objv[i]); +#ifdef TCL_TIP280 + eoFrame.line [i] = line; + { + char* w = Tcl_GetString (objv [i]); + TclAdvanceLines (&line, w, w+ strlen(w)); + } +#endif + } + +#ifdef TCL_TIP280 + iPtr->cmdFramePtr = &eoFrame; +#endif + result = Tcl_EvalObjv(interp, objc, objv, flags); +#ifdef TCL_TIP280 + iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr; + Tcl_DecrRefCount (eoFrame.cmd.listPtr); +#endif + + for (i=0; i < objc; i++) { + TclDecrRefCount(objv[i]); + } + if (objv != staticObjv) { + ckfree((char *) objv); + } +#ifdef TCL_TIP280 + ckfree ((char*) eoFrame.line); + eoFrame.line = NULL; + eoFrame.nline = 0; +#endif } else { +#ifndef TCL_TIP280 script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); result = Tcl_EvalEx(interp, script, numSrcBytes, flags); +#else + /* + * TIP #280. Propagate context as much as we can. Especially if + * the script to evaluate is a single literal it makes sense to + * look if our context is one with absolute line numbers we can + * then track into the literal itself too. + * + * See also tclCompile.c, TclInitCompileEnv, for the equivalent + * code in the bytecode compiler. + */ + + if (invoker == NULL) { + /* No context, force opening of our own */ + script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); + result = Tcl_EvalEx(interp, script, numSrcBytes, flags); + } else { + /* We have an invoker, describing the command asking for the + * evaluation of a subordinate script. This script may + * originate in a literal word, or from a variable, etc. Using + * the line array we now check if we have good line + * information for the relevant word. The type of context is + * relevant as well. In a non-'source' context we don't have + * to try tracking lines. + * + * First see if the word exists and is a literal. If not we go + * through the easy dynamic branch. No need to perform more + * complex invokations. + */ + + if ((invoker->nline <= word) || (invoker->line[word] < 0)) { + /* Dynamic script, or dynamic context, force our own + * context */ + + script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); + result = Tcl_EvalEx(interp, script, numSrcBytes, flags); + + } else { + /* Try to get an absolute context for the evaluation + */ + + CmdFrame ctx = *invoker; + int pc = 0; + + if (invoker->type == TCL_LOCATION_BC) { + /* Note: Type BC => ctx.data.eval.path is not used. + * ctx.data.tebc.codePtr is used instead. + */ + TclGetSrcInfoForPc (&ctx); + pc = 1; + } + + if (ctx.type == TCL_LOCATION_SOURCE) { + /* Absolute context to reuse. */ + + iPtr->invokeCmdFramePtr = &ctx; + iPtr->evalFlags |= TCL_EVAL_CTX; + + script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); + result = EvalEx(interp, script, numSrcBytes, flags, ctx.line [word]); + + if (pc) { + /* Death of SrcInfo reference */ + Tcl_DecrRefCount (ctx.data.eval.path); + } + } else { + /* Dynamic context or script, easier to make our own as + * well */ + script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); + result = Tcl_EvalEx(interp, script, numSrcBytes, flags); + } + } + } +#endif } } else { /* * Let the compiler/engine subsystem do the evaluation. + * + * TIP #280 The invoker provides us with the context for the + * script. We transfer this to the byte code compiler. */ savedVarFramePtr = iPtr->varFramePtr; if (flags & TCL_EVAL_GLOBAL) { iPtr->varFramePtr = NULL; } +#ifndef TCL_TIP280 result = TclCompEvalObj(interp, objPtr); +#else + result = TclCompEvalObj(interp, objPtr, invoker, word); +#endif /* * If we are again at the top level, process any unusual * return code returned by the evaluated code. */ @@ -4014,16 +4595,18 @@ ProcessUnexpectedResult(interp, result); result = TCL_ERROR; /* * If an error was created here, record information about - * what was being executed when the error occurred. + * what was being executed when the error occurred. Remove + * the extra \n added by tclMain.c in the command sent to + * Tcl_LogCommandInfo [Bug 833150]. */ if (!(iPtr->flags & ERR_ALREADY_LOGGED)) { script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); - Tcl_LogCommandInfo(interp, script, script, numSrcBytes); + Tcl_LogCommandInfo(interp, script, script, --numSrcBytes); iPtr->flags &= ~ERR_ALREADY_LOGGED; } } } iPtr->evalFlags = 0; @@ -4114,15 +4697,33 @@ result = Tcl_ExprObj(interp, exprPtr, &resultPtr); if (result == TCL_OK) { /* * Store an integer based on the expression result. */ - + if (resultPtr->typePtr == &tclIntType) { *ptr = resultPtr->internalRep.longValue; } else if (resultPtr->typePtr == &tclDoubleType) { *ptr = (long) resultPtr->internalRep.doubleValue; + } else if (resultPtr->typePtr == &tclWideIntType) { +#ifndef TCL_WIDE_INT_IS_LONG + /* + * See Tcl_GetIntFromObj for conversion comments. + */ + Tcl_WideInt w = resultPtr->internalRep.wideValue; + if ((w >= -(Tcl_WideInt)(ULONG_MAX)) + && (w <= (Tcl_WideInt)(ULONG_MAX))) { + *ptr = Tcl_WideAsLong(w); + } else { + Tcl_SetResult(interp, + "integer value too large to represent as non-long integer", + TCL_STATIC); + result = TCL_ERROR; + } +#else + *ptr = resultPtr->internalRep.longValue; +#endif } else { Tcl_SetResult(interp, "expression didn't have numeric value", TCL_STATIC); result = TCL_ERROR; } @@ -4165,15 +4766,33 @@ result = Tcl_ExprObj(interp, exprPtr, &resultPtr); if (result == TCL_OK) { /* * Store a double based on the expression result. */ - + if (resultPtr->typePtr == &tclIntType) { *ptr = (double) resultPtr->internalRep.longValue; } else if (resultPtr->typePtr == &tclDoubleType) { *ptr = resultPtr->internalRep.doubleValue; + } else if (resultPtr->typePtr == &tclWideIntType) { +#ifndef TCL_WIDE_INT_IS_LONG + /* + * See Tcl_GetIntFromObj for conversion comments. + */ + Tcl_WideInt w = resultPtr->internalRep.wideValue; + if ((w >= -(Tcl_WideInt)(ULONG_MAX)) + && (w <= (Tcl_WideInt)(ULONG_MAX))) { + *ptr = (double) Tcl_WideAsLong(w); + } else { + Tcl_SetResult(interp, + "integer value too large to represent as non-long integer", + TCL_STATIC); + result = TCL_ERROR; + } +#else + *ptr = (double) resultPtr->internalRep.longValue; +#endif } else { Tcl_SetResult(interp, "expression didn't have numeric value", TCL_STATIC); result = TCL_ERROR; } @@ -4216,15 +4835,21 @@ result = Tcl_ExprObj(interp, exprPtr, &resultPtr); if (result == TCL_OK) { /* * Store a boolean based on the expression result. */ - + if (resultPtr->typePtr == &tclIntType) { *ptr = (resultPtr->internalRep.longValue != 0); } else if (resultPtr->typePtr == &tclDoubleType) { *ptr = (resultPtr->internalRep.doubleValue != 0.0); + } else if (resultPtr->typePtr == &tclWideIntType) { +#ifndef TCL_WIDE_INT_IS_LONG + *ptr = (resultPtr->internalRep.wideValue != 0); +#else + *ptr = (resultPtr->internalRep.longValue != 0); +#endif } else { result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr); } Tcl_DecrRefCount(resultPtr); /* discard the result object */ } @@ -4565,12 +5190,11 @@ Tcl_Command cmd; Command *cmdPtr; int localObjc; /* Used to invoke "unknown" if the */ Tcl_Obj **localObjv = NULL; /* command is not found. */ register int i; - int length, result; - char *bytes; + int result; if (interp == (Tcl_Interp *) NULL) { return TCL_ERROR; } @@ -4659,33 +5283,45 @@ */ if ((result == TCL_ERROR) && ((flags & TCL_INVOKE_NO_TRACEBACK) == 0) && ((iPtr->flags & ERR_ALREADY_LOGGED) == 0)) { - Tcl_DString ds; + Tcl_Obj *msg; - Tcl_DStringInit(&ds); if (!(iPtr->flags & ERR_IN_PROGRESS)) { - Tcl_DStringAppend(&ds, "\n while invoking\n\"", -1); + msg = Tcl_NewStringObj("\n while invoking\n\"", -1); } else { - Tcl_DStringAppend(&ds, "\n invoked from within\n\"", -1); + msg = Tcl_NewStringObj("\n invoked from within\n\"", -1); } + Tcl_IncrRefCount(msg); for (i = 0; i < objc; i++) { - bytes = Tcl_GetStringFromObj(objv[i], &length); - Tcl_DStringAppend(&ds, bytes, length); - if (i < (objc - 1)) { - Tcl_DStringAppend(&ds, " ", -1); - } else if (Tcl_DStringLength(&ds) > 100) { - Tcl_DStringSetLength(&ds, 100); - Tcl_DStringAppend(&ds, "...", -1); - break; - } - } - - Tcl_DStringAppend(&ds, "\"", -1); - Tcl_AddObjErrorInfo(interp, Tcl_DStringValue(&ds), -1); - Tcl_DStringFree(&ds); + CONST char *bytes; + int length; + + Tcl_AppendObjToObj(msg, objv[i]); + bytes = Tcl_GetStringFromObj(msg, &length); + if (length > 100) { + /* + * Back up truncation point so that we don't truncate + * in the middle of a multi-byte character. + */ + length = 100; + while ( (bytes[length] & 0xC0) == 0x80 ) { + length--; + } + Tcl_SetObjLength(msg, length); + Tcl_AppendToObj(msg, "...", -1); + break; + } + if (i != (objc - 1)) { + Tcl_AppendToObj(msg, " ", -1); + } + } + + Tcl_AppendToObj(msg, "\"", -1); + Tcl_AddObjErrorInfo(interp, Tcl_GetString(msg), -1); + Tcl_DecrRefCount(msg); iPtr->flags &= ~ERR_ALREADY_LOGGED; } /* * Free any locally allocated storage used to call "unknown". @@ -5051,25 +5687,45 @@ Tcl_Interp *interp; /* Interpreter that contains trace. */ Tcl_Trace trace; /* Token for trace (returned previously by * Tcl_CreateTrace). */ { Interp *iPtr = (Interp *) interp; - Trace *tracePtr = (Trace *) trace; + Trace *prevPtr, *tracePtr = (Trace *) trace; register Trace **tracePtr2 = &(iPtr->tracePtr); + ActiveInterpTrace *activePtr; /* * Locate the trace entry in the interpreter's trace list, * and remove it from the list. */ + prevPtr = NULL; while ((*tracePtr2) != NULL && (*tracePtr2) != tracePtr) { + prevPtr = *tracePtr2; tracePtr2 = &((*tracePtr2)->nextPtr); } if (*tracePtr2 == NULL) { return; } (*tracePtr2) = (*tracePtr2)->nextPtr; + + /* + * The code below makes it possible to delete traces while traces + * are active: it makes sure that the deleted trace won't be + * processed by TclCheckInterpTraces. + */ + + for (activePtr = iPtr->activeInterpTracePtr; activePtr != NULL; + activePtr = activePtr->nextPtr) { + if (activePtr->nextTracePtr == tracePtr) { + if (activePtr->reverseScan) { + activePtr->nextTracePtr = prevPtr; + } else { + activePtr->nextTracePtr = tracePtr->nextPtr; + } + } + } /* * If the trace forbids bytecode compilation, change the interpreter's * state. If bytecode compilation is now permitted, flag the fact and * advance the compilation epoch so that procs will be recompiled to @@ -5159,11 +5815,11 @@ int length; /* The number of bytes in the message. * If < 0, then append all bytes up to a * NULL byte. */ { register Interp *iPtr = (Interp *) interp; - Tcl_Obj *messagePtr; + Tcl_Obj *objPtr; /* * If we are just starting to log an error, errorInfo is initialized * from the error message in the interpreter's result. */ @@ -5173,35 +5829,41 @@ if (iPtr->result[0] == 0) { Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorInfo, NULL, iPtr->objResultPtr, TCL_GLOBAL_ONLY); } else { /* use the string result */ + objPtr = Tcl_NewStringObj(interp->result, -1); + Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorInfo, NULL, - Tcl_NewStringObj(interp->result, -1), TCL_GLOBAL_ONLY); + objPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(objPtr); } /* * If the errorCode variable wasn't set by the code that generated * the error, set it to "NONE". */ if (!(iPtr->flags & ERROR_CODE_SET)) { + objPtr = Tcl_NewStringObj("NONE", -1); + Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorCode, NULL, - Tcl_NewStringObj("NONE", -1), TCL_GLOBAL_ONLY); + objPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(objPtr); } } /* * Now append "message" to the end of errorInfo. */ if (length != 0) { - messagePtr = Tcl_NewStringObj(message, length); - Tcl_IncrRefCount(messagePtr); + objPtr = Tcl_NewStringObj(message, length); + Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorInfo, NULL, - messagePtr, (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE)); - Tcl_DecrRefCount(messagePtr); /* free msg object appended above */ + objPtr, (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE)); + Tcl_DecrRefCount(objPtr); /* free msg object appended above */ } } /* *--------------------------------------------------------------------------- @@ -5418,6 +6080,14 @@ } if (type != NULL) { *type = TCL_RELEASE_LEVEL; } } - + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ + Index: generic/tclBinary.c ================================================================== --- generic/tclBinary.c +++ generic/tclBinary.c @@ -8,11 +8,11 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclBinary.c,v 1.13 2003/02/21 21:54:11 dkf Exp $ + * RCS: @(#) $Id: tclBinary.c,v 1.13.2.4 2005/10/23 22:01:29 msofer Exp $ */ #include "tclInt.h" #include "tclPort.h" #include @@ -51,19 +51,22 @@ static void DupByteArrayInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)); static int FormatNumber _ANSI_ARGS_((Tcl_Interp *interp, int type, Tcl_Obj *src, unsigned char **cursorPtr)); +static void CopyNumber _ANSI_ARGS_((CONST VOID *from, VOID *to, + unsigned int length)); static void FreeByteArrayInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr)); static int GetFormatSpec _ANSI_ARGS_((char **formatPtr, char *cmdPtr, int *countPtr)); static Tcl_Obj * ScanNumber _ANSI_ARGS_((unsigned char *buffer, int type, Tcl_HashTable **numberCachePtr)); static int SetByteArrayFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static void UpdateStringOfByteArray _ANSI_ARGS_((Tcl_Obj *listPtr)); - +static void DeleteScanNumberCache _ANSI_ARGS_(( + Tcl_HashTable *numberCachePtr)); /* * The following object type represents an array of bytes. An array of * bytes is not equivalent to an internationalized string. Conceptually, a * string is an array of 16-bit quantities organized as a sequence of properly @@ -749,11 +752,11 @@ } break; } default: { errorString = str; - goto badfield; + goto badField; } } } if (offset > length) { length = offset; @@ -1048,13 +1051,11 @@ case 'a': case 'A': { unsigned char *src; if (arg >= objc) { - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } + DeleteScanNumberCache(numberCachePtr); goto badIndex; } if (count == BINARY_ALL) { count = length - offset; } else { @@ -1080,18 +1081,17 @@ } size--; } } valuePtr = Tcl_NewByteArrayObj(src, size); + Tcl_IncrRefCount(valuePtr); resultPtr = Tcl_ObjSetVar2(interp, objv[arg], NULL, valuePtr, TCL_LEAVE_ERR_MSG); + Tcl_DecrRefCount(valuePtr); arg++; if (resultPtr == NULL) { - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } - Tcl_DecrRefCount(valuePtr); /* unneeded */ + DeleteScanNumberCache(numberCachePtr); return TCL_ERROR; } offset += count; break; } @@ -1099,13 +1099,11 @@ case 'B': { unsigned char *src; char *dest; if (arg >= objc) { - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } + DeleteScanNumberCache(numberCachePtr); goto badIndex; } if (count == BINARY_ALL) { count = (length - offset) * 8; } else { @@ -1138,19 +1136,18 @@ value = *src++; } *dest++ = (char) ((value & 0x80) ? '1' : '0'); } } - + + Tcl_IncrRefCount(valuePtr); resultPtr = Tcl_ObjSetVar2(interp, objv[arg], NULL, valuePtr, TCL_LEAVE_ERR_MSG); + Tcl_DecrRefCount(valuePtr); arg++; if (resultPtr == NULL) { - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } - Tcl_DecrRefCount(valuePtr); /* unneeded */ + DeleteScanNumberCache(numberCachePtr); return TCL_ERROR; } offset += (count + 7 ) / 8; break; } @@ -1160,13 +1157,11 @@ unsigned char *src; int i; static char hexdigit[] = "0123456789abcdef"; if (arg >= objc) { - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } + DeleteScanNumberCache(numberCachePtr); goto badIndex; } if (count == BINARY_ALL) { count = (length - offset)*2; } else { @@ -1200,18 +1195,17 @@ } *dest++ = hexdigit[(value >> 4) & 0xf]; } } + Tcl_IncrRefCount(valuePtr); resultPtr = Tcl_ObjSetVar2(interp, objv[arg], NULL, valuePtr, TCL_LEAVE_ERR_MSG); + Tcl_DecrRefCount(valuePtr); arg++; if (resultPtr == NULL) { - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } - Tcl_DecrRefCount(valuePtr); /* unneeded */ + DeleteScanNumberCache(numberCachePtr); return TCL_ERROR; } offset += (count + 1) / 2; break; } @@ -1244,13 +1238,11 @@ size = sizeof(double); /* fall through */ scanNumber: if (arg >= objc) { - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } + DeleteScanNumberCache(numberCachePtr); goto badIndex; } if (count == BINARY_NOCOUNT) { if ((length - offset) < size) { goto done; @@ -1275,18 +1267,17 @@ elementPtr); } offset += count*size; } + Tcl_IncrRefCount(valuePtr); resultPtr = Tcl_ObjSetVar2(interp, objv[arg], NULL, valuePtr, TCL_LEAVE_ERR_MSG); + Tcl_DecrRefCount(valuePtr); arg++; if (resultPtr == NULL) { - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } - Tcl_DecrRefCount(valuePtr); /* unneeded */ + DeleteScanNumberCache(numberCachePtr); return TCL_ERROR; } break; } case 'x': { @@ -1312,13 +1303,11 @@ } break; } case '@': { if (count == BINARY_NOCOUNT) { - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } + DeleteScanNumberCache(numberCachePtr); goto badCount; } if ((count == BINARY_ALL) || (count > length)) { offset = length; } else { @@ -1325,15 +1314,13 @@ offset = count; } break; } default: { - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } + DeleteScanNumberCache(numberCachePtr); errorString = str; - goto badfield; + goto badField; } } } /* @@ -1341,13 +1328,11 @@ */ done: Tcl_ResetResult(interp); Tcl_SetLongObj(Tcl_GetObjResult(interp), arg - 4); - if (numberCachePtr != NULL) { - Tcl_DeleteHashTable(numberCachePtr); - } + DeleteScanNumberCache(numberCachePtr); break; } } return TCL_OK; @@ -1363,11 +1348,12 @@ badIndex: errorString = "not enough arguments for all format specifiers"; goto error; - badfield: { + badField: + { Tcl_UniChar ch; char buf[TCL_UTF_MAX + 1]; Tcl_UtfToUniChar(errorString, &ch); buf[Tcl_UniCharToUtf(ch, buf)] = '\0'; @@ -1479,11 +1465,15 @@ if (Tcl_GetDoubleFromObj(interp, src, &dvalue) != TCL_OK) { return TCL_ERROR; } if (type == 'd') { - memcpy((VOID *) *cursorPtr, (VOID *) &dvalue, sizeof(double)); + /* + * Can't just memcpy() here. [Bug 1116542] + */ + + CopyNumber(&dvalue, *cursorPtr, sizeof(double)); *cursorPtr += sizeof(double); } else { float fvalue; /* @@ -1555,10 +1545,20 @@ *(*cursorPtr)++ = (unsigned char) value; } return TCL_OK; } } + +/* Ugly workaround for old and broken compiler! */ +static void +CopyNumber(from, to, length) + CONST VOID *from; + VOID *to; + unsigned int length; +{ + memcpy(to, from, length); +} /* *---------------------------------------------------------------------- * * ScanNumber -- @@ -1665,20 +1665,26 @@ * for the rest of the scan. * * Note that anyone just using the 'c' conversion * (for bytes) cannot trigger this. */ - Tcl_DeleteHashTable(tablePtr); + DeleteScanNumberCache(tablePtr); *numberCachePtrPtr = NULL; return Tcl_NewLongObj(value); } else { register Tcl_Obj *objPtr = Tcl_NewLongObj(value); - /* Don't need to fiddle with refcount... */ + + Tcl_IncrRefCount(objPtr); Tcl_SetHashValue(hPtr, (ClientData) objPtr); return objPtr; } } + + /* + * Do not cache wide values; they are already too large to + * use as keys. + */ case 'w': uwvalue = ((Tcl_WideUInt) buffer[0]) | (((Tcl_WideUInt) buffer[1]) << 8) | (((Tcl_WideUInt) buffer[2]) << 16) | (((Tcl_WideUInt) buffer[3]) << 24) @@ -1695,10 +1701,16 @@ | (((Tcl_WideUInt) buffer[3]) << 32) | (((Tcl_WideUInt) buffer[2]) << 40) | (((Tcl_WideUInt) buffer[1]) << 48) | (((Tcl_WideUInt) buffer[0]) << 56); return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue); + + /* + * Do not cache double values; they are already too large + * to use as keys and the values stored are utterly + * incompatible too. + */ case 'f': { float fvalue; memcpy((VOID *) &fvalue, (VOID *) buffer, sizeof(float)); return Tcl_NewDoubleObj(fvalue); } @@ -1708,5 +1720,46 @@ return Tcl_NewDoubleObj(dvalue); } } return NULL; } + +/* + *---------------------------------------------------------------------- + * + * DeleteScanNumberCache -- + * + * Deletes the hash table acting as a scan number cache. + * + * Results: + * None + * + * Side effects: + * Decrements the reference counts of the objects in the cache. + * + *---------------------------------------------------------------------- + */ + +static void +DeleteScanNumberCache(numberCachePtr) + Tcl_HashTable *numberCachePtr; /* Pointer to the hash table, or + * NULL (when the cache has already + * been deleted due to overflow.) */ +{ + Tcl_HashEntry *hEntry; + Tcl_HashSearch search; + + if (numberCachePtr == NULL) { + return; + } + + hEntry = Tcl_FirstHashEntry(numberCachePtr, &search); + while (hEntry != NULL) { + register Tcl_Obj *value = (Tcl_Obj *) Tcl_GetHashValue(hEntry); + + if (value != NULL) { + Tcl_DecrRefCount(value); + } + hEntry = Tcl_NextHashEntry(&search); + } + Tcl_DeleteHashTable(numberCachePtr); +} Index: generic/tclClock.c ================================================================== --- generic/tclClock.c +++ generic/tclClock.c @@ -9,11 +9,11 @@ * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclClock.c,v 1.20 2003/02/01 21:27:55 kennykb Exp $ + * RCS: @(#) $Id: tclClock.c,v 1.20.2.3 2007/04/21 22:42:49 kennykb Exp $ */ #include "tcl.h" #include "tclInt.h" #include "tclPort.h" @@ -27,11 +27,11 @@ /* * Function prototypes for local procedures in this file: */ static int FormatClock _ANSI_ARGS_((Tcl_Interp *interp, - unsigned long clockVal, int useGMT, + Tcl_WideInt clockVal, int useGMT, char *format)); /* *------------------------------------------------------------------------- * @@ -60,11 +60,11 @@ int index; Tcl_Obj *CONST *objPtr; int useGMT = 0; char *format = "%a %b %d %X %Z %Y"; int dummy; - unsigned long baseClock, clockVal; + Tcl_WideInt baseClock, clockVal; long zone; Tcl_Obj *baseObjPtr = NULL; char *scanStr; int n; @@ -126,11 +126,11 @@ Tcl_WrongNumArgs(interp, 2, objv, "clockval ?-format string? ?-gmt boolean?"); return TCL_ERROR; } - if (Tcl_GetLongFromObj(interp, objv[2], (long*) &clockVal) + if (Tcl_GetWideIntFromObj(interp, objv[2], &clockVal) != TCL_OK) { return TCL_ERROR; } objPtr = objv+3; @@ -155,11 +155,11 @@ objc -= 2; } if (objc != 0) { goto wrongFmtArgs; } - return FormatClock(interp, (unsigned long) clockVal, useGMT, + return FormatClock(interp, clockVal, useGMT, format); case COMMAND_SCAN: /* scan */ if ((objc < 3) || (objc > 7)) { wrongScanArgs: @@ -192,37 +192,37 @@ if (objc != 0) { goto wrongScanArgs; } if (baseObjPtr != NULL) { - if (Tcl_GetLongFromObj(interp, baseObjPtr, - (long*) &baseClock) != TCL_OK) { + if (Tcl_GetWideIntFromObj(interp, baseObjPtr, + &baseClock) != TCL_OK) { return TCL_ERROR; } } else { baseClock = TclpGetSeconds(); } if (useGMT) { zone = -50000; /* Force GMT */ } else { - zone = TclpGetTimeZone((unsigned long) baseClock); + zone = TclpGetTimeZone(baseClock); } scanStr = Tcl_GetStringFromObj(objv[2], &dummy); Tcl_MutexLock(&clockMutex); - if (TclGetDate(scanStr, (unsigned long) baseClock, zone, - (unsigned long *) &clockVal) < 0) { + if (TclGetDate(scanStr, baseClock, zone, + &clockVal) < 0) { Tcl_MutexUnlock(&clockMutex); Tcl_AppendStringsToObj(resultPtr, "unable to convert date-time string \"", scanStr, "\"", (char *) NULL); return TCL_ERROR; } Tcl_MutexUnlock(&clockMutex); - Tcl_SetLongObj(resultPtr, (long) clockVal); + Tcl_SetWideIntObj(resultPtr, clockVal); return TCL_OK; case COMMAND_SECONDS: /* seconds */ if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); @@ -253,11 +253,11 @@ */ static int FormatClock(interp, clockVal, useGMT, format) Tcl_Interp *interp; /* Current interpreter. */ - unsigned long clockVal; /* Time in seconds. */ + Tcl_WideInt clockVal; /* Time in seconds. */ int useGMT; /* Boolean */ char *format; /* Format string */ { struct tm *timeDataPtr; Tcl_DString buffer, uniBuffer; @@ -264,12 +264,12 @@ int bufSize; char *p; int result; time_t tclockVal; #if !defined(HAVE_TM_ZONE) && !defined(WIN32) - int savedTimeZone = 0; /* lint. */ - char *savedTZEnv = NULL; /* lint. */ + TIMEZONE_t savedTimeZone = 0; /* lint. */ + char *savedTZEnv = NULL; /* lint. */ #endif #ifdef HAVE_TZSET /* * Some systems forgot to call tzset in localtime, make sure its done. @@ -308,18 +308,18 @@ if (varValue != NULL) { savedTZEnv = strcpy(ckalloc(strlen(varValue) + 1), varValue); } else { savedTZEnv = NULL; } - Tcl_SetVar2(interp, "env", "TZ", "GMT", TCL_GLOBAL_ONLY); + Tcl_SetVar2(interp, "env", "TZ", "GMT0", TCL_GLOBAL_ONLY); savedTimeZone = timezone; timezone = 0; tzset(); } #endif - tclockVal = clockVal; + tclockVal = (time_t) clockVal; timeDataPtr = TclpGetDate((TclpTime_t) &tclockVal, useGMT); /* * Make a guess at the upper limit on the substituted string size * based on the number of percents in the string. Index: generic/tclCmdAH.c ================================================================== --- generic/tclCmdAH.c +++ generic/tclCmdAH.c @@ -9,11 +9,11 @@ * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCmdAH.c,v 1.27 2002/07/02 12:16:05 vincentdarley Exp $ + * RCS: @(#) $Id: tclCmdAH.c,v 1.27.2.16 2006/11/28 22:20:00 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclPort.h" #include @@ -233,27 +233,29 @@ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Obj *varNamePtr = NULL; int result; +#ifdef TCL_TIP280 + Interp* iPtr = (Interp*) interp; +#endif if ((objc != 2) && (objc != 3)) { Tcl_WrongNumArgs(interp, 1, objv, "command ?varName?"); return TCL_ERROR; } - /* - * Save a pointer to the variable name object, if any, in case the - * Tcl_EvalObj reallocates the bytecode interpreter's evaluation - * stack rendering objv invalid. - */ - if (objc == 3) { varNamePtr = objv[2]; } +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[1], 0); +#else + /* TIP #280. Make invoking context available to caught script */ + result = TclEvalObjEx(interp, objv[1], 0, iPtr->cmdFramePtr,1); +#endif if (objc == 3) { if (Tcl_ObjSetVar2(interp, varNamePtr, NULL, Tcl_GetObjResult(interp), 0) == NULL) { Tcl_ResetResult(interp); @@ -444,28 +446,25 @@ } switch ((enum options) index) { case ENC_CONVERTTO: case ENC_CONVERTFROM: { - char *name; Tcl_Obj *data; if (objc == 3) { - name = NULL; + encoding = Tcl_GetEncoding(interp, NULL); data = objv[2]; } else if (objc == 4) { - name = Tcl_GetString(objv[2]); + if (TclGetEncodingFromObj(interp, objv[2], &encoding) + != TCL_OK) { + return TCL_ERROR; + } data = objv[3]; } else { Tcl_WrongNumArgs(interp, 2, objv, "?encoding? data"); return TCL_ERROR; } - encoding = Tcl_GetEncoding(interp, name); - if (!encoding) { - return TCL_ERROR; - } - if ((enum options) index == ENC_CONVERTFROM) { /* * Treat the string as binary data. */ @@ -557,11 +556,11 @@ return TCL_ERROR; } if (objc >= 3) { /* process the optional info argument */ info = Tcl_GetStringFromObj(objv[2], &infoLen); - if (*info != 0) { + if (infoLen > 0) { Tcl_AddObjErrorInfo(interp, info, infoLen); iPtr->flags |= ERR_ALREADY_LOGGED; } } @@ -599,26 +598,40 @@ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int result; register Tcl_Obj *objPtr; +#ifdef TCL_TIP280 + Interp* iPtr = (Interp*) interp; +#endif if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "arg ?arg ...?"); return TCL_ERROR; } if (objc == 2) { +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[1], TCL_EVAL_DIRECT); +#else + /* TIP #280. Make invoking context available to eval'd script */ + result = TclEvalObjEx(interp, objv[1], TCL_EVAL_DIRECT, + iPtr->cmdFramePtr,1); +#endif } else { /* * More than one argument: concatenate them together with spaces * between, then evaluate the result. Tcl_EvalObjEx will delete * the object when it decrements its refcount after eval'ing it. */ objPtr = Tcl_ConcatObj(objc-1, objv+1); +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_DIRECT); +#else + /* TIP #280. Make invoking context available to eval'd script */ + result = TclEvalObjEx(interp, objPtr, TCL_EVAL_DIRECT, NULL, 0); +#endif } if (result == TCL_ERROR) { char msg[32 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"eval\" body line %d)", interp->errorLine); @@ -761,11 +774,11 @@ * See the user documentation for details on what it does. * PLEASE NOTE THAT THIS FAILS WITH FILENAMES AND PATHS WITH * EMBEDDED NULLS, WHICH COULD THEORETICALLY HAPPEN ON A MAC. * With the object-based Tcl_FS APIs, the above NOTE may no * longer be true. In any case this assertion should be tested. - * + * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. @@ -799,20 +812,20 @@ "stat", "system", "tail", "type", "volumes", "writable", (char *) NULL }; enum options { - FILE_ATIME, FILE_ATTRIBUTES, FILE_CHANNELS, FILE_COPY, - FILE_DELETE, - FILE_DIRNAME, FILE_EXECUTABLE, FILE_EXISTS, FILE_EXTENSION, - FILE_ISDIRECTORY, FILE_ISFILE, FILE_JOIN, FILE_LINK, - FILE_LSTAT, FILE_MTIME, FILE_MKDIR, FILE_NATIVENAME, - FILE_NORMALIZE, FILE_OWNED, - FILE_PATHTYPE, FILE_READABLE, FILE_READLINK, FILE_RENAME, - FILE_ROOTNAME, FILE_SEPARATOR, FILE_SIZE, FILE_SPLIT, - FILE_STAT, FILE_SYSTEM, - FILE_TAIL, FILE_TYPE, FILE_VOLUMES, FILE_WRITABLE + FCMD_ATIME, FCMD_ATTRIBUTES, FCMD_CHANNELS, FCMD_COPY, + FCMD_DELETE, + FCMD_DIRNAME, FCMD_EXECUTABLE, FCMD_EXISTS, FCMD_EXTENSION, + FCMD_ISDIRECTORY, FCMD_ISFILE, FCMD_JOIN, FCMD_LINK, + FCMD_LSTAT, FCMD_MTIME, FCMD_MKDIR, FCMD_NATIVENAME, + FCMD_NORMALIZE, FCMD_OWNED, + FCMD_PATHTYPE, FCMD_READABLE, FCMD_READLINK, FCMD_RENAME, + FCMD_ROOTNAME, FCMD_SEPARATOR, FCMD_SIZE, FCMD_SPLIT, + FCMD_STAT, FCMD_SYSTEM, + FCMD_TAIL, FCMD_TYPE, FCMD_VOLUMES, FCMD_WRITABLE }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); return TCL_ERROR; @@ -821,11 +834,11 @@ &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { - case FILE_ATIME: { + case FCMD_ATIME: { Tcl_StatBuf buf; struct utimbuf tval; if ((objc < 3) || (objc > 4)) { Tcl_WrongNumArgs(interp, 2, objv, "name ?time?"); @@ -833,15 +846,16 @@ } if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } if (objc == 4) { - if (Tcl_GetLongFromObj(interp, objv[3], - (long*)(&buf.st_atime)) != TCL_OK) { + long newTime; + + if (Tcl_GetLongFromObj(interp, objv[3], &newTime) != TCL_OK) { return TCL_ERROR; } - tval.actime = buf.st_atime; + tval.actime = newTime; tval.modtime = buf.st_mtime; if (Tcl_FSUtime(objv[2], &tval) != 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not set access time for file \"", Tcl_GetString(objv[2]), "\": ", @@ -859,28 +873,28 @@ } } Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) buf.st_atime); return TCL_OK; } - case FILE_ATTRIBUTES: { + case FCMD_ATTRIBUTES: { return TclFileAttrsCmd(interp, objc, objv); } - case FILE_CHANNELS: { + case FCMD_CHANNELS: { if ((objc < 2) || (objc > 3)) { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } return Tcl_GetChannelNamesEx(interp, ((objc == 2) ? NULL : Tcl_GetString(objv[2]))); } - case FILE_COPY: { + case FCMD_COPY: { return TclFileCopyCmd(interp, objc, objv); } - case FILE_DELETE: { + case FCMD_DELETE: { return TclFileDeleteCmd(interp, objc, objv); } - case FILE_DIRNAME: { + case FCMD_DIRNAME: { Tcl_Obj *dirPtr; if (objc != 3) { goto only3Args; } dirPtr = TclFileDirname(interp, objv[2]); @@ -890,23 +904,23 @@ Tcl_SetObjResult(interp, dirPtr); Tcl_DecrRefCount(dirPtr); return TCL_OK; } } - case FILE_EXECUTABLE: { + case FCMD_EXECUTABLE: { if (objc != 3) { goto only3Args; } return CheckAccess(interp, objv[2], X_OK); } - case FILE_EXISTS: { + case FCMD_EXISTS: { if (objc != 3) { goto only3Args; } return CheckAccess(interp, objv[2], F_OK); } - case FILE_EXTENSION: { + case FCMD_EXTENSION: { char *fileName, *extension; if (objc != 3) { goto only3Args; } fileName = Tcl_GetString(objv[2]); @@ -914,11 +928,11 @@ if (extension != NULL) { Tcl_SetStringObj(Tcl_GetObjResult(interp), extension, -1); } return TCL_OK; } - case FILE_ISDIRECTORY: { + case FCMD_ISDIRECTORY: { int value; Tcl_StatBuf buf; if (objc != 3) { goto only3Args; @@ -928,11 +942,11 @@ value = S_ISDIR(buf.st_mode); } Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value); return TCL_OK; } - case FILE_ISFILE: { + case FCMD_ISFILE: { int value; Tcl_StatBuf buf; if (objc != 3) { goto only3Args; @@ -942,11 +956,11 @@ value = S_ISREG(buf.st_mode); } Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value); return TCL_OK; } - case FILE_JOIN: { + case FCMD_JOIN: { Tcl_Obj *resObj; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "name ?name ...?"); return TCL_ERROR; @@ -953,11 +967,11 @@ } resObj = Tcl_FSJoinToPath(NULL, objc - 2, objv + 2); Tcl_SetObjResult(interp, resObj); return TCL_OK; } - case FILE_LINK: { + case FCMD_LINK: { Tcl_Obj *contents; int index; if (objc < 3 || objc > 5) { Tcl_WrongNumArgs(interp, 2, objv, @@ -1043,11 +1057,11 @@ */ Tcl_DecrRefCount(contents); } return TCL_OK; } - case FILE_LSTAT: { + case FCMD_LSTAT: { char *varName; Tcl_StatBuf buf; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "name varName"); @@ -1057,11 +1071,11 @@ return TCL_ERROR; } varName = Tcl_GetString(objv[3]); return StoreStatData(interp, varName, &buf); } - case FILE_MTIME: { + case FCMD_MTIME: { Tcl_StatBuf buf; struct utimbuf tval; if ((objc < 3) || (objc > 4)) { Tcl_WrongNumArgs(interp, 2, objv, "name ?time?"); @@ -1069,16 +1083,17 @@ } if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } if (objc == 4) { - if (Tcl_GetLongFromObj(interp, objv[3], - (long*)(&buf.st_mtime)) != TCL_OK) { + long newTime; + + if (Tcl_GetLongFromObj(interp, objv[3], &newTime) != TCL_OK) { return TCL_ERROR; } tval.actime = buf.st_atime; - tval.modtime = buf.st_mtime; + tval.modtime = newTime; if (Tcl_FSUtime(objv[2], &tval) != 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not set modification time for file \"", Tcl_GetString(objv[2]), "\": ", Tcl_PosixError(interp), (char *) NULL); @@ -1095,18 +1110,18 @@ } } Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) buf.st_mtime); return TCL_OK; } - case FILE_MKDIR: { + case FCMD_MKDIR: { if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "name ?name ...?"); return TCL_ERROR; } return TclFileMakeDirsCmd(interp, objc, objv); } - case FILE_NATIVENAME: { + case FCMD_NATIVENAME: { CONST char *fileName; Tcl_DString ds; if (objc != 3) { goto only3Args; @@ -1119,23 +1134,26 @@ Tcl_SetStringObj(Tcl_GetObjResult(interp), fileName, Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); return TCL_OK; } - case FILE_NORMALIZE: { + case FCMD_NORMALIZE: { Tcl_Obj *fileName; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "filename"); return TCL_ERROR; } fileName = Tcl_FSGetNormalizedPath(interp, objv[2]); + if (fileName == NULL) { + return TCL_ERROR; + } Tcl_SetObjResult(interp, fileName); return TCL_OK; } - case FILE_OWNED: { + case FCMD_OWNED: { int value; Tcl_StatBuf buf; if (objc != 3) { goto only3Args; @@ -1154,11 +1172,11 @@ #endif } Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value); return TCL_OK; } - case FILE_PATHTYPE: { + case FCMD_PATHTYPE: { if (objc != 3) { goto only3Args; } switch (Tcl_FSGetPathType(objv[2])) { case TCL_PATH_ABSOLUTE: @@ -1172,17 +1190,17 @@ "volumerelative", -1); break; } return TCL_OK; } - case FILE_READABLE: { + case FCMD_READABLE: { if (objc != 3) { goto only3Args; } return CheckAccess(interp, objv[2], R_OK); } - case FILE_READLINK: { + case FCMD_READLINK: { Tcl_Obj *contents; if (objc != 3) { goto only3Args; } @@ -1201,14 +1219,14 @@ } Tcl_SetObjResult(interp, contents); Tcl_DecrRefCount(contents); return TCL_OK; } - case FILE_RENAME: { + case FCMD_RENAME: { return TclFileRenameCmd(interp, objc, objv); } - case FILE_ROOTNAME: { + case FCMD_ROOTNAME: { int length; char *fileName, *extension; if (objc != 3) { goto only3Args; @@ -1221,11 +1239,11 @@ Tcl_SetStringObj(Tcl_GetObjResult(interp), fileName, (int) (length - strlen(extension))); } return TCL_OK; } - case FILE_SEPARATOR: { + case FCMD_SEPARATOR: { if ((objc < 2) || (objc > 3)) { Tcl_WrongNumArgs(interp, 2, objv, "?name?"); return TCL_ERROR; } if (objc == 2) { @@ -1252,11 +1270,11 @@ return TCL_ERROR; } } return TCL_OK; } - case FILE_SIZE: { + case FCMD_SIZE: { Tcl_StatBuf buf; if (objc != 3) { goto only3Args; } @@ -1265,18 +1283,18 @@ } Tcl_SetWideIntObj(Tcl_GetObjResult(interp), (Tcl_WideInt) buf.st_size); return TCL_OK; } - case FILE_SPLIT: { + case FCMD_SPLIT: { if (objc != 3) { goto only3Args; } Tcl_SetObjResult(interp, Tcl_FSSplitPath(objv[2], NULL)); return TCL_OK; } - case FILE_STAT: { + case FCMD_STAT: { char *varName; Tcl_StatBuf buf; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "stat name varName"); @@ -1286,11 +1304,11 @@ return TCL_ERROR; } varName = Tcl_GetString(objv[3]); return StoreStatData(interp, varName, &buf); } - case FILE_SYSTEM: { + case FCMD_SYSTEM: { Tcl_Obj* fsInfo; if (objc != 3) { goto only3Args; } fsInfo = Tcl_FSFileSystemInfo(objv[2]); @@ -1301,11 +1319,11 @@ Tcl_SetObjResult(interp, Tcl_NewStringObj("Unrecognised path",-1)); return TCL_ERROR; } } - case FILE_TAIL: { + case FCMD_TAIL: { int splitElements; Tcl_Obj *splitPtr; if (objc != 3) { goto only3Args; @@ -1342,11 +1360,11 @@ } } Tcl_DecrRefCount(splitPtr); return TCL_OK; } - case FILE_TYPE: { + case FCMD_TYPE: { Tcl_StatBuf buf; if (objc != 3) { goto only3Args; } @@ -1355,19 +1373,19 @@ } Tcl_SetStringObj(Tcl_GetObjResult(interp), GetTypeFromMode((unsigned short) buf.st_mode), -1); return TCL_OK; } - case FILE_VOLUMES: { + case FCMD_VOLUMES: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_FSListVolumes()); return TCL_OK; } - case FILE_WRITABLE: { + case FCMD_WRITABLE: { if (objc != 3) { goto only3Args; } return CheckAccess(interp, objv[2], W_OK); } @@ -1609,17 +1627,25 @@ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int result, value; +#ifdef TCL_TIP280 + Interp* iPtr = (Interp*) interp; +#endif if (objc != 5) { Tcl_WrongNumArgs(interp, 1, objv, "start test next command"); return TCL_ERROR; } +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[1], 0); +#else + /* TIP #280. Make invoking context available to initial script */ + result = TclEvalObjEx(interp, objv[1], 0, iPtr->cmdFramePtr,1); +#endif if (result != TCL_OK) { if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (\"for\" initial command)"); } return result; @@ -1637,21 +1663,31 @@ return result; } if (!value) { break; } +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[4], 0); +#else + /* TIP #280. Make invoking context available to loop body */ + result = TclEvalObjEx(interp, objv[4], 0, iPtr->cmdFramePtr,4); +#endif if ((result != TCL_OK) && (result != TCL_CONTINUE)) { if (result == TCL_ERROR) { char msg[32 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"for\" body line %d)",interp->errorLine); Tcl_AddErrorInfo(interp, msg); } break; } +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[3], 0); +#else + /* TIP #280. Make invoking context available to next script */ + result = TclEvalObjEx(interp, objv[3], 0, iPtr->cmdFramePtr,3); +#endif if (result == TCL_BREAK) { break; } else if (result != TCL_OK) { if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (\"for\" loop-end command)"); @@ -1721,10 +1757,13 @@ int *index = indexArray; /* Array of value list indices */ int *varcList = varcListArray; /* # loop variables per list */ Tcl_Obj ***varvList = varvListArray; /* Array of var name lists */ int *argcList = argcListArray; /* Array of value list sizes */ Tcl_Obj ***argvList = argvListArray; /* Array of value lists */ +#ifdef TCL_TIP280 + Interp* iPtr = (Interp*) interp; +#endif if (objc < 4 || (objc%2 != 0)) { Tcl_WrongNumArgs(interp, 1, objv, "varList list ?varList list ...? command"); return TCL_ERROR; @@ -1828,24 +1867,21 @@ } for (v = 0; v < varcList[i]; v++) { int k = index[i]++; Tcl_Obj *valuePtr, *varValuePtr; - int isEmptyObj = 0; if (k < argcList[i]) { valuePtr = argvList[i][k]; } else { valuePtr = Tcl_NewObj(); /* empty string */ - isEmptyObj = 1; } + Tcl_IncrRefCount(valuePtr); varValuePtr = Tcl_ObjSetVar2(interp, varvList[i][v], NULL, valuePtr, 0); + Tcl_DecrRefCount(valuePtr); if (varValuePtr == NULL) { - if (isEmptyObj) { - Tcl_DecrRefCount(valuePtr); - } Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "couldn't set loop variable: \"", Tcl_GetString(varvList[i][v]), "\"", (char *) NULL); result = TCL_ERROR; @@ -1853,11 +1889,16 @@ } } } +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, bodyPtr, 0); +#else + /* TIP #280. Make invoking context available to loop body */ + result = TclEvalObjEx(interp, bodyPtr, 0, iPtr->cmdFramePtr,objc-1); +#endif if (result != TCL_OK) { if (result == TCL_CONTINUE) { result = TCL_OK; } else if (result == TCL_BREAK) { result = TCL_OK; @@ -1935,14 +1976,12 @@ * it's a one-word integer or char value */ char *ptrValue = NULL; /* Used to hold value to pass to sprintf, if * it's a one-word value. */ double doubleValue; /* Used to hold value to pass to sprintf if * it's a double value. */ -#ifndef TCL_WIDE_INT_IS_LONG Tcl_WideInt wideValue; /* Used to hold value to pass to sprintf if * it's a 'long long' value. */ -#endif /* TCL_WIDE_INT_IS_LONG */ int whichValue; /* Indicates which of intValue, ptrValue, * or doubleValue has the value to pass to * sprintf, according to the following * definitions: */ # define INT_VALUE 0 @@ -1953,16 +1992,16 @@ # define WIDE_VALUE 5 # define MAX_FLOAT_SIZE 320 Tcl_Obj *resultPtr; /* Where result is stored finally. */ char staticBuf[MAX_FLOAT_SIZE + 1]; - /* A static buffer to copy the format results + /* A static buffer to copy the format results * into */ char *dst = staticBuf; /* The buffer that sprintf writes into each * time the format processes a specifier */ int dstSize = MAX_FLOAT_SIZE; - /* The size of the dst buffer */ + /* The size of the dst buffer */ int noPercent; /* Special case for speed: indicates there's * no field specifier, just a string to copy.*/ int objIndex; /* Index of argument to substitute next. */ int gotXpg = 0; /* Non-zero means that an XPG3 %n$-style * specifier has been seen. */ @@ -1977,13 +2016,11 @@ * been seen in the current field. */ int gotPrecision; /* Non-zero indicates that a precision has * been set for the current field. */ int gotZero; /* Non-zero indicates that a zero flag has * been seen in the current field. */ -#ifndef TCL_WIDE_INT_IS_LONG int useWide; /* Value to be printed is Tcl_WideInt. */ -#endif /* TCL_WIDE_INT_IS_LONG */ /* * This procedure is a bit nasty. The goal is to use sprintf to * do most of the dirty work. There are several problems: * 1. this procedure can't trust its arguments. @@ -1996,11 +2033,11 @@ * So, what happens here is to scan the format string one % group * at a time, making many individual calls to sprintf. */ if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "formatString ?arg arg ...?"); + Tcl_WrongNumArgs(interp, 1, objv, "formatString ?arg arg ...?"); return TCL_ERROR; } format = Tcl_GetStringFromObj(objv[1], &formatLen); endPtr = format + formatLen; @@ -2010,13 +2047,11 @@ while (format < endPtr) { register char *newPtr = newFormat; width = precision = noPercent = useShort = 0; gotZero = gotMinus = gotPrecision = 0; -#ifndef TCL_WIDE_INT_IS_LONG useWide = 0; -#endif /* TCL_WIDE_INT_IS_LONG */ whichValue = PTR_VALUE; /* * Get rid of any characters before the next field specifier. */ @@ -2156,15 +2191,25 @@ while (*newPtr != 0) { newPtr++; } } if (*format == 'l') { -#ifndef TCL_WIDE_INT_IS_LONG useWide = 1; - strcpy(newPtr, TCL_LL_MODIFIER); - newPtr += TCL_LL_MODIFIER_SIZE; -#endif /* TCL_WIDE_INT_IS_LONG */ + /* + * Only add a 'll' modifier for integer values as it makes + * some libc's go into spasm otherwise. [Bug #702622] + */ + switch (format[1]) { + case 'i': + case 'd': + case 'o': + case 'u': + case 'x': + case 'X': + strcpy(newPtr, TCL_LL_MODIFIER); + newPtr += TCL_LL_MODIFIER_SIZE; + } format++; } else if (*format == 'h') { useShort = 1; *newPtr = 'h'; newPtr++; @@ -2175,99 +2220,111 @@ *newPtr = 0; if (objIndex >= objc) { goto badIndex; } switch (*format) { - case 'i': - newPtr[-1] = 'd'; - case 'd': - case 'o': - case 'u': - case 'x': - case 'X': -#ifndef TCL_WIDE_INT_IS_LONG - if (useWide) { - if (Tcl_GetWideIntFromObj(interp, /* INTL: Tcl source. */ - objv[objIndex], &wideValue) != TCL_OK) { - goto fmtError; - } - whichValue = WIDE_VALUE; - size = 40 + precision; - break; - } -#endif /* TCL_WIDE_INT_IS_LONG */ - if (Tcl_GetLongFromObj(interp, /* INTL: Tcl source. */ - objv[objIndex], &intValue) != TCL_OK) { - goto fmtError; - } -#if (LONG_MAX > INT_MAX) - /* - * Add the 'l' for long format type because we are on - * an LP64 archtecture and we are really going to pass - * a long argument to sprintf. + case 'i': + newPtr[-1] = 'd'; + case 'd': + case 'o': + case 'u': + case 'x': + case 'X': + if (useWide) { + if (Tcl_GetWideIntFromObj(interp, /* INTL: Tcl source. */ + objv[objIndex], &wideValue) != TCL_OK) { + goto fmtError; + } + whichValue = WIDE_VALUE; + size = 40 + precision; + break; + } + if (Tcl_GetLongFromObj(interp, /* INTL: Tcl source. */ + objv[objIndex], &intValue) != TCL_OK) { + if (Tcl_GetWideIntFromObj(interp, /* INTL: Tcl source. */ + objv[objIndex], &wideValue) != TCL_OK) { + goto fmtError; + } + intValue = Tcl_WideAsLong(wideValue); + } + +#if (LONG_MAX > INT_MAX) + if (!useShort) { + /* + * Add the 'l' for long format type because we are on an + * LP64 archtecture and we are really going to pass a long + * argument to sprintf. + * + * Do not add this if we're going to pass in a short (i.e. + * if we've got an 'h' modifier already in the string); some + * libc implementations of sprintf() do not like it at all. + * [Bug 1154163] */ newPtr++; *newPtr = 0; newPtr[-1] = newPtr[-2]; newPtr[-2] = 'l'; -#endif /* LONG_MAX > INT_MAX */ - whichValue = INT_VALUE; - size = 40 + precision; - break; - case 's': - /* - * Compute the length of the string in characters and add - * any additional space required by the field width. All of - * the extra characters will be spaces, so one byte per - * character is adequate. - */ - - whichValue = STRING_VALUE; - ptrValue = Tcl_GetStringFromObj(objv[objIndex], &size); - stringLen = Tcl_NumUtfChars(ptrValue, size); - if (gotPrecision && (precision < stringLen)) { - stringLen = precision; - } - size = Tcl_UtfAtIndex(ptrValue, stringLen) - ptrValue; - if (width > stringLen) { - size += (width - stringLen); - } - break; - case 'c': - if (Tcl_GetLongFromObj(interp, /* INTL: Tcl source. */ - objv[objIndex], &intValue) != TCL_OK) { - goto fmtError; - } - whichValue = CHAR_VALUE; - size = width + TCL_UTF_MAX; - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - if (Tcl_GetDoubleFromObj(interp, /* INTL: Tcl source. */ - objv[objIndex], &doubleValue) != TCL_OK) { - goto fmtError; - } - whichValue = DOUBLE_VALUE; - size = MAX_FLOAT_SIZE; - if (precision > 10) { - size += precision; - } - break; - case 0: - Tcl_SetResult(interp, - "format string ended in middle of field specifier", - TCL_STATIC); - goto fmtError; - default: { - char buf[40]; - sprintf(buf, "bad field specifier \"%c\"", *format); - Tcl_SetResult(interp, buf, TCL_VOLATILE); - goto fmtError; - } + } +#endif /* LONG_MAX > INT_MAX */ + whichValue = INT_VALUE; + size = 40 + precision; + break; + case 's': + /* + * Compute the length of the string in characters and add + * any additional space required by the field width. All + * of the extra characters will be spaces, so one byte per + * character is adequate. + */ + + whichValue = STRING_VALUE; + ptrValue = Tcl_GetStringFromObj(objv[objIndex], &size); + stringLen = Tcl_NumUtfChars(ptrValue, size); + if (gotPrecision && (precision < stringLen)) { + stringLen = precision; + } + size = Tcl_UtfAtIndex(ptrValue, stringLen) - ptrValue; + if (width > stringLen) { + size += (width - stringLen); + } + break; + case 'c': + if (Tcl_GetLongFromObj(interp, /* INTL: Tcl source. */ + objv[objIndex], &intValue) != TCL_OK) { + goto fmtError; + } + whichValue = CHAR_VALUE; + size = width + TCL_UTF_MAX; + break; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + if (Tcl_GetDoubleFromObj(interp, /* INTL: Tcl source. */ + objv[objIndex], &doubleValue) != TCL_OK) { + goto fmtError; + } + whichValue = DOUBLE_VALUE; + size = MAX_FLOAT_SIZE; + if (precision > 10) { + size += precision; + } + break; + case 0: + Tcl_SetResult(interp, + "format string ended in middle of field specifier", + TCL_STATIC); + goto fmtError; + default: + { + char buf[40]; + + sprintf(buf, "bad field specifier \"%c\"", *format); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + goto fmtError; + } } objIndex++; format++; /* @@ -2288,106 +2345,109 @@ } dst = (char *) ckalloc((unsigned) (size + 1)); dstSize = size; } switch (whichValue) { - case DOUBLE_VALUE: { - sprintf(dst, newFormat, doubleValue); /* INTL: user locale. */ - break; - } -#ifndef TCL_WIDE_INT_IS_LONG - case WIDE_VALUE: { - sprintf(dst, newFormat, wideValue); - break; - } -#endif /* TCL_WIDE_INT_IS_LONG */ - case INT_VALUE: { - if (useShort) { - sprintf(dst, newFormat, (short) intValue); - } else { - sprintf(dst, newFormat, intValue); - } - break; - } - case CHAR_VALUE: { - char *ptr; - char padChar = (gotZero ? '0' : ' '); - ptr = dst; - if (!gotMinus) { - for ( ; --width > 0; ptr++) { - *ptr = padChar; - } - } - ptr += Tcl_UniCharToUtf(intValue, ptr); - for ( ; --width > 0; ptr++) { - *ptr = padChar; - } - *ptr = '\0'; - break; - } - case STRING_VALUE: { - char *ptr; - char padChar = (gotZero ? '0' : ' '); - int pad; - - ptr = dst; - if (width > stringLen) { - pad = width - stringLen; - } else { - pad = 0; - } - - if (!gotMinus) { - while (pad > 0) { - *ptr++ = padChar; - pad--; - } - } - - size = Tcl_UtfAtIndex(ptrValue, stringLen) - ptrValue; - if (size) { - memcpy(ptr, ptrValue, (size_t) size); - ptr += size; - } - while (pad > 0) { - *ptr++ = padChar; - pad--; - } - *ptr = '\0'; - break; - } - default: { - sprintf(dst, newFormat, ptrValue); - break; - } + case DOUBLE_VALUE: + sprintf(dst, newFormat, doubleValue); /* INTL: user locale. */ + break; + case WIDE_VALUE: + sprintf(dst, newFormat, wideValue); + break; + case INT_VALUE: + if (useShort) { + sprintf(dst, newFormat, (short) intValue); + } else { + sprintf(dst, newFormat, intValue); + } + break; + case CHAR_VALUE: { + char *ptr; + char padChar = (gotZero ? '0' : ' '); + ptr = dst; + if (!gotMinus) { + for ( ; --width > 0; ptr++) { + *ptr = padChar; + } + } + ptr += Tcl_UniCharToUtf(intValue, ptr); + for ( ; --width > 0; ptr++) { + *ptr = padChar; + } + *ptr = '\0'; + break; + } + case STRING_VALUE: { + char *ptr; + char padChar = (gotZero ? '0' : ' '); + int pad; + + ptr = dst; + if (width > stringLen) { + pad = width - stringLen; + } else { + pad = 0; + } + + if (!gotMinus) { + while (pad > 0) { + *ptr++ = padChar; + pad--; + } + } + + size = Tcl_UtfAtIndex(ptrValue, stringLen) - ptrValue; + if (size) { + memcpy(ptr, ptrValue, (size_t) size); + ptr += size; + } + while (pad > 0) { + *ptr++ = padChar; + pad--; + } + *ptr = '\0'; + break; + } + default: + sprintf(dst, newFormat, ptrValue); + break; } Tcl_AppendToObj(resultPtr, dst, -1); } } Tcl_SetObjResult(interp, resultPtr); - if(dst != staticBuf) { - ckfree(dst); + if (dst != staticBuf) { + ckfree(dst); } return TCL_OK; mixedXPG: Tcl_SetResult(interp, - "cannot mix \"%\" and \"%n$\" conversion specifiers", TCL_STATIC); + "cannot mix \"%\" and \"%n$\" conversion specifiers", TCL_STATIC); goto fmtError; badIndex: if (gotXpg) { - Tcl_SetResult(interp, - "\"%n$\" argument index out of range", TCL_STATIC); + Tcl_SetResult(interp, + "\"%n$\" argument index out of range", TCL_STATIC); } else { - Tcl_SetResult(interp, - "not enough arguments for all format specifiers", TCL_STATIC); + Tcl_SetResult(interp, + "not enough arguments for all format specifiers", TCL_STATIC); } fmtError: - if(dst != staticBuf) { - ckfree(dst); + if (dst != staticBuf) { + ckfree(dst); } Tcl_DecrRefCount(resultPtr); return TCL_ERROR; } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ + Index: generic/tclCmdIL.c ================================================================== --- generic/tclCmdIL.c +++ generic/tclCmdIL.c @@ -13,11 +13,11 @@ * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCmdIL.c,v 1.47 2003/02/27 16:01:55 dkf Exp $ + * RCS: @(#) $Id: tclCmdIL.c,v 1.47.2.11 2007/03/10 14:57:38 dkf Exp $ */ #include "tclInt.h" #include "tclPort.h" #include "tclRegexp.h" @@ -107,10 +107,16 @@ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoExistsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); +#ifdef TCL_TIP280 +/* TIP #280 - New 'info' subcommand 'frame' */ +static int InfoFrameCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); +#endif static int InfoFunctionsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoGlobalsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, @@ -186,10 +192,13 @@ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int thenScriptIndex = 0; /* then script to be evaled after syntax check */ +#ifdef TCL_TIP280 + Interp* iPtr = (Interp*) interp; +#endif int i, result, value; char *clause; i = 1; while (1) { /* @@ -238,11 +247,17 @@ */ i++; if (i >= objc) { if (thenScriptIndex) { +#ifndef TCL_TIP280 return Tcl_EvalObjEx(interp, objv[thenScriptIndex], 0); +#else + /* TIP #280. Make invoking context available to branch */ + return TclEvalObjEx(interp, objv[thenScriptIndex], 0, + iPtr->cmdFramePtr,thenScriptIndex); +#endif } return TCL_OK; } clause = Tcl_GetString(objv[i]); if ((clause[0] == 'e') && (strcmp(clause, "elseif") == 0)) { @@ -272,13 +287,23 @@ "wrong # args: extra words after \"else\" clause in \"if\" command", (char *) NULL); return TCL_ERROR; } if (thenScriptIndex) { +#ifndef TCL_TIP280 return Tcl_EvalObjEx(interp, objv[thenScriptIndex], 0); +#else + /* TIP #280. Make invoking context available to branch/else */ + return TclEvalObjEx(interp, objv[thenScriptIndex], 0, + iPtr->cmdFramePtr,thenScriptIndex); +#endif } +#ifndef TCL_TIP280 return Tcl_EvalObjEx(interp, objv[i], 0); +#else + return TclEvalObjEx(interp, objv[i], 0, iPtr->cmdFramePtr,i); +#endif } /* *---------------------------------------------------------------------- * @@ -321,25 +346,23 @@ */ if (objc == 2) { incrAmount = 1; } else { -#ifdef TCL_WIDE_INT_IS_LONG if (Tcl_GetLongFromObj(interp, objv[2], &incrAmount) != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (reading increment)"); return TCL_ERROR; } -#else /* * Need to be a bit cautious to ensure that [expr]-like rules * are enforced for interpretation of wide integers, despite * the fact that the underlying API itself is a 'long' only one. */ if (objv[2]->typePtr == &tclIntType) { incrAmount = objv[2]->internalRep.longValue; } else if (objv[2]->typePtr == &tclWideIntType) { - incrAmount = Tcl_WideAsLong(objv[2]->internalRep.wideValue); + TclGetLongFromWide(incrAmount,objv[2]); } else { Tcl_WideInt wide; if (Tcl_GetWideIntFromObj(interp, objv[2], &wide) != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (reading increment)"); @@ -350,11 +373,10 @@ && (wide >= Tcl_LongAsWide(LONG_MIN))) { objv[2]->typePtr = &tclIntType; objv[2]->internalRep.longValue = incrAmount; } } -#endif } /* * Increment the variable's value. */ @@ -398,20 +420,28 @@ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { static CONST char *subCmds[] = { - "args", "body", "cmdcount", "commands", - "complete", "default", "exists", "functions", "globals", - "hostname", "level", "library", "loaded", + "args", "body", "cmdcount", "commands", + "complete", "default", "exists", +#ifdef TCL_TIP280 + "frame", +#endif + "functions", + "globals", "hostname", "level", "library", "loaded", "locals", "nameofexecutable", "patchlevel", "procs", "script", "sharedlibextension", "tclversion", "vars", (char *) NULL}; enum ISubCmdIdx { IArgsIdx, IBodyIdx, ICmdCountIdx, ICommandsIdx, - ICompleteIdx, IDefaultIdx, IExistsIdx, IFunctionsIdx, IGlobalsIdx, - IHostnameIdx, ILevelIdx, ILibraryIdx, ILoadedIdx, + ICompleteIdx, IDefaultIdx, IExistsIdx, +#ifdef TCL_TIP280 + IFrameIdx, +#endif + IFunctionsIdx, + IGlobalsIdx, IHostnameIdx, ILevelIdx, ILibraryIdx, ILoadedIdx, ILocalsIdx, INameOfExecutableIdx, IPatchLevelIdx, IProcsIdx, IScriptIdx, ISharedLibExtensionIdx, ITclVersionIdx, IVarsIdx }; int index, result; @@ -446,10 +476,16 @@ result = InfoDefaultCmd(clientData, interp, objc, objv); break; case IExistsIdx: result = InfoExistsCmd(clientData, interp, objc, objv); break; +#ifdef TCL_TIP280 + case IFrameIdx: + /* TIP #280 - New method 'frame' */ + result = InfoFrameCmd(clientData, interp, objc, objv); + break; +#endif case IFunctionsIdx: result = InfoFunctionsCmd(clientData, interp, objc, objv); break; case IGlobalsIdx: result = InfoGlobalsCmd(clientData, interp, objc, objv); @@ -735,10 +771,18 @@ } } else { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } + + /* + * Exit as quickly as possible if we couldn't find the namespace. + */ + + if (nsPtr == NULL) { + return TCL_OK; + } /* * Scan through the effective namespace's command table and create a * list with all commands that match the pattern. If a specific * namespace was requested in the pattern, qualify the command names @@ -745,11 +789,37 @@ * with the namespace name. */ listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); - if (nsPtr != NULL) { + if (simplePattern != NULL && TclMatchIsTrivial(simplePattern)) { + /* + * Special case for when the pattern doesn't include any of + * glob's special characters. This lets us avoid scans of any + * hash tables. + */ + entryPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, simplePattern); + if (entryPtr != NULL) { + if (specificNsInPattern) { + cmd = (Tcl_Command) Tcl_GetHashValue(entryPtr); + elemObjPtr = Tcl_NewObj(); + Tcl_GetCommandFullName(interp, cmd, elemObjPtr); + } else { + cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr); + elemObjPtr = Tcl_NewStringObj(cmdName, -1); + } + Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); + } else if ((nsPtr != globalNsPtr) && !specificNsInPattern) { + entryPtr = Tcl_FindHashEntry(&globalNsPtr->cmdTable, + simplePattern); + if (entryPtr != NULL) { + cmdName = Tcl_GetHashKey(&globalNsPtr->cmdTable, entryPtr); + Tcl_ListObjAppendElement(interp, listPtr, + Tcl_NewStringObj(cmdName, -1)); + } + } + } else { entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); while (entryPtr != NULL) { cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr); if ((simplePattern == NULL) || Tcl_StringMatch(cmdName, simplePattern)) { @@ -900,14 +970,15 @@ return TCL_ERROR; } Tcl_SetIntObj(Tcl_GetObjResult(interp), 1); } else { Tcl_Obj *nullObjPtr = Tcl_NewObj(); + Tcl_IncrRefCount(nullObjPtr); valueObjPtr = Tcl_ObjSetVar2(interp, objv[4], NULL, nullObjPtr, 0); + Tcl_DecrRefCount(nullObjPtr); /* free unneeded obj */ if (valueObjPtr == NULL) { - Tcl_DecrRefCount(nullObjPtr); /* free unneeded obj */ goto defStoreError; } Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); } return TCL_OK; @@ -962,10 +1033,247 @@ } else { Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); } return TCL_OK; } + +#ifdef TCL_TIP280 +/* + *---------------------------------------------------------------------- + * + * InfoFrameCmd -- + * TIP #280 + * + * Called to implement the "info frame" command that returns the + * location of either the currently executing command, or its caller. + * Handles the following syntax: + * + * info frame ?number? + * + * Results: + * Returns TCL_OK if successful and TCL_ERROR if there is an error. + * + * Side effects: + * Returns a result in the interpreter's result object. If there is + * an error, the result is an error message. + * + *---------------------------------------------------------------------- + */ + +static int +InfoFrameCmd(dummy, interp, objc, objv) + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + Interp *iPtr = (Interp *) interp; + + if (objc == 2) { + /* just "info frame" */ + int levels = (iPtr->cmdFramePtr == NULL + ? 0 + : iPtr->cmdFramePtr->level); + + Tcl_SetIntObj(Tcl_GetObjResult(interp), levels); + return TCL_OK; + + } else if (objc == 3) { + /* "info frame level" */ + int level; + CmdFrame *framePtr; + + if (Tcl_GetIntFromObj(interp, objv[2], &level) != TCL_OK) { + return TCL_ERROR; + } + if (level <= 0) { + /* Relative adressing */ + + if (iPtr->cmdFramePtr == NULL) { + levelError: + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "bad level \"", + Tcl_GetString(objv[2]), + "\"", (char *) NULL); + return TCL_ERROR; + } + /* Convert to absolute. */ + + level += iPtr->cmdFramePtr->level; + } + for (framePtr = iPtr->cmdFramePtr; + framePtr != NULL; + framePtr = framePtr->nextPtr) { + + if (framePtr->level == level) { + break; + } + } + if (framePtr == NULL) { + goto levelError; + } + + /* + * Pull the information and construct the dictionary to return, as + * list. Regarding use of the CmdFrame fields see tclInt.h, and its + * definition. + */ + + { + Tcl_Obj* lv [20]; /* Keep uptodate when more keys are added to the dict */ + int lc = 0; + + /* This array is indexed by the TCL_LOCATION_... values, except + * for _LAST. + */ + + static CONST char* typeString [TCL_LOCATION_LAST] = { + "eval", "eval", "eval", "precompiled", "source", "proc" + }; + + switch (framePtr->type) { + case TCL_LOCATION_EVAL: + /* Evaluation, dynamic script. Type, line, cmd, the latter + * through str. */ + + lv [lc ++] = Tcl_NewStringObj ("type",-1); + lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1); + lv [lc ++] = Tcl_NewStringObj ("line",-1); + lv [lc ++] = Tcl_NewIntObj (framePtr->line[0]); + lv [lc ++] = Tcl_NewStringObj ("cmd",-1); + lv [lc ++] = Tcl_NewStringObj (framePtr->cmd.str.cmd, + framePtr->cmd.str.len); + break; + + case TCL_LOCATION_EVAL_LIST: + /* List optimized evaluation. Type, line, cmd, the latter + * through listPtr, possibly a frame. */ + + lv [lc ++] = Tcl_NewStringObj ("type",-1); + lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1); + lv [lc ++] = Tcl_NewStringObj ("line",-1); + lv [lc ++] = Tcl_NewIntObj (framePtr->line[0]); + + /* We put a duplicate of the command list obj into the result + * to ensure that the 'pure List'-property of the command + * itself is not destroyed. Otherwise the query here would + * disable the list optimization path in Tcl_EvalObjEx. + */ + + lv [lc ++] = Tcl_NewStringObj ("cmd",-1); + lv [lc ++] = Tcl_DuplicateObj (framePtr->cmd.listPtr); + break; + + case TCL_LOCATION_PREBC: + /* Precompiled. Result contains the type as signal, nothing + * else */ + + lv [lc ++] = Tcl_NewStringObj ("type",-1); + lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1); + break; + + case TCL_LOCATION_BC: { + /* Execution of bytecode. Talk to the BC engine to fill out + * the frame. */ + + CmdFrame f = *framePtr; + Proc* procPtr = f.framePtr ? f.framePtr->procPtr : NULL; + + /* Note: Type BC => f.data.eval.path is not used. + * f.data.tebc.codePtr is used instead. + */ + + TclGetSrcInfoForPc (&f); + /* Now filled: cmd.str.(cmd,len), line */ + /* Possibly modified: type, path! */ + + lv [lc ++] = Tcl_NewStringObj ("type",-1); + lv [lc ++] = Tcl_NewStringObj (typeString [f.type],-1); + lv [lc ++] = Tcl_NewStringObj ("line",-1); + lv [lc ++] = Tcl_NewIntObj (f.line[0]); + + if (f.type == TCL_LOCATION_SOURCE) { + lv [lc ++] = Tcl_NewStringObj ("file",-1); + lv [lc ++] = f.data.eval.path; + /* Death of reference by TclGetSrcInfoForPc */ + Tcl_DecrRefCount (f.data.eval.path); + } + + lv [lc ++] = Tcl_NewStringObj ("cmd",-1); + lv [lc ++] = Tcl_NewStringObj (f.cmd.str.cmd, f.cmd.str.len); + + if (procPtr != NULL) { + Tcl_HashEntry* namePtr = procPtr->cmdPtr->hPtr; + char* procName = Tcl_GetHashKey (namePtr->tablePtr, namePtr); + char* nsName = procPtr->cmdPtr->nsPtr->fullName; + + lv [lc ++] = Tcl_NewStringObj ("proc",-1); + lv [lc ++] = Tcl_NewStringObj (nsName,-1); + + if (strcmp (nsName, "::") != 0) { + Tcl_AppendToObj (lv [lc-1], "::", -1); + } + Tcl_AppendToObj (lv [lc-1], procName, -1); + } + break; + } + + case TCL_LOCATION_SOURCE: + /* Evaluation of a script file */ + + lv [lc ++] = Tcl_NewStringObj ("type",-1); + lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1); + lv [lc ++] = Tcl_NewStringObj ("line",-1); + lv [lc ++] = Tcl_NewIntObj (framePtr->line[0]); + lv [lc ++] = Tcl_NewStringObj ("file",-1); + lv [lc ++] = framePtr->data.eval.path; + /* Refcount framePtr->data.eval.path goes up when lv + * is converted into the result list object. + */ + lv [lc ++] = Tcl_NewStringObj ("cmd",-1); + lv [lc ++] = Tcl_NewStringObj (framePtr->cmd.str.cmd, + framePtr->cmd.str.len); + break; + + case TCL_LOCATION_PROC: + Tcl_Panic ("TCL_LOCATION_PROC found in standard frame"); + break; + } + + + /* 'level'. Common to all frame types. Conditional on having an + * associated _visible_ CallFrame */ + + if ((framePtr->framePtr != NULL) && (iPtr->varFramePtr != NULL)) { + CallFrame* current = framePtr->framePtr; + CallFrame* top = iPtr->varFramePtr; + CallFrame* idx; + + for (idx = top; + idx != NULL; + idx = idx->callerVarPtr) { + if (idx == current) { + int c = framePtr->framePtr->level; + int t = iPtr->varFramePtr->level; + + lv [lc ++] = Tcl_NewStringObj ("level",-1); + lv [lc ++] = Tcl_NewIntObj (t - c); + break; + } + } + } + + Tcl_SetObjResult(interp, Tcl_NewListObj (lc, lv)); + return TCL_OK; + } + } + + Tcl_WrongNumArgs(interp, 2, objv, "?number?"); + + return TCL_ERROR; +} +#endif /* *---------------------------------------------------------------------- * * InfoFunctionsCmd -- @@ -1049,11 +1357,19 @@ Tcl_Obj *listPtr; if (objc == 2) { pattern = NULL; } else if (objc == 3) { - pattern = Tcl_GetString(objv[2]); + pattern = Tcl_GetString(objv[2]); + /* + * Strip leading global-namespace qualifiers. [Bug 1057461] + */ + if (pattern[0] == ':' && pattern[1] == ':') { + while (*pattern == ':') { + pattern++; + } + } } else { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } @@ -1061,22 +1377,33 @@ * Scan through the global :: namespace's variable table and create a * list of all global variables that match the pattern. */ listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); - for (entryPtr = Tcl_FirstHashEntry(&globalNsPtr->varTable, &search); - entryPtr != NULL; - entryPtr = Tcl_NextHashEntry(&search)) { - varPtr = (Var *) Tcl_GetHashValue(entryPtr); - if (TclIsVarUndefined(varPtr)) { - continue; - } - varName = Tcl_GetHashKey(&globalNsPtr->varTable, entryPtr); - if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { - Tcl_ListObjAppendElement(interp, listPtr, - Tcl_NewStringObj(varName, -1)); - } + if (pattern != NULL && TclMatchIsTrivial(pattern)) { + entryPtr = Tcl_FindHashEntry(&globalNsPtr->varTable, pattern); + if (entryPtr != NULL) { + varPtr = (Var *) Tcl_GetHashValue(entryPtr); + if (!TclIsVarUndefined(varPtr)) { + Tcl_ListObjAppendElement(interp, listPtr, + Tcl_NewStringObj(pattern, -1)); + } + } + } else { + for (entryPtr = Tcl_FirstHashEntry(&globalNsPtr->varTable, &search); + entryPtr != NULL; + entryPtr = Tcl_NextHashEntry(&search)) { + varPtr = (Var *) Tcl_GetHashValue(entryPtr); + if (TclIsVarUndefined(varPtr)) { + continue; + } + varName = Tcl_GetHashKey(&globalNsPtr->varTable, entryPtr); + if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { + Tcl_ListObjAppendElement(interp, listPtr, + Tcl_NewStringObj(varName, -1)); + } + } } Tcl_SetObjResult(interp, listPtr); return TCL_OK; } @@ -1578,40 +1905,72 @@ } } else { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } + + if (nsPtr == NULL) { + return TCL_OK; + } /* * Scan through the effective namespace's command table and create a * list with all procs that match the pattern. If a specific * namespace was requested in the pattern, qualify the command names * with the namespace name. */ listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); - if (nsPtr != NULL) { +#ifndef INFO_PROCS_SEARCH_GLOBAL_NS + if (simplePattern != NULL && TclMatchIsTrivial(simplePattern)) { + entryPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, simplePattern); + if (entryPtr != NULL) { + cmdPtr = (Command *) Tcl_GetHashValue(entryPtr); + + if (!TclIsProc(cmdPtr)) { + realCmdPtr = (Command *) + TclGetOriginalCommand((Tcl_Command) cmdPtr); + if (realCmdPtr != NULL && TclIsProc(realCmdPtr)) { + goto simpleProcOK; + } + } else { + simpleProcOK: + if (specificNsInPattern) { + elemObjPtr = Tcl_NewObj(); + Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, + elemObjPtr); + } else { + elemObjPtr = Tcl_NewStringObj(simplePattern, -1); + } + Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); + } + } + } else +#endif /* !INFO_PROCS_SEARCH_GLOBAL_NS */ + { entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); while (entryPtr != NULL) { cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr); if ((simplePattern == NULL) || Tcl_StringMatch(cmdName, simplePattern)) { cmdPtr = (Command *) Tcl_GetHashValue(entryPtr); - realCmdPtr = (Command *) - TclGetOriginalCommand((Tcl_Command) cmdPtr); - - if (TclIsProc(cmdPtr) - || ((realCmdPtr != NULL) && TclIsProc(realCmdPtr))) { + if (!TclIsProc(cmdPtr)) { + realCmdPtr = (Command *) + TclGetOriginalCommand((Tcl_Command) cmdPtr); + if (realCmdPtr != NULL && TclIsProc(realCmdPtr)) { + goto procOK; + } + } else { + procOK: if (specificNsInPattern) { elemObjPtr = Tcl_NewObj(); Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, elemObjPtr); } else { elemObjPtr = Tcl_NewStringObj(cmdName, -1); } - Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); } } entryPtr = Tcl_NextHashEntry(&search); } @@ -1887,58 +2246,98 @@ * to activate a namespace, or we are in a procedure call frame * but a specific namespace was specified. Create a list containing * only the variables in the effective namespace's variable table. */ - entryPtr = Tcl_FirstHashEntry(&nsPtr->varTable, &search); - while (entryPtr != NULL) { - varPtr = (Var *) Tcl_GetHashValue(entryPtr); - if (!TclIsVarUndefined(varPtr) - || (varPtr->flags & VAR_NAMESPACE_VAR)) { - varName = Tcl_GetHashKey(&nsPtr->varTable, entryPtr); - if ((simplePattern == NULL) - || Tcl_StringMatch(varName, simplePattern)) { + if (simplePattern != NULL && TclMatchIsTrivial(simplePattern)) { + /* + * If we can just do hash lookups, that simplifies things + * a lot. + */ + + entryPtr = Tcl_FindHashEntry(&nsPtr->varTable, simplePattern); + if (entryPtr != NULL) { + varPtr = (Var *) Tcl_GetHashValue(entryPtr); + if (!TclIsVarUndefined(varPtr) + || (varPtr->flags & VAR_NAMESPACE_VAR)) { if (specificNsInPattern) { elemObjPtr = Tcl_NewObj(); Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, - elemObjPtr); + elemObjPtr); } else { - elemObjPtr = Tcl_NewStringObj(varName, -1); + elemObjPtr = Tcl_NewStringObj(simplePattern, -1); } Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); } - } - entryPtr = Tcl_NextHashEntry(&search); - } - - /* - * If the effective namespace isn't the global :: namespace, and a - * specific namespace wasn't requested in the pattern (i.e., the - * pattern only specifies variable names), then add in all global :: - * variables that match the simple pattern. Of course, add in only - * those variables that aren't hidden by a variable in the effective - * namespace. - */ - - if ((nsPtr != globalNsPtr) && !specificNsInPattern) { - entryPtr = Tcl_FirstHashEntry(&globalNsPtr->varTable, &search); + } else if ((nsPtr != globalNsPtr) && !specificNsInPattern) { + entryPtr = Tcl_FindHashEntry(&globalNsPtr->varTable, + simplePattern); + if (entryPtr != NULL) { + varPtr = (Var *) Tcl_GetHashValue(entryPtr); + if (!TclIsVarUndefined(varPtr) + || (varPtr->flags & VAR_NAMESPACE_VAR)) { + Tcl_ListObjAppendElement(interp, listPtr, + Tcl_NewStringObj(simplePattern, -1)); + } + } + } + } else { + /* + * Have to scan the tables of variables. + */ + + entryPtr = Tcl_FirstHashEntry(&nsPtr->varTable, &search); while (entryPtr != NULL) { varPtr = (Var *) Tcl_GetHashValue(entryPtr); if (!TclIsVarUndefined(varPtr) - || (varPtr->flags & VAR_NAMESPACE_VAR)) { - varName = Tcl_GetHashKey(&globalNsPtr->varTable, - entryPtr); + || (varPtr->flags & VAR_NAMESPACE_VAR)) { + varName = Tcl_GetHashKey(&nsPtr->varTable, entryPtr); if ((simplePattern == NULL) - || Tcl_StringMatch(varName, simplePattern)) { - if (Tcl_FindHashEntry(&nsPtr->varTable, varName) == NULL) { - Tcl_ListObjAppendElement(interp, listPtr, - Tcl_NewStringObj(varName, -1)); + || Tcl_StringMatch(varName, simplePattern)) { + if (specificNsInPattern) { + elemObjPtr = Tcl_NewObj(); + Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, + elemObjPtr); + } else { + elemObjPtr = Tcl_NewStringObj(varName, -1); } + Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); } } entryPtr = Tcl_NextHashEntry(&search); } + + /* + * If the effective namespace isn't the global :: + * namespace, and a specific namespace wasn't requested in + * the pattern (i.e., the pattern only specifies variable + * names), then add in all global :: variables that match + * the simple pattern. Of course, add in only those + * variables that aren't hidden by a variable in the + * effective namespace. + */ + + if ((nsPtr != globalNsPtr) && !specificNsInPattern) { + entryPtr = Tcl_FirstHashEntry(&globalNsPtr->varTable, &search); + while (entryPtr != NULL) { + varPtr = (Var *) Tcl_GetHashValue(entryPtr); + if (!TclIsVarUndefined(varPtr) + || (varPtr->flags & VAR_NAMESPACE_VAR)) { + varName = Tcl_GetHashKey(&globalNsPtr->varTable, + entryPtr); + if ((simplePattern == NULL) + || Tcl_StringMatch(varName, simplePattern)) { + if (Tcl_FindHashEntry(&nsPtr->varTable, + varName) == NULL) { + Tcl_ListObjAppendElement(interp, listPtr, + Tcl_NewStringObj(varName, -1)); + } + } + } + entryPtr = Tcl_NextHashEntry(&search); + } + } } } else if (((Interp *)interp)->varFramePtr->procPtr != NULL) { AppendLocals(interp, listPtr, simplePattern, 1); } @@ -2892,14 +3291,29 @@ } if ((enum modes) mode == REGEXP) { /* * We can shimmer regexp/list if listv[i] == pattern, so get the - * regexp rep before the list rep. + * regexp rep before the list rep. First time round, omit the interp + * and hope that the compilation will succeed. If it fails, we'll + * recompile in "expensive" mode with a place to put error messages. */ - regexp = Tcl_GetRegExpFromObj(interp, objv[objc - 1], + + regexp = Tcl_GetRegExpFromObj(NULL, objv[objc - 1], TCL_REG_ADVANCED | TCL_REG_NOSUB); + if (regexp == NULL) { + /* + * Failed to compile the RE. Try again without the TCL_REG_NOSUB + * flag in case the RE had sub-expressions in it [Bug 1366683]. + * If this fails, an error message will be left in the + * interpreter. + */ + + regexp = Tcl_GetRegExpFromObj(interp, objv[objc - 1], + TCL_REG_ADVANCED); + } + if (regexp == NULL) { if (startPtr) { Tcl_DecrRefCount(startPtr); } return TCL_ERROR; @@ -2926,12 +3340,23 @@ result = TclGetIntForIndex(interp, startPtr, listc-1, &offset); Tcl_DecrRefCount(startPtr); if (result != TCL_OK) { return result; } + + /* + * If the search started past the end of the list, we just return a + * "did not match anything at all" result straight away. [Bug 1374778] + */ + if (offset > listc-1) { - offset = listc-1; + if (allMatches || inlineReturn) { + Tcl_ResetResult(interp); + } else { + Tcl_SetObjResult(interp, Tcl_NewIntObj(-1)); + } + return TCL_OK; } if (offset < 0) { offset = 0; } } @@ -3372,10 +3797,19 @@ elementArray = (SortElement *) ckalloc(length * sizeof(SortElement)); for (i=0; i < length; i++){ elementArray[i].objPtr = listObjPtrs[i]; elementArray[i].count = 0; elementArray[i].nextPtr = &elementArray[i+1]; + + /* + * When sorting using a command, we are reentrant and therefore might + * have the representation of the list being sorted shimmered out from + * underneath our feet. Increment the reference counts of the elements + * to sort to prevent this. [Bug 1675116] + */ + + Tcl_IncrRefCount(elementArray[i].objPtr); } elementArray[length-1].nextPtr = NULL; elementPtr = MergeSort(elementArray, &sortInfo); if (sortInfo.resultCode == TCL_OK) { /* @@ -3397,10 +3831,13 @@ Tcl_ListObjAppendElement(interp, resultPtr, elementPtr->objPtr); } } } + for (i=0; iinterp, Tcl_GetObjResult(infoPtr->interp), &order) != TCL_OK) { Tcl_ResetResult(infoPtr->interp); Tcl_AppendToObj(Tcl_GetObjResult(infoPtr->interp), - "-compare command returned non-numeric result", -1); + "-compare command returned non-integer result", -1); infoPtr->resultCode = TCL_ERROR; return order; } } if (!infoPtr->isIncreasing) { @@ -3842,5 +4279,14 @@ if (diff == 0) { diff = secondaryDiff; } return diff; } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ + Index: generic/tclCmdMZ.c ================================================================== --- generic/tclCmdMZ.c +++ generic/tclCmdMZ.c @@ -12,19 +12,20 @@ * Copyright (c) 2002 ActiveState Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCmdMZ.c,v 1.82 2003/02/27 00:54:36 hobbs Exp $ + * RCS: @(#) $Id: tclCmdMZ.c,v 1.82.2.28 2007/05/10 18:23:58 dgp Exp $ */ #include "tclInt.h" #include "tclPort.h" #include "tclRegexp.h" +#include "tclCompile.h" /* - * Structure used to hold information about variable traces: + * Structures used to hold information about variable traces: */ typedef struct { int flags; /* Operations for which Tcl command is * to be invoked. */ @@ -34,10 +35,15 @@ * hold command. This field must be the * last in the structure, so that it can * be larger than 4 bytes. */ } TraceVarInfo; +typedef struct { + VarTrace trace; + TraceVarInfo tvar; +} CompoundVarTrace; + /* * Structure used to hold information about command traces: */ typedef struct { @@ -130,10 +136,14 @@ static void TraceCommandProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, CONST char *oldName, CONST char *newName, int flags)); static Tcl_CmdObjTraceProc TraceExecutionProc; +#ifdef TCL_TIP280 +static void ListLines _ANSI_ARGS_((CONST char* listStr, int line, + int n, int* lines)); +#endif /* *---------------------------------------------------------------------- * * Tcl_PwdObjCmd -- * @@ -366,11 +376,14 @@ * string. */ while (1) { match = Tcl_RegExpExecObj(interp, regExpr, objPtr, - offset /* offset */, numMatchesSaved, eflags); + offset /* offset */, numMatchesSaved, eflags + | ((offset > 0 && + (Tcl_GetUniChar(objPtr,offset-1) != (Tcl_UniChar)'\n')) + ? TCL_REG_NOTBOL : 0)); if (match < 0) { return TCL_ERROR; } @@ -455,13 +468,14 @@ Tcl_DecrRefCount(newPtr); return TCL_ERROR; } } else { Tcl_Obj *valuePtr; + Tcl_IncrRefCount(newPtr); valuePtr = Tcl_ObjSetVar2(interp, objv[i], NULL, newPtr, 0); + Tcl_DecrRefCount(newPtr); if (valuePtr == NULL) { - Tcl_DecrRefCount(newPtr); Tcl_AppendResult(interp, "couldn't set variable \"", Tcl_GetString(objv[i]), "\"", (char *) NULL); return TCL_ERROR; } } @@ -717,23 +731,28 @@ /* * The following loop is to handle multiple matches within the * same source string; each iteration handles one match and its * corresponding substitution. If "-all" hasn't been specified - * then the loop body only gets executed once. + * then the loop body only gets executed once. We must use + * 'offset <= wlen' in particular for the case where the regexp + * pattern can match the empty string - this is useful when + * doing, say, 'regsub -- ^ $str ...' when $str might be empty. */ numMatches = 0; - for ( ; offset < wlen; ) { + for ( ; offset <= wlen; ) { /* * The flags argument is set if string is part of a larger string, * so that "^" won't match. */ match = Tcl_RegExpExecObj(interp, regExpr, objPtr, offset, - 10 /* matches */, ((offset > 0) ? TCL_REG_NOTBOL : 0)); + 10 /* matches */, ((offset > 0 && + (wstring[offset-1] != (Tcl_UniChar)'\n')) + ? TCL_REG_NOTBOL : 0)); if (match < 0) { result = TCL_ERROR; goto done; } @@ -817,14 +836,27 @@ /* * Always consume at least one character of the input string * in order to prevent infinite loops. */ - Tcl_AppendUnicodeToObj(resultPtr, wstring + offset, 1); + if (offset < wlen) { + Tcl_AppendUnicodeToObj(resultPtr, wstring + offset, 1); + } offset++; } else { offset += end; + if (start == end) { + /* + * We matched an empty string, which means we must go + * forward one more step so we don't match again at the + * same spot. + */ + if (offset < wlen) { + Tcl_AppendUnicodeToObj(resultPtr, wstring + offset, 1); + } + offset++; + } } if (!all) { break; } } @@ -1568,18 +1600,12 @@ } break; case STR_IS_BOOL: case STR_IS_TRUE: case STR_IS_FALSE: - if (objPtr->typePtr == &tclBooleanType) { - if ((((enum isOptions) index == STR_IS_TRUE) && - objPtr->internalRep.longValue == 0) || - (((enum isOptions) index == STR_IS_FALSE) && - objPtr->internalRep.longValue != 0)) { - result = 0; - } - } else if ((Tcl_GetBoolean(NULL, string1, &i) + /* Optimizers, beware Bug 1187123 ! */ + if ((Tcl_GetBoolean(NULL, string1, &i) == TCL_ERROR) || (((enum isOptions) index == STR_IS_TRUE) && i == 0) || (((enum isOptions) index == STR_IS_FALSE) && i != 0)) { @@ -1657,34 +1683,32 @@ case STR_IS_GRAPH: chcomp = Tcl_UniCharIsGraph; break; case STR_IS_INT: { char *stop; + long int l = 0; - if ((objPtr->typePtr == &tclIntType) || - (Tcl_GetInt(NULL, string1, &i) == TCL_OK)) { + if (TCL_OK == Tcl_GetIntFromObj(NULL, objPtr, &i)) { break; } /* * Like STR_IS_DOUBLE, but we use strtoul. - * Since Tcl_GetInt already failed, we set result to 0. + * Since Tcl_GetIntFromObj already failed, + * we set result to 0. */ result = 0; errno = 0; -#ifdef TCL_WIDE_INT_IS_LONG - strtoul(string1, &stop, 0); /* INTL: Tcl source. */ -#else - strtoull(string1, &stop, 0); /* INTL: Tcl source. */ -#endif - if (errno == ERANGE) { + l = strtol(string1, &stop, 0); /* INTL: Tcl source. */ + if ((errno == ERANGE) || (l > INT_MAX) || (l < INT_MIN)) { /* * if (errno == ERANGE), then it was an over/underflow * problem, but in this method, we only want to know * yes or no, so bad flow returns 0 (false) and sets * the failVarObj to the string length. */ failat = -1; + } else if (stop == string1) { /* * In this case, nothing like a number was found */ failat = 0; @@ -1742,14 +1766,20 @@ str_is_done: /* * Only set the failVarObj when we will return 0 * and we have indicated a valid fail index (>= 0) */ - if ((result == 0) && (failVarObj != NULL) && - Tcl_ObjSetVar2(interp, failVarObj, NULL, Tcl_NewIntObj(failat), - TCL_LEAVE_ERR_MSG) == NULL) { - return TCL_ERROR; + if ((result == 0) && (failVarObj != NULL)) { + Tcl_Obj *resPtr, *tmpPtr = Tcl_NewIntObj(failat); + + Tcl_IncrRefCount(tmpPtr); + resPtr = Tcl_ObjSetVar2(interp, failVarObj, NULL, tmpPtr, + TCL_LEAVE_ERR_MSG); + Tcl_DecrRefCount(tmpPtr); + if (resPtr == NULL) { + return TCL_ERROR; + } } Tcl_SetBooleanObj(resultPtr, result); break; } case STR_LAST: { @@ -1836,12 +1866,12 @@ } Tcl_SetIntObj(resultPtr, length1); break; } case STR_MAP: { - int mapElemc, nocase = 0; - Tcl_Obj **mapElemv; + int mapElemc, nocase = 0, copySource = 0; + Tcl_Obj **mapElemv, *sourceObj; Tcl_UniChar *ustring1, *ustring2, *p, *end; int (*strCmpFn)_ANSI_ARGS_((CONST Tcl_UniChar*, CONST Tcl_UniChar*, unsigned long)); if (objc < 4 || objc > 5) { @@ -1877,17 +1907,30 @@ * The charMap must be an even number of key/value items */ Tcl_SetStringObj(resultPtr, "char map list unbalanced", -1); return TCL_ERROR; } - objc--; - ustring1 = Tcl_GetUnicodeFromObj(objv[objc], &length1); + /* + * Take a copy of the source string object if it is the + * same as the map string to cut out nasty sharing + * crashes. [Bug 1018562] + */ + if (objv[objc-2] == objv[objc-1]) { + sourceObj = Tcl_DuplicateObj(objv[objc-1]); + copySource = 1; + } else { + sourceObj = objv[objc-1]; + } + ustring1 = Tcl_GetUnicodeFromObj(sourceObj, &length1); if (length1 == 0) { /* * Empty input string, just stop now */ + if (copySource) { + Tcl_DecrRefCount(sourceObj); + } break; } end = ustring1 + length1; strCmpFn = nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp; @@ -1907,11 +1950,12 @@ int mapLen; Tcl_UniChar *mapString, u2lc; ustring2 = Tcl_GetUnicodeFromObj(mapElemv[0], &length2); p = ustring1; - if (length2 == 0) { + if ((length2 > length1) || (length2 == 0)) { + /* match string is either longer than input or empty */ ustring1 = end; } else { mapString = Tcl_GetUnicodeFromObj(mapElemv[1], &mapLen); u2lc = (nocase ? Tcl_UniCharToLower(*ustring2) : 0); for (; ustring1 < end; ustring1++) { @@ -1965,10 +2009,12 @@ ustring2 = mapStrings[index]; length2 = mapLens[index]; if ((length2 > 0) && ((*ustring1 == *ustring2) || (nocase && (Tcl_UniCharToLower(*ustring1) == u2lc[index/2]))) && + /* restrict max compare length */ + ((end - ustring1) >= length2) && ((length2 == 1) || strCmpFn(ustring2, ustring1, (unsigned long) length2) == 0)) { if (p != ustring1) { /* * Put the skipped chars onto the result first @@ -2003,10 +2049,13 @@ /* * Put the rest of the unmapped chars onto result */ Tcl_AppendUnicodeToObj(resultPtr, p, ustring1 - p); } + if (copySource) { + Tcl_DecrRefCount(sourceObj); + } break; } case STR_MATCH: { Tcl_UniChar *ustring1, *ustring2; int nocase = 0; @@ -2104,12 +2153,21 @@ if (length1 > 0) { /* * Only build up a string that has data. Instead of * building it up with repeated appends, we just allocate * the necessary space once and copy the string value in. + * Check for overflow with back-division. [Bug #714106] */ length2 = length1 * count; + if ((length2 / count) != length1) { + char buf[TCL_INTEGER_SPACE+1]; + sprintf(buf, "%d", INT_MAX); + Tcl_AppendStringsToObj(resultPtr, + "string size overflow, must be less than ", + buf, (char *) NULL); + return TCL_ERROR; + } /* * Include space for the NULL */ string2 = (char *) ckalloc((size_t) length2+1); for (index = 0; index < count; index++) { @@ -2524,21 +2582,16 @@ Tcl_Obj *objPtr; int flags; { Tcl_Obj *resultObj; char *p, *old; + int length; - old = p = Tcl_GetString(objPtr); + old = p = Tcl_GetStringFromObj(objPtr, &length); resultObj = Tcl_NewStringObj("", 0); - while (1) { + while (length) { switch (*p) { - case 0: - if (p != old) { - Tcl_AppendToObj(resultObj, old, p-old); - } - return resultObj; - case '\\': if (flags & TCL_SUBST_BACKSLASHES) { char buf[TCL_UTF_MAX]; int count; @@ -2545,14 +2598,14 @@ if (p != old) { Tcl_AppendToObj(resultObj, old, p-old); } Tcl_AppendToObj(resultObj, buf, Tcl_UtfBackslash(p, &count, buf)); - p += count; + p += count; length -= count; old = p; } else { - p++; + p++; length--; } break; case '$': if (flags & TCL_SUBST_VARIABLES) { @@ -2575,17 +2628,18 @@ if (parse.numTokens == 1) { /* * There isn't a variable name after all: the $ is * just a $. */ - p++; + p++; length--; break; } if (p != old) { Tcl_AppendToObj(resultObj, old, p-old); } p += parse.tokenPtr->size; + length -= parse.tokenPtr->size; code = Tcl_EvalTokensStandard(interp, parse.tokenPtr, parse.numTokens); if (code == TCL_ERROR) { goto errorResult; } @@ -2597,11 +2651,11 @@ Tcl_AppendObjToObj(resultObj, Tcl_GetObjResult(interp)); } Tcl_ResetResult(interp); old = p; } else { - p++; + p++; length--; } break; case '[': if (flags & TCL_SUBST_COMMANDS) { @@ -2610,11 +2664,16 @@ if (p != old) { Tcl_AppendToObj(resultObj, old, p-old); } iPtr->evalFlags = TCL_BRACKET_TERM; - code = Tcl_EvalEx(interp, p+1, -1, 0); + iPtr->numLevels++; + code = TclInterpReady(interp); + if (code == TCL_OK) { + code = Tcl_EvalEx(interp, p+1, -1, 0); + } + iPtr->numLevels--; switch (code) { case TCL_ERROR: goto errorResult; case TCL_BREAK: Tcl_ResetResult(interp); @@ -2622,20 +2681,25 @@ default: Tcl_AppendObjToObj(resultObj, Tcl_GetObjResult(interp)); case TCL_CONTINUE: Tcl_ResetResult(interp); old = p = (p+1 + iPtr->termOffset + 1); + length -= (iPtr->termOffset + 2); } } else { - p++; + p++; length--; } break; default: - p++; + p++; length--; break; } } + if (p != old) { + Tcl_AppendToObj(resultObj, old, p-old); + } + return resultObj; errorResult: Tcl_DecrRefCount(resultObj); return NULL; } @@ -2667,10 +2731,19 @@ { int i, j, index, mode, matched, result, splitObjs; char *string, *pattern; Tcl_Obj *stringObj; Tcl_Obj *CONST *savedObjv = objv; +#ifdef TCL_TIP280 + Interp* iPtr = (Interp*) interp; + int pc = 0; + int bidx = 0; /* Index of body argument */ + Tcl_Obj* blist = NULL; /* List obj which is the body */ + CmdFrame ctx; /* Copy of the topmost cmdframe, + * to allow us to mess with the + * line information */ +#endif static CONST char *options[] = { "-exact", "-glob", "-regexp", "--", NULL }; enum options { @@ -2701,20 +2774,29 @@ } stringObj = objv[i]; objc -= i + 1; objv += i + 1; +#ifdef TCL_TIP280 + bidx = i+1; /* First after the match string */ +#endif /* * If all of the pattern/command pairs are lumped into a single * argument, split them out again. + * + * TIP #280: Determine the lines the words in the list start at, based on + * the same data for the list word itself. The cmdFramePtr line information + * is manipulated directly. */ splitObjs = 0; if (objc == 1) { Tcl_Obj **listv; - +#ifdef TCL_TIP280 + blist = objv[0]; +#endif if (Tcl_ListObjGetElements(interp, objv[0], &objc, &listv) != TCL_OK) { return TCL_ERROR; } /* @@ -2809,11 +2891,61 @@ } /* * We've got a match. Find a body to execute, skipping bodies * that are "-". + * + * TIP#280: Now is also the time to determine a line number for the + * single-word case. */ + +#ifdef TCL_TIP280 + ctx = *iPtr->cmdFramePtr; + + if (splitObjs) { + /* We have to perform the GetSrc and other type dependent handling + * of the frame here because we are munging with the line numbers, + * something the other commands like if, etc. are not doing. Them + * are fine with simply passing the CmdFrame through and having + * the special handling done in 'info frame', or the bc compiler + */ + + if (ctx.type == TCL_LOCATION_BC) { + /* Note: Type BC => ctx.data.eval.path is not used. + * ctx.data.tebc.codePtr is used instead. + */ + TclGetSrcInfoForPc (&ctx); + pc = 1; + /* The line information in the cmdFrame is now a copy we do + * not own */ + } + + if (ctx.type == TCL_LOCATION_SOURCE) { + int bline = ctx.line [bidx]; + if (bline >= 0) { + ctx.line = (int*) ckalloc (objc * sizeof(int)); + ctx.nline = objc; + + ListLines (Tcl_GetString (blist), bline, objc, ctx.line); + } else { + int k; + /* Dynamic code word ... All elements are relative to themselves */ + + ctx.line = (int*) ckalloc (objc * sizeof(int)); + ctx.nline = objc; + for (k=0; k < objc; k++) {ctx.line[k] = -1;} + } + } else { + int k; + /* Anything else ... No information, or dynamic ... */ + + ctx.line = (int*) ckalloc (objc * sizeof(int)); + ctx.nline = objc; + for (k=0; k < objc; k++) {ctx.line[k] = -1;} + } + } +#endif for (j = i + 1; ; j += 2) { if (j >= objc) { /* * This shouldn't happen since we've checked that the @@ -2823,11 +2955,23 @@ } if (strcmp(Tcl_GetString(objv[j]), "-") != 0) { break; } } +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[j], 0); +#else + /* TIP #280. Make invoking context available to switch branch */ + result = TclEvalObjEx(interp, objv[j], 0, &ctx, j); + if (splitObjs) { + ckfree ((char*) ctx.line); + if (pc && (ctx.type == TCL_LOCATION_SOURCE)) { + /* Death of SrcInfo reference */ + Tcl_DecrRefCount (ctx.data.eval.path); + } + } +#endif if (result == TCL_ERROR) { char msg[100 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"%.50s\" arm line %d)", pattern, interp->errorLine); @@ -2862,15 +3006,15 @@ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Tcl_Obj *objPtr; + Tcl_Obj *objs[4]; register int i, result; int count; double totalMicroSec; Tcl_Time start, stop; - char buf[100]; if (objc == 2) { count = 1; } else if (objc == 3) { result = Tcl_GetIntFromObj(interp, objv[2], &count); @@ -2893,14 +3037,20 @@ } Tcl_GetTime(&stop); totalMicroSec = ( ( (double) ( stop.sec - start.sec ) ) * 1.0e6 + ( stop.usec - start.usec ) ); - sprintf(buf, "%.0f microseconds per iteration", - ((count <= 0) ? 0 : totalMicroSec/count)); - Tcl_ResetResult(interp); - Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1); + if (count <= 1) { + /* Use int obj since we know time is not fractional [Bug 1202178] */ + objs[0] = Tcl_NewIntObj((count <= 0) ? 0 : (int) totalMicroSec); + } else { + objs[0] = Tcl_NewDoubleObj(totalMicroSec/count); + } + objs[1] = Tcl_NewStringObj("microseconds", -1); + objs[2] = Tcl_NewStringObj("per", -1); + objs[3] = Tcl_NewStringObj("iteration", -1); + Tcl_SetObjResult(interp, Tcl_NewListObj(4, objs)); return TCL_OK; } /* *---------------------------------------------------------------------- @@ -2929,13 +3079,12 @@ ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { - int optionIndex, commandLength; - char *name, *flagOps, *command, *p; - size_t length; + int optionIndex; + char *name, *flagOps, *p; /* Main sub commands to 'trace' */ static CONST char *traceOptions[] = { "add", "info", "remove", #ifndef TCL_REMOVE_OBSOLETE_TRACES "variable", "vdelete", "vinfo", @@ -2976,112 +3125,58 @@ if (Tcl_GetIndexFromObj(interp, objv[2], traceTypeOptions, "option", 0, &typeIndex) != TCL_OK) { return TCL_ERROR; } return (traceSubCmds[typeIndex])(interp, optionIndex, objc, objv); - break; } #ifndef TCL_REMOVE_OBSOLETE_TRACES - case TRACE_OLD_VARIABLE: { - int flags; - TraceVarInfo *tvarPtr; - if (objc != 5) { - Tcl_WrongNumArgs(interp, 2, objv, "name ops command"); - return TCL_ERROR; - } - - flags = 0; - flagOps = Tcl_GetString(objv[3]); - for (p = flagOps; *p != 0; p++) { - if (*p == 'r') { - flags |= TCL_TRACE_READS; - } else if (*p == 'w') { - flags |= TCL_TRACE_WRITES; - } else if (*p == 'u') { - flags |= TCL_TRACE_UNSETS; - } else if (*p == 'a') { - flags |= TCL_TRACE_ARRAY; - } else { - goto badVarOps; - } - } - if (flags == 0) { - goto badVarOps; - } - flags |= TCL_TRACE_OLD_STYLE; - - command = Tcl_GetStringFromObj(objv[4], &commandLength); - length = (size_t) commandLength; - tvarPtr = (TraceVarInfo *) ckalloc((unsigned) - (sizeof(TraceVarInfo) - sizeof(tvarPtr->command) - + length + 1)); - tvarPtr->flags = flags; - tvarPtr->length = length; - flags |= TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT; - strcpy(tvarPtr->command, command); - name = Tcl_GetString(objv[2]); - if (Tcl_TraceVar(interp, name, flags, TraceVarProc, - (ClientData) tvarPtr) != TCL_OK) { - ckfree((char *) tvarPtr); - return TCL_ERROR; - } - break; - } + case TRACE_OLD_VARIABLE: case TRACE_OLD_VDELETE: { - int flags; - TraceVarInfo *tvarPtr; - ClientData clientData; + Tcl_Obj *copyObjv[6]; + Tcl_Obj *opsList; + int code, numFlags; if (objc != 5) { Tcl_WrongNumArgs(interp, 2, objv, "name ops command"); return TCL_ERROR; } - flags = 0; - flagOps = Tcl_GetString(objv[3]); - for (p = flagOps; *p != 0; p++) { - if (*p == 'r') { - flags |= TCL_TRACE_READS; - } else if (*p == 'w') { - flags |= TCL_TRACE_WRITES; - } else if (*p == 'u') { - flags |= TCL_TRACE_UNSETS; - } else if (*p == 'a') { - flags |= TCL_TRACE_ARRAY; - } else { - goto badVarOps; - } - } - if (flags == 0) { - goto badVarOps; - } - flags |= TCL_TRACE_OLD_STYLE; - - /* - * Search through all of our traces on this variable to - * see if there's one with the given command. If so, then - * delete the first one that matches. - */ - - command = Tcl_GetStringFromObj(objv[4], &commandLength); - length = (size_t) commandLength; - clientData = 0; - name = Tcl_GetString(objv[2]); - while ((clientData = Tcl_VarTraceInfo(interp, name, 0, - TraceVarProc, clientData)) != 0) { - tvarPtr = (TraceVarInfo *) clientData; - if ((tvarPtr->length == length) && (tvarPtr->flags == flags) - && (strncmp(command, tvarPtr->command, - (size_t) length) == 0)) { - Tcl_UntraceVar2(interp, name, NULL, - flags | TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT, - TraceVarProc, clientData); - Tcl_EventuallyFree((ClientData) tvarPtr, TCL_DYNAMIC); - break; - } - } - break; + opsList = Tcl_NewObj(); + Tcl_IncrRefCount(opsList); + flagOps = Tcl_GetStringFromObj(objv[3], &numFlags); + if (numFlags == 0) { + Tcl_DecrRefCount(opsList); + goto badVarOps; + } + for (p = flagOps; *p != 0; p++) { + if (*p == 'r') { + Tcl_ListObjAppendElement(NULL, opsList, + Tcl_NewStringObj("read", -1)); + } else if (*p == 'w') { + Tcl_ListObjAppendElement(NULL, opsList, + Tcl_NewStringObj("write", -1)); + } else if (*p == 'u') { + Tcl_ListObjAppendElement(NULL, opsList, + Tcl_NewStringObj("unset", -1)); + } else if (*p == 'a') { + Tcl_ListObjAppendElement(NULL, opsList, + Tcl_NewStringObj("array", -1)); + } else { + Tcl_DecrRefCount(opsList); + goto badVarOps; + } + } + copyObjv[0] = NULL; + memcpy(copyObjv+1, objv, objc*sizeof(Tcl_Obj *)); + copyObjv[4] = opsList; + if (optionIndex == TRACE_OLD_VARIABLE) { + code = (traceSubCmds[2])(interp,TRACE_ADD,objc+1,copyObjv); + } else { + code = (traceSubCmds[2])(interp,TRACE_REMOVE,objc+1,copyObjv); + } + Tcl_DecrRefCount(opsList); + return code; } case TRACE_OLD_VINFO: { ClientData clientData; char ops[5]; Tcl_Obj *resultListPtr, *pairObjPtr, *elemObjPtr; @@ -3238,12 +3333,14 @@ tcmdPtr->startLevel = 0; tcmdPtr->startCmd = NULL; tcmdPtr->length = length; tcmdPtr->refCount = 1; flags |= TCL_TRACE_DELETE; - if (flags & (TRACE_EXEC_ENTER_STEP | TRACE_EXEC_LEAVE_STEP)) { - flags |= (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC); + if (flags & (TCL_TRACE_ENTER_DURING_EXEC | + TCL_TRACE_LEAVE_DURING_EXEC)) { + flags |= (TCL_TRACE_ENTER_EXEC | + TCL_TRACE_LEAVE_EXEC); } strcpy(tcmdPtr->command, command); name = Tcl_GetString(objv[3]); if (Tcl_TraceCommand(interp, name, flags, TraceCommandProc, (ClientData) tcmdPtr) != TCL_OK) { @@ -3280,12 +3377,12 @@ TCL_TRACE_RENAME | TCL_TRACE_DELETE)) == flags) && (strncmp(command, tcmdPtr->command, (size_t) length) == 0)) { flags |= TCL_TRACE_DELETE; - if (flags & (TRACE_EXEC_ENTER_STEP | - TRACE_EXEC_LEAVE_STEP)) { + if (flags & (TCL_TRACE_ENTER_DURING_EXEC | + TCL_TRACE_LEAVE_DURING_EXEC)) { flags |= (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC); } Tcl_UntraceCommand(interp, name, flags, TraceCommandProc, clientData); @@ -3302,11 +3399,15 @@ } if (tcmdPtr->flags & TCL_TRACE_EXEC_IN_PROGRESS) { /* Postpone deletion */ tcmdPtr->flags = 0; } - if ((--tcmdPtr->refCount) <= 0) { + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("TclTraceExecutionObjCmd: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } break; } } @@ -3331,23 +3432,23 @@ } resultListPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); while ((clientData = Tcl_CommandTraceInfo(interp, name, 0, TraceCommandProc, clientData)) != NULL) { + int numOps = 0; TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) clientData; - eachTraceObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); - /* * Build a list with the ops list as the first obj * element and the tcmdPtr->command string as the * second obj element. Append this list (as an * element) to the end of the result object list. */ elemObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); + Tcl_IncrRefCount(elemObjPtr); if (tcmdPtr->flags & TCL_TRACE_ENTER_EXEC) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("enter",5)); } if (tcmdPtr->flags & TCL_TRACE_LEAVE_EXEC) { @@ -3360,11 +3461,18 @@ } if (tcmdPtr->flags & TCL_TRACE_LEAVE_DURING_EXEC) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("leavestep",9)); } + Tcl_ListObjLength(NULL, elemObjPtr, &numOps); + if (0 == numOps) { + Tcl_DecrRefCount(elemObjPtr); + continue; + } + eachTraceObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, elemObjPtr); + Tcl_DecrRefCount(elemObjPtr); elemObjPtr = NULL; Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, Tcl_NewStringObj(tcmdPtr->command, -1)); Tcl_ListObjAppendElement(interp, resultListPtr, @@ -3497,11 +3605,15 @@ (size_t) length) == 0)) { Tcl_UntraceCommand(interp, name, flags | TCL_TRACE_DELETE, TraceCommandProc, clientData); tcmdPtr->flags |= TCL_TRACE_DESTROYED; - if ((--tcmdPtr->refCount) <= 0) { + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("TclTraceCommandObjCmd: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { ckfree((char *) tcmdPtr); } break; } } @@ -3526,32 +3638,39 @@ } resultListPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); while ((clientData = Tcl_CommandTraceInfo(interp, name, 0, TraceCommandProc, clientData)) != NULL) { + int numOps = 0; TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) clientData; - eachTraceObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); - /* * Build a list with the ops list as * the first obj element and the tcmdPtr->command string * as the second obj element. Append this list (as an * element) to the end of the result object list. */ elemObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); + Tcl_IncrRefCount(elemObjPtr); if (tcmdPtr->flags & TCL_TRACE_RENAME) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("rename",6)); } if (tcmdPtr->flags & TCL_TRACE_DELETE) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("delete",6)); } + Tcl_ListObjLength(NULL, elemObjPtr, &numOps); + if (0 == numOps) { + Tcl_DecrRefCount(elemObjPtr); + continue; + } + eachTraceObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, elemObjPtr); + Tcl_DecrRefCount(elemObjPtr); elemObjPtr = Tcl_NewStringObj(tcmdPtr->command, -1); Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, elemObjPtr); Tcl_ListObjAppendElement(interp, resultListPtr, eachTraceObjPtr); @@ -3646,24 +3765,55 @@ } } command = Tcl_GetStringFromObj(objv[5], &commandLength); length = (size_t) commandLength; if ((enum traceOptions) optionIndex == TRACE_ADD) { + /* + * This code essentially mallocs together the VarTrace and the + * TraceVarInfo, then inlines the Tcl_TraceVar(). This is + * necessary in order to have the TraceVarInfo to be freed + * automatically when the VarTrace is freed [Bug 1348775] + */ + + CompoundVarTrace *compTracePtr; TraceVarInfo *tvarPtr; - tvarPtr = (TraceVarInfo *) ckalloc((unsigned) - (sizeof(TraceVarInfo) - sizeof(tvarPtr->command) + Var *varPtr, *arrayPtr; + VarTrace *tracePtr; + int flagMask; + + compTracePtr = (CompoundVarTrace *) ckalloc((unsigned) + (sizeof(CompoundVarTrace) - sizeof(tvarPtr->command) + length + 1)); + tracePtr = &(compTracePtr->trace); + tvarPtr = &(compTracePtr->tvar); tvarPtr->flags = flags; + if (objv[0] == NULL) { + tvarPtr->flags |= TCL_TRACE_OLD_STYLE; + } tvarPtr->length = length; flags |= TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT; strcpy(tvarPtr->command, command); name = Tcl_GetString(objv[3]); - if (Tcl_TraceVar(interp, name, flags, TraceVarProc, - (ClientData) tvarPtr) != TCL_OK) { - ckfree((char *) tvarPtr); + flagMask = TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY; + varPtr = TclLookupVar(interp, name, NULL, + (flags & flagMask) | TCL_LEAVE_ERR_MSG, "trace", + /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); + if (varPtr == NULL) { + ckfree((char *) tracePtr); return TCL_ERROR; } + flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES + | TCL_TRACE_UNSETS | TCL_TRACE_ARRAY + | TCL_TRACE_RESULT_DYNAMIC | TCL_TRACE_RESULT_OBJECT; +#ifndef TCL_REMOVE_OBSOLETE_TRACES + flagMask |= TCL_TRACE_OLD_STYLE; +#endif + tracePtr->traceProc = TraceVarProc; + tracePtr->clientData = (ClientData) tvarPtr; + tracePtr->flags = flags & flagMask; + tracePtr->nextPtr = varPtr->tracePtr; + varPtr->tracePtr = tracePtr; } else { /* * Search through all of our traces on this variable to * see if there's one with the given command. If so, then * delete the first one that matches. @@ -3674,17 +3824,16 @@ name = Tcl_GetString(objv[3]); while ((clientData = Tcl_VarTraceInfo(interp, name, 0, TraceVarProc, clientData)) != 0) { tvarPtr = (TraceVarInfo *) clientData; if ((tvarPtr->length == length) - && (tvarPtr->flags == flags) + && ((tvarPtr->flags & ~TCL_TRACE_OLD_STYLE)==flags) && (strncmp(command, tvarPtr->command, (size_t) length) == 0)) { Tcl_UntraceVar2(interp, name, NULL, flags | TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT, TraceVarProc, clientData); - Tcl_EventuallyFree((ClientData) tvarPtr, TCL_DYNAMIC); break; } } } break; @@ -3703,11 +3852,10 @@ while ((clientData = Tcl_VarTraceInfo(interp, name, 0, TraceVarProc, clientData)) != 0) { TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData; - eachTraceObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); /* * Build a list with the ops list as * the first obj element and the tcmdPtr->command string * as the second obj element. Append this list (as an * element) to the end of the result object list. @@ -3728,10 +3876,11 @@ } if (tvarPtr->flags & TCL_TRACE_UNSETS) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("unset", 5)); } + eachTraceObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, elemObjPtr); elemObjPtr = Tcl_NewStringObj(tvarPtr->command, -1); Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, elemObjPtr); Tcl_ListObjAppendElement(interp, resultListPtr, @@ -3944,11 +4093,15 @@ */ for (activePtr = iPtr->activeCmdTracePtr; activePtr != NULL; activePtr = activePtr->nextPtr) { if (activePtr->nextTracePtr == tracePtr) { - activePtr->nextTracePtr = tracePtr->nextPtr; + if (activePtr->reverseScan) { + activePtr->nextTracePtr = prevPtr; + } else { + activePtr->nextTracePtr = tracePtr->nextPtr; + } } } if (prevPtr == NULL) { cmdPtr->tracePtr = tracePtr->nextPtr; } else { @@ -4012,11 +4165,11 @@ int code; Tcl_DString cmd; tcmdPtr->refCount++; - if ((tcmdPtr->flags & flags) && !(flags & TCL_INTERP_DESTROYED)) { + if ((tcmdPtr->flags & flags) && !Tcl_InterpDeleted(interp)) { /* * Generate a command to execute by appending list elements * for the old and new command name and the operation. */ @@ -4061,10 +4214,12 @@ /* * We delete when the trace was destroyed or if this is a delete trace, * because command deletes are unconditional, so the trace must go away. */ if (flags & (TCL_TRACE_DESTROYED | TCL_TRACE_DELETE)) { + int untraceFlags = tcmdPtr->flags; + if (tcmdPtr->stepTrace != NULL) { Tcl_DeleteTrace(interp, tcmdPtr->stepTrace); tcmdPtr->stepTrace = NULL; if (tcmdPtr->startCmd != NULL) { ckfree((char *)tcmdPtr->startCmd); @@ -4072,17 +4227,51 @@ } if (tcmdPtr->flags & TCL_TRACE_EXEC_IN_PROGRESS) { /* Postpone deletion, until exec trace returns */ tcmdPtr->flags = 0; } + + /* + * We need to construct the same flags for Tcl_UntraceCommand + * as were passed to Tcl_TraceCommand. Reproduce the processing + * of [trace add execution/command]. Be careful to keep this + * code in sync with that. + */ + + if (untraceFlags & TCL_TRACE_ANY_EXEC) { + untraceFlags |= TCL_TRACE_DELETE; + if (untraceFlags & (TCL_TRACE_ENTER_DURING_EXEC + | TCL_TRACE_LEAVE_DURING_EXEC)) { + untraceFlags |= (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC); + } + } else if (untraceFlags & TCL_TRACE_RENAME) { + untraceFlags |= TCL_TRACE_DELETE; + } + /* - * Decrement the refCount since the command which held our - * reference (ever since we were created) has just gone away + * Remove the trace since TCL_TRACE_DESTROYED tells us to, or the + * command we're tracing has just gone away. Then decrement the + * clientData refCount that was set up by trace creation. + * + * Note that we save the (return) state of the interpreter to prevent + * bizarre error messages. */ + + Tcl_SaveResult(interp, &state); + stateCode = iPtr->returnCode; + Tcl_UntraceCommand(interp, oldName, untraceFlags, + TraceCommandProc, clientData); + Tcl_RestoreResult(interp, &state); + iPtr->returnCode = stateCode; + tcmdPtr->refCount--; } - if ((--tcmdPtr->refCount) <= 0) { + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("TraceCommandProc: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } return; } @@ -4146,31 +4335,41 @@ for (tracePtr = cmdPtr->tracePtr; (traceCode == TCL_OK) && (tracePtr != NULL); tracePtr = active.nextTracePtr) { if (traceFlags & TCL_TRACE_LEAVE_EXEC) { /* execute the trace command in order of creation for "leave" */ + active.reverseScan = 1; active.nextTracePtr = NULL; tracePtr = cmdPtr->tracePtr; while (tracePtr->nextPtr != lastTracePtr) { active.nextTracePtr = tracePtr; tracePtr = tracePtr->nextPtr; } } else { + active.reverseScan = 0; active.nextTracePtr = tracePtr->nextPtr; } - tcmdPtr = (TraceCommandInfo*)tracePtr->clientData; - if (tcmdPtr->flags != 0) { - tcmdPtr->curFlags = traceFlags | TCL_TRACE_EXEC_DIRECT; - tcmdPtr->curCode = code; - tcmdPtr->refCount++; - traceCode = TraceExecutionProc((ClientData)tcmdPtr, interp, - curLevel, command, (Tcl_Command)cmdPtr, objc, objv); - if ((--tcmdPtr->refCount) <= 0) { - ckfree((char*)tcmdPtr); + if (tracePtr->traceProc == TraceCommandProc) { + tcmdPtr = (TraceCommandInfo*)tracePtr->clientData; + if (tcmdPtr->flags != 0) { + tcmdPtr->curFlags = traceFlags | TCL_TRACE_EXEC_DIRECT; + tcmdPtr->curCode = code; + tcmdPtr->refCount++; + traceCode = TraceExecutionProc((ClientData)tcmdPtr, interp, + curLevel, command, (Tcl_Command)cmdPtr, objc, objv); + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("TclCheckExecutionTraces: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { + ckfree((char*)tcmdPtr); + } } } - lastTracePtr = tracePtr; + if (active.nextTracePtr) { + lastTracePtr = active.nextTracePtr->nextPtr; + } } iPtr->activeCmdTracePtr = active.nextPtr; return(traceCode); } @@ -4213,18 +4412,17 @@ Interp *iPtr = (Interp *) interp; Trace *tracePtr, *lastTracePtr; ActiveInterpTrace active; int curLevel; int traceCode = TCL_OK; - TraceCommandInfo* tcmdPtr; if (command == NULL || iPtr->tracePtr == NULL || (iPtr->flags & INTERP_TRACE_IN_PROGRESS)) { return(traceCode); } - curLevel = ((iPtr->varFramePtr == NULL) ? 0 : iPtr->varFramePtr->level); + curLevel = iPtr->numLevels; active.nextPtr = iPtr->activeInterpTracePtr; iPtr->activeInterpTracePtr = &active; lastTracePtr = NULL; @@ -4238,17 +4436,19 @@ * "enterstep" instead of for "leavestep" as was done in * TclCheckExecutionTraces because for step traces, * Tcl_CreateObjTrace creates one more linked list of traces * which results in one more reversal of trace invocation. */ + active.reverseScan = 1; active.nextTracePtr = NULL; tracePtr = iPtr->tracePtr; while (tracePtr->nextPtr != lastTracePtr) { active.nextTracePtr = tracePtr; tracePtr = tracePtr->nextPtr; } } else { + active.reverseScan = 0; active.nextTracePtr = tracePtr->nextPtr; } if (tracePtr->level > 0 && curLevel > tracePtr->level) { continue; } @@ -4263,20 +4463,20 @@ Tcl_Preserve((ClientData) tracePtr); tracePtr->flags |= TCL_TRACE_EXEC_IN_PROGRESS; if (tracePtr->flags & (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC)) { /* New style trace */ - if ((tracePtr->flags != TCL_TRACE_EXEC_IN_PROGRESS) && - ((tracePtr->flags & traceFlags) != 0)) { - tcmdPtr = (TraceCommandInfo*)tracePtr->clientData; - tcmdPtr->curFlags = traceFlags; - tcmdPtr->curCode = code; - traceCode = (tracePtr->proc)((ClientData)tcmdPtr, - (Tcl_Interp*)interp, - curLevel, command, - (Tcl_Command)cmdPtr, - objc, objv); + if (tracePtr->flags & traceFlags) { + if (tracePtr->proc == TraceExecutionProc) { + TraceCommandInfo *tcmdPtr = + (TraceCommandInfo *) tracePtr->clientData; + tcmdPtr->curFlags = traceFlags; + tcmdPtr->curCode = code; + } + traceCode = (tracePtr->proc)(tracePtr->clientData, + interp, curLevel, command, (Tcl_Command)cmdPtr, + objc, objv); } } else { /* Old-style trace */ if (traceFlags & TCL_TRACE_ENTER_EXEC) { @@ -4289,11 +4489,13 @@ } } tracePtr->flags &= ~TCL_TRACE_EXEC_IN_PROGRESS; Tcl_Release((ClientData) tracePtr); } - lastTracePtr = tracePtr; + if (active.nextTracePtr) { + lastTracePtr = active.nextTracePtr->nextPtr; + } } iPtr->activeInterpTracePtr = active.nextPtr; return(traceCode); } @@ -4369,12 +4571,16 @@ *---------------------------------------------------------------------- */ static void CommandObjTraceDeleted(ClientData clientData) { TraceCommandInfo* tcmdPtr = (TraceCommandInfo*)clientData; - if ((--tcmdPtr->refCount) <= 0) { - ckfree((char*)tcmdPtr); + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("CommandObjTraceDeleted: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { + ckfree((char*)tcmdPtr); } } /* *---------------------------------------------------------------------- @@ -4419,22 +4625,22 @@ * be called for the same trace. */ return traceCode; } - if (!(flags & TCL_INTERP_DESTROYED)) { + if (!Tcl_InterpDeleted(interp)) { /* * Check whether the current call is going to eval arbitrary * Tcl code with a generated trace, or whether we are only * going to setup interpreter-wide traces to implement the * 'step' traces. This latter situation can happen if * we create a command trace without either before or after * operations, but with either of the step operations. */ if (flags & TCL_TRACE_EXEC_DIRECT) { - call = flags & tcmdPtr->flags & (TCL_TRACE_ENTER_EXEC | - TCL_TRACE_LEAVE_EXEC); + call = flags & tcmdPtr->flags + & (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC); } else { call = 1; } /* * First, if we have returned back to the level at which we @@ -4455,14 +4661,13 @@ /* * Second, create the tcl callback, if required. */ if (call) { Tcl_SavedResult state; - int stateCode; + int stateCode, i, saveInterpFlags; Tcl_DString cmd; Tcl_DString sub; - int i; Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, tcmdPtr->command, (int)tcmdPtr->length); /* Append command with arguments */ Tcl_DStringInit(&sub); @@ -4512,30 +4717,38 @@ */ Tcl_SaveResult(interp, &state); stateCode = iPtr->returnCode; - tcmdPtr->flags |= TCL_TRACE_EXEC_IN_PROGRESS; + saveInterpFlags = iPtr->flags; iPtr->flags |= INTERP_TRACE_IN_PROGRESS; + tcmdPtr->flags |= TCL_TRACE_EXEC_IN_PROGRESS; tcmdPtr->refCount++; /* * This line can have quite arbitrary side-effects, * including deleting the trace, the command being * traced, or even the interpreter. */ traceCode = Tcl_Eval(interp, Tcl_DStringValue(&cmd)); tcmdPtr->flags &= ~TCL_TRACE_EXEC_IN_PROGRESS; - iPtr->flags &= ~INTERP_TRACE_IN_PROGRESS; + + /* + * Restore the interp tracing flag to prevent cmd traces + * from affecting interp traces + */ + iPtr->flags = saveInterpFlags;; if (tcmdPtr->flags == 0) { flags |= TCL_TRACE_DESTROYED; } if (traceCode == TCL_OK) { /* Restore result if trace execution was successful */ Tcl_RestoreResult(interp, &state); iPtr->returnCode = stateCode; - } + } else { + Tcl_DiscardResult(&state); + } Tcl_DStringFree(&cmd); } /* @@ -4568,11 +4781,15 @@ ckfree((char *)tcmdPtr->startCmd); } } } if (call) { - if ((--tcmdPtr->refCount) <= 0) { + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("TraceExecutionProc: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } } return traceCode; } @@ -4607,25 +4824,22 @@ * information. */ { Tcl_SavedResult state; TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData; char *result; - int code; + int code, destroy = 0; Tcl_DString cmd; /* - * We might call Tcl_Eval() below, and that might evaluate - * [trace vdelete] which might try to free tvarPtr. We want - * to use tvarPtr until the end of this function, so we use - * Tcl_Preserve() and Tcl_Release() to be sure it is not - * freed while we still need it. + * We might call Tcl_Eval() below, and that might evaluate [trace + * vdelete] which might try to free tvarPtr. However we do not + * need to protect anything here; it's done by our caller because + * the TraceVarInfo is really part of a CompoundVarTrace. [Bug 1348775] */ - Tcl_Preserve((ClientData) tvarPtr); - result = NULL; - if ((tvarPtr->flags & flags) && !(flags & TCL_INTERP_DESTROYED)) { + if ((tvarPtr->flags & flags) && !Tcl_InterpDeleted(interp)) { if (tvarPtr->length != (size_t) 0) { /* * Generate a command to execute by appending list elements * for the two variable names and the operation. */ @@ -4668,11 +4882,13 @@ * other areas that this will be destroyed by us, otherwise a * double-free might occur depending on what the eval does. */ Tcl_SaveResult(interp, &state); - if (flags & TCL_TRACE_DESTROYED) { + if ((flags & TCL_TRACE_DESTROYED) + && !(tvarPtr->flags & TCL_TRACE_DESTROYED)) { + destroy = 1; tvarPtr->flags |= TCL_TRACE_DESTROYED; } code = Tcl_EvalEx(interp, Tcl_DStringValue(&cmd), Tcl_DStringLength(&cmd), 0); @@ -4685,20 +4901,18 @@ Tcl_RestoreResult(interp, &state); Tcl_DStringFree(&cmd); } } - if (flags & TCL_TRACE_DESTROYED) { + if (destroy) { if (result != NULL) { register Tcl_Obj *errMsgObj = (Tcl_Obj *) result; Tcl_DecrRefCount(errMsgObj); result = NULL; } - Tcl_EventuallyFree((ClientData) tvarPtr, TCL_DYNAMIC); } - Tcl_Release((ClientData) tvarPtr); return result; } /* *---------------------------------------------------------------------- @@ -4728,10 +4942,13 @@ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int result, value; +#ifdef TCL_TIP280 + Interp* iPtr = (Interp*) interp; +#endif if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "test command"); return TCL_ERROR; } @@ -4742,11 +4959,16 @@ return result; } if (!value) { break; } +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[2], 0); +#else + /* TIP #280. */ + result = TclEvalObjEx(interp, objv[2], 0, iPtr->cmdFramePtr,2); +#endif if ((result != TCL_OK) && (result != TCL_CONTINUE)) { if (result == TCL_ERROR) { char msg[32 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"while\" body line %d)", @@ -4762,6 +4984,47 @@ if (result == TCL_OK) { Tcl_ResetResult(interp); } return result; } + +#ifdef TCL_TIP280 +static void +ListLines(listStr, line, n, lines) + CONST char* listStr; /* Pointer to string with list structure. + * Assumed to be valid. Assumed to contain + * n elements. + */ + int line; /* line the list as a whole starts on */ + int n; /* #elements in lines */ + int* lines; /* Array of line numbers, to fill */ +{ + int i; + int length = strlen( listStr); + CONST char *element = NULL; + CONST char* next = NULL; + + for (i = 0; i < n; i++) { + TclFindElement(NULL, listStr, length, &element, &next, NULL, NULL); + + TclAdvanceLines (&line, listStr, element); /* Leading whitespace */ + lines [i] = line; + length -= (next - listStr); + TclAdvanceLines (&line, element, next); /* Element */ + listStr = next; + + if (*element == 0) { + /* ASSERT i == n */ + break; + } + } +} +#endif + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ Index: generic/tclCompCmds.c ================================================================== --- generic/tclCompCmds.c +++ generic/tclCompCmds.c @@ -9,11 +9,11 @@ * Copyright (c) 2002 ActiveState Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompCmds.c,v 1.39 2003/02/07 01:07:05 mdejong Exp $ + * RCS: @(#) $Id: tclCompCmds.c,v 1.39.2.6 2007/03/01 16:06:19 dkf Exp $ */ #include "tclInt.h" #include "tclCompile.h" @@ -21,13 +21,20 @@ * Prototypes for procedures defined later in this file: */ static ClientData DupForeachInfo _ANSI_ARGS_((ClientData clientData)); static void FreeForeachInfo _ANSI_ARGS_((ClientData clientData)); +#ifndef TCL_TIP280 static int TclPushVarName _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags, int *localIndexPtr, int *simpleVarNamePtr, int *isScalarPtr)); +#else +static int TclPushVarName _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags, + int *localIndexPtr, int *simpleVarNamePtr, int *isScalarPtr, + int line)); +#endif /* * Flags bits used by TclPushVarName. */ @@ -75,10 +82,20 @@ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr, *valueTokenPtr; int simpleVarName, isScalar, localIndex, numWords; int code = TCL_OK; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif numWords = parsePtr->numWords; if (numWords == 1) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), @@ -107,11 +124,16 @@ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, +#ifndef TCL_TIP280 &localIndex, &simpleVarName, &isScalar); +#else + &localIndex, &simpleVarName, &isScalar, + mapPtr->loc [eclIndex].line [1]); +#endif if (code != TCL_OK) { goto done; } /* @@ -124,10 +146,13 @@ valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [2]; +#endif code = TclCompileTokens(interp, valueTokenPtr+1, valueTokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } @@ -243,10 +268,20 @@ Tcl_Token *cmdTokenPtr, *nameTokenPtr; CONST char *name; int localIndex, nameChars, range, startOffset, jumpDist; int code; int savedStackDepth = envPtr->currStackDepth; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"catch command ?varName?\"", -1); @@ -306,10 +341,13 @@ * an instruction to eval the body. Care has to be taken to * register the correct startOffset for the catch range so that * errors in the substitution are not catched [Bug 219184] */ +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [1]; +#endif if (cmdTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { startOffset = (envPtr->codeNext - envPtr->codeStart); code = TclCompileCmdWord(interp, cmdTokenPtr+1, 1, envPtr); } else { code = TclCompileTokens(interp, cmdTokenPtr+1, @@ -460,10 +498,15 @@ Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"expr arg ?arg ...?\"", -1); return TCL_ERROR; } +#ifdef TCL_TIP280 + /* TIP #280 : Use the per-word line information of the current command. + */ + envPtr->line = envPtr->extCmdMapPtr->loc [envPtr->extCmdMapPtr->nuloc - 1].line [1]; +#endif firstWordPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); return TclCompileExprWords(interp, firstWordPtr, (parsePtr->numWords-1), envPtr); } @@ -497,10 +540,20 @@ JumpFixup jumpEvalCondFixup; int testCodeOffset, bodyCodeOffset, nextCodeOffset, jumpDist; int bodyRange, nextRange, code; char buffer[32 + TCL_INTEGER_SPACE]; int savedStackDepth = envPtr->currStackDepth; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif if (parsePtr->numWords != 5) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"for start test next command\"", -1); @@ -546,10 +599,13 @@ /* * Inline compile the initial command. */ +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [1]; +#endif code = TclCompileCmdWord(interp, startTokenPtr+1, startTokenPtr->numComponents, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { Tcl_AddObjErrorInfo(interp, @@ -577,10 +633,13 @@ * Compile the loop body. */ bodyCodeOffset = (envPtr->codeNext - envPtr->codeStart); +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [4]; +#endif code = TclCompileCmdWord(interp, bodyTokenPtr+1, bodyTokenPtr->numComponents, envPtr); envPtr->currStackDepth = savedStackDepth + 1; if (code != TCL_OK) { if (code == TCL_ERROR) { @@ -599,10 +658,13 @@ * Compile the "next" subcommand. */ nextCodeOffset = (envPtr->codeNext - envPtr->codeStart); +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [3]; +#endif envPtr->currStackDepth = savedStackDepth; code = TclCompileCmdWord(interp, nextTokenPtr+1, nextTokenPtr->numComponents, envPtr); envPtr->currStackDepth = savedStackDepth + 1; if (code != TCL_OK) { @@ -629,11 +691,13 @@ if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) { bodyCodeOffset += 3; nextCodeOffset += 3; testCodeOffset += 3; } - +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [2]; +#endif envPtr->currStackDepth = savedStackDepth; code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { Tcl_AddObjErrorInfo(interp, @@ -720,10 +784,21 @@ int jumpDist, jumpBackDist, jumpBackOffset, infoIndex, range; int numWords, numLists, numVars, loopIndex, tempVar, i, j, code; char buffer[32 + TCL_INTEGER_SPACE]; int savedStackDepth = envPtr->currStackDepth; +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; + int bodyIndex; +#endif + /* * We parse the variable list argument words and create two arrays: * varcList[i] is number of variables in i-th var list * varvList[i] points to array of var names in i-th var list */ @@ -761,10 +836,13 @@ } bodyTokenPtr = tokenPtr; if (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { return TCL_OUT_LINE_COMPILE; } +#ifdef TCL_TIP280 + bodyIndex = i-1; +#endif /* * Allocate storage for the varcList and varvList arrays if necessary. */ @@ -814,10 +892,22 @@ Tcl_DStringFree(&varList); if (code != TCL_OK) { goto done; } numVars = varcList[loopIndex]; + + /* + * If the variable list is empty, we can enter an infinite + * loop when the interpreted version would not. Take care to + * ensure this does not happen. [Bug 1671138] + */ + + if (numVars == 0) { + code = TCL_OUT_LINE_COMPILE; + goto done; + } + for (j = 0; j < numVars; j++) { CONST char *varName = varvList[loopIndex][j]; if (!TclIsLocalScalar(varName, (int) strlen(varName))) { code = TCL_OUT_LINE_COMPILE; goto done; @@ -884,10 +974,13 @@ loopIndex = 0; for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++, tokenPtr += (tokenPtr->numComponents + 1)) { if ((i%2 == 0) && (i > 0)) { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [i]; +#endif code = TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } @@ -921,10 +1014,13 @@ /* * Inline compile the loop body. */ +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [bodyIndex]; +#endif envPtr->exceptArrayPtr[range].codeOffset = (envPtr->codeNext - envPtr->codeStart); code = TclCompileCmdWord(interp, bodyTokenPtr+1, bodyTokenPtr->numComponents, envPtr); envPtr->currStackDepth = savedStackDepth + 1; @@ -1150,10 +1246,20 @@ * to this value at the start of each test. */ int realCond = 1; /* set to 0 for static conditions: "if 0 {..}" */ int boolVal; /* value of static condition */ int compileScripts = 1; +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif + /* * Only compile the "if" command if all arguments are simple * words, in order to insure correct substitution [Bug 219166] */ @@ -1194,12 +1300,12 @@ } else { break; } if (wordIdx >= numWords) { sprintf(buffer, - "wrong # args: no expression after \"%.30s\" argument", - word); + "wrong # args: no expression after \"%.*s\" argument", + (numBytes > 50 ? 50 : numBytes), word); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buffer, -1); code = TCL_ERROR; goto done; } @@ -1231,10 +1337,13 @@ if (!boolVal) { compileScripts = 0; } } else { Tcl_ResetResult(interp); +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [wordIdx]; +#endif code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { Tcl_AddObjErrorInfo(interp, "\n (\"if\" test expression)", -1); @@ -1257,11 +1366,14 @@ */ tokenPtr = testTokenPtr + (testTokenPtr->numComponents + 1); wordIdx++; if (wordIdx >= numWords) { - sprintf(buffer, "wrong # args: no script following \"%.20s\" argument", testTokenPtr->start); + sprintf(buffer, + "wrong # args: no script following \"%.*s\" argument", + (testTokenPtr->size > 50 ? 50 : testTokenPtr->size), + testTokenPtr->start); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buffer, -1); code = TCL_ERROR; goto done; } @@ -1284,10 +1396,13 @@ /* * Compile the "then" command body. */ if (compileScripts) { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [wordIdx]; +#endif envPtr->currStackDepth = savedStackDepth; code = TclCompileCmdWord(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { @@ -1386,11 +1501,13 @@ if (compileScripts) { /* * Compile the else command body. */ - +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [wordIdx]; +#endif code = TclCompileCmdWord(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { sprintf(buffer, "\n (\"if\" else script line %d)", @@ -1497,10 +1614,20 @@ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr, *incrTokenPtr; int simpleVarName, isScalar, localIndex, haveImmValue, immValue; int code = TCL_OK; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"incr varName ?increment?\"", -1); @@ -1510,11 +1637,16 @@ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); code = TclPushVarName(interp, varTokenPtr, envPtr, (TCL_NO_LARGE_INDEX | TCL_CREATE_VAR), +#ifndef TCL_TIP280 &localIndex, &simpleVarName, &isScalar); +#else + &localIndex, &simpleVarName, &isScalar, + mapPtr->loc [eclIndex].line [1]); +#endif if (code != TCL_OK) { goto done; } /* @@ -1521,51 +1653,50 @@ * If an increment is given, push it, but see first if it's a small * integer. */ haveImmValue = 0; - immValue = 0; + immValue = 1; if (parsePtr->numWords == 3) { incrTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (incrTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { CONST char *word = incrTokenPtr[1].start; int numBytes = incrTokenPtr[1].size; - int validLength = TclParseInteger(word, numBytes); - long n; /* * Note there is a danger that modifying the string could have - * undesirable side effects. In this case, TclLooksLikeInt and - * TclGetLong do not have any dependencies on shared strings so we - * should be safe. + * undesirable side effects. In this case, TclLooksLikeInt has + * no dependencies on shared strings so we should be safe. */ - if (validLength == numBytes) { + if (TclLooksLikeInt(word, numBytes)) { int code; - Tcl_Obj *longObj = Tcl_NewStringObj(word, numBytes); - Tcl_IncrRefCount(longObj); - code = Tcl_GetLongFromObj(NULL, longObj, &n); - Tcl_DecrRefCount(longObj); - if ((code == TCL_OK) && (-127 <= n) && (n <= 127)) { + Tcl_Obj *intObj = Tcl_NewStringObj(word, numBytes); + Tcl_IncrRefCount(intObj); + code = Tcl_GetIntFromObj(NULL, intObj, &immValue); + Tcl_DecrRefCount(intObj); + if ((code == TCL_OK) + && (-127 <= immValue) && (immValue <= 127)) { haveImmValue = 1; - immValue = n; } } if (!haveImmValue) { TclEmitPush( TclRegisterNewLiteral(envPtr, word, numBytes), envPtr); } } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [2]; +#endif code = TclCompileTokens(interp, incrTokenPtr+1, incrTokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } } } else { /* no incr amount given so use 1 */ haveImmValue = 1; - immValue = 1; } /* * Emit the instruction to increment the variable. */ @@ -1646,10 +1777,20 @@ { Tcl_Token *varTokenPtr, *valueTokenPtr; int simpleVarName, isScalar, localIndex, numWords; int code = TCL_OK; +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif + /* * If we're not in a procedure, don't compile. */ if (envPtr->procPtr == NULL) { return TCL_OUT_LINE_COMPILE; @@ -1679,11 +1820,16 @@ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, +#ifndef TCL_TIP280 &localIndex, &simpleVarName, &isScalar); +#else + &localIndex, &simpleVarName, &isScalar, + mapPtr->loc [eclIndex].line [1]); +#endif if (code != TCL_OK) { goto done; } /* @@ -1695,10 +1841,13 @@ valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [2]; +#endif code = TclCompileTokens(interp, valueTokenPtr+1, valueTokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } @@ -1771,10 +1920,20 @@ * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr; int code, i; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif int numWords; numWords = parsePtr->numWords; /* @@ -1796,10 +1955,13 @@ if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush( TclRegisterNewLiteral( envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [i]; +#endif code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } @@ -1849,10 +2011,20 @@ Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif + /* * If we're not in a procedure, don't compile. */ if (envPtr->procPtr == NULL) { return TCL_OUT_LINE_COMPILE; @@ -1878,10 +2050,13 @@ for (i = 1; i < numWords; i++) { if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [i]; +#endif code = TclCompileTokens(interp, valueTokenPtr+1, valueTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } @@ -1922,10 +2097,20 @@ * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr; int code; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif if (parsePtr->numWords != 2) { Tcl_SetResult(interp, "wrong # args: should be \"llength list\"", TCL_STATIC); return TCL_ERROR; @@ -1939,10 +2124,13 @@ * that value, but that is too rare a case to waste the code space. */ TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [1]; +#endif code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } @@ -2013,10 +2201,20 @@ int localIndex; /* Index of var in local var table */ int simpleVarName; /* Flag == 1 if var name is simple */ int isScalar; /* Flag == 1 if scalar, 0 if array */ int i; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif /* Check argument count */ if ( parsePtr->numWords < 3 ) { /* Fail at run time, not in compilation */ @@ -2032,11 +2230,16 @@ */ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); result = TclPushVarName( interp, varTokenPtr, envPtr, +#ifndef TCL_TIP280 TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar ); +#else + TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar, + mapPtr->loc [eclIndex].line [1]); +#endif if (result != TCL_OK) { return result; } /* Push the "index" args and the new element value. */ @@ -2051,10 +2254,13 @@ if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral( envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [i]; +#endif result = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if ( result != TCL_OK ) { return result; } @@ -2180,10 +2386,20 @@ { Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing * the parse of the RE or string */ int i, len, code, nocase, anchorLeft, anchorRight, start; char *str; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif /* * We are only interested in compiling simple regexp cases. * Currently supported compile cases are: * regexp ?-nocase? ?--? staticString $var @@ -2328,10 +2544,13 @@ varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [parsePtr->numWords-1]; +#endif code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } @@ -2377,10 +2596,20 @@ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr; int code; int index = envPtr->exceptArrayNext - 1; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif /* * If we're not in a procedure, don't compile. */ @@ -2435,10 +2664,13 @@ * variable reference and nested command cases. If the * parse token can be byte-compiled, then this instance of * "return" will be byte-compiled; otherwise it will be * out line compiled. */ +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [1]; +#endif code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } @@ -2494,10 +2726,20 @@ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr, *valueTokenPtr; int isAssignment, isScalar, simpleVarName, localIndex, numWords; int code = TCL_OK; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif numWords = parsePtr->numWords; if ((numWords != 2) && (numWords != 3)) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), @@ -2516,11 +2758,16 @@ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, +#ifndef TCL_TIP280 &localIndex, &simpleVarName, &isScalar); +#else + &localIndex, &simpleVarName, &isScalar, + mapPtr->loc [eclIndex].line [1]); +#endif if (code != TCL_OK) { goto done; } /* @@ -2531,10 +2778,13 @@ valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [2]; +#endif code = TclCompileTokens(interp, valueTokenPtr+1, valueTokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } @@ -2632,10 +2882,20 @@ STR_MAP, STR_MATCH, STR_RANGE, STR_REPEAT, STR_REPLACE, STR_TOLOWER, STR_TOUPPER, STR_TOTITLE, STR_TRIM, STR_TRIMLEFT, STR_TRIMRIGHT, STR_WORDEND, STR_WORDSTART }; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif if (parsePtr->numWords < 2) { /* Fail at run time, not in compilation */ return TCL_OUT_LINE_COMPILE; } @@ -2694,10 +2954,13 @@ for (i = 0; i < 2; i++) { if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [i]; +#endif code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } @@ -2724,10 +2987,13 @@ for (i = 0; i < 2; i++) { if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [i]; +#endif code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } @@ -2754,10 +3020,13 @@ varTokenPtr[1].size); len = sprintf(buf, "%d", len); TclEmitPush(TclRegisterNewLiteral(envPtr, buf, len), envPtr); return TCL_OK; } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [2]; +#endif code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } @@ -2811,10 +3080,13 @@ Tcl_DecrRefCount(copy); } TclEmitPush( TclRegisterNewLiteral(envPtr, str, length), envPtr); } else { +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [i]; +#endif code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } @@ -2926,10 +3198,20 @@ int savedStackDepth = envPtr->currStackDepth; int loopMayEnd = 1; /* This is set to 0 if it is recognized as * an infinite loop. */ Tcl_Obj *boolObj; int boolVal; + +#ifdef TCL_TIP280 + /* TIP #280 : Remember the per-word line information of the current + * command. An index is used instead of a pointer as recursive compilation + * may reallocate, i.e. move, the array. This is also the reason to save + * the nuloc now, it may change during the course of the function. + */ + ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr; + int eclIndex = mapPtr->nuloc - 1; +#endif if (parsePtr->numWords != 3) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"while test command\"", -1); @@ -3012,10 +3294,13 @@ /* * Compile the loop body. */ +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [2]; +#endif bodyCodeOffset = (envPtr->codeNext - envPtr->codeStart); code = TclCompileCmdWord(interp, bodyTokenPtr+1, bodyTokenPtr->numComponents, envPtr); envPtr->currStackDepth = savedStackDepth + 1; if (code != TCL_OK) { @@ -3041,10 +3326,13 @@ if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) { bodyCodeOffset += 3; testCodeOffset += 3; } envPtr->currStackDepth = savedStackDepth; +#ifdef TCL_TIP280 + envPtr->line = mapPtr->loc [eclIndex].line [1]; +#endif code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { Tcl_AddObjErrorInfo(interp, "\n (\"while\" test expression)", -1); @@ -3113,19 +3401,26 @@ *---------------------------------------------------------------------- */ static int TclPushVarName(interp, varTokenPtr, envPtr, flags, localIndexPtr, +#ifndef TCL_TIP280 simpleVarNamePtr, isScalarPtr) +#else + simpleVarNamePtr, isScalarPtr, line) +#endif Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Token *varTokenPtr; /* Points to a variable token. */ CompileEnv *envPtr; /* Holds resulting instructions. */ int flags; /* takes TCL_CREATE_VAR or * TCL_NO_LARGE_INDEX */ int *localIndexPtr; /* must not be NULL */ int *simpleVarNamePtr; /* must not be NULL */ int *isScalarPtr; /* must not be NULL */ +#ifdef TCL_TIP280 + int line; /* line the token starts on */ +#endif { register CONST char *p; CONST char *name, *elName; register int i, n; int nameChars, elNameChars, simpleVarName, localIndex; @@ -3303,10 +3598,13 @@ * Compile the element script, if any. */ if (elName != NULL) { if (elNameChars) { +#ifdef TCL_TIP280 + envPtr->line = line; +#endif code = TclCompileTokens(interp, elemTokenPtr, elemTokenCount, envPtr); if (code != TCL_OK) { goto done; } @@ -3317,10 +3615,13 @@ } else { /* * The var name isn't simple: compile and push it. */ +#ifdef TCL_TIP280 + envPtr->line = line; +#endif code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } @@ -3336,5 +3637,14 @@ *localIndexPtr = localIndex; *simpleVarNamePtr = simpleVarName; *isScalarPtr = (elName == NULL); return code; } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ + Index: generic/tclCompExpr.c ================================================================== --- generic/tclCompExpr.c +++ generic/tclCompExpr.c @@ -7,11 +7,11 @@ * Copyright (c) 1998-2000 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompExpr.c,v 1.13 2003/02/16 01:36:32 msofer Exp $ + * RCS: @(#) $Id: tclCompExpr.c,v 1.13.2.3 2006/11/28 22:20:00 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclCompile.h" @@ -255,10 +255,15 @@ code = Tcl_ParseExpr(interp, script, numBytes, &parse); if (code != TCL_OK) { goto done; } + +#ifdef TCL_TIP280 + /* TIP #280 : Track Lines within the expression */ + TclAdvanceLines (&envPtr->line, script, parse.tokenPtr->start); +#endif code = CompileSubExpr(parse.tokenPtr, &info, envPtr); if (code != TCL_OK) { Tcl_FreeParse(&parse); goto done; @@ -284,13 +289,11 @@ *---------------------------------------------------------------------- * * TclFinalizeCompilation -- * * Clean up the compilation environment so it can later be - * properly reinitialized. This procedure is called by - * TclFinalizeCompExecEnv() in tclObj.c, which in turn is called - * by Tcl_Finalize(). + * properly reinitialized. This procedure is called by Tcl_Finalize(). * * Results: * None. * * Side effects: @@ -338,11 +341,12 @@ ExprInfo *infoPtr; /* Describes the compilation state for the * expression being compiled. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Interp *interp = infoPtr->interp; - Tcl_Token *tokenPtr, *endPtr, *afterSubexprPtr; + Tcl_Token *tokenPtr, *endPtr = NULL; /* silence gcc 4 warning */ + Tcl_Token *afterSubexprPtr; OperatorDesc *opDescPtr; Tcl_HashEntry *hPtr; CONST char *operator; Tcl_DString opBuf; int objIndex, opIndex, length, code; Index: generic/tclCompile.c ================================================================== --- generic/tclCompile.c +++ generic/tclCompile.c @@ -9,11 +9,11 @@ * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompile.c,v 1.43 2003/02/19 14:33:39 msofer Exp $ + * RCS: @(#) $Id: tclCompile.c,v 1.43.2.7 2006/11/28 22:20:00 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclCompile.h" @@ -298,10 +298,20 @@ static void RecordByteCodeStats _ANSI_ARGS_(( ByteCode *codePtr)); #endif /* TCL_COMPILE_STATS */ static int SetByteCodeFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); + +#ifdef TCL_TIP280 +/* TIP #280 : Helper for building the per-word line information of all + * compiled commands */ +static void EnterCmdWordData _ANSI_ARGS_(( + ExtCmdLoc *eclPtr, int srcOffset, Tcl_Token* tokenPtr, + CONST char* cmd, int len, int numWords, int line, + int** lines)); +#endif + /* * The structure below defines the bytecode Tcl object type by * means of procedures that can be invoked by generic object code. */ @@ -372,11 +382,23 @@ nested = 1; } else { nested = 0; } string = Tcl_GetStringFromObj(objPtr, &length); +#ifndef TCL_TIP280 TclInitCompileEnv(interp, &compEnv, string, length); +#else + /* + * TIP #280. Pick up the CmdFrame in which the BC compiler was invoked + * and use to initialize the tracking in the compiler. This information + * was stored by TclCompEvalObj (tclExecute.c), and ProcCompileProc + * (tclProc.c). + */ + + TclInitCompileEnv(interp, &compEnv, string, length, + iPtr->invokeCmdFramePtr, iPtr->invokeWord); +#endif result = TclCompileScript(interp, string, length, nested, &compEnv); if (result == TCL_OK) { /* * Successful compilation. Add a "done" instruction at the end. @@ -564,10 +586,13 @@ void TclCleanupByteCode(codePtr) register ByteCode *codePtr; /* Points to the ByteCode to free. */ { Tcl_Interp *interp = (Tcl_Interp *) *codePtr->interpHandle; +#ifdef TCL_TIP280 + Interp* iPtr = (Interp*) interp; +#endif int numLitObjects = codePtr->numLitObjects; int numAuxDataItems = codePtr->numAuxDataItems; register Tcl_Obj **objArrayPtr; register AuxData *auxDataPtr; int i; @@ -660,10 +685,42 @@ if (auxDataPtr->type->freeProc != NULL) { (*auxDataPtr->type->freeProc)(auxDataPtr->clientData); } auxDataPtr++; } + +#ifdef TCL_TIP280 + /* + * TIP #280. Release the location data associated with this byte code + * structure, if any. NOTE: The interp we belong to may be gone already, + * and the data with it. + * + * See also tclBasic.c, DeleteInterpProc + */ + + if (iPtr) { + Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr); + if (hePtr) { + ExtCmdLoc* eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hePtr); + int i; + + if (eclPtr->type == TCL_LOCATION_SOURCE) { + Tcl_DecrRefCount (eclPtr->path); + } + for (i=0; i< eclPtr->nuloc; i++) { + ckfree ((char*) eclPtr->loc[i].line); + } + + if (eclPtr->loc != NULL) { + ckfree ((char*) eclPtr->loc); + } + + ckfree ((char*) eclPtr); + Tcl_DeleteHashEntry (hePtr); + } + } +#endif TclHandleRelease(codePtr->interpHandle); ckfree((char *) codePtr); } @@ -683,17 +740,26 @@ * *---------------------------------------------------------------------- */ void +#ifndef TCL_TIP280 TclInitCompileEnv(interp, envPtr, string, numBytes) +#else +TclInitCompileEnv(interp, envPtr, string, numBytes, invoker, word) +#endif Tcl_Interp *interp; /* The interpreter for which a CompileEnv * structure is initialized. */ register CompileEnv *envPtr; /* Points to the CompileEnv structure to * initialize. */ char *string; /* The source string to be compiled. */ int numBytes; /* Number of bytes in source string. */ +#ifdef TCL_TIP280 + CONST CmdFrame* invoker; /* Location context invoking the bcc */ + int word; /* Index of the word in that context + * getting compiled */ +#endif { Interp *iPtr = (Interp *) interp; envPtr->iPtr = iPtr; envPtr->source = string; @@ -722,11 +788,78 @@ envPtr->mallocedExceptArray = 0; envPtr->cmdMapPtr = envPtr->staticCmdMapSpace; envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE; envPtr->mallocedCmdMap = 0; - + +#ifdef TCL_TIP280 + /* + * TIP #280: Set up the extended command location information, based on + * the context invoking the byte code compiler. This structure is used to + * keep the per-word line information for all compiled commands. + * + * See also tclBasic.c, TclEvalObjEx, for the equivalent code in the + * non-compiling evaluator + */ + + envPtr->extCmdMapPtr = (ExtCmdLoc*) ckalloc (sizeof (ExtCmdLoc)); + envPtr->extCmdMapPtr->loc = NULL; + envPtr->extCmdMapPtr->nloc = 0; + envPtr->extCmdMapPtr->nuloc = 0; + envPtr->extCmdMapPtr->path = NULL; + + if (invoker == NULL) { + /* Initialize the compiler for relative counting */ + + envPtr->line = 1; + envPtr->extCmdMapPtr->type = (envPtr->procPtr + ? TCL_LOCATION_PROC + : TCL_LOCATION_BC); + } else { + /* Initialize the compiler using the context, making counting absolute + * to that context. Note that the context can be byte code + * execution. In that case we have to fill out the missing pieces + * (line, path, ...). Which may make change the type as well. + */ + + if ((invoker->nline <= word) || (invoker->line[word] < 0)) { + /* Word is not a literal, relative counting */ + + envPtr->line = 1; + envPtr->extCmdMapPtr->type = (envPtr->procPtr + ? TCL_LOCATION_PROC + : TCL_LOCATION_BC); + } else { + CmdFrame ctx = *invoker; + int pc = 0; + + if (invoker->type == TCL_LOCATION_BC) { + /* Note: Type BC => ctx.data.eval.path is not used. + * ctx.data.tebc.codePtr is used instead. + */ + TclGetSrcInfoForPc (&ctx); + pc = 1; + } + + envPtr->line = ctx.line [word]; + envPtr->extCmdMapPtr->type = ctx.type; + + if (ctx.type == TCL_LOCATION_SOURCE) { + if (pc) { + /* The reference 'TclGetSrcInfoForPc' made is transfered */ + envPtr->extCmdMapPtr->path = ctx.data.eval.path; + ctx.data.eval.path = NULL; + } else { + /* We have a new reference here */ + envPtr->extCmdMapPtr->path = ctx.data.eval.path; + Tcl_IncrRefCount (envPtr->extCmdMapPtr->path); + } + } + } + } +#endif + envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace; envPtr->auxDataArrayNext = 0; envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE; envPtr->mallocedAuxDataArray = 0; } @@ -771,10 +904,58 @@ } if (envPtr->mallocedAuxDataArray) { ckfree((char *) envPtr->auxDataArrayPtr); } } + +#ifdef TCL_TIP280 +/* + *---------------------------------------------------------------------- + * + * TclWordKnownAtCompileTime -- + * + * Test whether the value of a token is completely known at compile time. + * + * Results: + * Returns true if the tokenPtr argument points to a word value that is + * completely known at compile time. Generally, values that are known at + * compile time can be compiled to their values, while values that cannot + * be known until substitution at runtime must be compiled to bytecode + * instructions that perform that substitution. For several commands, + * whether or not arguments are known at compile time determine whether + * it is worthwhile to compile at all. + * + * Side effects: + * None. + * + * TIP #280 + *---------------------------------------------------------------------- + */ + +int +TclWordKnownAtCompileTime (tokenPtr) + Tcl_Token* tokenPtr; +{ + int i; + Tcl_Token* sub; + + if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {return 1;}; + if (tokenPtr->type != TCL_TOKEN_WORD) {return 0;}; + + /* Check the sub tokens of the word. It is a literal if we find + * only BS and TEXT tokens */ + + for (i=0, sub = tokenPtr + 1; + i < tokenPtr->numComponents; + i++, sub ++) { + if (sub->type == TCL_TOKEN_TEXT) continue; + if (sub->type == TCL_TOKEN_BS) continue; + return 0; + } + return 1; +} +#endif /* *---------------------------------------------------------------------- * * TclCompileScript -- @@ -825,10 +1006,17 @@ Command *cmdPtr; Tcl_Token *tokenPtr; int bytesLeft, isFirstCmd, gotParse, wordIdx, currCmdIndex; int commandLength, objIndex, code; Tcl_DString ds; + +#ifdef TCL_TIP280 + /* TIP #280 */ + ExtCmdLoc* eclPtr = envPtr->extCmdMapPtr; + int* wlines; + int wlineat, cmdLine; +#endif Tcl_DStringInit(&ds); if (numBytes < 0) { numBytes = strlen(script); @@ -842,10 +1030,14 @@ */ p = script; bytesLeft = numBytes; gotParse = 0; +#ifdef TCL_TIP280 + cmdLine = envPtr->line; +#endif + do { if (Tcl_ParseCommand(interp, p, bytesLeft, nested, &parse) != TCL_OK) { code = TCL_ERROR; goto error; } @@ -950,14 +1142,32 @@ lastTopLevelCmdIndex = currCmdIndex; } startCodeOffset = (envPtr->codeNext - envPtr->codeStart); EnterCmdStartData(envPtr, currCmdIndex, (parse.commandStart - envPtr->source), startCodeOffset); - + +#ifdef TCL_TIP280 + /* TIP #280. Scan the words and compute the extended location + * information. The map first contain full per-word line + * information for use by the compiler. This is later replaced by + * a reduced form which signals non-literal words, stored in + * 'wlines'. + */ + + TclAdvanceLines (&cmdLine, p, parse.commandStart); + EnterCmdWordData (eclPtr, (parse.commandStart - envPtr->source), + parse.tokenPtr, parse.commandStart, parse.commandSize, + parse.numWords, cmdLine, &wlines); + wlineat = eclPtr->nuloc - 1; +#endif + for (wordIdx = 0, tokenPtr = parse.tokenPtr; wordIdx < parse.numWords; wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) { +#ifdef TCL_TIP280 + envPtr->line = eclPtr->loc [wlineat].line [wordIdx]; +#endif if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { /* * If this is the first word and the command has a * compile procedure, let it compile the command. */ @@ -987,16 +1197,26 @@ if ((cmdPtr != NULL) && (cmdPtr->compileProc != NULL) && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES) && !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) { + int savedNumCmds = envPtr->numCommands; + unsigned int savedCodeNext = + envPtr->codeNext - envPtr->codeStart; + code = (*(cmdPtr->compileProc))(interp, &parse, envPtr); if (code == TCL_OK) { goto finishCommand; } else if (code == TCL_OUT_LINE_COMPILE) { - /* do nothing */ + /* + * Restore numCommands and codeNext to their correct + * values, removing any commands compiled before + * TCL_OUT_LINE_COMPILE [Bugs 705406 and 735055] + */ + envPtr->numCommands = savedNumCmds; + envPtr->codeNext = envPtr->codeStart + savedCodeNext; } else { /* an error */ /* * There was a compilation error, the last * command did not get compiled into (*envPtr). * Decrement the number of commands @@ -1027,11 +1247,10 @@ TclEmitPush(objIndex, envPtr); } else { /* * The word is not a simple string of characters. */ - code = TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto log; } @@ -1058,19 +1277,31 @@ finishCommand: EnterCmdExtentData(envPtr, currCmdIndex, commandLength, (envPtr->codeNext-envPtr->codeStart) - startCodeOffset); isFirstCmd = 0; + +#ifdef TCL_TIP280 + /* TIP #280: Free full form of per-word line data and insert + * the reduced form now + */ + ckfree ((char*) eclPtr->loc [wlineat].line); + eclPtr->loc [wlineat].line = wlines; +#endif } /* end if parse.numWords > 0 */ /* * Advance to the next command in the script. */ - + next = parse.commandStart + parse.commandSize; bytesLeft -= (next - p); p = next; +#ifdef TCL_TIP280 + /* TIP #280 : Track lines in the just compiled command */ + TclAdvanceLines (&cmdLine, parse.commandStart, p); +#endif Tcl_FreeParse(&parse); gotParse = 0; if (nested && (*parse.term == ']')) { /* * We get here in the special case where TCL_BRACKET_TERM was @@ -1453,19 +1684,14 @@ code = TCL_OK; /* * If the expression is a single word that doesn't require - * substitutions, just compile it's string into inline instructions. + * substitutions, just compile its string into inline instructions. */ if ((numWords == 1) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) { - /* - * Temporarily overwrite the character just after the end of the - * string with a 0 byte. - */ - script = tokenPtr[1].start; numBytes = tokenPtr[1].size; code = TclCompileExpr(interp, script, numBytes, envPtr); return code; } @@ -1538,14 +1764,19 @@ { register ByteCode *codePtr; size_t codeBytes, objArrayBytes, exceptArrayBytes, cmdLocBytes; size_t auxDataArrayBytes, structureSize; register unsigned char *p; +#ifdef TCL_COMPILE_DEBUG unsigned char *nextPtr; +#endif int numLitObjects = envPtr->literalArrayNext; Namespace *namespacePtr; int i; +#ifdef TCL_TIP280 + int new; +#endif Interp *iPtr; iPtr = envPtr->iPtr; codeBytes = (envPtr->codeNext - envPtr->codeStart); @@ -1619,12 +1850,14 @@ } else { codePtr->auxDataArrayPtr = NULL; } p += auxDataArrayBytes; +#ifndef TCL_COMPILE_DEBUG + EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p); +#else nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p); -#ifdef TCL_COMPILE_DEBUG if (((size_t)(nextPtr - p)) != cmdLocBytes) { panic("TclInitByteCodeObj: encoded cmd location bytes %d != expected size %d\n", (nextPtr - p), cmdLocBytes); } #endif @@ -1651,10 +1884,20 @@ (objPtr->typePtr->freeIntRepProc != NULL)) { (*objPtr->typePtr->freeIntRepProc)(objPtr); } objPtr->internalRep.otherValuePtr = (VOID *) codePtr; objPtr->typePtr = &tclByteCodeType; + +#ifdef TCL_TIP280 + /* TIP #280. Associate the extended per-word line information with the + * byte code object (internal rep), for use with the bc compiler. + */ + + Tcl_SetHashValue (Tcl_CreateHashEntry (iPtr->lineBCPtr, (char*) codePtr, &new), + envPtr->extCmdMapPtr); + envPtr->extCmdMapPtr = NULL; +#endif } /* *---------------------------------------------------------------------- * @@ -1722,10 +1965,18 @@ length = strlen(command); } if (length > 150) { length = 150; ellipsis = "..."; + } + while ( (command[length] & 0xC0) == 0x80 ) { + /* + * Back up truncation point so that we don't truncate in the + * middle of a multi-byte character (in UTF-8) + */ + length--; + ellipsis = "..."; } sprintf(buffer, "\n while compiling\n\"%.*s%s\"", length, command, ellipsis); Tcl_AddObjErrorInfo(interp, buffer, -1); } @@ -2115,10 +2366,102 @@ cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]); cmdLocPtr->numSrcBytes = numSrcBytes; cmdLocPtr->numCodeBytes = numCodeBytes; } + +#ifdef TCL_TIP280 +/* + *---------------------------------------------------------------------- + * TIP #280 + * + * EnterCmdWordData -- + * + * Registers the lines for the words of a command. This information + * is used at runtime by 'info frame'. + * + * Results: + * None. + * + * Side effects: + * Inserts word location information into the compilation + * environment envPtr for the command at index cmdIndex. The + * compilation environment's ExtCmdLoc.ECL array is grown if necessary. + * + *---------------------------------------------------------------------- + */ + +static void +EnterCmdWordData(eclPtr, srcOffset, tokenPtr, cmd, len, numWords, line, wlines) + ExtCmdLoc *eclPtr; /* Points to the map environment + * structure in which to enter command + * location information. */ + int srcOffset; /* Offset of first char of the command. */ + Tcl_Token* tokenPtr; + CONST char* cmd; + int len; + int numWords; + int line; + int** wlines; +{ + ECL* ePtr; + int wordIdx; + CONST char* last; + int wordLine; + int* wwlines; + + if (eclPtr->nuloc >= eclPtr->nloc) { + /* + * Expand the ECL array by allocating more storage from the + * heap. The currently allocated ECL entries are stored from + * eclPtr->loc[0] up to eclPtr->loc[eclPtr->nuloc-1] (inclusive). + */ + + size_t currElems = eclPtr->nloc; + size_t newElems = (currElems ? 2*currElems : 1); + size_t currBytes = currElems * sizeof(ECL); + size_t newBytes = newElems * sizeof(ECL); + ECL * newPtr = (ECL *) ckalloc((unsigned) newBytes); + + /* + * Copy from old ECL array to new, free old ECL array if + * needed. + */ + + if (currBytes) { + memcpy((VOID *) newPtr, (VOID *) eclPtr->loc, currBytes); + } + if (eclPtr->loc != NULL) { + ckfree((char *) eclPtr->loc); + } + eclPtr->loc = (ECL *) newPtr; + eclPtr->nloc = newElems; + } + + ePtr = &eclPtr->loc [eclPtr->nuloc]; + ePtr->srcOffset = srcOffset; + ePtr->line = (int*) ckalloc (numWords * sizeof (int)); + ePtr->nline = numWords; + wwlines = (int*) ckalloc (numWords * sizeof (int)); + + last = cmd; + wordLine = line; + for (wordIdx = 0; + wordIdx < numWords; + wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) { + TclAdvanceLines (&wordLine, last, tokenPtr->start); + wwlines [wordIdx] = (TclWordKnownAtCompileTime (tokenPtr) + ? wordLine + : -1); + ePtr->line [wordIdx] = wordLine; + last = tokenPtr->start; + } + + *wlines = wwlines; + eclPtr->nuloc ++; +} +#endif /* *---------------------------------------------------------------------- * * TclCreateExceptRange -- @@ -3464,5 +3807,14 @@ statsPtr->currentAuxBytes += (double) (codePtr->numAuxDataItems * sizeof(AuxData)); statsPtr->currentCmdMapBytes += (double) codePtr->numCmdLocBytes; } #endif /* TCL_COMPILE_STATS */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ + Index: generic/tclCompile.h ================================================================== --- generic/tclCompile.h +++ generic/tclCompile.h @@ -6,11 +6,11 @@ * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompile.h,v 1.33 2002/10/09 11:54:05 das Exp $ + * RCS: @(#) $Id: tclCompile.h,v 1.33.2.1 2006/11/28 22:20:00 andreas_kupries Exp $ */ #ifndef _TCLCOMPILATION #define _TCLCOMPILATION 1 @@ -118,10 +118,37 @@ int codeOffset; /* Offset of first byte of command code. */ int numCodeBytes; /* Number of bytes for command's code. */ int srcOffset; /* Offset of first char of the command. */ int numSrcBytes; /* Number of command source chars. */ } CmdLocation; + +#ifdef TCL_TIP280 +/* + * TIP #280 + * Structure to record additional location information for byte code. + * This information is internal and not saved. I.e. tbcload'ed code + * will not have this information. It records the lines for all words + * of all commands found in the byte code. The association with a + * ByteCode structure BC is done through the 'lineBCPtr' HashTable in + * Interp, keyed by the address of BC. Also recorded is information + * coming from the context, i.e. type of the frame and associated + * information, like the path of a sourced file. + */ + +typedef struct ECL { + int srcOffset; /* cmd location to find the entry */ + int nline; + int* line; /* line information for all words in the command */ +} ECL; +typedef struct ExtCmdLoc { + int type; /* Context type */ + Tcl_Obj* path; /* Path of the sourced file the command is in */ + ECL* loc; /* Command word locations (lines) */ + int nloc; /* Number of allocated entries in 'loc' */ + int nuloc; /* Number of used entries in 'loc' */ +} ExtCmdLoc; +#endif /* * CompileProcs need the ability to record information during compilation * that can be used by bytecode instructions during execution. The AuxData * structure provides this "auxiliary data" mechanism. An arbitrary number @@ -262,10 +289,18 @@ /* Initial ExceptionRange array storage. */ CmdLocation staticCmdMapSpace[COMPILEENV_INIT_CMD_MAP_SIZE]; /* Initial storage for cmd location map. */ AuxData staticAuxDataArraySpace[COMPILEENV_INIT_AUX_DATA_SIZE]; /* Initial storage for aux data array. */ +#ifdef TCL_TIP280 + /* TIP #280 */ + ExtCmdLoc* extCmdMapPtr; /* Extended command location information + * for 'info frame'. */ + int line; /* First line of the script, based on the + * invoking context, then the line of the + * command currently compiled. */ +#endif } CompileEnv; /* * The structure defining the bytecode instructions resulting from compiling * a Tcl script. Note that this structure is variable length: a single heap @@ -725,12 +760,18 @@ *---------------------------------------------------------------- * Procedures exported by the engine to be used by tclBasic.c *---------------------------------------------------------------- */ +#ifndef TCL_TIP280 EXTERN int TclCompEvalObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); +#else +EXTERN int TclCompEvalObj _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr, CONST CmdFrame* invoker, + int word)); +#endif /* *---------------------------------------------------------------- * Procedures shared among Tcl bytecode compilation and execution * modules but not used outside: @@ -782,13 +823,19 @@ JumpFixupArray *fixupArrayPtr)); EXTERN void TclInitAuxDataTypeTable _ANSI_ARGS_((void)); EXTERN void TclInitByteCodeObj _ANSI_ARGS_((Tcl_Obj *objPtr, CompileEnv *envPtr)); EXTERN void TclInitCompilation _ANSI_ARGS_((void)); +#ifndef TCL_TIP280 EXTERN void TclInitCompileEnv _ANSI_ARGS_((Tcl_Interp *interp, CompileEnv *envPtr, char *string, int numBytes)); +#else +EXTERN void TclInitCompileEnv _ANSI_ARGS_((Tcl_Interp *interp, + CompileEnv *envPtr, char *string, + int numBytes, CONST CmdFrame* invoker, int word)); +#endif EXTERN void TclInitJumpFixupArray _ANSI_ARGS_(( JumpFixupArray *fixupArrayPtr)); EXTERN void TclInitLiteralTable _ANSI_ARGS_(( LiteralTable *tablePtr)); #ifdef TCL_COMPILE_STATS @@ -1037,10 +1084,5 @@ # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCLCOMPILATION */ - - - - - Index: generic/tclDate.c ================================================================== --- generic/tclDate.c +++ generic/tclDate.c @@ -8,11 +8,11 @@ * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclDate.c,v 1.20 2001/10/18 20:20:28 hobbs Exp $ + * RCS: @(#) $Id: tclDate.c,v 1.20.4.3 2006/06/14 15:21:14 patthoyts Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -332,10 +332,13 @@ { "wast", tZONE, -HOUR( 7) }, /* West Australian Standard */ { "wadt", tDAYZONE, -HOUR( 7) }, /* West Australian Daylight */ { "jt", tZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */ { "cct", tZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */ { "jst", tZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */ + { "jdt", tDAYZONE, -HOUR( 9) }, /* Japan Daylight */ + { "kst", tZONE, -HOUR( 9) }, /* Korea Standard */ + { "kdt", tDAYZONE, -HOUR( 9) }, /* Korea Daylight */ { "cast", tZONE, -HOUR(19/2) }, /* Central Australian Standard */ { "cadt", tDAYZONE, -HOUR(19/2) }, /* Central Australian Daylight */ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ @@ -473,11 +476,11 @@ Julian += DaysInMonth[i]; if (Year >= EPOCH) { for (i = EPOCH; i < Year; i++) Julian += 365 + IsLeapYear(i); } else { - for (i = Year; i < EPOCH; i++) + for (i = (int)Year; i < EPOCH; i++) Julian -= 365 + IsLeapYear(i); } Julian *= SECSPERDAY; /* Add the timezone offset ?? */ @@ -542,11 +545,11 @@ * add n to year value * if currentMonth < requestedMonth decrement year value by 1 (so that * doing next february from january gives us february of the current year) * set day to 1, time to 0 */ - tm->tm_year += MonthOrdinal; + tm->tm_year += (int)MonthOrdinal; if (tm->tm_mon < MonthNumber - 1) { tm->tm_year--; } result = Convert(MonthNumber, (time_t) 1, tm->tm_year + TM_YEAR_BASE, (time_t) 0, (time_t) 0, (time_t) 0, MER24, DSTmaybe, &now); @@ -830,24 +833,24 @@ */ int TclGetDate(p, now, zone, timePtr) char *p; - unsigned long now; + Tcl_WideInt now; long zone; - unsigned long *timePtr; + Tcl_WideInt *timePtr; { struct tm *tm; time_t Start; time_t Time; time_t tod; int thisyear; TclDateInput = p; /* now has to be cast to a time_t for 64bit compliance */ - Start = now; - tm = TclpGetDate((TclpTime_t) &Start, 0); + Start = (time_t) now; + tm = TclpGetDate((TclpTime_t) &Start, (zone == -50000)); thisyear = tm->tm_year + TM_YEAR_BASE; TclDateYear = thisyear; TclDateMonth = tm->tm_mon + 1; TclDateDay = tm->tm_mday; TclDateTimezone = zone; @@ -902,11 +905,11 @@ if (Convert(TclDateMonth, TclDateDay, TclDateYear, TclDateHour, TclDateMinutes, TclDateSeconds, TclDateMeridian, TclDateDSTmode, &Start) < 0) { return -1; } } else { - Start = now; + Start = (time_t) now; if (!TclDateHaveRel) { Start -= ((tm->tm_hour * 60L * 60L) + tm->tm_min * 60L) + tm->tm_sec; } } Index: generic/tclDecls.h ================================================================== --- generic/tclDecls.h +++ generic/tclDecls.h @@ -6,11 +6,11 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclDecls.h,v 1.93 2002/08/05 15:01:04 dgp Exp $ + * RCS: @(#) $Id: tclDecls.h,v 1.93.2.7 2006/09/22 01:26:23 andreas_kupries Exp $ */ #ifndef _TCLDECLS #define _TCLDECLS @@ -1303,11 +1303,11 @@ Tcl_ChannelType * chanTypePtr)); /* 411 */ EXTERN Tcl_DriverHandlerProc * Tcl_ChannelHandlerProc _ANSI_ARGS_(( Tcl_ChannelType * chanTypePtr)); /* 412 */ -EXTERN int Tcl_JoinThread _ANSI_ARGS_((Tcl_ThreadId id, +EXTERN int Tcl_JoinThread _ANSI_ARGS_((Tcl_ThreadId threadId, int* result)); /* 413 */ EXTERN int Tcl_IsChannelShared _ANSI_ARGS_((Tcl_Channel channel)); /* 414 */ EXTERN int Tcl_IsChannelRegistered _ANSI_ARGS_(( @@ -1562,10 +1562,96 @@ /* 492 */ EXTERN Tcl_WideInt Tcl_Tell _ANSI_ARGS_((Tcl_Channel chan)); /* 493 */ EXTERN Tcl_DriverWideSeekProc * Tcl_ChannelWideSeekProc _ANSI_ARGS_(( Tcl_ChannelType * chanTypePtr)); +/* Slot 494 is reserved */ +/* Slot 495 is reserved */ +/* Slot 496 is reserved */ +/* Slot 497 is reserved */ +/* Slot 498 is reserved */ +/* Slot 499 is reserved */ +/* Slot 500 is reserved */ +/* Slot 501 is reserved */ +/* Slot 502 is reserved */ +/* Slot 503 is reserved */ +/* Slot 504 is reserved */ +/* Slot 505 is reserved */ +/* Slot 506 is reserved */ +/* Slot 507 is reserved */ +/* Slot 508 is reserved */ +/* Slot 509 is reserved */ +/* Slot 510 is reserved */ +/* Slot 511 is reserved */ +/* Slot 512 is reserved */ +/* Slot 513 is reserved */ +/* Slot 514 is reserved */ +/* Slot 515 is reserved */ +/* Slot 516 is reserved */ +/* Slot 517 is reserved */ +/* Slot 518 is reserved */ +/* Slot 519 is reserved */ +/* Slot 520 is reserved */ +/* Slot 521 is reserved */ +/* Slot 522 is reserved */ +/* Slot 523 is reserved */ +/* Slot 524 is reserved */ +/* Slot 525 is reserved */ +/* Slot 526 is reserved */ +/* Slot 527 is reserved */ +/* Slot 528 is reserved */ +/* Slot 529 is reserved */ +/* Slot 530 is reserved */ +/* Slot 531 is reserved */ +/* Slot 532 is reserved */ +/* Slot 533 is reserved */ +/* Slot 534 is reserved */ +/* Slot 535 is reserved */ +/* Slot 536 is reserved */ +/* Slot 537 is reserved */ +/* Slot 538 is reserved */ +/* Slot 539 is reserved */ +/* Slot 540 is reserved */ +/* Slot 541 is reserved */ +/* Slot 542 is reserved */ +/* Slot 543 is reserved */ +/* Slot 544 is reserved */ +/* Slot 545 is reserved */ +/* Slot 546 is reserved */ +/* Slot 547 is reserved */ +/* Slot 548 is reserved */ +/* Slot 549 is reserved */ +/* Slot 550 is reserved */ +/* Slot 551 is reserved */ +/* Slot 552 is reserved */ +/* Slot 553 is reserved */ +/* 554 */ +EXTERN Tcl_DriverThreadActionProc * Tcl_ChannelThreadActionProc _ANSI_ARGS_(( + Tcl_ChannelType * chanTypePtr)); +/* Slot 555 is reserved */ +/* Slot 556 is reserved */ +/* Slot 557 is reserved */ +/* Slot 558 is reserved */ +/* Slot 559 is reserved */ +/* Slot 560 is reserved */ +/* Slot 561 is reserved */ +/* Slot 562 is reserved */ +/* Slot 563 is reserved */ +/* Slot 564 is reserved */ +/* Slot 565 is reserved */ +/* Slot 566 is reserved */ +/* Slot 567 is reserved */ +/* Slot 568 is reserved */ +/* Slot 569 is reserved */ +/* Slot 570 is reserved */ +/* Slot 571 is reserved */ +/* Slot 572 is reserved */ +/* 573 */ +EXTERN int Tcl_PkgRequireProc _ANSI_ARGS_((Tcl_Interp * interp, + CONST char * name, int objc, + Tcl_Obj *CONST objv[], + ClientData * clientDataPtr)); typedef struct TclStubHooks { struct TclPlatStubs *tclPlatStubs; struct TclIntStubs *tclIntStubs; struct TclIntPlatStubs *tclIntPlatStubs; @@ -2033,11 +2119,11 @@ Tcl_DriverGetOptionProc * (*tcl_ChannelGetOptionProc) _ANSI_ARGS_((Tcl_ChannelType * chanTypePtr)); /* 407 */ Tcl_DriverWatchProc * (*tcl_ChannelWatchProc) _ANSI_ARGS_((Tcl_ChannelType * chanTypePtr)); /* 408 */ Tcl_DriverGetHandleProc * (*tcl_ChannelGetHandleProc) _ANSI_ARGS_((Tcl_ChannelType * chanTypePtr)); /* 409 */ Tcl_DriverFlushProc * (*tcl_ChannelFlushProc) _ANSI_ARGS_((Tcl_ChannelType * chanTypePtr)); /* 410 */ Tcl_DriverHandlerProc * (*tcl_ChannelHandlerProc) _ANSI_ARGS_((Tcl_ChannelType * chanTypePtr)); /* 411 */ - int (*tcl_JoinThread) _ANSI_ARGS_((Tcl_ThreadId id, int* result)); /* 412 */ + int (*tcl_JoinThread) _ANSI_ARGS_((Tcl_ThreadId threadId, int* result)); /* 412 */ int (*tcl_IsChannelShared) _ANSI_ARGS_((Tcl_Channel channel)); /* 413 */ int (*tcl_IsChannelRegistered) _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Channel channel)); /* 414 */ void (*tcl_CutChannel) _ANSI_ARGS_((Tcl_Channel channel)); /* 415 */ void (*tcl_SpliceChannel) _ANSI_ARGS_((Tcl_Channel channel)); /* 416 */ void (*tcl_ClearChannelHandlers) _ANSI_ARGS_((Tcl_Channel channel)); /* 417 */ @@ -2115,10 +2201,90 @@ void (*tcl_SetWideIntObj) _ANSI_ARGS_((Tcl_Obj * objPtr, Tcl_WideInt wideValue)); /* 489 */ Tcl_StatBuf * (*tcl_AllocStatBuf) _ANSI_ARGS_((void)); /* 490 */ Tcl_WideInt (*tcl_Seek) _ANSI_ARGS_((Tcl_Channel chan, Tcl_WideInt offset, int mode)); /* 491 */ Tcl_WideInt (*tcl_Tell) _ANSI_ARGS_((Tcl_Channel chan)); /* 492 */ Tcl_DriverWideSeekProc * (*tcl_ChannelWideSeekProc) _ANSI_ARGS_((Tcl_ChannelType * chanTypePtr)); /* 493 */ + void *reserved494; + void *reserved495; + void *reserved496; + void *reserved497; + void *reserved498; + void *reserved499; + void *reserved500; + void *reserved501; + void *reserved502; + void *reserved503; + void *reserved504; + void *reserved505; + void *reserved506; + void *reserved507; + void *reserved508; + void *reserved509; + void *reserved510; + void *reserved511; + void *reserved512; + void *reserved513; + void *reserved514; + void *reserved515; + void *reserved516; + void *reserved517; + void *reserved518; + void *reserved519; + void *reserved520; + void *reserved521; + void *reserved522; + void *reserved523; + void *reserved524; + void *reserved525; + void *reserved526; + void *reserved527; + void *reserved528; + void *reserved529; + void *reserved530; + void *reserved531; + void *reserved532; + void *reserved533; + void *reserved534; + void *reserved535; + void *reserved536; + void *reserved537; + void *reserved538; + void *reserved539; + void *reserved540; + void *reserved541; + void *reserved542; + void *reserved543; + void *reserved544; + void *reserved545; + void *reserved546; + void *reserved547; + void *reserved548; + void *reserved549; + void *reserved550; + void *reserved551; + void *reserved552; + void *reserved553; + Tcl_DriverThreadActionProc * (*tcl_ChannelThreadActionProc) _ANSI_ARGS_((Tcl_ChannelType * chanTypePtr)); /* 554 */ + void *reserved555; + void *reserved556; + void *reserved557; + void *reserved558; + void *reserved559; + void *reserved560; + void *reserved561; + void *reserved562; + void *reserved563; + void *reserved564; + void *reserved565; + void *reserved566; + void *reserved567; + void *reserved568; + void *reserved569; + void *reserved570; + void *reserved571; + void *reserved572; + int (*tcl_PkgRequireProc) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * name, int objc, Tcl_Obj *CONST objv[], ClientData * clientDataPtr)); /* 573 */ } TclStubs; #ifdef __cplusplus extern "C" { #endif @@ -4131,12 +4297,98 @@ #endif #ifndef Tcl_ChannelWideSeekProc #define Tcl_ChannelWideSeekProc \ (tclStubsPtr->tcl_ChannelWideSeekProc) /* 493 */ #endif +/* Slot 494 is reserved */ +/* Slot 495 is reserved */ +/* Slot 496 is reserved */ +/* Slot 497 is reserved */ +/* Slot 498 is reserved */ +/* Slot 499 is reserved */ +/* Slot 500 is reserved */ +/* Slot 501 is reserved */ +/* Slot 502 is reserved */ +/* Slot 503 is reserved */ +/* Slot 504 is reserved */ +/* Slot 505 is reserved */ +/* Slot 506 is reserved */ +/* Slot 507 is reserved */ +/* Slot 508 is reserved */ +/* Slot 509 is reserved */ +/* Slot 510 is reserved */ +/* Slot 511 is reserved */ +/* Slot 512 is reserved */ +/* Slot 513 is reserved */ +/* Slot 514 is reserved */ +/* Slot 515 is reserved */ +/* Slot 516 is reserved */ +/* Slot 517 is reserved */ +/* Slot 518 is reserved */ +/* Slot 519 is reserved */ +/* Slot 520 is reserved */ +/* Slot 521 is reserved */ +/* Slot 522 is reserved */ +/* Slot 523 is reserved */ +/* Slot 524 is reserved */ +/* Slot 525 is reserved */ +/* Slot 526 is reserved */ +/* Slot 527 is reserved */ +/* Slot 528 is reserved */ +/* Slot 529 is reserved */ +/* Slot 530 is reserved */ +/* Slot 531 is reserved */ +/* Slot 532 is reserved */ +/* Slot 533 is reserved */ +/* Slot 534 is reserved */ +/* Slot 535 is reserved */ +/* Slot 536 is reserved */ +/* Slot 537 is reserved */ +/* Slot 538 is reserved */ +/* Slot 539 is reserved */ +/* Slot 540 is reserved */ +/* Slot 541 is reserved */ +/* Slot 542 is reserved */ +/* Slot 543 is reserved */ +/* Slot 544 is reserved */ +/* Slot 545 is reserved */ +/* Slot 546 is reserved */ +/* Slot 547 is reserved */ +/* Slot 548 is reserved */ +/* Slot 549 is reserved */ +/* Slot 550 is reserved */ +/* Slot 551 is reserved */ +/* Slot 552 is reserved */ +/* Slot 553 is reserved */ +#ifndef Tcl_ChannelThreadActionProc +#define Tcl_ChannelThreadActionProc \ + (tclStubsPtr->tcl_ChannelThreadActionProc) /* 554 */ +#endif +/* Slot 555 is reserved */ +/* Slot 556 is reserved */ +/* Slot 557 is reserved */ +/* Slot 558 is reserved */ +/* Slot 559 is reserved */ +/* Slot 560 is reserved */ +/* Slot 561 is reserved */ +/* Slot 562 is reserved */ +/* Slot 563 is reserved */ +/* Slot 564 is reserved */ +/* Slot 565 is reserved */ +/* Slot 566 is reserved */ +/* Slot 567 is reserved */ +/* Slot 568 is reserved */ +/* Slot 569 is reserved */ +/* Slot 570 is reserved */ +/* Slot 571 is reserved */ +/* Slot 572 is reserved */ +#ifndef Tcl_PkgRequireProc +#define Tcl_PkgRequireProc \ + (tclStubsPtr->tcl_PkgRequireProc) /* 573 */ +#endif #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ /* !END!: Do not edit above this line. */ #endif /* _TCLDECLS */ Index: generic/tclEncoding.c ================================================================== --- generic/tclEncoding.c +++ generic/tclEncoding.c @@ -6,11 +6,11 @@ * Copyright (c) 1996-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclEncoding.c,v 1.16 2003/02/21 02:40:58 hobbs Exp $ + * RCS: @(#) $Id: tclEncoding.c,v 1.16.2.14 2007/02/12 19:25:42 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -176,10 +176,12 @@ static int BinaryProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); +static void DupEncodingIntRep _ANSI_ARGS_((Tcl_Obj *srcPtr, + Tcl_Obj *dupPtr)); static void EscapeFreeProc _ANSI_ARGS_((ClientData clientData)); static int EscapeFromUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, @@ -188,10 +190,11 @@ CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static void FreeEncoding _ANSI_ARGS_((Tcl_Encoding encoding)); +static void FreeEncodingIntRep _ANSI_ARGS_((Tcl_Obj *objPtr)); static Encoding * GetTableEncoding _ANSI_ARGS_(( EscapeEncodingData *dataPtr, int state)); static Tcl_Encoding LoadEncodingFile _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name)); static Tcl_Encoding LoadTableEncoding _ANSI_ARGS_((Tcl_Interp *interp, @@ -224,12 +227,108 @@ int *dstCharsPtr)); static int UtfToUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, + int *dstCharsPtr, int pureNullMode)); +static int UtfIntToUtfExtProc _ANSI_ARGS_((ClientData clientData, + CONST char *src, int srcLen, int flags, + Tcl_EncodingState *statePtr, char *dst, int dstLen, + int *srcReadPtr, int *dstWrotePtr, + int *dstCharsPtr)); +static int UtfExtToUtfIntProc _ANSI_ARGS_((ClientData clientData, + CONST char *src, int srcLen, int flags, + Tcl_EncodingState *statePtr, char *dst, int dstLen, + int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); +static int TclFindEncodings _ANSI_ARGS_((CONST char *argv0)); +/* + * A Tcl_ObjType for holding a cached Tcl_Encoding as the intrep. + * This should help the lifetime of encodings be more useful. + * See concerns raised in [Bug 1077262]. + */ + +static Tcl_ObjType EncodingType = { + "encoding", FreeEncodingIntRep, DupEncodingIntRep, NULL, NULL +}; + + +/* + *---------------------------------------------------------------------- + * + * TclGetEncodingFromObj -- + * + * Writes to (*encodingPtr) the Tcl_Encoding value of (*objPtr), + * if possible, and returns TCL_OK. If no such encoding exists, + * TCL_ERROR is returned, and if interp is non-NULL, an error message + * is written there. + * + * Results: + * Standard Tcl return code. + * + * Side effects: + * Caches the Tcl_Encoding value as the internal rep of (*objPtr). + * + *---------------------------------------------------------------------- + */ +int +TclGetEncodingFromObj(interp, objPtr, encodingPtr) + Tcl_Interp *interp; + Tcl_Obj *objPtr; + Tcl_Encoding *encodingPtr; +{ + CONST char *name = Tcl_GetString(objPtr); + if (objPtr->typePtr != &EncodingType) { + Tcl_Encoding encoding = Tcl_GetEncoding(interp, name); + + if (encoding == NULL) { + return TCL_ERROR; + } + if (objPtr->typePtr && objPtr->typePtr->freeIntRepProc) { + objPtr->typePtr->freeIntRepProc(objPtr); + } + objPtr->internalRep.otherValuePtr = (VOID *) encoding; + objPtr->typePtr = &EncodingType; + } + *encodingPtr = Tcl_GetEncoding(NULL, name); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FreeEncodingIntRep -- + * + * The Tcl_FreeInternalRepProc for the "encoding" Tcl_ObjType. + * + *---------------------------------------------------------------------- + */ +static void +FreeEncodingIntRep(objPtr) + Tcl_Obj *objPtr; +{ + Tcl_FreeEncoding((Tcl_Encoding) objPtr->internalRep.otherValuePtr); +} + +/* + *---------------------------------------------------------------------- + * + * DupEncodingIntRep -- + * + * The Tcl_DupInternalRepProc for the "encoding" Tcl_ObjType. + * + *---------------------------------------------------------------------- + */ +static void +DupEncodingIntRep(srcPtr, dupPtr) + Tcl_Obj *srcPtr; + Tcl_Obj *dupPtr; +{ + dupPtr->internalRep.otherValuePtr = (VOID *) + Tcl_GetEncoding(NULL, srcPtr->bytes); +} /* *--------------------------------------------------------------------------- * * TclInitEncodingSubsystem -- @@ -270,12 +369,12 @@ defaultEncoding = Tcl_CreateEncoding(&type); systemEncoding = Tcl_GetEncoding(NULL, type.encodingName); type.encodingName = "utf-8"; - type.toUtfProc = UtfToUtfProc; - type.fromUtfProc = UtfToUtfProc; + type.toUtfProc = UtfExtToUtfIntProc; + type.fromUtfProc = UtfIntToUtfExtProc; type.freeProc = NULL; type.nullSize = 1; type.clientData = NULL; Tcl_CreateEncoding(&type); @@ -311,10 +410,11 @@ Tcl_HashSearch search; Tcl_HashEntry *hPtr; Tcl_MutexLock(&encodingMutex); encodingsInitialized = 0; + FreeEncoding(systemEncoding); hPtr = Tcl_FirstHashEntry(&encodingTable, &search); while (hPtr != NULL) { /* * Call FreeEncoding instead of doing it directly to handle refcounts * like escape encodings use. [Bug #524674] @@ -1109,10 +1209,11 @@ void Tcl_FindExecutable(argv0) CONST char *argv0; /* The value of the application's argv[0] * (native). */ { + int mustCleanUtf; CONST char *name; Tcl_DString buffer, nameString; TclInitSubsystems(argv0); @@ -1127,36 +1228,44 @@ goto done; } /* * The value returned from TclpNameOfExecutable is a UTF string that - * is possibly dirty depending on when it was initialized. To assure - * that the UTF string is a properly encoded native string for this - * system, convert the UTF string to the default native encoding - * before the default encoding is initialized. Then, convert it back - * to UTF after the system encoding is loaded. + * is possibly dirty depending on when it was initialized. + * TclFindEncodings will indicate whether we must "clean" the UTF (as + * reported by the underlying system). To assure that the UTF string + * is a properly encoded native string for this system, convert the + * UTF string to the default native encoding before the default + * encoding is initialized. Then, convert it back to UTF after the + * system encoding is loaded. */ Tcl_UtfToExternalDString(NULL, name, -1, &buffer); - TclFindEncodings(argv0); + mustCleanUtf = TclFindEncodings(argv0); /* * Now it is OK to convert the native string back to UTF and set * the value of the tclExecutableName. */ - Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&buffer), -1, &nameString); - tclExecutableName = (char *) - ckalloc((unsigned) (Tcl_DStringLength(&nameString) + 1)); - strcpy(tclExecutableName, Tcl_DStringValue(&nameString)); + if (mustCleanUtf) { + Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&buffer), -1, + &nameString); + tclExecutableName = (char *) + ckalloc((unsigned) (Tcl_DStringLength(&nameString) + 1)); + strcpy(tclExecutableName, Tcl_DStringValue(&nameString)); + Tcl_DStringFree(&nameString); + } else { + tclExecutableName = (char *) ckalloc((unsigned) (strlen(name) + 1)); + strcpy(tclExecutableName, name); + } Tcl_DStringFree(&buffer); - Tcl_DStringFree(&nameString); return; done: - TclFindEncodings(argv0); + (void) TclFindEncodings(argv0); } /* *--------------------------------------------------------------------------- * @@ -1244,10 +1353,13 @@ break; } } if ((encoding == NULL) && (interp != NULL)) { Tcl_AppendResult(interp, "invalid encoding file \"", name, "\"", NULL); + if (ch == 'E') { + Tcl_AppendResult(interp, " or missing sub-encoding", NULL); + } } Tcl_Close(NULL, chan); return encoding; unknown: @@ -1611,11 +1723,11 @@ static Tcl_Encoding LoadEscapeEncoding(name, chan) CONST char *name; /* Name for new encoding. */ Tcl_Channel chan; /* File containing new encoding. */ { - int i; + int i, missingSubEncoding = 0; unsigned int size; Tcl_DString escapeData; char init[16], final[16]; EscapeEncodingData *dataPtr; Tcl_EncodingType type; @@ -1655,19 +1767,30 @@ est.sequenceLen = strlen(est.sequence); strncpy(est.name, argv[0], sizeof(est.name)); est.name[sizeof(est.name) - 1] = '\0'; - /* To avoid infinite recursion in [encoding system iso2022-*]*/ - Tcl_GetEncoding(NULL, est.name); + /* + * Load the subencodings first so we're never stuck + * trying to use a half-loaded system encoding to + * open/read a *.enc file. + */ - est.encodingPtr = NULL; + est.encodingPtr = (Encoding *) Tcl_GetEncoding(NULL, est.name); + if ((est.encodingPtr == NULL) + || (est.encodingPtr->toUtfProc != TableToUtfProc)) { + missingSubEncoding = 1; + } Tcl_DStringAppend(&escapeData, (char *) &est, sizeof(est)); } } ckfree((char *) argv); Tcl_DStringFree(&lineString); + } + if (missingSubEncoding) { + Tcl_DStringFree(&escapeData); + return NULL; } size = sizeof(EscapeEncodingData) - sizeof(EscapeSubTable) + Tcl_DStringLength(&escapeData); dataPtr = (EscapeEncodingData *) ckalloc(size); @@ -1757,16 +1880,113 @@ } *srcReadPtr = srcLen; *dstWrotePtr = srcLen; *dstCharsPtr = srcLen; - for ( ; --srcLen >= 0; ) { - *dst++ = *src++; - } + memcpy((void *) dst, (void *) src, (size_t) srcLen); return result; } + +/* + *------------------------------------------------------------------------- + * + * UtfExtToUtfIntProc -- + * + * Convert from UTF-8 to UTF-8. While converting null-bytes from + * the Tcl's internal representation (0xc0, 0x80) to the official + * representation (0x00). See UtfToUtfProc for details. + * + * Results: + * Returns TCL_OK if conversion was successful. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ +static int +UtfIntToUtfExtProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, + srcReadPtr, dstWrotePtr, dstCharsPtr) + ClientData clientData; /* Not used. */ + CONST char *src; /* Source string in UTF-8. */ + int srcLen; /* Source string length in bytes. */ + int flags; /* Conversion control flags. */ + Tcl_EncodingState *statePtr;/* Place for conversion routine to store + * state information used during a piecewise + * conversion. Contents of statePtr are + * initialized and/or reset by conversion + * routine under control of flags argument. */ + char *dst; /* Output buffer in which converted string + * is stored. */ + int dstLen; /* The maximum length of output buffer in + * bytes. */ + int *srcReadPtr; /* Filled with the number of bytes from the + * source string that were converted. This + * may be less than the original source length + * if there was a problem converting some + * source characters. */ + int *dstWrotePtr; /* Filled with the number of bytes that were + * stored in the output buffer as a result of + * the conversion. */ + int *dstCharsPtr; /* Filled with the number of characters that + * correspond to the bytes stored in the + * output buffer. */ +{ + return UtfToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, + srcReadPtr, dstWrotePtr, dstCharsPtr, 1); +} + +/* + *------------------------------------------------------------------------- + * + * UtfExtToUtfIntProc -- + * + * Convert from UTF-8 to UTF-8 while converting null-bytes from + * the official representation (0x00) to Tcl's internal + * representation (0xc0, 0x80). See UtfToUtfProc for details. + * + * Results: + * Returns TCL_OK if conversion was successful. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ +static int +UtfExtToUtfIntProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, + srcReadPtr, dstWrotePtr, dstCharsPtr) + ClientData clientData; /* Not used. */ + CONST char *src; /* Source string in UTF-8. */ + int srcLen; /* Source string length in bytes. */ + int flags; /* Conversion control flags. */ + Tcl_EncodingState *statePtr;/* Place for conversion routine to store + * state information used during a piecewise + * conversion. Contents of statePtr are + * initialized and/or reset by conversion + * routine under control of flags argument. */ + char *dst; /* Output buffer in which converted string + * is stored. */ + int dstLen; /* The maximum length of output buffer in + * bytes. */ + int *srcReadPtr; /* Filled with the number of bytes from the + * source string that were converted. This + * may be less than the original source length + * if there was a problem converting some + * source characters. */ + int *dstWrotePtr; /* Filled with the number of bytes that were + * stored in the output buffer as a result of + * the conversion. */ + int *dstCharsPtr; /* Filled with the number of characters that + * correspond to the bytes stored in the + * output buffer. */ +{ + return UtfToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, + srcReadPtr, dstWrotePtr, dstCharsPtr, 0); +} + /* *------------------------------------------------------------------------- * * UtfToUtfProc -- * @@ -1783,11 +2003,11 @@ *------------------------------------------------------------------------- */ static int UtfToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, - srcReadPtr, dstWrotePtr, dstCharsPtr) + srcReadPtr, dstWrotePtr, dstCharsPtr, pureNullMode) ClientData clientData; /* Not used. */ CONST char *src; /* Source string in UTF-8. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store @@ -1808,10 +2028,14 @@ * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ + int pureNullMode; /* Convert embedded nulls from + * internal representation to real + * null-bytes or vice versa */ + { CONST char *srcStart, *srcEnd, *srcClose; char *dstStart, *dstEnd; int result, numChars; Tcl_UniChar ch; @@ -1840,19 +2064,42 @@ } if (dst > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } - if (UCHAR(*src) < 0x80) { + if (UCHAR(*src) < 0x80 && + !(UCHAR(*src) == 0 && pureNullMode == 0)) { + /* + * Copy 7bit chatacters, but skip null-bytes when we are + * in input mode, so that they get converted to 0xc080. + */ *dst++ = *src++; + } else if (pureNullMode == 1 && + UCHAR(*src) == 0xc0 && + UCHAR(*(src+1)) == 0x80) { + /* + * Convert 0xc080 to real nulls when we are in output mode. + */ + *dst++ = 0; + src += 2; + } else if (!Tcl_UtfCharComplete(src, srcEnd - src)) { + /* Always check before using Tcl_UtfToUniChar. Not doing + * can so cause it run beyond the endof the buffer! If we + * * happen such an incomplete char its byts are made to * + * represent themselves. + */ + + ch = (Tcl_UniChar) *src; + src += 1; + dst += Tcl_UniCharToUtf(ch, dst); } else { src += Tcl_UtfToUniChar(src, &ch); dst += Tcl_UniCharToUtf(ch, dst); } } - *srcReadPtr = src - srcStart; + *srcReadPtr = src - srcStart; *dstWrotePtr = dst - dstStart; *dstCharsPtr = numChars; return result; } @@ -1898,46 +2145,47 @@ * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { - CONST Tcl_UniChar *wSrc, *wSrcStart, *wSrcEnd; + CONST char *srcStart, *srcEnd; char *dstEnd, *dstStart; int result, numChars; - + Tcl_UniChar ch; + result = TCL_OK; if ((srcLen % sizeof(Tcl_UniChar)) != 0) { result = TCL_CONVERT_MULTIBYTE; srcLen /= sizeof(Tcl_UniChar); srcLen *= sizeof(Tcl_UniChar); } - wSrc = (Tcl_UniChar *) src; - - wSrcStart = (Tcl_UniChar *) src; - wSrcEnd = (Tcl_UniChar *) (src + srcLen); + srcStart = src; + srcEnd = src + srcLen; dstStart = dst; dstEnd = dst + dstLen - TCL_UTF_MAX; - for (numChars = 0; wSrc < wSrcEnd; numChars++) { + for (numChars = 0; src < srcEnd; numChars++) { if (dst > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } /* - * Special case for 1-byte utf chars for speed. + * Special case for 1-byte utf chars for speed. Make sure we + * work with Tcl_UniChar-size data. */ - if (*wSrc && *wSrc < 0x80) { - *dst++ = (char) *wSrc; + ch = *(Tcl_UniChar *)src; + if (ch && ch < 0x80) { + *dst++ = (ch & 0xFF); } else { - dst += Tcl_UniCharToUtf(*wSrc, dst); + dst += Tcl_UniCharToUtf(ch, dst); } - wSrc++; + src += sizeof(Tcl_UniChar); } - *srcReadPtr = (char *) wSrc - (char *) wSrcStart; + *srcReadPtr = src - srcStart; *dstWrotePtr = dst - dstStart; *dstCharsPtr = numChars; return result; } @@ -1983,24 +2231,23 @@ * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { - CONST char *srcStart, *srcEnd, *srcClose; - Tcl_UniChar *wDst, *wDstStart, *wDstEnd; + CONST char *srcStart, *srcEnd, *srcClose, *dstStart, *dstEnd; int result, numChars; - + Tcl_UniChar ch; + srcStart = src; srcEnd = src + srcLen; srcClose = srcEnd; if ((flags & TCL_ENCODING_END) == 0) { srcClose -= TCL_UTF_MAX; } - wDst = (Tcl_UniChar *) dst; - wDstStart = (Tcl_UniChar *) dst; - wDstEnd = (Tcl_UniChar *) (dst + dstLen - sizeof(Tcl_UniChar)); + dstStart = dst; + dstEnd = dst + dstLen - sizeof(Tcl_UniChar); result = TCL_OK; for (numChars = 0; src < srcEnd; numChars++) { if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) { /* @@ -2009,19 +2256,30 @@ */ result = TCL_CONVERT_MULTIBYTE; break; } - if (wDst > wDstEnd) { + if (dst > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } - src += TclUtfToUniChar(src, wDst); - wDst++; + src += TclUtfToUniChar(src, &ch); + /* + * Need to handle this in a way that won't cause misalignment + * by casting dst to a Tcl_UniChar. [Bug 1122671] + * XXX: This hard-codes the assumed size of Tcl_UniChar as 2. + */ +#ifdef WORDS_BIGENDIAN + *dst++ = (ch >> 8); + *dst++ = (ch & 0xFF); +#else + *dst++ = (ch & 0xFF); + *dst++ = (ch >> 8); +#endif } *srcReadPtr = src - srcStart; - *dstWrotePtr = (char *) wDst - (char *) wDstStart; + *dstWrotePtr = dst - dstStart; *dstCharsPtr = numChars; return result; } /* @@ -2211,11 +2469,22 @@ result = TCL_CONVERT_MULTIBYTE; break; } len = TclUtfToUniChar(src, &ch); - word = fromUnicode[(ch >> 8)][ch & 0xff]; + +#if TCL_UTF_MAX > 3 + /* + * This prevents a crash condition. More evaluation is required + * for full support of int Tcl_UniChar. [Bug 1004065] + */ + if (ch & 0xffff0000) { + word = 0; + } else +#endif + word = fromUnicode[(ch >> 8)][ch & 0xff]; + if ((word == 0) && (ch != 0)) { if (flags & TCL_ENCODING_STOPONERROR) { result = TCL_CONVERT_UNKNOWN; break; } @@ -2563,11 +2832,11 @@ * characters, and that the text must end in ASCII. [Patch #474358] */ if (flags & TCL_ENCODING_START) { state = 0; - if (dst + dataPtr->initLen > dstEnd) { + if ((dst + dataPtr->initLen) > dstEnd) { *srcReadPtr = 0; *dstWrotePtr = 0; return TCL_CONVERT_NOSPACE; } memcpy((VOID *) dst, (VOID *) dataPtr->init, @@ -2670,11 +2939,22 @@ src += len; } if ((result == TCL_OK) && (flags & TCL_ENCODING_END)) { unsigned int len = dataPtr->subTables[0].sequenceLen; - if (dst + dataPtr->finalLen + (state?len:0) > dstEnd) { + /* + * [Bug 1516109]. + * Certain encodings like iso2022-jp need to write + * an escape sequence after all characters have + * been converted. This logic checks that enough + * room is available in the buffer for the escape bytes. + * The TCL_ENCODING_END flag is cleared after a final + * escape sequence has been added to the buffer so + * that another call to this method does not attempt + * to append escape bytes a second time. + */ + if ((dst + dataPtr->finalLen + (state?len:0)) > dstEnd) { result = TCL_CONVERT_NOSPACE; } else { if (state) { memcpy((VOID *) dst, (VOID *) dataPtr->subTables[0].sequence, (size_t) len); @@ -2681,10 +2961,11 @@ dst += len; } memcpy((VOID *) dst, (VOID *) dataPtr->final, (size_t) dataPtr->finalLen); dst += dataPtr->finalLen; + state &= ~TCL_ENCODING_END; } } *statePtr = (Tcl_EncodingState) state; *srcReadPtr = src - srcStart; @@ -2759,10 +3040,15 @@ Encoding *encodingPtr; subTablePtr = &dataPtr->subTables[state]; encodingPtr = subTablePtr->encodingPtr; if (encodingPtr == NULL) { + /* + * Now that escape encodings load their sub-encodings first, and + * fail to load if any sub-encodings are missing, this branch should + * never happen. + */ encodingPtr = (Encoding *) Tcl_GetEncoding(NULL, subTablePtr->name); if ((encodingPtr == NULL) || (encodingPtr->toUtfProc != TableToUtfProc)) { panic("EscapeToUtfProc: invalid sub table"); } @@ -2799,11 +3085,10 @@ while (*p != 0x0000) { p++; } return (char *) p - src; } - /* *------------------------------------------------------------------------- * * TclFindEncodings -- @@ -2812,65 +3097,68 @@ * Before this is called, Tcl makes assumptions about the * native string representation, but the true encoding is not * assured. * * Results: - * None. + * Return result of TclpInitLibraryPath, which reports whether the + * path is clean (0) or dirty (1) UTF. * * Side effects: * Varied, see the respective initialization routines. * *------------------------------------------------------------------------- */ -void +static int TclFindEncodings(argv0) CONST char *argv0; /* Name of executable from argv[0] to main() * in native multi-byte encoding. */ { - char *native; - Tcl_Obj *pathPtr; - Tcl_DString libPath, buffer; + int mustCleanUtf = 0; if (encodingsInitialized == 0) { /* * Double check inside the mutex. There may be calls * back into this routine from some of the procedures below. */ TclpInitLock(); if (encodingsInitialized == 0) { + char *native; + Tcl_Obj *pathPtr; + Tcl_DString libPath, buffer; + /* * Have to set this bit here to avoid deadlock with the * routines below us that call into TclInitSubsystems. */ encodingsInitialized = 1; native = TclpFindExecutable(argv0); - TclpInitLibraryPath(native); + mustCleanUtf = TclpInitLibraryPath(native); /* * The library path was set in the TclpInitLibraryPath routine. * The string set is a dirty UTF string. To preserve the value * convert the UTF string back to native before setting the new * default encoding. */ - + pathPtr = TclGetLibraryPath(); - if (pathPtr != NULL) { + if ((pathPtr != NULL) && mustCleanUtf) { Tcl_UtfToExternalDString(NULL, Tcl_GetString(pathPtr), -1, &libPath); } TclpSetInitialEncodings(); /* * Now convert the native string back to UTF. */ - - if (pathPtr != NULL) { + + if ((pathPtr != NULL) && mustCleanUtf) { Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&libPath), -1, &buffer); pathPtr = Tcl_NewStringObj(Tcl_DStringValue(&buffer), -1); TclSetLibraryPath(pathPtr); @@ -2878,7 +3166,8 @@ Tcl_DStringFree(&buffer); } } TclpInitUnlock(); } + + return mustCleanUtf; } - Index: generic/tclEnv.c ================================================================== --- generic/tclEnv.c +++ generic/tclEnv.c @@ -10,11 +10,11 @@ * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclEnv.c,v 1.20 2003/01/14 02:06:11 mdejong Exp $ + * RCS: @(#) $Id: tclEnv.c,v 1.20.2.3 2006/10/31 22:25:08 das Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -24,10 +24,15 @@ static char **environCache = NULL; /* Array containing all of the environment * strings that Tcl has allocated. */ #ifndef USE_PUTENV +static char **ourEnviron = NULL;/* Cache of the array that we allocate. + * We need to track this in case another + * subsystem swaps around the environ array + * like we do. + */ static int environSize = 0; /* Non-zero means that the environ array was * malloced and has this many total entries * allocated to it (not all may be in use at * once). Zero means that the environment * array is in its original static state. */ @@ -36,10 +41,11 @@ /* * For MacOS X */ #if defined(__APPLE__) && defined(__DYNAMIC__) #include +__private_extern__ char **environ; char **environ = NULL; #endif /* * Declarations for local procedures defined in this file: @@ -189,21 +195,26 @@ Tcl_MutexLock(&envMutex); index = TclpFindVariable(name, &length); if (index == -1) { #ifndef USE_PUTENV - if ((length + 2) > environSize) { + /* + * We need to handle the case where the environment may be changed + * outside our control. environSize is only valid if the current + * environment is the one we allocated. [Bug 979640] + */ + if ((ourEnviron != environ) || ((length + 2) > environSize)) { char **newEnviron; newEnviron = (char **) ckalloc((unsigned) ((length + 5) * sizeof(char *))); memcpy((VOID *) newEnviron, (VOID *) environ, length*sizeof(char *)); - if (environSize != 0) { - ckfree((char *) environ); + if ((environSize != 0) && (ourEnviron != NULL)) { + ckfree((char *) ourEnviron); } - environ = newEnviron; + environ = ourEnviron = newEnviron; environSize = length + 5; #if defined(__APPLE__) && defined(__DYNAMIC__) { char ***e = _NSGetEnviron(); *e = environ; @@ -235,11 +246,10 @@ Tcl_DStringFree(&envString); oldValue = environ[index]; nameLength = length; } - /* * Create a new entry. Build a complete UTF string that contains * a "name=value" pattern. Then convert the string to the native * encoding, and set the environ array value. @@ -376,11 +386,11 @@ CONST char *name; /* Name of variable to remove (UTF-8). */ { char *oldValue; int length; int index; -#ifdef USE_PUTENV +#ifdef USE_PUTENV_FOR_UNSET Tcl_DString envString; char *string; #else char **envPtr; #endif @@ -390,11 +400,11 @@ /* * First make sure that the environment variable exists to avoid * doing needless work and to avoid recursion on the unset. */ - + if (index == -1) { Tcl_MutexUnlock(&envMutex); return; } /* @@ -406,16 +416,26 @@ /* * Update the system environment. This must be done before we * update the interpreters or we will recurse. */ -#ifdef USE_PUTENV +#ifdef USE_PUTENV_FOR_UNSET + /* + * For those platforms that support putenv to unset, Linux indicates + * that no = should be included, and Windows requires it. + */ +#ifdef WIN32 string = ckalloc((unsigned int) length+2); memcpy((VOID *) string, (VOID *) name, (size_t) length); string[length] = '='; string[length+1] = '\0'; - +#else + string = ckalloc((unsigned int) length+1); + memcpy((VOID *) string, (VOID *) name, (size_t) length); + string[length] = '\0'; +#endif + Tcl_UtfToExternalDString(NULL, string, -1, &envString); string = ckrealloc(string, (unsigned) (Tcl_DStringLength(&envString)+1)); strcpy(string, Tcl_DStringValue(&envString)); Tcl_DStringFree(&envString); @@ -427,10 +447,15 @@ * update the string in the cache. */ if (environ[index] == string) { ReplaceString(oldValue, string); +#ifdef HAVE_PUTENV_THAT_COPIES + } else { + /* This putenv() copies instead of taking ownership */ + ckfree(string); +#endif } #else for (envPtr = environ+index+1; ; envPtr++) { envPtr[-1] = *envPtr; if (*envPtr == NULL) { @@ -626,29 +651,29 @@ */ if (environCache[i]) { ckfree(environCache[i]); } - + if (newStr) { environCache[i] = newStr; } else { for (; i < cacheSize-1; i++) { environCache[i] = environCache[i+1]; } environCache[cacheSize-1] = NULL; } - } else { + } else { int allocatedSize = (cacheSize + 5) * sizeof(char *); /* * We need to grow the cache in order to hold the new string. */ newCache = (char **) ckalloc((unsigned) allocatedSize); (VOID *) memset(newCache, (int) 0, (size_t) allocatedSize); - + if (environCache) { memcpy((VOID *) newCache, (VOID *) environCache, (size_t) (cacheSize * sizeof(char*))); ckfree((char *) environCache); } Index: generic/tclEvent.c ================================================================== --- generic/tclEvent.c +++ generic/tclEvent.c @@ -9,11 +9,11 @@ * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclEvent.c,v 1.28 2003/02/22 09:23:16 vasiljevic Exp $ + * RCS: @(#) $Id: tclEvent.c,v 1.28.2.15 2007/03/19 17:06:25 dgp Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -98,12 +98,24 @@ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * Common string for the library path for sharing across threads. + * This is ckalloc'd and cleared in Tcl_Finalize. */ -char *tclLibraryPathStr; +static char *tclLibraryPathStr = NULL; + + +#ifdef TCL_THREADS + +typedef struct { + Tcl_ThreadCreateProc *proc; /* Main() function of the thread */ + ClientData clientData; /* The one argument to Main() */ +} ThreadClientData; +static Tcl_ThreadCreateType NewThreadProc _ANSI_ARGS_(( + ClientData clientData)); +#endif /* * Prototypes for procedures referenced only in this file: */ @@ -591,10 +603,12 @@ TclSetLibraryPath(pathPtr) Tcl_Obj *pathPtr; /* A Tcl list object whose elements are * the new library path. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + const char *toDupe; + int size; if (pathPtr != NULL) { Tcl_IncrRefCount(pathPtr); } if (tsdPtr->tclLibraryPath != NULL) { @@ -604,11 +618,16 @@ /* * No mutex locking is needed here as up the stack we're within * TclpInitLock(). */ - tclLibraryPathStr = Tcl_GetStringFromObj(pathPtr, NULL); + if (tclLibraryPathStr != NULL) { + ckfree(tclLibraryPathStr); + } + toDupe = Tcl_GetStringFromObj(pathPtr, &size); + tclLibraryPathStr = ckalloc((unsigned)size+1); + memcpy(tclLibraryPathStr, toDupe, (unsigned)size+1); } /* *------------------------------------------------------------------------- * @@ -710,22 +729,23 @@ /* * Initialize locks used by the memory allocators before anything * interesting happens so we can use the allocators in the * implementation of self-initializing locks. */ + #if USE_TCLALLOC TclInitAlloc(); /* process wide mutex init */ #endif #ifdef TCL_MEM_DEBUG TclInitDbCkalloc(); /* process wide mutex init */ #endif TclpInitPlatform(); /* creates signal handler(s) */ - TclInitObjSubsystem(); /* register obj types, create mutexes */ + TclInitObjSubsystem(); /* register obj types, create mutexes */ TclInitIOSubsystem(); /* inits a tsd key (noop) */ TclInitEncodingSubsystem(); /* process wide encoding init */ - TclInitNamespaceSubsystem(); /* register ns obj type (mutexed) */ + TclInitNamespaceSubsystem(); /* register ns obj type (mutexed) */ } TclpInitUnlock(); } if (tsdPtr == NULL) { @@ -761,40 +781,44 @@ void Tcl_Finalize() { ExitHandler *exitPtr; - ThreadSpecificData *tsdPtr; + + /* + * Invoke exit handlers first. + */ + + Tcl_MutexLock(&exitMutex); + inFinalize = 1; + for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) { + /* + * Be careful to remove the handler from the list before + * invoking its callback. This protects us against + * double-freeing if the callback should call + * Tcl_DeleteExitHandler on itself. + */ + + firstExitPtr = exitPtr->nextPtr; + Tcl_MutexUnlock(&exitMutex); + (*exitPtr->proc)(exitPtr->clientData); + ckfree((char *) exitPtr); + Tcl_MutexLock(&exitMutex); + } + firstExitPtr = NULL; + Tcl_MutexUnlock(&exitMutex); TclpInitLock(); if (subsystemsInitialized != 0) { subsystemsInitialized = 0; - tsdPtr = TCL_TSD_INIT(&dataKey); - - /* - * Invoke exit handlers first. - */ - - Tcl_MutexLock(&exitMutex); - inFinalize = 1; - for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) { - /* - * Be careful to remove the handler from the list before - * invoking its callback. This protects us against - * double-freeing if the callback should call - * Tcl_DeleteExitHandler on itself. - */ - - firstExitPtr = exitPtr->nextPtr; - Tcl_MutexUnlock(&exitMutex); - (*exitPtr->proc)(exitPtr->clientData); - ckfree((char *) exitPtr); - Tcl_MutexLock(&exitMutex); - } - firstExitPtr = NULL; - Tcl_MutexUnlock(&exitMutex); + /* + * Ensure the thread-specific data is initialised as it is + * used in Tcl_FinalizeThread() + */ + + (void) TCL_TSD_INIT(&dataKey); /* * Clean up after the current thread now, after exit handlers. * In particular, the testexithandler command sets up something * that writes to standard output, which gets closed. @@ -807,19 +831,33 @@ * Now finalize the Tcl execution environment. Note that this * must be done after the exit handlers, because there are * order dependencies. */ - TclFinalizeCompExecEnv(); + TclFinalizeCompilation(); + TclFinalizeExecution(); TclFinalizeEnvironment(); /* * Finalizing the filesystem must come after anything which * might conceivably interact with the 'Tcl_FS' API. */ + TclFinalizeFilesystem(); + /* + * Undo all the Tcl_ObjType registrations, and reset the master list + * of free Tcl_Obj's. After this returns, no more Tcl_Obj's should + * be allocated or freed. + * + * Note in particular that TclFinalizeObjects() must follow + * TclFinalizeFilesystem() because TclFinalizeFilesystem free's + * the Tcl_Obj that holds the path of the current working directory. + */ + + TclFinalizeObjects(); + /* * We must be sure the encoding finalization doesn't need * to examine the filesystem in any way. Since it only * needs to clean up internal data structures, this is * fine. @@ -836,19 +874,45 @@ } if (tclDefaultEncodingDir != NULL) { ckfree(tclDefaultEncodingDir); tclDefaultEncodingDir = NULL; } + if (tclLibraryPathStr != NULL) { + ckfree(tclLibraryPathStr); + tclLibraryPathStr = NULL; + } Tcl_SetPanicProc(NULL); + /* + * There have been several bugs in the past that cause + * exit handlers to be established during Tcl_Finalize + * processing. Such exit handlers leave malloc'ed memory, + * and Tcl_FinalizeThreadAlloc or Tcl_FinalizeMemorySubsystem + * will result in a corrupted heap. The result can be a + * mysterious crash on process exit. Check here that + * nobody's done this. + */ + +#ifdef TCL_MEM_DEBUG + if ( firstExitPtr != NULL ) { + Tcl_Panic( "exit handlers were created during Tcl_Finalize" ); + } +#endif + + TclFinalizePreserve(); + /* * Free synchronization objects. There really should only be one * thread alive at this moment. */ TclFinalizeSynchronization(); + +#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG) && !defined(PURIFY) + TclFinalizeThreadAlloc(); +#endif /* * We defer unloading of packages until very late * to avoid memory access issues. Both exit callbacks and * synchronization variables may be stored in packages. @@ -865,17 +929,17 @@ TclFinalizeLoad(); TclResetFilesystem(); /* - * There shouldn't be any malloc'ed memory after this. + * At this point, there should no longer be any ckalloc'ed memory. */ TclFinalizeMemorySubsystem(); inFinalize = 0; } - TclpInitUnlock(); + TclFinalizeLock(); } /* *---------------------------------------------------------------------- * @@ -895,13 +959,13 @@ void Tcl_FinalizeThread() { ExitHandler *exitPtr; - ThreadSpecificData *tsdPtr = - (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr; + tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr != NULL) { tsdPtr->inExit = 1; /* * Clean up the library path now, before we invalidate thread-local @@ -928,21 +992,21 @@ TclFinalizeIOSubsystem(); TclFinalizeNotifier(); TclFinalizeAsync(); } - /* - * Blow away all thread local storage blocks. + /* + * Blow away all thread local storage blocks. * * Note that Tcl API allows creation of threads which do not use any * Tcl interp or other Tcl subsytems. Those threads might, however, * use thread local storage, so we must unconditionally finalize it. * * Fix [Bug #571002] - */ + */ - TclFinalizeThreadData(); + TclFinalizeThreadData(); } /* *---------------------------------------------------------------------- * @@ -1130,5 +1194,81 @@ */ Tcl_ResetResult(interp); return TCL_OK; } + +#ifdef TCL_THREADS +/* + *----------------------------------------------------------------------------- + * + * NewThreadProc -- + * + * Bootstrap function of a new Tcl thread. + * + * Results: + * None. + * + * Side Effects: + * Initializes Tcl notifier for the current thread. + * + *----------------------------------------------------------------------------- + */ + +static Tcl_ThreadCreateType +NewThreadProc(ClientData clientData) +{ + ThreadClientData *cdPtr; + ClientData threadClientData; + Tcl_ThreadCreateProc *threadProc; + + cdPtr = (ThreadClientData*)clientData; + threadProc = cdPtr->proc; + threadClientData = cdPtr->clientData; + ckfree((char*)clientData); /* Allocated in Tcl_CreateThread() */ + + (*threadProc)(threadClientData); + + TCL_THREAD_CREATE_RETURN; +} +#endif +/* + *---------------------------------------------------------------------- + * + * Tcl_CreateThread -- + * + * This procedure creates a new thread. This actually belongs + * to the tclThread.c file but since we use some private + * data structures local to this file, it is placed here. + * + * Results: + * TCL_OK if the thread could be created. The thread ID is + * returned in a parameter. + * + * Side effects: + * A new thread is created. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags) + Tcl_ThreadId *idPtr; /* Return, the ID of the thread */ + Tcl_ThreadCreateProc proc; /* Main() function of the thread */ + ClientData clientData; /* The one argument to Main() */ + int stackSize; /* Size of stack for the new thread */ + int flags; /* Flags controlling behaviour of + * the new thread */ +{ +#ifdef TCL_THREADS + ThreadClientData *cdPtr; + + cdPtr = (ThreadClientData*)ckalloc(sizeof(ThreadClientData)); + cdPtr->proc = proc; + cdPtr->clientData = clientData; + + return TclpThreadCreate(idPtr, NewThreadProc, (ClientData)cdPtr, + stackSize, flags); +#else + return TCL_ERROR; +#endif /* TCL_THREADS */ +} Index: generic/tclExecute.c ================================================================== --- generic/tclExecute.c +++ generic/tclExecute.c @@ -9,11 +9,11 @@ * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclExecute.c,v 1.94 2003/02/19 14:33:39 msofer Exp $ + * RCS: @(#) $Id: tclExecute.c,v 1.94.2.21 2007/03/13 16:26:32 dgp Exp $ */ #include "tclInt.h" #include "tclCompile.h" @@ -256,22 +256,10 @@ # define TRACE_APPEND(a) # define TRACE_WITH_OBJ(a, objPtr) # define O2S(objPtr) #endif /* TCL_COMPILE_DEBUG */ - -/* - * Most of the code to support working with wide values is factored - * out here because it greatly reduces the number of conditionals - * through the rest of the file. Note that this needs to be - * conditional because we do not want to alter Tcl's behaviour on - * native-64bit platforms... - */ - -#ifndef TCL_WIDE_INT_IS_LONG -#define W0 Tcl_LongAsWide(0) - /* * Macro to read a string containing either a wide or an int and * decide which it is while decoding it at the same time. This * enforces the policy that integer constants between LONG_MIN and * LONG_MAX (inclusive) are represented by normal longs, and integer @@ -295,12 +283,30 @@ && (wideVar) <= Tcl_LongAsWide(LONG_MAX)) { \ (objPtr)->typePtr = &tclIntType; \ (objPtr)->internalRep.longValue = (longVar) \ = Tcl_WideAsLong(wideVar); \ } +/* + * Combined with REQUIRE_WIDE_OR_INT, this gets a long value from + * an obj. + */ +#define FORCE_LONG(objPtr, longVar, wideVar) \ + if ((objPtr)->typePtr == &tclWideIntType) { \ + (longVar) = Tcl_WideAsLong(wideVar); \ + } #define IS_INTEGER_TYPE(typePtr) \ ((typePtr) == &tclIntType || (typePtr) == &tclWideIntType) +#define IS_NUMERIC_TYPE(typePtr) \ + (IS_INTEGER_TYPE(typePtr) || (typePtr) == &tclDoubleType) + +#define W0 Tcl_LongAsWide(0) +/* + * For tracing that uses wide values. + */ +#define LLD "%" TCL_LL_MODIFIER "d" + +#ifndef TCL_WIDE_INT_IS_LONG /* * Extract a double value from a general numeric object. */ #define GET_DOUBLE_VALUE(doubleVar, objPtr, typePtr) \ if ((typePtr) == &tclIntType) { \ @@ -308,46 +314,18 @@ } else if ((typePtr) == &tclWideIntType) { \ (doubleVar) = Tcl_WideAsDouble((objPtr)->internalRep.wideValue);\ } else { \ (doubleVar) = (objPtr)->internalRep.doubleValue; \ } -/* - * Combined with REQUIRE_WIDE_OR_INT, this gets a long value from - * an obj. - */ -#define FORCE_LONG(objPtr, longVar, wideVar) \ - if ((objPtr)->typePtr == &tclWideIntType) { \ - (longVar) = Tcl_WideAsLong(wideVar); \ - } -/* - * For tracing that uses wide values. - */ -#define LLTRACE(a) TRACE(a) -#define LLTRACE_WITH_OBJ(a,b) TRACE_WITH_OBJ(a,b) -#define LLD "%" TCL_LL_MODIFIER "d" #else /* TCL_WIDE_INT_IS_LONG */ -/* - * Versions of the above that do not use wide values. - */ -#define REQUIRE_WIDE_OR_INT(resultVar, objPtr, longVar, wideVar) \ - (resultVar) = Tcl_GetLongFromObj(interp, (objPtr), &(longVar)); -#define GET_WIDE_OR_INT(resultVar, objPtr, longVar, wideVar) \ - (resultVar) = Tcl_GetLongFromObj((Tcl_Interp *) NULL, (objPtr), \ - &(longVar)); -#define IS_INTEGER_TYPE(typePtr) ((typePtr) == &tclIntType) #define GET_DOUBLE_VALUE(doubleVar, objPtr, typePtr) \ - if ((typePtr) == &tclIntType) { \ + if (((typePtr) == &tclIntType) || ((typePtr) == &tclWideIntType)) { \ (doubleVar) = (double) (objPtr)->internalRep.longValue; \ } else { \ (doubleVar) = (objPtr)->internalRep.doubleValue; \ } -#define FORCE_LONG(objPtr, longVar, wideVar) -#define LLTRACE(a) -#define LLTRACE_WITH_OBJ(a,b) #endif /* TCL_WIDE_INT_IS_LONG */ -#define IS_NUMERIC_TYPE(typePtr) \ - (IS_INTEGER_TYPE(typePtr) || (typePtr) == &tclDoubleType) /* * Declarations for local procedures to this file: */ @@ -369,14 +347,12 @@ ExecEnv *eePtr, ClientData clientData)); static int ExprSrandFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); static int ExprUnaryFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); -#ifndef TCL_WIDE_INT_IS_LONG static int ExprWideFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); -#endif /* TCL_WIDE_INT_IS_LONG */ #ifdef TCL_COMPILE_STATS static int EvalStatsCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); #endif /* TCL_COMPILE_STATS */ @@ -435,15 +411,11 @@ {"double", 1, {TCL_EITHER}, ExprDoubleFunc, 0}, {"int", 1, {TCL_EITHER}, ExprIntFunc, 0}, {"rand", 0, {TCL_EITHER}, ExprRandFunc, 0}, /* NOTE: rand takes no args. */ {"round", 1, {TCL_EITHER}, ExprRoundFunc, 0}, {"srand", 1, {TCL_INT}, ExprSrandFunc, 0}, -#ifdef TCL_WIDE_INT_IS_LONG - {"wide", 1, {TCL_EITHER}, ExprIntFunc, 0}, -#else {"wide", 1, {TCL_EITHER}, ExprWideFunc, 0}, -#endif /* TCL_WIDE_INT_IS_LONG */ {0}, }; /* *---------------------------------------------------------------------- @@ -773,11 +745,16 @@ objPtr->typePtr = (Tcl_ObjType *) NULL; } } } if (objPtr->typePtr != &tclByteCodeType) { +#ifndef TCL_TIP280 TclInitCompileEnv(interp, &compEnv, string, length); +#else + /* TIP #280 : No invoker (yet) - Expression compilation */ + TclInitCompileEnv(interp, &compEnv, string, length, NULL, 0); +#endif result = TclCompileExpr(interp, string, length, &compEnv); /* * Free the compilation environment's literal table bucket array if * it was dynamically allocated. @@ -903,13 +880,21 @@ * *---------------------------------------------------------------------- */ int +#ifndef TCL_TIP280 TclCompEvalObj(interp, objPtr) +#else +TclCompEvalObj(interp, objPtr, invoker, word) +#endif Tcl_Interp *interp; Tcl_Obj *objPtr; +#ifdef TCL_TIP280 + CONST CmdFrame* invoker; /* Frame of the command doing the eval */ + int word; /* Index of the word which is in objPtr */ +#endif { register Interp *iPtr = (Interp *) interp; register ByteCode* codePtr; /* Tcl Internal type of bytecode. */ int oldCount = iPtr->cmdCount; /* Used to tell whether any commands * at all were executed. */ @@ -921,11 +906,13 @@ /* * Check that the interpreter is ready to execute scripts */ + iPtr->numLevels++; if (TclInterpReady(interp) == TCL_ERROR) { + iPtr->numLevels--; return TCL_ERROR; } if (iPtr->varFramePtr != NULL) { namespacePtr = iPtr->varFramePtr->nsPtr; @@ -941,15 +928,30 @@ */ if (objPtr->typePtr != &tclByteCodeType) { recompileObj: iPtr->errorLine = 1; + +#ifdef TCL_TIP280 + /* TIP #280. Remember the invoker for a moment in the interpreter + * structures so that the byte code compiler can pick it up when + * initializing the compilation environment, i.e. the extended + * location information. + */ + + iPtr->invokeCmdFramePtr = invoker; + iPtr->invokeWord = word; +#endif result = tclByteCodeType.setFromAnyProc(interp, objPtr); +#ifdef TCL_TIP280 + iPtr->invokeCmdFramePtr = NULL; +#endif + if (result != TCL_OK) { + iPtr->numLevels--; return result; } - iPtr->evalFlags = 0; codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; } else { /* * Make sure the Bytecode hasn't been invalidated by, e.g., someone * redefining a command with a compile procedure (this might make the @@ -1002,20 +1004,20 @@ * Increment the code's ref count while it is being executed. If * afterwards no references to it remain, free the code. */ codePtr->refCount++; - iPtr->numLevels++; result = TclExecuteByteCode(interp, codePtr); - iPtr->numLevels--; codePtr->refCount--; if (codePtr->refCount <= 0) { TclCleanupByteCode(codePtr); } } else { result = TCL_OK; } + iPtr->numLevels--; + /* * If no commands at all were executed, check for asynchronous * handlers so that they at least get one change to execute. * This is needed to handle event loops written in Tcl with @@ -1095,18 +1097,22 @@ int storeFlags; Tcl_Obj *valuePtr, *value2Ptr, *objPtr; char *bytes; int length; long i = 0; /* Init. avoids compiler warning. */ -#ifndef TCL_WIDE_INT_IS_LONG Tcl_WideInt w; -#endif register int cleanup; Tcl_Obj *objResultPtr; char *part1, *part2; Var *varPtr, *arrayPtr; CallFrame *varFramePtr = iPtr->varFramePtr; + +#ifdef TCL_TIP280 + /* TIP #280 : Structures for tracking lines */ + CmdFrame bcFrame; +#endif + #ifdef TCL_COMPILE_DEBUG int traceInstructions = (tclTraceExec == 3); char cmdNameBuf[21]; #endif @@ -1119,10 +1125,30 @@ #define STATIC_CATCH_STACK_SIZE 4 int (catchStackStorage[STATIC_CATCH_STACK_SIZE]); int *catchStackPtr = catchStackStorage; int catchTop = -1; + +#ifdef TCL_TIP280 + /* TIP #280 : Initialize the frame. Do not push it yet. */ + + bcFrame.type = ((codePtr->flags & TCL_BYTECODE_PRECOMPILED) + ? TCL_LOCATION_PREBC + : TCL_LOCATION_BC); + bcFrame.level = (iPtr->cmdFramePtr == NULL ? + 1 : + iPtr->cmdFramePtr->level + 1); + bcFrame.framePtr = iPtr->framePtr; + bcFrame.nextPtr = iPtr->cmdFramePtr; + bcFrame.nline = 0; + bcFrame.line = NULL; + + bcFrame.data.tebc.codePtr = codePtr; + bcFrame.data.tebc.pc = NULL; + bcFrame.cmd.str.cmd = NULL; + bcFrame.cmd.str.len = 0; +#endif #ifdef TCL_COMPILE_DEBUG if (tclTraceExec >= 2) { PrintByteCodeInfo(codePtr); fprintf(stdout, " Starting stack top=%d\n", eePtr->stackTop); @@ -1288,10 +1314,26 @@ case INST_CONCAT1: opnd = TclGetUInt1AtPtr(pc+1); { int totalLen = 0; + /* + * Peephole optimisation for appending an empty string. + * This enables replacing 'K $x [set x{}]' by '$x[set x{}]' + * for fastest execution. Avoid doing the optimisation for wide + * ints - a case where equal strings may refer to different values + * (see [Bug 1251791]). + */ + + if ((opnd == 2) && (stackPtr[stackTop-1]->typePtr != &tclWideIntType)) { + Tcl_GetStringFromObj(stackPtr[stackTop], &length); + if (length == 0) { + /* Just drop the top item from the stack */ + NEXT_INST_F(2, 1, 0); + } + } + /* * Concatenate strings (with no separators) from the top * opnd items on the stack starting with the deepest item. * First, determine how many characters are needed. */ @@ -1421,17 +1463,27 @@ preservedStackRefCountPtr = (char **) (stackPtr-1); ++*preservedStackRefCountPtr; /* - * Finally, let TclEvalObjvInternal handle the command. + * Finally, let TclEvalObjvInternal handle the command. + * + * TIP #280 : Record the last piece of info needed by + * 'TclGetSrcInfoForPc', and push the frame. */ - Tcl_ResetResult(interp); +#ifdef TCL_TIP280 + bcFrame.data.tebc.pc = pc; + iPtr->cmdFramePtr = &bcFrame; +#endif DECACHE_STACK_INFO(); + Tcl_ResetResult(interp); result = TclEvalObjvInternal(interp, objc, objv, bytes, length, 0); CACHE_STACK_INFO(); +#ifdef TCL_TIP280 + iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr; +#endif /* * If the old stack is going to be released, it is * safe to do so now, since no references to objv are * going to be used from now on. @@ -1450,11 +1502,30 @@ TRACE_WITH_OBJ(("%u => ... after \"%.20s\": TCL_OK, result=", objc, cmdNameBuf), Tcl_GetObjResult(interp)); objResultPtr = Tcl_GetObjResult(interp); - NEXT_INST_V(pcAdjustment, opnd, 1); + + /* + * Reset the interp's result to avoid possible duplications + * of large objects [Bug 781585]. We do not call + * Tcl_ResetResult() to avoid any side effects caused by + * the resetting of errorInfo and errorCode [Bug 804681], + * which are not needed here. We chose instead to manipulate + * the interp's object result directly. + * + * Note that the result object is now in objResultPtr, it + * keeps the refCount it had in its role of iPtr->objResultPtr. + */ + { + Tcl_Obj *newObjResultPtr; + TclNewObj(newObjResultPtr); + Tcl_IncrRefCount(newObjResultPtr); + iPtr->objResultPtr = newObjResultPtr; + } + + NEXT_INST_V(pcAdjustment, opnd, -1); } else { cleanup = opnd; goto processExceptionReturn; } } @@ -1466,30 +1537,58 @@ * checkForCatch! DO NOT OPTIMISE! */ objPtr = stackPtr[stackTop]; DECACHE_STACK_INFO(); +#ifndef TCL_TIP280 result = TclCompEvalObj(interp, objPtr); +#else + /* TIP #280: The invoking context is left NULL for a dynamically + * constructed command. We cannot match its lines to the outer + * context. + */ + + result = TclCompEvalObj(interp, objPtr, NULL,0); +#endif CACHE_STACK_INFO(); if (result == TCL_OK) { /* * Normal return; push the eval's object result. */ objResultPtr = Tcl_GetObjResult(interp); TRACE_WITH_OBJ(("\"%.30s\" => ", O2S(objPtr)), Tcl_GetObjResult(interp)); - NEXT_INST_F(1, 1, 1); + + /* + * Reset the interp's result to avoid possible duplications + * of large objects [Bug 781585]. We do not call + * Tcl_ResetResult() to avoid any side effects caused by + * the resetting of errorInfo and errorCode [Bug 804681], + * which are not needed here. We chose instead to manipulate + * the interp's object result directly. + * + * Note that the result object is now in objResultPtr, it + * keeps the refCount it had in its role of iPtr->objResultPtr. + */ + { + Tcl_Obj *newObjResultPtr; + TclNewObj(newObjResultPtr); + Tcl_IncrRefCount(newObjResultPtr); + iPtr->objResultPtr = newObjResultPtr; + } + + NEXT_INST_F(1, 1, -1); } else { cleanup = 1; goto processExceptionReturn; } case INST_EXPR_STK: objPtr = stackPtr[stackTop]; - Tcl_ResetResult(interp); DECACHE_STACK_INFO(); + Tcl_ResetResult(interp); result = Tcl_ExprObj(interp, objPtr, &valuePtr); CACHE_STACK_INFO(); if (result != TCL_OK) { TRACE_WITH_OBJ(("\"%.30s\" => ERROR: ", O2S(objPtr)), Tcl_GetObjResult(interp)); @@ -1907,20 +2006,20 @@ case INST_INCR_STK: opnd = TclGetUInt1AtPtr(pc+1); valuePtr = stackPtr[stackTop]; if (valuePtr->typePtr == &tclIntType) { i = valuePtr->internalRep.longValue; -#ifndef TCL_WIDE_INT_IS_LONG } else if (valuePtr->typePtr == &tclWideIntType) { - i = Tcl_WideAsLong(valuePtr->internalRep.wideValue); -#endif /* TCL_WIDE_INT_IS_LONG */ + TclGetLongFromWide(i,valuePtr); } else { REQUIRE_WIDE_OR_INT(result, valuePtr, i, w); if (result != TCL_OK) { TRACE_WITH_OBJ(("%u (by %s) => ERROR converting increment amount to int: ", opnd, O2S(valuePtr)), Tcl_GetObjResult(interp)); + DECACHE_STACK_INFO(); Tcl_AddErrorInfo(interp, "\n (reading increment)"); + CACHE_STACK_INFO(); goto checkForCatch; } FORCE_LONG(valuePtr, i, w); } stackTop--; @@ -1958,12 +2057,14 @@ part1 = TclGetString(objPtr); varPtr = TclObjLookupVar(interp, objPtr, part2, TCL_LEAVE_ERR_MSG, "read", 0, 1, &arrayPtr); if (varPtr == NULL) { + DECACHE_STACK_INFO(); Tcl_AddObjErrorInfo(interp, "\n (reading value of variable to increment)", -1); + CACHE_STACK_INFO(); TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); result = TCL_ERROR; goto checkForCatch; } cleanup = ((part2 == NULL)? 1 : 2); @@ -2097,14 +2198,13 @@ valuePtr = stackPtr[stackTop]; if (valuePtr->typePtr == &tclIntType) { b = (valuePtr->internalRep.longValue != 0); } else if (valuePtr->typePtr == &tclDoubleType) { b = (valuePtr->internalRep.doubleValue != 0.0); -#ifndef TCL_WIDE_INT_IS_LONG } else if (valuePtr->typePtr == &tclWideIntType) { - b = (valuePtr->internalRep.wideValue != W0); -#endif /* TCL_WIDE_INT_IS_LONG */ + TclGetWide(w,valuePtr); + b = (w != W0); } else { result = Tcl_GetBooleanFromObj(interp, valuePtr, &b); if (result != TCL_OK) { TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp)); goto checkForCatch; @@ -2152,74 +2252,64 @@ t1Ptr = valuePtr->typePtr; t2Ptr = value2Ptr->typePtr; if ((t1Ptr == &tclIntType) || (t1Ptr == &tclBooleanType)) { i1 = (valuePtr->internalRep.longValue != 0); -#ifndef TCL_WIDE_INT_IS_LONG } else if (t1Ptr == &tclWideIntType) { - i1 = (valuePtr->internalRep.wideValue != W0); -#endif /* TCL_WIDE_INT_IS_LONG */ + TclGetWide(w,valuePtr); + i1 = (w != W0); } else if (t1Ptr == &tclDoubleType) { i1 = (valuePtr->internalRep.doubleValue != 0.0); } else { s = Tcl_GetStringFromObj(valuePtr, &length); if (TclLooksLikeInt(s, length)) { -#ifdef TCL_WIDE_INT_IS_LONG - result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, - valuePtr, &i); - i1 = (i != 0); -#else /* !TCL_WIDE_INT_IS_LONG */ GET_WIDE_OR_INT(result, valuePtr, i, w); if (valuePtr->typePtr == &tclIntType) { i1 = (i != 0); } else { i1 = (w != W0); } -#endif /* TCL_WIDE_INT_IS_LONG */ } else { result = Tcl_GetBooleanFromObj((Tcl_Interp *) NULL, valuePtr, &i1); i1 = (i1 != 0); } if (result != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr), (t1Ptr? t1Ptr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); + CACHE_STACK_INFO(); goto checkForCatch; } } if ((t2Ptr == &tclIntType) || (t2Ptr == &tclBooleanType)) { i2 = (value2Ptr->internalRep.longValue != 0); -#ifndef TCL_WIDE_INT_IS_LONG } else if (t2Ptr == &tclWideIntType) { - i2 = (value2Ptr->internalRep.wideValue != W0); -#endif /* TCL_WIDE_INT_IS_LONG */ + TclGetWide(w,value2Ptr); + i2 = (w != W0); } else if (t2Ptr == &tclDoubleType) { i2 = (value2Ptr->internalRep.doubleValue != 0.0); } else { s = Tcl_GetStringFromObj(value2Ptr, &length); if (TclLooksLikeInt(s, length)) { -#ifdef TCL_WIDE_INT_IS_LONG - result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, - value2Ptr, &i); - i2 = (i != 0); -#else /* !TCL_WIDE_INT_IS_LONG */ GET_WIDE_OR_INT(result, value2Ptr, i, w); if (value2Ptr->typePtr == &tclIntType) { i2 = (i != 0); } else { i2 = (w != W0); } -#endif /* TCL_WIDE_INT_IS_LONG */ } else { result = Tcl_GetBooleanFromObj((Tcl_Interp *) NULL, value2Ptr, &i2); } if (result != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(value2Ptr), (t2Ptr? t2Ptr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, value2Ptr); + CACHE_STACK_INFO(); goto checkForCatch; } } /* @@ -2701,30 +2791,71 @@ long iResult = 0; /* Init. avoids compiler warning. */ value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop - 1]; + /* + * Be careful in the equal-object case; 'NaN' isn't supposed + * to be equal to even itself. [Bug 761471] + */ + + t1Ptr = valuePtr->typePtr; if (valuePtr == value2Ptr) { /* - * Optimize the equal object case. + * If we are numeric already, we can proceed to the main + * equality check right now. Otherwise, we need to try to + * coerce to a numeric type so we can see if we've got a + * NaN but haven't parsed it as numeric. */ + if (!IS_NUMERIC_TYPE(t1Ptr)) { + if (t1Ptr == &tclListType) { + int length; + /* + * Only a list of length 1 can be NaN or such + * things. + */ + (void) Tcl_ListObjLength(NULL, valuePtr, &length); + if (length == 1) { + goto mustConvertForNaNCheck; + } + } else { + /* + * Too bad, we'll have to compute the string and + * try the conversion + */ + + mustConvertForNaNCheck: + s1 = Tcl_GetStringFromObj(valuePtr, &length); + if (TclLooksLikeInt(s1, length)) { + GET_WIDE_OR_INT(iResult, valuePtr, i, w); + } else { + (void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, + valuePtr, &d1); + } + t1Ptr = valuePtr->typePtr; + } + } + switch (*pc) { - case INST_EQ: - case INST_LE: - case INST_GE: - iResult = 1; - break; - case INST_NEQ: - case INST_LT: - case INST_GT: - iResult = 0; - break; + case INST_EQ: + case INST_LE: + case INST_GE: + iResult = !((t1Ptr == &tclDoubleType) + && IS_NAN(valuePtr->internalRep.doubleValue)); + break; + case INST_LT: + case INST_GT: + iResult = 0; + break; + case INST_NEQ: + iResult = ((t1Ptr == &tclDoubleType) + && IS_NAN(valuePtr->internalRep.doubleValue)); + break; } goto foundResult; } - t1Ptr = valuePtr->typePtr; t2Ptr = value2Ptr->typePtr; /* * We only want to coerce numeric validation if neither type * is NULL. A NULL type means the arg is essentially an empty @@ -2823,26 +2954,25 @@ break; case INST_GE: iResult = d1 >= d2; break; } -#ifndef TCL_WIDE_INT_IS_LONG } else if ((t1Ptr == &tclWideIntType) || (t2Ptr == &tclWideIntType)) { Tcl_WideInt w2; /* * Compare as wide ints (neither are doubles) */ if (t1Ptr == &tclIntType) { w = Tcl_LongAsWide(valuePtr->internalRep.longValue); - w2 = value2Ptr->internalRep.wideValue; + TclGetWide(w2,value2Ptr); } else if (t2Ptr == &tclIntType) { - w = valuePtr->internalRep.wideValue; + TclGetWide(w,valuePtr); w2 = Tcl_LongAsWide(value2Ptr->internalRep.longValue); } else { - w = valuePtr->internalRep.wideValue; - w2 = value2Ptr->internalRep.wideValue; + TclGetWide(w,valuePtr); + TclGetWide(w2,value2Ptr); } switch (*pc) { case INST_EQ: iResult = w == w2; break; @@ -2860,11 +2990,10 @@ break; case INST_GE: iResult = w >= w2; break; } -#endif /* TCL_WIDE_INT_IS_LONG */ } else { /* * Compare as ints. */ i = valuePtr->internalRep.longValue; @@ -2927,48 +3056,46 @@ * Only integers are allowed. We compute value op value2. */ long i2 = 0, rem, negative; long iResult = 0; /* Init. avoids compiler warning. */ -#ifndef TCL_WIDE_INT_IS_LONG Tcl_WideInt w2, wResult = W0; int doWide = 0; -#endif /* TCL_WIDE_INT_IS_LONG */ value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop - 1]; if (valuePtr->typePtr == &tclIntType) { i = valuePtr->internalRep.longValue; -#ifndef TCL_WIDE_INT_IS_LONG } else if (valuePtr->typePtr == &tclWideIntType) { - w = valuePtr->internalRep.wideValue; -#endif /* TCL_WIDE_INT_IS_LONG */ + TclGetWide(w,valuePtr); } else { /* try to convert to int */ REQUIRE_WIDE_OR_INT(result, valuePtr, i, w); if (result != TCL_OK) { TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr), O2S(value2Ptr), (valuePtr->typePtr? valuePtr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); + CACHE_STACK_INFO(); goto checkForCatch; } } if (value2Ptr->typePtr == &tclIntType) { i2 = value2Ptr->internalRep.longValue; -#ifndef TCL_WIDE_INT_IS_LONG } else if (value2Ptr->typePtr == &tclWideIntType) { - w2 = value2Ptr->internalRep.wideValue; -#endif /* TCL_WIDE_INT_IS_LONG */ + TclGetWide(w2,value2Ptr); } else { REQUIRE_WIDE_OR_INT(result, value2Ptr, i2, w2); if (result != TCL_OK) { TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr), O2S(value2Ptr), (value2Ptr->typePtr? value2Ptr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, value2Ptr); + CACHE_STACK_INFO(); goto checkForCatch; } } switch (*pc) { @@ -2977,35 +3104,27 @@ * This code is tricky: C doesn't guarantee much about * the quotient or remainder, but Tcl does. The * remainder always has the same sign as the divisor and * a smaller absolute value. */ -#ifdef TCL_WIDE_INT_IS_LONG - if (i2 == 0) { - TRACE(("%ld %ld => DIVIDE BY ZERO\n", i, i2)); - goto divideByZero; - } -#else /* !TCL_WIDE_INT_IS_LONG */ if (value2Ptr->typePtr == &tclWideIntType && w2 == W0) { if (valuePtr->typePtr == &tclIntType) { - LLTRACE(("%ld "LLD" => DIVIDE BY ZERO\n", i, w2)); + TRACE(("%ld "LLD" => DIVIDE BY ZERO\n", i, w2)); } else { - LLTRACE((LLD" "LLD" => DIVIDE BY ZERO\n", w, w2)); + TRACE((LLD" "LLD" => DIVIDE BY ZERO\n", w, w2)); } goto divideByZero; } if (value2Ptr->typePtr == &tclIntType && i2 == 0) { if (valuePtr->typePtr == &tclIntType) { TRACE(("%ld %ld => DIVIDE BY ZERO\n", i, i2)); } else { - LLTRACE((LLD" %ld => DIVIDE BY ZERO\n", w, i2)); + TRACE((LLD" %ld => DIVIDE BY ZERO\n", w, i2)); } goto divideByZero; } -#endif /* TCL_WIDE_INT_IS_LONG */ negative = 0; -#ifndef TCL_WIDE_INT_IS_LONG if (valuePtr->typePtr == &tclWideIntType || value2Ptr->typePtr == &tclWideIntType) { Tcl_WideInt wRemainder; /* * Promote to wide @@ -3029,11 +3148,10 @@ } wResult = wRemainder; doWide = 1; break; } -#endif /* TCL_WIDE_INT_IS_LONG */ if (i2 < 0) { i2 = -i2; i = -i; negative = 1; } @@ -3045,58 +3163,122 @@ rem = -rem; } iResult = rem; break; case INST_LSHIFT: -#ifndef TCL_WIDE_INT_IS_LONG /* * Shifts are never usefully 64-bits wide! */ FORCE_LONG(value2Ptr, i2, w2); if (valuePtr->typePtr == &tclWideIntType) { #ifdef TCL_COMPILE_DEBUG w2 = Tcl_LongAsWide(i2); #endif /* TCL_COMPILE_DEBUG */ - wResult = w << i2; + wResult = w; + /* + * Shift in steps when the shift gets large to prevent + * annoying compiler/processor bugs. [Bug 868467] + */ + if (i2 >= 64) { + wResult = Tcl_LongAsWide(0); + } else if (i2 > 60) { + wResult = w << 30; + wResult <<= 30; + wResult <<= i2-60; + } else if (i2 > 30) { + wResult = w << 30; + wResult <<= i2-30; + } else { + wResult = w << i2; + } doWide = 1; break; } -#endif /* TCL_WIDE_INT_IS_LONG */ - iResult = i << i2; + /* + * Shift in steps when the shift gets large to prevent + * annoying compiler/processor bugs. [Bug 868467] + */ + if (i2 >= 64) { + iResult = 0; + } else if (i2 > 60) { + iResult = i << 30; + iResult <<= 30; + iResult <<= i2-60; + } else if (i2 > 30) { + iResult = i << 30; + iResult <<= i2-30; + } else { + iResult = i << i2; + } break; case INST_RSHIFT: /* * The following code is a bit tricky: it ensures that * right shifts propagate the sign bit even on machines * where ">>" won't do it by default. */ -#ifndef TCL_WIDE_INT_IS_LONG /* * Shifts are never usefully 64-bits wide! */ FORCE_LONG(value2Ptr, i2, w2); if (valuePtr->typePtr == &tclWideIntType) { #ifdef TCL_COMPILE_DEBUG w2 = Tcl_LongAsWide(i2); #endif /* TCL_COMPILE_DEBUG */ if (w < 0) { - wResult = ~((~w) >> i2); + wResult = ~w; + } else { + wResult = w; + } + /* + * Shift in steps when the shift gets large to prevent + * annoying compiler/processor bugs. [Bug 868467] + */ + if (i2 >= 64) { + wResult = Tcl_LongAsWide(0); + } else if (i2 > 60) { + wResult >>= 30; + wResult >>= 30; + wResult >>= i2-60; + } else if (i2 > 30) { + wResult >>= 30; + wResult >>= i2-30; } else { - wResult = w >> i2; + wResult >>= i2; + } + if (w < 0) { + wResult = ~wResult; } doWide = 1; break; } -#endif /* TCL_WIDE_INT_IS_LONG */ + if (i < 0) { + iResult = ~i; + } else { + iResult = i; + } + /* + * Shift in steps when the shift gets large to prevent + * annoying compiler/processor bugs. [Bug 868467] + */ + if (i2 >= 64) { + iResult = 0; + } else if (i2 > 60) { + iResult >>= 30; + iResult >>= 30; + iResult >>= i2-60; + } else if (i2 > 30) { + iResult >>= 30; + iResult >>= i2-30; + } else { + iResult >>= i2; + } if (i < 0) { - iResult = ~((~i) >> i2); - } else { - iResult = i >> i2; + iResult = ~iResult; } break; case INST_BITOR: -#ifndef TCL_WIDE_INT_IS_LONG if (valuePtr->typePtr == &tclWideIntType || value2Ptr->typePtr == &tclWideIntType) { /* * Promote to wide */ @@ -3107,15 +3289,13 @@ } wResult = w | w2; doWide = 1; break; } -#endif /* TCL_WIDE_INT_IS_LONG */ iResult = i | i2; break; case INST_BITXOR: -#ifndef TCL_WIDE_INT_IS_LONG if (valuePtr->typePtr == &tclWideIntType || value2Ptr->typePtr == &tclWideIntType) { /* * Promote to wide */ @@ -3126,15 +3306,13 @@ } wResult = w ^ w2; doWide = 1; break; } -#endif /* TCL_WIDE_INT_IS_LONG */ iResult = i ^ i2; break; case INST_BITAND: -#ifndef TCL_WIDE_INT_IS_LONG if (valuePtr->typePtr == &tclWideIntType || value2Ptr->typePtr == &tclWideIntType) { /* * Promote to wide */ @@ -3145,44 +3323,35 @@ } wResult = w & w2; doWide = 1; break; } -#endif /* TCL_WIDE_INT_IS_LONG */ iResult = i & i2; break; } /* * Reuse the valuePtr object already on stack if possible. */ if (Tcl_IsShared(valuePtr)) { -#ifndef TCL_WIDE_INT_IS_LONG if (doWide) { objResultPtr = Tcl_NewWideIntObj(wResult); - LLTRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); + TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); } else { -#endif /* TCL_WIDE_INT_IS_LONG */ objResultPtr = Tcl_NewLongObj(iResult); TRACE(("%ld %ld => %ld\n", i, i2, iResult)); -#ifndef TCL_WIDE_INT_IS_LONG } -#endif /* TCL_WIDE_INT_IS_LONG */ NEXT_INST_F(1, 2, 1); } else { /* reuse the valuePtr object */ -#ifndef TCL_WIDE_INT_IS_LONG if (doWide) { - LLTRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); + TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); Tcl_SetWideIntObj(valuePtr, wResult); } else { -#endif /* TCL_WIDE_INT_IS_LONG */ TRACE(("%ld %ld => %ld\n", i, i2, iResult)); Tcl_SetLongObj(valuePtr, iResult); -#ifndef TCL_WIDE_INT_IS_LONG } -#endif /* TCL_WIDE_INT_IS_LONG */ NEXT_INST_F(1, 1, 0); } } case INST_ADD: @@ -3199,27 +3368,23 @@ long i2 = 0, quot, rem; /* Init. avoids compiler warning. */ double d1, d2; long iResult = 0; /* Init. avoids compiler warning. */ double dResult = 0.0; /* Init. avoids compiler warning. */ int doDouble = 0; /* 1 if doing floating arithmetic */ -#ifndef TCL_WIDE_INT_IS_LONG Tcl_WideInt w2, wquot, wrem; Tcl_WideInt wResult = W0; /* Init. avoids compiler warning. */ int doWide = 0; /* 1 if doing wide arithmetic. */ -#endif /* TCL_WIDE_INT_IS_LONG */ value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop - 1]; t1Ptr = valuePtr->typePtr; t2Ptr = value2Ptr->typePtr; if (t1Ptr == &tclIntType) { i = valuePtr->internalRep.longValue; -#ifndef TCL_WIDE_INT_IS_LONG } else if (t1Ptr == &tclWideIntType) { - w = valuePtr->internalRep.wideValue; -#endif /* TCL_WIDE_INT_IS_LONG */ + TclGetWide(w,valuePtr); } else if ((t1Ptr == &tclDoubleType) && (valuePtr->bytes == NULL)) { /* * We can only use the internal rep directly if there is * no string rep. Otherwise the string rep might actually @@ -3238,22 +3403,22 @@ if (result != TCL_OK) { TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", s, O2S(valuePtr), (valuePtr->typePtr? valuePtr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); + CACHE_STACK_INFO(); goto checkForCatch; } t1Ptr = valuePtr->typePtr; } if (t2Ptr == &tclIntType) { i2 = value2Ptr->internalRep.longValue; -#ifndef TCL_WIDE_INT_IS_LONG } else if (t2Ptr == &tclWideIntType) { - w2 = value2Ptr->internalRep.wideValue; -#endif /* TCL_WIDE_INT_IS_LONG */ + TclGetWide(w2,value2Ptr); } else if ((t2Ptr == &tclDoubleType) && (value2Ptr->bytes == NULL)) { /* * We can only use the internal rep directly if there is * no string rep. Otherwise the string rep might actually @@ -3272,11 +3437,13 @@ if (result != TCL_OK) { TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(value2Ptr), s, (value2Ptr->typePtr? value2Ptr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, value2Ptr); + CACHE_STACK_INFO(); goto checkForCatch; } t2Ptr = value2Ptr->typePtr; } @@ -3287,16 +3454,14 @@ doDouble = 1; if (t1Ptr == &tclIntType) { d1 = i; /* promote value 1 to double */ } else if (t2Ptr == &tclIntType) { d2 = i2; /* promote value 2 to double */ -#ifndef TCL_WIDE_INT_IS_LONG } else if (t1Ptr == &tclWideIntType) { d1 = Tcl_WideAsDouble(w); } else if (t2Ptr == &tclWideIntType) { d2 = Tcl_WideAsDouble(w2); -#endif /* TCL_WIDE_INT_IS_LONG */ } switch (*pc) { case INST_ADD: dResult = d1 + d2; break; @@ -3320,15 +3485,16 @@ */ if (IS_NAN(dResult) || IS_INF(dResult)) { TRACE(("%.20s %.20s => IEEE FLOATING PT ERROR\n", O2S(valuePtr), O2S(value2Ptr))); + DECACHE_STACK_INFO(); TclExprFloatError(interp, dResult); + CACHE_STACK_INFO(); result = TCL_ERROR; goto checkForCatch; } -#ifndef TCL_WIDE_INT_IS_LONG } else if ((t1Ptr == &tclWideIntType) || (t2Ptr == &tclWideIntType)) { /* * Do wide integer arithmetic. */ @@ -3354,11 +3520,11 @@ * about the quotient or remainder, but Tcl does. * The remainder always has the same sign as the * divisor and a smaller absolute value. */ if (w2 == W0) { - LLTRACE((LLD" "LLD" => DIVIDE BY ZERO\n", w, w2)); + TRACE((LLD" "LLD" => DIVIDE BY ZERO\n", w, w2)); goto divideByZero; } if (w2 < 0) { w2 = -w2; w = -w; @@ -3369,11 +3535,10 @@ wquot -= 1; } wResult = wquot; break; } -#endif /* TCL_WIDE_INT_IS_LONG */ } else { /* * Do integer arithmetic. */ switch (*pc) { @@ -3417,29 +3582,25 @@ if (Tcl_IsShared(valuePtr)) { if (doDouble) { objResultPtr = Tcl_NewDoubleObj(dResult); TRACE(("%.6g %.6g => %.6g\n", d1, d2, dResult)); -#ifndef TCL_WIDE_INT_IS_LONG } else if (doWide) { objResultPtr = Tcl_NewWideIntObj(wResult); - LLTRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); -#endif /* TCL_WIDE_INT_IS_LONG */ + TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); } else { objResultPtr = Tcl_NewLongObj(iResult); TRACE(("%ld %ld => %ld\n", i, i2, iResult)); } NEXT_INST_F(1, 2, 1); } else { /* reuse the valuePtr object */ if (doDouble) { /* NB: stack top is off by 1 */ TRACE(("%.6g %.6g => %.6g\n", d1, d2, dResult)); Tcl_SetDoubleObj(valuePtr, dResult); -#ifndef TCL_WIDE_INT_IS_LONG } else if (doWide) { - LLTRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); + TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); Tcl_SetWideIntObj(valuePtr, wResult); -#endif /* TCL_WIDE_INT_IS_LONG */ } else { TRACE(("%ld %ld => %ld\n", i, i2, iResult)); Tcl_SetLongObj(valuePtr, iResult); } NEXT_INST_F(1, 1, 0); @@ -3466,11 +3627,13 @@ result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d); } if (result != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", s, (tPtr? tPtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); + CACHE_STACK_INFO(); goto checkForCatch; } tPtr = valuePtr->typePtr; } @@ -3485,15 +3648,13 @@ if (Tcl_IsShared(valuePtr)) { if (tPtr == &tclIntType) { i = valuePtr->internalRep.longValue; objResultPtr = Tcl_NewLongObj(i); -#ifndef TCL_WIDE_INT_IS_LONG } else if (tPtr == &tclWideIntType) { - w = valuePtr->internalRep.wideValue; + TclGetWide(w,valuePtr); objResultPtr = Tcl_NewWideIntObj(w); -#endif /* TCL_WIDE_INT_IS_LONG */ } else { d = valuePtr->internalRep.doubleValue; objResultPtr = Tcl_NewDoubleObj(d); } TRACE_WITH_OBJ(("%s => ", O2S(objResultPtr)), objResultPtr); @@ -3541,11 +3702,13 @@ i = (long)boolvar; /* i is long, not int! */ } if (result != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s\n", s, (tPtr? tPtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); + CACHE_STACK_INFO(); goto checkForCatch; } } tPtr = valuePtr->typePtr; } @@ -3557,20 +3720,18 @@ if ((tPtr == &tclIntType) || (tPtr == &tclBooleanType)) { i = valuePtr->internalRep.longValue; objResultPtr = Tcl_NewLongObj( (*pc == INST_UMINUS)? -i : !i); TRACE_WITH_OBJ(("%ld => ", i), objResultPtr); -#ifndef TCL_WIDE_INT_IS_LONG } else if (tPtr == &tclWideIntType) { - w = valuePtr->internalRep.wideValue; + TclGetWide(w,valuePtr); if (*pc == INST_UMINUS) { objResultPtr = Tcl_NewWideIntObj(-w); } else { objResultPtr = Tcl_NewLongObj(w == W0); } - LLTRACE_WITH_OBJ((LLD" => ", w), objResultPtr); -#endif /* TCL_WIDE_INT_IS_LONG */ + TRACE_WITH_OBJ((LLD" => ", w), objResultPtr); } else { d = valuePtr->internalRep.doubleValue; if (*pc == INST_UMINUS) { objResultPtr = Tcl_NewDoubleObj(-d); } else { @@ -3590,20 +3751,18 @@ if ((tPtr == &tclIntType) || (tPtr == &tclBooleanType)) { i = valuePtr->internalRep.longValue; Tcl_SetLongObj(valuePtr, (*pc == INST_UMINUS)? -i : !i); TRACE_WITH_OBJ(("%ld => ", i), valuePtr); -#ifndef TCL_WIDE_INT_IS_LONG } else if (tPtr == &tclWideIntType) { - w = valuePtr->internalRep.wideValue; + TclGetWide(w,valuePtr); if (*pc == INST_UMINUS) { Tcl_SetWideIntObj(valuePtr, -w); } else { Tcl_SetLongObj(valuePtr, w == W0); } - LLTRACE_WITH_OBJ((LLD" => ", w), valuePtr); -#endif /* TCL_WIDE_INT_IS_LONG */ + TRACE_WITH_OBJ((LLD" => ", w), valuePtr); } else { d = valuePtr->internalRep.doubleValue; if (*pc == INST_UMINUS) { Tcl_SetDoubleObj(valuePtr, -d); } else { @@ -3635,32 +3794,32 @@ if (!IS_INTEGER_TYPE(tPtr)) { REQUIRE_WIDE_OR_INT(result, valuePtr, i, w); if (result != TCL_OK) { /* try to convert to double */ TRACE(("\"%.20s\" => ILLEGAL TYPE %s\n", O2S(valuePtr), (tPtr? tPtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); + CACHE_STACK_INFO(); goto checkForCatch; } } -#ifndef TCL_WIDE_INT_IS_LONG if (valuePtr->typePtr == &tclWideIntType) { - w = valuePtr->internalRep.wideValue; + TclGetWide(w,valuePtr); if (Tcl_IsShared(valuePtr)) { objResultPtr = Tcl_NewWideIntObj(~w); - LLTRACE(("0x%llx => (%llu)\n", w, ~w)); + TRACE(("0x%llx => (%llu)\n", w, ~w)); NEXT_INST_F(1, 1, 1); } else { /* * valuePtr is unshared. Modify it directly. */ Tcl_SetWideIntObj(valuePtr, ~w); - LLTRACE(("0x%llx => (%llu)\n", w, ~w)); + TRACE(("0x%llx => (%llu)\n", w, ~w)); NEXT_INST_F(1, 0, 0); } } else { -#endif /* TCL_WIDE_INT_IS_LONG */ i = valuePtr->internalRep.longValue; if (Tcl_IsShared(valuePtr)) { objResultPtr = Tcl_NewLongObj(~i); TRACE(("0x%lx => (%lu)\n", i, ~i)); NEXT_INST_F(1, 1, 1); @@ -3670,13 +3829,11 @@ */ Tcl_SetLongObj(valuePtr, ~i); TRACE(("0x%lx => (%lu)\n", i, ~i)); NEXT_INST_F(1, 0, 0); } -#ifndef TCL_WIDE_INT_IS_LONG } -#endif /* TCL_WIDE_INT_IS_LONG */ } case INST_CALL_BUILTIN_FUNC1: opnd = TclGetUInt1AtPtr(pc+1); { @@ -3786,15 +3943,13 @@ */ needNew = 1; if (tPtr == &tclIntType) { i = valuePtr->internalRep.longValue; objResultPtr = Tcl_NewLongObj(i); -#ifndef TCL_WIDE_INT_IS_LONG } else if (tPtr == &tclWideIntType) { - w = valuePtr->internalRep.wideValue; + TclGetWide(w,valuePtr); objResultPtr = Tcl_NewWideIntObj(w); -#endif /* TCL_WIDE_INT_IS_LONG */ } else { d = valuePtr->internalRep.doubleValue; objResultPtr = Tcl_NewDoubleObj(d); } tPtr = objResultPtr->typePtr; @@ -3806,11 +3961,13 @@ if (tPtr == &tclDoubleType) { d = objResultPtr->internalRep.doubleValue; if (IS_NAN(d) || IS_INF(d)) { TRACE(("\"%.20s\" => IEEE FLOATING PT ERROR\n", O2S(objResultPtr))); + DECACHE_STACK_INFO(); TclExprFloatError(interp, d); + CACHE_STACK_INFO(); result = TCL_ERROR; goto checkForCatch; } } converted = converted; /* lint, converted not used. */ @@ -3826,17 +3983,21 @@ NEXT_INST_F(1, 0, 0); } } case INST_BREAK: + DECACHE_STACK_INFO(); Tcl_ResetResult(interp); + CACHE_STACK_INFO(); result = TCL_BREAK; cleanup = 0; goto processExceptionReturn; case INST_CONTINUE: + DECACHE_STACK_INFO(); Tcl_ResetResult(interp); + CACHE_STACK_INFO(); result = TCL_CONTINUE; cleanup = 0; goto processExceptionReturn; case INST_FOREACH_START4: @@ -3889,11 +4050,10 @@ codePtr->auxDataArrayPtr[opnd].clientData; ForeachVarList *varListPtr; int numLists = infoPtr->numLists; Var *compiledLocals = iPtr->varFramePtr->compiledLocals; Tcl_Obj *listPtr; - List *listRepPtr; Var *iterVarPtr, *listVarPtr; int iterNum, listTmpIndex, listLen, numVars; int varIndex, valIndex, continueLoop, j; /* @@ -3943,21 +4103,27 @@ varListPtr = infoPtr->varLists[i]; numVars = varListPtr->numVars; listVarPtr = &(compiledLocals[listTmpIndex]); listPtr = listVarPtr->value.objPtr; - listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; - listLen = listRepPtr->elemCount; - + valIndex = (iterNum * numVars); for (j = 0; j < numVars; j++) { - int setEmptyStr = 0; + Tcl_Obj **elements; + + /* + * The call to TclPtrSetVar might shimmer listPtr, + * so re-fetch pointers every iteration for safety. + * See test foreach-10.1. + */ + + Tcl_ListObjGetElements(NULL, listPtr, + &listLen, &elements); if (valIndex >= listLen) { - setEmptyStr = 1; TclNewObj(valuePtr); } else { - valuePtr = listRepPtr->elements[valIndex]; + valuePtr = elements[valIndex]; } varIndex = varListPtr->varIndexes[j]; varPtr = &(varFramePtr->compiledLocals[varIndex]); part1 = varPtr->name; @@ -3978,20 +4144,19 @@ varPtr->value.objPtr = valuePtr; Tcl_IncrRefCount(valuePtr); } } else { DECACHE_STACK_INFO(); + Tcl_IncrRefCount(valuePtr); value2Ptr = TclPtrSetVar(interp, varPtr, NULL, part1, NULL, valuePtr, TCL_LEAVE_ERR_MSG); + TclDecrRefCount(valuePtr); CACHE_STACK_INFO(); if (value2Ptr == NULL) { TRACE_WITH_OBJ(("%u => ERROR init. index temp %d: ", opnd, varIndex), Tcl_GetObjResult(interp)); - if (setEmptyStr) { - TclDecrRefCount(valuePtr); - } result = TCL_ERROR; goto checkForCatch; } } valIndex++; @@ -4034,11 +4199,22 @@ NEXT_INST_F(1, 0, 0); case INST_PUSH_RESULT: objResultPtr = Tcl_GetObjResult(interp); TRACE_WITH_OBJ(("=> "), Tcl_GetObjResult(interp)); - NEXT_INST_F(1, 0, 1); + + /* + * See the comments at INST_INVOKE_STK + */ + { + Tcl_Obj *newObjResultPtr; + TclNewObj(newObjResultPtr); + Tcl_IncrRefCount(newObjResultPtr); + iPtr->objResultPtr = newObjResultPtr; + } + + NEXT_INST_F(1, 0, -1); case INST_PUSH_RETURN_CODE: objResultPtr = Tcl_NewLongObj(result); TRACE(("=> %u\n", result)); NEXT_INST_F(1, 0, 1); @@ -4051,14 +4227,17 @@ * Division by zero in an expression. Control only reaches this * point by "goto divideByZero". */ divideByZero: + DECACHE_STACK_INFO(); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "divide by zero", -1); Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", (char *) NULL); + CACHE_STACK_INFO(); + result = TCL_ERROR; goto checkForCatch; /* * An external evaluation (INST_INVOKE or INST_EVAL) returned @@ -4144,11 +4323,13 @@ checkForCatch: if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) { bytes = GetSrcInfoForPc(pc, codePtr, &length); if (bytes != NULL) { + DECACHE_STACK_INFO(); Tcl_LogCommandInfo(interp, codePtr->source, bytes, length); + CACHE_STACK_INFO(); iPtr->flags |= ERR_ALREADY_LOGGED; } } if (catchTop == -1) { #ifdef TCL_COMPILE_DEBUG @@ -4506,11 +4687,11 @@ } /* *---------------------------------------------------------------------- * - * GetSrcInfoForPc -- + * TclGetSrcInfoForPc, GetSrcInfoForPc -- * * Given a program counter value, finds the closest command in the * bytecode code unit's CmdLocation array and returns information about * that command's source: a pointer to its first byte and the number of * characters. @@ -4526,10 +4707,67 @@ * Side effects: * None. * *---------------------------------------------------------------------- */ + +#ifdef TCL_TIP280 +void +TclGetSrcInfoForPc (cfPtr) + CmdFrame* cfPtr; +{ + ByteCode* codePtr = (ByteCode*) cfPtr->data.tebc.codePtr; + + if (cfPtr->cmd.str.cmd == NULL) { + cfPtr->cmd.str.cmd = GetSrcInfoForPc((char*) cfPtr->data.tebc.pc, + codePtr, + &cfPtr->cmd.str.len); + } + + if (cfPtr->cmd.str.cmd != NULL) { + /* We now have the command. We can get the srcOffset back and + * from there find the list of word locations for this command + */ + + ExtCmdLoc* eclPtr; + ECL* locPtr = NULL; + int srcOffset; + + Interp* iPtr = (Interp*) *codePtr->interpHandle; + Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr); + + if (!hePtr) return; + + srcOffset = cfPtr->cmd.str.cmd - codePtr->source; + eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hePtr); + + { + int i; + for (i=0; i < eclPtr->nuloc; i++) { + if (eclPtr->loc [i].srcOffset == srcOffset) { + locPtr = &(eclPtr->loc [i]); + break; + } + } + } + + if (locPtr == NULL) {Tcl_Panic ("LocSearch failure");} + + cfPtr->line = locPtr->line; + cfPtr->nline = locPtr->nline; + cfPtr->type = eclPtr->type; + + if (eclPtr->type == TCL_LOCATION_SOURCE) { + cfPtr->data.eval.path = eclPtr->path; + Tcl_IncrRefCount (cfPtr->data.eval.path); + } + /* Do not set cfPtr->data.eval.path NULL for non-SOURCE + * Needed for cfPtr->data.tebc.codePtr. + */ + } +} +#endif static char * GetSrcInfoForPc(pc, codePtr, lengthPtr) unsigned char *pc; /* The program counter value for which to * return the closest command's source info. @@ -4758,17 +4996,13 @@ } else { int length, result = TCL_OK; char *s = Tcl_GetStringFromObj(objPtr, &length); if (TclLooksLikeInt(s, length)) { -#ifdef TCL_WIDE_INT_IS_LONG long i; - result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, objPtr, &i); -#else /* !TCL_WIDE_INT_IS_LONG */ Tcl_WideInt w; - result = Tcl_GetWideIntFromObj((Tcl_Interp *) NULL, objPtr, &w); -#endif /* TCL_WIDE_INT_IS_LONG */ + GET_WIDE_OR_INT(result, objPtr, i, w); } else { double d; result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, objPtr, &d); } if ((result != TCL_OK) && (interp != NULL)) { @@ -4975,27 +5209,37 @@ * Push a Tcl object with the result. */ if (valuePtr->typePtr == &tclIntType) { i = valuePtr->internalRep.longValue; if (i < 0) { - iResult = -i; - if (iResult < 0) { - Tcl_ResetResult(interp); - Tcl_AppendToObj(Tcl_GetObjResult(interp), - "integer value too large to represent", -1); + if (i == LONG_MIN) { +#ifdef TCL_WIDE_INT_IS_LONG + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "integer value too large to represent", -1)); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", "integer value too large to represent", (char *) NULL); result = TCL_ERROR; goto done; +#else + /* + * Special case: abs(MIN_INT) must promote to wide. + */ + + PUSH_OBJECT( Tcl_NewWideIntObj(-(Tcl_WideInt) i) ); + result = TCL_OK; + goto done; +#endif + } + iResult = -i; } else { iResult = i; } PUSH_OBJECT(Tcl_NewLongObj(iResult)); -#ifndef TCL_WIDE_INT_IS_LONG } else if (valuePtr->typePtr == &tclWideIntType) { - Tcl_WideInt wResult, w = valuePtr->internalRep.wideValue; + Tcl_WideInt wResult, w; + TclGetWide(w,valuePtr); if (w < W0) { wResult = -w; if (wResult < 0) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), @@ -5007,11 +5251,10 @@ } } else { wResult = w; } PUSH_OBJECT(Tcl_NewWideIntObj(wResult)); -#endif /* TCL_WIDE_INT_IS_LONG */ } else { d = valuePtr->internalRep.doubleValue; if (d < 0.0) { dResult = -d; } else { @@ -5118,14 +5361,12 @@ goto done; } if (valuePtr->typePtr == &tclIntType) { iResult = valuePtr->internalRep.longValue; -#ifndef TCL_WIDE_INT_IS_LONG } else if (valuePtr->typePtr == &tclWideIntType) { - iResult = Tcl_WideAsLong(valuePtr->internalRep.wideValue); -#endif /* TCL_WIDE_INT_IS_LONG */ + TclGetLongFromWide(iResult,valuePtr); } else { d = valuePtr->internalRep.doubleValue; if (d < 0.0) { if (d < (double) (long) LONG_MIN) { tooLarge: @@ -5164,11 +5405,10 @@ TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); return result; } -#ifndef TCL_WIDE_INT_IS_LONG static int ExprWideFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing @@ -5199,11 +5439,11 @@ result = TCL_ERROR; goto done; } if (valuePtr->typePtr == &tclWideIntType) { - wResult = valuePtr->internalRep.wideValue; + TclGetWide(wResult,valuePtr); } else if (valuePtr->typePtr == &tclIntType) { wResult = Tcl_LongAsWide(valuePtr->internalRep.longValue); } else { d = valuePtr->internalRep.doubleValue; if (d < 0.0) { @@ -5243,11 +5483,10 @@ done: TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); return result; } -#endif /* TCL_WIDE_INT_IS_LONG */ static int ExprRandFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ @@ -5356,13 +5595,12 @@ * the function. */ ClientData clientData; /* Ignored. */ { Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ - Tcl_Obj *valuePtr; - long iResult; - double d, temp; + Tcl_Obj *valuePtr, *resPtr; + double d, f, i; int result; /* * Set stackPtr and stackTop from eePtr. */ @@ -5378,61 +5616,73 @@ if (VerifyExprObjType(interp, valuePtr) != TCL_OK) { result = TCL_ERROR; goto done; } - - if (valuePtr->typePtr == &tclIntType) { - iResult = valuePtr->internalRep.longValue; -#ifndef TCL_WIDE_INT_IS_LONG - } else if (valuePtr->typePtr == &tclWideIntType) { - PUSH_OBJECT(Tcl_NewWideIntObj(valuePtr->internalRep.wideValue)); - goto done; -#endif /* TCL_WIDE_INT_IS_LONG */ - } else { - d = valuePtr->internalRep.doubleValue; - if (d < 0.0) { - if (d <= (((double) (long) LONG_MIN) - 0.5)) { - tooLarge: - Tcl_ResetResult(interp); - Tcl_AppendToObj(Tcl_GetObjResult(interp), - "integer value too large to represent", -1); - Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", - "integer value too large to represent", - (char *) NULL); - result = TCL_ERROR; - goto done; - } - temp = (long) (d - 0.5); - } else { - if (d >= (((double) LONG_MAX + 0.5))) { - goto tooLarge; - } - temp = (long) (d + 0.5); - } - if (IS_NAN(temp) || IS_INF(temp)) { - TclExprFloatError(interp, temp); - result = TCL_ERROR; - goto done; - } - iResult = (long) temp; - } - - /* - * Push a Tcl object with the result. - */ - - PUSH_OBJECT(Tcl_NewLongObj(iResult)); - - /* - * Reflect the change to stackTop back in eePtr. - */ - + + if ((valuePtr->typePtr == &tclIntType) || + (valuePtr->typePtr == &tclWideIntType)) { + result = TCL_OK; + resPtr = valuePtr; + } else { + + /* + * Round the number to the nearest integer. I'd like to use round(), + * but it's C99 (or BSD), and not yet universal. + */ + + d = valuePtr->internalRep.doubleValue; + f = modf(d, &i); + if (d < 0.0) { + if (f <= -0.5) { + i += -1.0; + } + if (i <= Tcl_WideAsDouble(LLONG_MIN)) { + goto tooLarge; + } else if (i <= (double) LONG_MIN) { + resPtr = Tcl_NewWideIntObj(Tcl_DoubleAsWide(i)); + } else { + resPtr = Tcl_NewLongObj((long) i); + } + } else { + if (f >= 0.5) { + i += 1.0; + } + if (i >= Tcl_WideAsDouble(LLONG_MAX)) { + goto tooLarge; + } else if (i >= (double) LONG_MAX) { + resPtr = Tcl_NewWideIntObj(Tcl_DoubleAsWide(i)); + } else { + resPtr = Tcl_NewLongObj((long) i); + } + } + } + + /* + * Push the result object and free the argument Tcl_Obj. + */ + + PUSH_OBJECT(resPtr); + done: TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); return result; + + /* + * Error return: result cannot be represented as an integer. + */ + + tooLarge: + Tcl_ResetResult(interp); + Tcl_AppendToObj(Tcl_GetObjResult(interp), + "integer value too large to represent", -1); + Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", + "integer value too large to represent", + (char *) NULL); + result = TCL_ERROR; + goto done; } static int ExprSrandFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the @@ -5462,28 +5712,22 @@ if (VerifyExprObjType(interp, valuePtr) != TCL_OK) { goto badValue; } - if (valuePtr->typePtr == &tclIntType) { - i = valuePtr->internalRep.longValue; -#ifndef TCL_WIDE_INT_IS_LONG - } else if (valuePtr->typePtr == &tclWideIntType) { - i = Tcl_WideAsLong(valuePtr->internalRep.wideValue); -#endif /* TCL_WIDE_INT_IS_LONG */ - } else { - /* - * At this point, the only other possible type is double - */ - Tcl_ResetResult(interp); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "can't use floating-point value as argument to srand", - (char *) NULL); + if (Tcl_GetLongFromObj(NULL, valuePtr, &i) != TCL_OK) { + Tcl_WideInt w; + + if (Tcl_GetWideIntFromObj(interp, valuePtr, &w) != TCL_OK) { badValue: - TclDecrRefCount(valuePtr); - DECACHE_STACK_INFO(); - return TCL_ERROR; + Tcl_AddErrorInfo(interp, "\n (argument to \"srand()\")"); + TclDecrRefCount(valuePtr); + DECACHE_STACK_INFO(); + return TCL_ERROR; + } + + i = Tcl_WideAsLong(w); } /* * Reset the seed. Make sure 1 <= randSeed <= 2^31 - 2. * See comments in ExprRandFunc() for more details. @@ -5604,43 +5848,38 @@ if (valuePtr->typePtr == &tclIntType) { i = valuePtr->internalRep.longValue; if (mathFuncPtr->argTypes[k] == TCL_DOUBLE) { args[k].type = TCL_DOUBLE; args[k].doubleValue = i; -#ifndef TCL_WIDE_INT_IS_LONG } else if (mathFuncPtr->argTypes[k] == TCL_WIDE_INT) { args[k].type = TCL_WIDE_INT; args[k].wideValue = Tcl_LongAsWide(i); -#endif /* !TCL_WIDE_INT_IS_LONG */ } else { args[k].type = TCL_INT; args[k].intValue = i; } -#ifndef TCL_WIDE_INT_IS_LONG } else if (valuePtr->typePtr == &tclWideIntType) { - Tcl_WideInt w = valuePtr->internalRep.wideValue; + Tcl_WideInt w; + TclGetWide(w,valuePtr); if (mathFuncPtr->argTypes[k] == TCL_DOUBLE) { args[k].type = TCL_DOUBLE; - args[k].wideValue = (Tcl_WideInt) Tcl_WideAsDouble(w); + args[k].doubleValue = Tcl_WideAsDouble(w); } else if (mathFuncPtr->argTypes[k] == TCL_INT) { args[k].type = TCL_INT; - args[k].wideValue = Tcl_WideAsLong(w); + args[k].intValue = Tcl_WideAsLong(w); } else { args[k].type = TCL_WIDE_INT; args[k].wideValue = w; } -#endif /* !TCL_WIDE_INT_IS_LONG */ } else { d = valuePtr->internalRep.doubleValue; if (mathFuncPtr->argTypes[k] == TCL_INT) { args[k].type = TCL_INT; args[k].intValue = (long) d; -#ifndef TCL_WIDE_INT_IS_LONG } else if (mathFuncPtr->argTypes[k] == TCL_WIDE_INT) { args[k].type = TCL_WIDE_INT; args[k].wideValue = Tcl_DoubleAsWide(d); -#endif /* !TCL_WIDE_INT_IS_LONG */ } else { args[k].type = TCL_DOUBLE; args[k].doubleValue = d; } } @@ -5670,14 +5909,12 @@ * Push the call's object result. */ if (funcResult.type == TCL_INT) { PUSH_OBJECT(Tcl_NewLongObj(funcResult.intValue)); -#ifndef TCL_WIDE_INT_IS_LONG } else if (funcResult.type == TCL_WIDE_INT) { PUSH_OBJECT(Tcl_NewWideIntObj(funcResult.wideValue)); -#endif /* !TCL_WIDE_INT_IS_LONG */ } else { d = funcResult.doubleValue; if (IS_NAN(d) || IS_INF(d)) { TclExprFloatError(interp, d); result = TCL_ERROR; @@ -6212,5 +6449,14 @@ } TclFormatInt(buf, result); return buf; } #endif /* TCL_COMPILE_DEBUG */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ + Index: generic/tclFCmd.c ================================================================== --- generic/tclFCmd.c +++ generic/tclFCmd.c @@ -7,11 +7,11 @@ * Copyright (c) 1996-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclFCmd.c,v 1.20 2002/08/08 10:41:22 hobbs Exp $ + * RCS: @(#) $Id: tclFCmd.c,v 1.20.2.2 2005/08/17 17:46:36 hobbs Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -259,23 +259,49 @@ if (!S_ISDIR(statBuf.st_mode)) { errno = EEXIST; errfile = target; goto done; } - } else if ((errno != ENOENT) - || (Tcl_FSCreateDirectory(target) != TCL_OK)) { + } else if (errno != ENOENT) { + /* + * If Tcl_FSStat() failed and the error is anything + * other than non-existence of the target, throw the + * error. + */ errfile = target; goto done; + } else if (Tcl_FSCreateDirectory(target) != TCL_OK) { + /* + * Create might have failed because of being in a race + * condition with another process trying to create the + * same subdirectory. + */ + if (errno == EEXIST) { + if ((Tcl_FSStat(target, &statBuf) == 0) + && S_ISDIR(statBuf.st_mode)) { + /* + * It is a directory that wasn't there before, + * so keep going without error. + */ + Tcl_ResetResult(interp); + } else { + errfile = target; + goto done; + } + } else { + errfile = target; + goto done; + } } - /* Forget about this sub-path */ + /* Forget about this sub-path */ Tcl_DecrRefCount(target); target = NULL; } Tcl_DecrRefCount(split); split = NULL; } - + done: if (errfile != NULL) { Tcl_AppendResult(interp, "can't create directory \"", Tcl_GetString(errfile), "\": ", Tcl_PosixError(interp), (char *) NULL); @@ -656,10 +682,18 @@ * We could examine 'errno' to double-check if the problem * was with the target, but we checked the source above, * so it should be quite clear */ errfile = target; + /* + * We now need to reset the result, because the above call, + * if it failed, may have put an error message in place. + * (Ideally we would prefer not to pass an interpreter in + * above, but the channel IO code used by + * TclCrossFilesystemCopy currently requires one) + */ + Tcl_ResetResult(interp); } } if ((copyFlag == 0) && (result == TCL_OK)) { if (S_ISDIR(sourceStatBuf.st_mode)) { result = Tcl_FSRemoveDirectory(source, 1, &errorBuffer); Index: generic/tclFileName.c ================================================================== --- generic/tclFileName.c +++ generic/tclFileName.c @@ -8,11 +8,11 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclFileName.c,v 1.40 2003/01/09 10:01:59 vincentdarley Exp $ + * RCS: @(#) $Id: tclFileName.c,v 1.40.2.15 2006/10/03 18:20:33 dgp Exp $ */ #include "tclInt.h" #include "tclPort.h" #include "tclRegexp.h" @@ -242,41 +242,51 @@ return tail; } } else { int abs = 0; - if (path[0] == 'c' && path[1] == 'o') { - if (path[2] == 'm' && path[3] >= '1' && path[3] <= '9') { - /* May have match for 'com[1-9]:?', which is a serial port */ - if (path[4] == '\0') { - abs = 4; - } else if (path [4] == ':' && path[5] == '\0') { + if ((path[0] == 'c' || path[0] == 'C') + && (path[1] == 'o' || path[1] == 'O')) { + if ((path[2] == 'm' || path[2] == 'M') + && path[3] >= '1' && path[3] <= '4') { + /* May have match for 'com[1-4]:?', which is a serial port */ + if (path[4] == '\0') { + abs = 4; + } else if (path [4] == ':' && path[5] == '\0') { abs = 5; - } - } else if (path[2] == 'n' && path[3] == '\0') { + } + } else if ((path[2] == 'n' || path[2] == 'N') && path[3] == '\0') { /* Have match for 'con' */ abs = 3; } - } else if (path[0] == 'l' && path[1] == 'p' && path[2] == 't') { - if (path[3] >= '1' && path[3] <= '9') { - /* May have match for 'lpt[1-9]:?' */ + } else if ((path[0] == 'l' || path[0] == 'L') + && (path[1] == 'p' || path[1] == 'P') + && (path[2] == 't' || path[2] == 'T')) { + if (path[3] >= '1' && path[3] <= '3') { + /* May have match for 'lpt[1-3]:?' */ if (path[4] == '\0') { abs = 4; } else if (path [4] == ':' && path[5] == '\0') { abs = 5; } } - } else if (path[0] == 'p' && path[1] == 'r' - && path[2] == 'n' && path[3] == '\0') { + } else if ((path[0] == 'p' || path[0] == 'P') + && (path[1] == 'r' || path[1] == 'R') + && (path[2] == 'n' || path[2] == 'N') + && path[3] == '\0') { /* Have match for 'prn' */ abs = 3; - } else if (path[0] == 'n' && path[1] == 'u' - && path[2] == 'l' && path[3] == '\0') { + } else if ((path[0] == 'n' || path[0] == 'N') + && (path[1] == 'u' || path[1] == 'U') + && (path[2] == 'l' || path[2] == 'L') + && path[3] == '\0') { /* Have match for 'nul' */ abs = 3; - } else if (path[0] == 'a' && path[1] == 'u' - && path[2] == 'x' && path[3] == '\0') { + } else if ((path[0] == 'a' || path[0] == 'A') + && (path[1] == 'u' || path[1] == 'U') + && (path[2] == 'x' || path[2] == 'X') + && path[3] == '\0') { /* Have match for 'aux' */ abs = 3; } if (abs != 0) { *typePtr = TCL_PATH_ABSOLUTE; @@ -780,12 +790,13 @@ Tcl_DStringLength(&buf))); } Tcl_DStringFree(&buf); /* - * Split on slashes. Embedded elements that start with tilde will be - * prefixed with "./" so they are not affected by tilde substitution. + * Split on slashes. Embedded elements that start with tilde + * or a drive letter will be prefixed with "./" so they are not + * affected by tilde substitution. */ do { elementStart = p; while ((*p != '\0') && (*p != '/') && (*p != '\\')) { @@ -792,11 +803,14 @@ p++; } length = p - elementStart; if (length > 0) { Tcl_Obj *nextElt; - if ((elementStart[0] == '~') && (elementStart != path)) { + if ((elementStart != path) + && ((elementStart[0] == '~') + || (isalpha(UCHAR(elementStart[0])) + && elementStart[1] == ':'))) { nextElt = Tcl_NewStringObj("./",2); Tcl_AppendToObj(nextElt, elementStart, length); } else { nextElt = Tcl_NewStringObj(elementStart, length); } @@ -1113,26 +1127,28 @@ char *dest, *p, *start; start = Tcl_GetStringFromObj(prefix, &length); /* - * Remove the ./ from tilde prefixed elements unless - * it is the first component. + * Remove the ./ from tilde prefixed elements, and drive-letter + * prefixed elements on Windows, unless it is the first component. */ p = joining; if (length != 0) { - if ((p[0] == '.') && (p[1] == '/') && (p[2] == '~')) { + if ((p[0] == '.') && (p[1] == '/') + && ((p[2] == '~') + || ((tclPlatform == TCL_PLATFORM_WINDOWS) + && isalpha(UCHAR(p[2])) + && (p[3] == ':')))) { p += 2; } } - if (*p == '\0') { return; } - switch (tclPlatform) { case TCL_PLATFORM_UNIX: /* * Append a separator if needed. @@ -1378,53 +1394,36 @@ * directory). */ Tcl_DString *bufferPtr; /* Uninitialized or free DString filled * with name after tilde substitution. */ { Tcl_Obj *path = Tcl_NewStringObj(name, -1); - CONST char *result; + Tcl_Obj *transPtr; Tcl_IncrRefCount(path); - result = Tcl_FSGetTranslatedStringPath(interp, path); - if (result == NULL) { + transPtr = Tcl_FSGetTranslatedPath(interp, path); + if (transPtr == NULL) { Tcl_DecrRefCount(path); return NULL; } + Tcl_DStringInit(bufferPtr); - Tcl_DStringAppend(bufferPtr, result, -1); + Tcl_DStringAppend(bufferPtr, Tcl_GetString(transPtr), -1); Tcl_DecrRefCount(path); - + Tcl_DecrRefCount(transPtr); + /* * Convert forward slashes to backslashes in Windows paths because * some system interfaces don't accept forward slashes. */ if (tclPlatform == TCL_PLATFORM_WINDOWS) { -#if defined(__CYGWIN__) && defined(__WIN32__) - - extern int cygwin_conv_to_win32_path - _ANSI_ARGS_((CONST char *, char *)); - char winbuf[MAX_PATH]; - - /* - * In the Cygwin world, call conv_to_win32_path in order to use the - * mount table to translate the file name into something Windows will - * understand. Take care when converting empty strings! - */ - if (Tcl_DStringLength(bufferPtr)) { - cygwin_conv_to_win32_path(Tcl_DStringValue(bufferPtr), winbuf); - Tcl_DStringFree(bufferPtr); - Tcl_DStringAppend(bufferPtr, winbuf, -1); - } -#else /* __CYGWIN__ && __WIN32__ */ - register char *p; for (p = Tcl_DStringValue(bufferPtr); *p != '\0'; p++) { if (*p == '/') { *p = '\\'; } } -#endif /* __CYGWIN__ && __WIN32__ */ } return Tcl_DStringValue(bufferPtr); } /* @@ -1600,11 +1599,10 @@ globFlags = 0; join = 0; dir = PATH_NONE; typePtr = NULL; - resultPtr = Tcl_GetObjResult(interp); for (i = 1; i < objc; i++) { if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index) != TCL_OK) { string = Tcl_GetStringFromObj(objv[i], &length); if (string[0] == '-') { @@ -1626,18 +1624,18 @@ case GLOB_NOCOMPLAIN: /* -nocomplain */ globFlags |= TCL_GLOBMODE_NO_COMPLAIN; break; case GLOB_DIR: /* -dir */ if (i == (objc-1)) { - Tcl_AppendToObj(resultPtr, - "missing argument to \"-directory\"", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "missing argument to \"-directory\"", -1)); return TCL_ERROR; } if (dir != PATH_NONE) { - Tcl_AppendToObj(resultPtr, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "\"-directory\" cannot be used with \"-path\"", - -1); + -1)); return TCL_ERROR; } dir = PATH_DIR; globFlags |= TCL_GLOBMODE_DIR; pathOrDir = objv[i+1]; @@ -1649,28 +1647,28 @@ case GLOB_TAILS: /* -tails */ globFlags |= TCL_GLOBMODE_TAILS; break; case GLOB_PATH: /* -path */ if (i == (objc-1)) { - Tcl_AppendToObj(resultPtr, - "missing argument to \"-path\"", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "missing argument to \"-path\"", -1)); return TCL_ERROR; } if (dir != PATH_NONE) { - Tcl_AppendToObj(resultPtr, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "\"-path\" cannot be used with \"-directory\"", - -1); + -1)); return TCL_ERROR; } dir = PATH_GENERAL; pathOrDir = objv[i+1]; i++; break; case GLOB_TYPE: /* -types */ if (i == (objc-1)) { - Tcl_AppendToObj(resultPtr, - "missing argument to \"-types\"", -1); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "missing argument to \"-types\"", -1)); return TCL_ERROR; } typePtr = objv[i+1]; if (Tcl_ListObjLength(interp, typePtr, &length) != TCL_OK) { return TCL_ERROR; @@ -1678,22 +1676,21 @@ i++; break; case GLOB_LAST: /* -- */ i++; goto endOfForLoop; - break; } } endOfForLoop: if (objc - i < 1) { Tcl_WrongNumArgs(interp, 1, objv, "?switches? name ?name ...?"); return TCL_ERROR; } if ((globFlags & TCL_GLOBMODE_TAILS) && (pathOrDir == NULL)) { - Tcl_AppendToObj(resultPtr, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "\"-tails\" must be used with either \"-directory\" or \"-path\"", - -1); + -1)); return TCL_ERROR; } separators = NULL; /* lint. */ switch (tclPlatform) { @@ -1734,10 +1731,20 @@ pathOrDir = NULL; } else { /* Have to split off the end */ Tcl_DStringAppend(&pref, last, first+pathlength-last); pathOrDir = Tcl_NewStringObj(first, last-first-1); + /* + * We must ensure that we haven't cut off too much, + * and turned a valid path like '/' or 'C:/' into + * an incorrect path like '' or 'C:'. The way we + * do this is to add a separator if there are none + * presently in the prefix. + */ + if (strpbrk(Tcl_GetString(pathOrDir), "\\/") == NULL) { + Tcl_AppendToObj(pathOrDir, last-1, 1); + } } /* Need to quote 'prefix' */ Tcl_DStringInit(&prefix); search = Tcl_DStringValue(&pref); while ((find = (strpbrk(search, "\\[]*?{}"))) != NULL) { @@ -1848,12 +1855,11 @@ continue; } } } /* - * Error cases. We re-get the interpreter's result, - * just to be sure it hasn't changed, and we reset + * Error cases. We reset * the 'join' flag to zero, since we haven't yet * made use of it. */ badTypesArg: resultPtr = Tcl_GetObjResult(interp); @@ -1861,14 +1867,13 @@ Tcl_AppendObjToObj(resultPtr, look); result = TCL_ERROR; join = 0; goto endOfGlob; badMacTypesArg: - resultPtr = Tcl_GetObjResult(interp); - Tcl_AppendToObj(resultPtr, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "only one MacOS type or creator argument" - " to \"-types\" allowed", -1); + " to \"-types\" allowed", -1)); result = TCL_ERROR; join = 0; goto endOfGlob; } } @@ -1880,15 +1885,10 @@ * etc. We use a 'goto' to ensure we free any memory allocated along * the way. */ objc -= i; objv += i; - /* - * We re-retrieve this, in case it was changed in - * the Tcl_ResetResult above - */ - resultPtr = Tcl_GetObjResult(interp); result = TCL_OK; if (join) { if (dir != PATH_GENERAL) { Tcl_DStringInit(&prefix); } @@ -2128,10 +2128,14 @@ * If the prefix is a directory, make sure it ends in a * directory separator. */ if (globFlags & TCL_GLOBMODE_DIR) { Tcl_DStringAppend(&buffer,separators,1); + /* Try to borrow that separator from the tail */ + if (*tail == *separators) { + tail++; + } } prefixLen++; } } @@ -2328,14 +2332,32 @@ */ count = 0; name = tail; for (; *tail != '\0'; tail++) { - if ((*tail == '\\') && (strchr(separators, tail[1]) != NULL)) { - tail++; + if (*tail == '\\') { + /* + * If the first character is escaped, either we have a directory + * separator, or we have any other character. In the latter case + * the rest of tail is a pattern, and we must break from the loop. + * This is particularly important on Windows where '\' is both + * the escaping character and a directory separator. + */ + if (strchr(separators, tail[1]) != NULL) { + tail++; + } else { + break; + } } else if (strchr(separators, *tail) == NULL) { break; + } + if (tclPlatform != TCL_PLATFORM_MAC) { + if (*tail == '\\') { + Tcl_DStringAppend(headPtr, separators, 1); + } else { + Tcl_DStringAppend(headPtr, tail, 1); + } } count++; } /* @@ -2374,30 +2396,10 @@ /* * If this is a drive relative path, add the colon and the * trailing slash if needed. Otherwise add the slash if * this is the first absolute element, or a later relative * element. Add an extra slash if this is a UNC path. - */ - -#if defined(__CYGWIN__) && defined(__WIN32__) - { - - extern int cygwin_conv_to_win32_path - _ANSI_ARGS_((CONST char *, char *)); - char winbuf[MAX_PATH]; - - /* - * In the Cygwin world, call conv_to_win32_path in order to use - * the mount table to translate the file name into something - * Windows will understand. - */ - cygwin_conv_to_win32_path(Tcl_DStringValue(headPtr), winbuf); - Tcl_DStringFree(headPtr); - Tcl_DStringAppend(headPtr, winbuf, -1); - - } -#endif /* __CYGWIN__ && __WIN32__ */ if (*name == ':') { Tcl_DStringAppend(headPtr, ":", 1); if (count > 1) { Tcl_DStringAppend(headPtr, "/", 1); @@ -2409,25 +2411,27 @@ Tcl_DStringAppend(headPtr, "/", 1); if ((length == 0) && (count > 1)) { Tcl_DStringAppend(headPtr, "/", 1); } } + */ break; - case TCL_PLATFORM_UNIX: + case TCL_PLATFORM_UNIX: { /* * Add a separator if this is the first absolute element, or * a later relative element. - */ if ((*tail != '\0') && (((length > 0) && (strchr(separators, lastChar) == NULL)) || ((length == 0) && (count > 0)))) { Tcl_DStringAppend(headPtr, "/", 1); } + */ break; + } } /* * Look for the first matching pair of braces or the first * directory separator that is not inside a pair of braces. @@ -2535,21 +2539,21 @@ */ if (*p == '\0') { ret = Tcl_FSMatchInDirectory(interp, Tcl_GetObjResult(interp), head, tail, types); } else { - Tcl_Obj* resultPtr; - /* * We do the recursion ourselves. This makes implementing * Tcl_FSMatchInDirectory for each filesystem much easier. */ Tcl_GlobTypeData dirOnly = { TCL_GLOB_TYPE_DIR, 0, NULL, NULL }; char save = *p; - - *p = '\0'; + Tcl_Obj *resultPtr; + resultPtr = Tcl_NewListObj(0, NULL); + Tcl_IncrRefCount(resultPtr); + *p = '\0'; ret = Tcl_FSMatchInDirectory(interp, resultPtr, head, tail, &dirOnly); *p = save; if (ret == TCL_OK) { int resLength; @@ -2562,11 +2566,11 @@ Tcl_ListObjIndex(interp, resultPtr, i, &elt); Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, Tcl_GetString(elt), -1); if(tclPlatform == TCL_PLATFORM_MAC) { Tcl_DStringAppend(&ds, ":",1); - } else { + } else { Tcl_DStringAppend(&ds, "/",1); } ret = TclDoGlob(interp, separators, &ds, p+1, types); Tcl_DStringFree(&ds); if (ret != TCL_OK) { @@ -2607,15 +2611,26 @@ } case TCL_PLATFORM_WINDOWS: { if (Tcl_DStringLength(headPtr) == 0) { if (((*name == '\\') && (name[1] == '/' || name[1] == '\\')) || (*name == '/')) { - Tcl_DStringAppend(headPtr, "\\", 1); + Tcl_DStringAppend(headPtr, "/", 1); } else { Tcl_DStringAppend(headPtr, ".", 1); } } +#if defined(__CYGWIN__) && defined(__WIN32__) + { + extern int cygwin_conv_to_win32_path + _ANSI_ARGS_((CONST char *, char *)); + char winbuf[MAX_PATH+1]; + + cygwin_conv_to_win32_path(Tcl_DStringValue(headPtr), winbuf); + Tcl_DStringFree(headPtr); + Tcl_DStringAppend(headPtr, winbuf, -1); + } +#endif /* __CYGWIN__ && __WIN32__ */ /* * Convert to forward slashes. This is required to pass * some Tcl tests. We should probably remove the conversions * here and in tclWinFile.c, since they aren't needed since * the dropping of support for Win32s. Index: generic/tclGet.c ================================================================== --- generic/tclGet.c +++ generic/tclGet.c @@ -9,11 +9,11 @@ * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclGet.c,v 1.8 2002/11/19 02:34:49 hobbs Exp $ + * RCS: @(#) $Id: tclGet.c,v 1.8.2.1 2005/04/20 16:06:17 dgp Exp $ */ #include "tclInt.h" #include "tclPort.h" #include "tclMath.h" @@ -90,11 +90,15 @@ * The second test below is needed on platforms where "long" is * larger than "int" to detect values that fit in a long but not in * an int. */ - if ((errno == ERANGE) || (((long)(int) i) != i)) { + if ((errno == ERANGE) +#if (LONG_MAX > INT_MAX) + || (i > UINT_MAX) || (i < -(long)UINT_MAX) +#endif + ) { if (interp != (Tcl_Interp *) NULL) { Tcl_SetResult(interp, "integer value too large to represent", TCL_STATIC); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", Tcl_GetStringResult(interp), (char *) NULL); Index: generic/tclGetDate.y ================================================================== --- generic/tclGetDate.y +++ generic/tclGetDate.y @@ -9,11 +9,11 @@ * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclGetDate.y,v 1.18 2001/10/18 20:20:28 hobbs Exp $ + * RCS: @(#) $Id: tclGetDate.y,v 1.18.4.2 2005/11/04 20:15:09 kennykb Exp $ */ %{ /* * tclDate.c -- @@ -551,10 +551,13 @@ { "wast", tZONE, -HOUR( 7) }, /* West Australian Standard */ { "wadt", tDAYZONE, -HOUR( 7) }, /* West Australian Daylight */ { "jt", tZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */ { "cct", tZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */ { "jst", tZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */ + { "jdt", tDAYZONE, -HOUR( 9) }, /* Japan Daylight */ + { "kst", tZONE, -HOUR( 9) }, /* Korea Standard */ + { "kdt", tDAYZONE, -HOUR( 9) }, /* Korea Daylight */ { "cast", tZONE, -HOUR(19/2) }, /* Central Australian Standard */ { "cadt", tDAYZONE, -HOUR(19/2) }, /* Central Australian Daylight */ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ @@ -1049,24 +1052,24 @@ */ int TclGetDate(p, now, zone, timePtr) char *p; - unsigned long now; + Tcl_WideInt now; long zone; - unsigned long *timePtr; + Tcl_WideInt *timePtr; { struct tm *tm; time_t Start; time_t Time; time_t tod; int thisyear; yyInput = p; /* now has to be cast to a time_t for 64bit compliance */ - Start = now; - tm = TclpGetDate((TclpTime_t) &Start, 0); + Start = (time_t) now; + tm = TclpGetDate((TclpTime_t) &Start, (zone == -50000)); thisyear = tm->tm_year + TM_YEAR_BASE; yyYear = thisyear; yyMonth = tm->tm_mon + 1; yyDay = tm->tm_mday; yyTimezone = zone; @@ -1121,11 +1124,11 @@ if (Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, yyMeridian, yyDSTmode, &Start) < 0) { return -1; } } else { - Start = now; + Start = (time_t) now; if (!yyHaveRel) { Start -= ((tm->tm_hour * 60L * 60L) + tm->tm_min * 60L) + tm->tm_sec; } } Index: generic/tclHash.c ================================================================== --- generic/tclHash.c +++ generic/tclHash.c @@ -8,11 +8,11 @@ * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclHash.c,v 1.12 2002/11/12 02:23:18 hobbs Exp $ + * RCS: @(#) $Id: tclHash.c,v 1.12.2.1 2004/11/11 01:18:07 das Exp $ */ #include "tclInt.h" /* @@ -314,18 +314,19 @@ /* * Search all of the entries in the appropriate bucket. */ if (typePtr->compareKeysProc) { + Tcl_CompareHashKeysProc *compareKeysProc = typePtr->compareKeysProc; for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH if (hash != (unsigned int) hPtr->hash) { continue; } #endif - if (typePtr->compareKeysProc ((VOID *) key, hPtr)) { + if (compareKeysProc ((VOID *) key, hPtr)) { return hPtr; } } } else { for (hPtr = tablePtr->buckets[index]; hPtr != NULL; @@ -412,18 +413,19 @@ /* * Search all of the entries in the appropriate bucket. */ if (typePtr->compareKeysProc) { + Tcl_CompareHashKeysProc *compareKeysProc = typePtr->compareKeysProc; for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH if (hash != (unsigned int) hPtr->hash) { continue; } #endif - if (typePtr->compareKeysProc ((VOID *) key, hPtr)) { + if (compareKeysProc ((VOID *) key, hPtr)) { *newPtr = 0; return hPtr; } } } else { @@ -701,17 +703,18 @@ * progress through the table. Must * have been initialized by calling * Tcl_FirstHashEntry. */ { Tcl_HashEntry *hPtr; + Tcl_HashTable *tablePtr = searchPtr->tablePtr; while (searchPtr->nextEntryPtr == NULL) { - if (searchPtr->nextIndex >= searchPtr->tablePtr->numBuckets) { + if (searchPtr->nextIndex >= tablePtr->numBuckets) { return NULL; } searchPtr->nextEntryPtr = - searchPtr->tablePtr->buckets[searchPtr->nextIndex]; + tablePtr->buckets[searchPtr->nextIndex]; searchPtr->nextIndex++; } hPtr = searchPtr->nextEntryPtr; searchPtr->nextEntryPtr = hPtr->nextPtr; return hPtr; Index: generic/tclIO.c ================================================================== --- generic/tclIO.c +++ generic/tclIO.c @@ -8,17 +8,21 @@ * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIO.c,v 1.61 2003/02/19 01:04:57 hobbs Exp $ + * RCS: @(#) $Id: tclIO.c,v 1.61.2.23 2007/05/24 19:31:55 dgp Exp $ */ #include "tclInt.h" #include "tclPort.h" #include "tclIO.h" #include + +#ifndef TCL_INHERIT_STD_CHANNELS +#define TCL_INHERIT_STD_CHANNELS 1 +#endif /* * All static variables used in this file are collected into a single * instance of the following structure. For multi-threaded implementations, @@ -183,11 +187,11 @@ /* *------------------------------------------------------------------------- * * TclFinalizeIOSubsystem -- * - * Releases all resources used by this subsystem on a per-process + * Releases all resources used by this subsystem on a per-thread * basis. Closes all extant channels that have not already been * closed because they were not owned by any interp. * * Results: * None. @@ -198,84 +202,110 @@ *------------------------------------------------------------------------- */ /* ARGSUSED */ void -TclFinalizeIOSubsystem() -{ - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - Channel *chanPtr; /* Iterates over open channels. */ - ChannelState *nextCSPtr; /* Iterates over open channels. */ - ChannelState *statePtr; /* state of channel stack */ - - for (statePtr = tsdPtr->firstCSPtr; statePtr != (ChannelState *) NULL; - statePtr = nextCSPtr) { - chanPtr = statePtr->topChanPtr; - nextCSPtr = statePtr->nextCSPtr; - - /* - * Set the channel back into blocking mode to ensure that we wait - * for all data to flush out. - */ - - (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, - "-blocking", "on"); - - if ((chanPtr == (Channel *) tsdPtr->stdinChannel) || - (chanPtr == (Channel *) tsdPtr->stdoutChannel) || - (chanPtr == (Channel *) tsdPtr->stderrChannel)) { - - /* - * Decrement the refcount which was earlier artificially bumped - * up to keep the channel from being closed. - */ - - statePtr->refCount--; - } - - if (statePtr->refCount <= 0) { - - /* - * Close it only if the refcount indicates that the channel is not - * referenced from any interpreter. If it is, that interpreter will - * close the channel when it gets destroyed. - */ - - (void) Tcl_Close((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); - - } else { - - /* - * The refcount is greater than zero, so flush the channel. - */ - - Tcl_Flush((Tcl_Channel) chanPtr); - - /* - * Call the device driver to actually close the underlying - * device for this channel. - */ - - if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { - (chanPtr->typePtr->closeProc)(chanPtr->instanceData, - (Tcl_Interp *) NULL); - } else { - (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, - (Tcl_Interp *) NULL, 0); - } - - /* - * Finally, we clean up the fields in the channel data structure - * since all of them have been deleted already. We mark the - * channel with CHANNEL_DEAD to prevent any further IO operations - * on it. - */ - - chanPtr->instanceData = (ClientData) NULL; - statePtr->flags |= CHANNEL_DEAD; - } - } +TclFinalizeIOSubsystem(void) +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + Channel *chanPtr = NULL; /* Iterates over open channels. */ + ChannelState *statePtr; /* State of channel stack */ + int active = 1; /* Flag == 1 while there's still work to do */ + + /* + * Walk all channel state structures known to this thread and + * close corresponding channels. + */ + + while (active) { + + /* + * Iterate through the open channel list, and find the first + * channel that isn't dead. We start from the head of the list + * each time, because the close action on one channel can close + * others. + */ + + active = 0; + for (statePtr = tsdPtr->firstCSPtr; + statePtr != NULL; + statePtr = statePtr->nextCSPtr) { + chanPtr = statePtr->topChanPtr; + if (!(statePtr->flags & CHANNEL_DEAD)) { + active = 1; + break; + } + } + + /* + * We've found a live channel. Close it. + */ + + if (active) { + + /* + * Set the channel back into blocking mode to ensure that we + * wait for all data to flush out. + */ + + (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, + "-blocking", "on"); + + if ((chanPtr == (Channel *) tsdPtr->stdinChannel) || + (chanPtr == (Channel *) tsdPtr->stdoutChannel) || + (chanPtr == (Channel *) tsdPtr->stderrChannel)) { + /* + * Decrement the refcount which was earlier artificially + * bumped up to keep the channel from being closed. + */ + + statePtr->refCount--; + } + + if (statePtr->refCount <= 0) { + /* + * Close it only if the refcount indicates that the channel + * is not referenced from any interpreter. If it is, that + * interpreter will close the channel when it gets destroyed. + */ + + (void) Tcl_Close(NULL, (Tcl_Channel) chanPtr); + } else { + /* + * The refcount is greater than zero, so flush the channel. + */ + + Tcl_Flush((Tcl_Channel) chanPtr); + + /* + * Call the device driver to actually close the underlying + * device for this channel. + */ + + if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { + (chanPtr->typePtr->closeProc)(chanPtr->instanceData, NULL); + } else { + (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, + NULL, 0); + } + + /* + * Finally, we clean up the fields in the channel data + * structure since all of them have been deleted already. + * We mark the channel with CHANNEL_DEAD to prevent any + * further IO operations + * on it. + */ + + chanPtr->instanceData = NULL; + statePtr->flags |= CHANNEL_DEAD; + } + } + } + + TclpFinalizeSockets(); + TclpFinalizePipes(); } /* *---------------------------------------------------------------------- @@ -770,10 +800,11 @@ panic("Tcl_RegisterChannel: duplicate channel names"); } Tcl_SetHashValue(hPtr, (ClientData) chanPtr); } + statePtr->refCount++; } /* *---------------------------------------------------------------------- @@ -806,10 +837,21 @@ Tcl_Interp *interp; /* Interpreter in which channel is defined. */ Tcl_Channel chan; /* Channel to delete. */ { ChannelState *statePtr; /* State of the real channel. */ + statePtr = ((Channel *) chan)->state->bottomChanPtr->state; + + if (statePtr->flags & CHANNEL_INCLOSE) { + if (interp != (Tcl_Interp*) NULL) { + Tcl_AppendResult(interp, + "Illegal recursive call to close through close-handler of channel", + (char *) NULL); + } + return TCL_ERROR; + } + if (DetachChannel(interp, chan) != TCL_OK) { return TCL_OK; } statePtr = ((Channel *) chan)->state->bottomChanPtr->state; @@ -1194,28 +1236,29 @@ * Link the channel into the list of all channels; create an on-exit * handler if there is not one already, to close off all the channels * in the list on exit. * * JH: Could call Tcl_SpliceChannel, but need to avoid NULL check. + * + * TIP #218. + * AK: Just initialize the field to NULL before invoking Tcl_SpliceChannel + * We need Tcl_SpliceChannel, for the threadAction calls. + * There is no real reason to duplicate all of this. + * NOTE: All drivers using thread actions now have to perform their TSD + * manipulation only in their thread action proc. Doing it when + * creating their instance structures will collide with the thread + * action activity and lead to damaged lists. */ - statePtr->nextCSPtr = tsdPtr->firstCSPtr; - tsdPtr->firstCSPtr = statePtr; - - /* - * TIP #10. Mark the current thread as the one managing the new - * channel. Note: 'Tcl_GetCurrentThread' returns sensible - * values even for a non-threaded core. - */ - - statePtr->managingThread = Tcl_GetCurrentThread (); + statePtr->nextCSPtr = (ChannelState *) NULL; + Tcl_SpliceChannel ((Tcl_Channel) chanPtr); /* * Install this channel in the first empty standard channel slot, if * the channel was previously closed explicitly. */ - +#if TCL_INHERIT_STD_CHANNELS if ((tsdPtr->stdinChannel == NULL) && (tsdPtr->stdinInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDIN); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } else if ((tsdPtr->stdoutChannel == NULL) && @@ -1224,11 +1267,12 @@ Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } else if ((tsdPtr->stderrChannel == NULL) && (tsdPtr->stderrInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDERR); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); - } + } +#endif return (Tcl_Channel) chanPtr; } /* *---------------------------------------------------------------------- @@ -1282,17 +1326,19 @@ */ statePtr = (ChannelState *) tsdPtr->firstCSPtr; prevChanPtr = ((Channel *) prevChan)->state->topChanPtr; - while (statePtr->topChanPtr != prevChanPtr) { + while ((statePtr != NULL) && (statePtr->topChanPtr != prevChanPtr)) { statePtr = statePtr->nextCSPtr; } if (statePtr == NULL) { - Tcl_AppendResult(interp, "couldn't find state for channel \"", - Tcl_GetChannelName(prevChan), "\"", (char *) NULL); + if (interp) { + Tcl_AppendResult(interp, "couldn't find state for channel \"", + Tcl_GetChannelName(prevChan), "\"", (char *) NULL); + } return (Tcl_Channel) NULL; } /* * Here we check if the given "mask" matches the "flags" @@ -1306,13 +1352,15 @@ * RW| | + | + | + | superceded one ! * --+---+---+---+----+ */ if ((mask & (statePtr->flags & (TCL_READABLE | TCL_WRITABLE))) == 0) { - Tcl_AppendResult(interp, - "reading and writing both disallowed for channel \"", - Tcl_GetChannelName(prevChan), "\"", (char *) NULL); + if (interp) { + Tcl_AppendResult(interp, + "reading and writing both disallowed for channel \"", + Tcl_GetChannelName(prevChan), "\"", (char *) NULL); + } return (Tcl_Channel) NULL; } /* * Flush the buffers. This ensures that any data still in them @@ -1327,12 +1375,14 @@ csPtr = statePtr->csPtr; statePtr->csPtr = (CopyState*) NULL; if (Tcl_Flush((Tcl_Channel) prevChanPtr) != TCL_OK) { statePtr->csPtr = csPtr; - Tcl_AppendResult(interp, "could not flush channel \"", - Tcl_GetChannelName(prevChan), "\"", (char *) NULL); + if (interp) { + Tcl_AppendResult(interp, "could not flush channel \"", + Tcl_GetChannelName(prevChan), "\"", (char *) NULL); + } return (Tcl_Channel) NULL; } statePtr->csPtr = csPtr; } @@ -1454,13 +1504,15 @@ csPtr = statePtr->csPtr; statePtr->csPtr = (CopyState*) NULL; if (Tcl_Flush((Tcl_Channel) chanPtr) != TCL_OK) { statePtr->csPtr = csPtr; - Tcl_AppendResult(interp, "could not flush channel \"", - Tcl_GetChannelName((Tcl_Channel) chanPtr), "\"", - (char *) NULL); + if (interp) { + Tcl_AppendResult(interp, "could not flush channel \"", + Tcl_GetChannelName((Tcl_Channel) chanPtr), "\"", + (char *) NULL); + } return TCL_ERROR; } statePtr->csPtr = csPtr; } @@ -2364,11 +2416,11 @@ * * Side effects: * Resets the field 'nextCSPtr' of the specified channel state to NULL. * * NOTE: - * The channel to splice out of the list must not be referenced + * The channel to cut out of the list must not be referenced * in any interpreter. This is something this procedure cannot * check (despite the refcount) because the caller usually wants * fiddle with the channel (like transfering it to a different * thread) and thus keeps the refcount artifically high to prevent * its destruction. @@ -2386,10 +2438,11 @@ ChannelState *prevCSPtr; /* Preceding channel state in list of * all states - used to splice a * channel out of the list on close. */ ChannelState *statePtr = ((Channel *) chan)->state; /* state of the channel stack. */ + Tcl_DriverThreadActionProc *threadActionProc; /* * Remove this channel from of the list of all channels * (in the current thread). */ @@ -2408,11 +2461,16 @@ prevCSPtr->nextCSPtr = statePtr->nextCSPtr; } statePtr->nextCSPtr = (ChannelState *) NULL; - TclpCutFileChannel(chan); + /* TIP #218, Channel Thread Actions */ + threadActionProc = Tcl_ChannelThreadActionProc (Tcl_GetChannelType (chan)); + if (threadActionProc != NULL) { + (*threadActionProc) (Tcl_GetChannelInstanceData(chan), + TCL_CHANNEL_THREAD_REMOVE); + } } /* *---------------------------------------------------------------------- * @@ -2427,11 +2485,11 @@ * * Side effects: * Nothing. * * NOTE: - * The channel to add to the list must not be referenced in any + * The channel to splice into the list must not be referenced in any * interpreter. This is something this procedure cannot check * (despite the refcount) because the caller usually wants figgle * with the channel (like transfering it to a different thread) * and thus keeps the refcount artifically high to prevent its * destruction. @@ -2445,10 +2503,11 @@ * not be referenced in any * interpreter. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); ChannelState *statePtr = ((Channel *) chan)->state; + Tcl_DriverThreadActionProc *threadActionProc; if (statePtr->nextCSPtr != (ChannelState *) NULL) { panic("Tcl_SpliceChannel: trying to add channel used in different list"); } @@ -2461,11 +2520,16 @@ * values even for a non-threaded core. */ statePtr->managingThread = Tcl_GetCurrentThread (); - TclpSpliceFileChannel(chan); + /* TIP #218, Channel Thread Actions */ + threadActionProc = Tcl_ChannelThreadActionProc (Tcl_GetChannelType (chan)); + if (threadActionProc != NULL) { + (*threadActionProc) (Tcl_GetChannelInstanceData(chan), + TCL_CHANNEL_THREAD_INSERT); + } } /* *---------------------------------------------------------------------- * @@ -2525,10 +2589,20 @@ chanPtr = statePtr->topChanPtr; if (statePtr->refCount > 0) { panic("called Tcl_Close on channel with refCount > 0"); } + + if (statePtr->flags & CHANNEL_INCLOSE) { + if (interp) { + Tcl_AppendResult(interp, + "Illegal recursive call to close through close-handler of channel", + (char *) NULL); + } + return TCL_ERROR; + } + statePtr->flags |= CHANNEL_INCLOSE; /* * When the channel has an escape sequence driven encoding such as * iso2022, the terminated escape sequence must write to the buffer. */ @@ -2548,10 +2622,12 @@ cbPtr = statePtr->closeCbPtr; statePtr->closeCbPtr = cbPtr->nextPtr; (cbPtr->proc) (cbPtr->clientData); ckfree((char *) cbPtr); } + + statePtr->flags &= ~CHANNEL_INCLOSE; /* * Ensure that the last output buffer will be flushed. */ @@ -2620,10 +2696,16 @@ chanPtr = (Channel *) channel; statePtr = chanPtr->state; chanPtr = statePtr->topChanPtr; + /* + * Cancel any outstanding timer. + */ + + Tcl_DeleteTimerHandler(statePtr->timer); + /* * Remove any references to channel handlers for this channel that * may be about to be invoked. */ @@ -2659,13 +2741,13 @@ * Must set the interest mask now to 0, otherwise infinite loops * will occur if Tcl_DoOneEvent is called before the channel is * finally deleted in FlushChannel. This can happen if the channel * has a background flush active. */ - + statePtr->interestMask = 0; - + /* * Remove any EventScript records for this channel. */ for (ePtr = statePtr->scriptRecordPtr; @@ -4223,15 +4305,27 @@ goto done; } statePtr->flags &= (~(CHANNEL_BLOCKED)); } - if ((statePtr->flags & CHANNEL_TIMER_FEV) && - (statePtr->flags & CHANNEL_NONBLOCKING)) { +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING + /* [SF Tcl Bug 943274]. Better emulation of non-blocking + * channels for channels without BlockModeProc, by keeping + * track of true fileevents generated by the OS == Data + * waiting and reading if and only if we are sure to have + * data. + */ + + if ((statePtr->flags & CHANNEL_NONBLOCKING) && + (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) && + !(statePtr->flags & CHANNEL_HAS_MORE_DATA)) { + + /* We bypass the driver, it would block, as no data is available */ nread = -1; result = EWOULDBLOCK; } else { +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ /* * Now go to the driver to get as much as is possible to * fill the remaining request. Do all the error handling * by ourselves. The code was stolen from 'GetInput' and * slightly adapted (different return value here). @@ -4239,11 +4333,13 @@ * The case of 'bytesToRead == 0' at this point cannot happen. */ nread = (chanPtr->typePtr->inputProc)(chanPtr->instanceData, bufPtr + copied, bytesToRead - copied, &result); +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING } +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ if (nread > 0) { /* * If we get a short read, signal up that we may be * BLOCKED. We should avoid calling the driver because * on some platforms we will block in the low level @@ -4252,10 +4348,18 @@ */ if (nread < (bytesToRead - copied)) { statePtr->flags |= CHANNEL_BLOCKED; } + +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING + if (nread <= (bytesToRead - copied)) { + /* [SF Tcl Bug 943274] We have read the available + * data, clear flag */ + statePtr->flags &= ~CHANNEL_HAS_MORE_DATA; + } +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ } else if (nread == 0) { statePtr->flags |= CHANNEL_EOF; statePtr->inputEncodingFlags |= TCL_ENCODING_END; } else if (nread < 0) { if ((result == EWOULDBLOCK) || (result == EAGAIN)) { @@ -4376,11 +4480,11 @@ ChannelState *statePtr = chanPtr->state; /* state info for channel */ ChannelBuffer *bufPtr; int offset, factor, copied, copiedNow, result; Tcl_Encoding encoding; #define UTF_EXPANSION_FACTOR 1024 - + /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; @@ -4631,16 +4735,17 @@ int toRead, factor, offset, spaceLeft, length, srcLen, dstNeeded; int srcRead, dstWrote, numChars, dstRead; ChannelBuffer *bufPtr; char *src, *dst; Tcl_EncodingState oldState; + int encEndFlagSuppressed = 0; factor = *factorPtr; offset = *offsetPtr; bufPtr = statePtr->inQueueHead; - src = bufPtr->buf + bufPtr->nextRemoved; + src = bufPtr->buf + bufPtr->nextRemoved; srcLen = bufPtr->nextAdded - bufPtr->nextRemoved; toRead = charsToRead; if ((unsigned)toRead > (unsigned)srcLen) { toRead = srcLen; @@ -4679,10 +4784,58 @@ */ dstNeeded = spaceLeft; } dst = objPtr->bytes + offset; + + /* + * SF Tcl Bug 1462248 + * The cause of the crash reported in the referenced bug is this: + * + * - ReadChars, called with a single buffer, with a incomplete + * multi-byte character at the end (only the first byte of it). + * - Encoding translation fails, asks for more data + * - Data is read, and eof is reached, TCL_ENCODING_END (TEE) is set. + * - ReadChar is called again, converts the first buffer, but due + * to TEE it does not check for incomplete multi-byte data, and the + * character just after the end of the first buffer is a valid + * completion of the multi-byte header in the actual buffer. The + * conversion reads more characters from the buffer then present. + * This causes nextRemoved to overshoot nextAdded and the next + * reads compute a negative srcLen, cause further translations to + * fail, causing copying of data into the next buffer using bad + * arguments, causing the mecpy for to eventually fail. + * + * In the end it is a memory access bug spiraling out of control + * if the conditions are _just so_. And ultimate cause is that TEE + * is given to a conversion where it should not. TEE signals that + * this is the last buffer. Except in our case it is not. + * + * My solution is to suppress TEE if the first buffer is not the + * last. We will eventually need it given that EOF has been + * reached, but not right now. This is what the new flag + * "endEncSuppressFlag" is for. + * + * The bug in 'Tcl_Utf2UtfProc' where it read from memory behind + * the actual buffer has been fixed as well, and fixes the problem + * with the crash too, but this would still allow the generic + * layer to accidentially break a multi-byte sequence if the + * conditions are just right, because again the ExternalToUtf + * would be successful where it should not. + */ + + if ((statePtr->inputEncodingFlags & TCL_ENCODING_END) && + (bufPtr->nextPtr != NULL)) { + + /* TEE is set for a buffer which is not the last. Squash it + * for now, and restore it later, before yielding control to + * our caller. + */ + + statePtr->inputEncodingFlags &= ~TCL_ENCODING_END; + encEndFlagSuppressed = 1; + } oldState = statePtr->inputEncodingState; if (statePtr->flags & INPUT_NEED_NL) { /* * We want a '\n' because the last character we saw was '\r'. @@ -4705,16 +4858,25 @@ *dst = '\r'; } statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; *offsetPtr += 1; + + if (encEndFlagSuppressed) { + statePtr->inputEncodingFlags |= TCL_ENCODING_END; + } return 1; } Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, dstNeeded + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); + + if (encEndFlagSuppressed) { + statePtr->inputEncodingFlags |= TCL_ENCODING_END; + } + if (srcRead == 0) { /* * Not enough bytes in src buffer to make a complete char. Copy * the bytes to the next buffer to make a new contiguous string, * then tell the caller to fill the buffer with more bytes. @@ -4741,10 +4903,27 @@ statePtr->flags |= CHANNEL_NEED_MORE_DATA; } return -1; } + + /* Space is made at the beginning of the buffer to copy the + * previous unused bytes there. Check first if the buffer we + * are using actually has enough space at its beginning for + * the data we are copying. Because if not we will write over the + * buffer management information, especially the 'nextPtr'. + * + * Note that the BUFFER_PADDING (See AllocChannelBuffer) is + * used to prevent exactly this situation. I.e. it should + * never happen. Therefore it is ok to panic should it happen + * despite the precautions. + */ + + if (nextPtr->nextRemoved - srcLen < 0) { + Tcl_Panic ("Buffer Underflow, BUFFER_PADDING not enough"); + } + nextPtr->nextRemoved -= srcLen; memcpy((VOID *) (nextPtr->buf + nextPtr->nextRemoved), (VOID *) src, (size_t) srcLen); RecycleBuffer(statePtr, bufPtr, 0); statePtr->inQueueHead = nextPtr; @@ -5039,13 +5218,12 @@ } statePtr->flags &= (~(CHANNEL_BLOCKED | CHANNEL_EOF)); bufPtr = AllocChannelBuffer(len); for (i = 0; i < len; i++) { - bufPtr->buf[i] = str[i]; + bufPtr->buf[bufPtr->nextAdded++] = str[i]; } - bufPtr->nextAdded += len; if (statePtr->inQueueHead == (ChannelBuffer *) NULL) { bufPtr->nextPtr = (ChannelBuffer *) NULL; statePtr->inQueueHead = bufPtr; statePtr->inQueueTail = bufPtr; @@ -5293,18 +5471,33 @@ if (statePtr->flags & CHANNEL_EOF) { return 0; } - if ((statePtr->flags & CHANNEL_TIMER_FEV) && - (statePtr->flags & CHANNEL_NONBLOCKING)) { +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING + /* [SF Tcl Bug 943274]. Better emulation of non-blocking channels + * for channels without BlockModeProc, by keeping track of true + * fileevents generated by the OS == Data waiting and reading if + * and only if we are sure to have data. + */ + + if ((statePtr->flags & CHANNEL_NONBLOCKING) && + (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) && + !(statePtr->flags & CHANNEL_HAS_MORE_DATA)) { + + /* Bypass the driver, it would block, as no data is available */ nread = -1; result = EWOULDBLOCK; } else { +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ + nread = (chanPtr->typePtr->inputProc)(chanPtr->instanceData, bufPtr->buf + bufPtr->nextAdded, toRead, &result); + +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING } +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ if (nread > 0) { bufPtr->nextAdded += nread; /* @@ -5315,10 +5508,19 @@ */ if (nread < toRead) { statePtr->flags |= CHANNEL_BLOCKED; } + +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING + if (nread <= toRead) { + /* [SF Tcl Bug 943274] We have read the available data, + * clear flag */ + statePtr->flags &= ~CHANNEL_HAS_MORE_DATA; + } +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ + } else if (nread == 0) { statePtr->flags |= CHANNEL_EOF; statePtr->inputEncodingFlags |= TCL_ENCODING_END; } else if (nread < 0) { if ((result == EWOULDBLOCK) || (result == EAGAIN)) { @@ -5475,19 +5677,19 @@ chanPtr->typePtr->wideSeekProc != NULL) { curPos = (chanPtr->typePtr->wideSeekProc) (chanPtr->instanceData, offset, mode, &result); } else if (offset < Tcl_LongAsWide(LONG_MIN) || offset > Tcl_LongAsWide(LONG_MAX)) { - Tcl_SetErrno(EOVERFLOW); + result = EOVERFLOW; curPos = Tcl_LongAsWide(-1); } else { curPos = Tcl_LongAsWide((chanPtr->typePtr->seekProc) ( chanPtr->instanceData, Tcl_WideAsLong(offset), mode, &result)); - if (curPos == Tcl_LongAsWide(-1)) { - Tcl_SetErrno(result); - } + } + if (curPos == Tcl_LongAsWide(-1)) { + Tcl_SetErrno(result); } } /* * Restore to nonblocking mode if that was the previous behavior. @@ -5916,11 +6118,11 @@ *---------------------------------------------------------------------- * * Tcl_SetChannelBufferSize -- * * Sets the size of buffers to allocate to store input or output - * in the channel. The size must be between 10 bytes and 1 MByte. + * in the channel. The size must be between 1 byte and 1 MByte. * * Results: * None. * * Side effects: @@ -5936,15 +6138,15 @@ int sz; /* The size to set. */ { ChannelState *statePtr; /* State of real channel structure. */ /* - * If the buffer size is smaller than 10 bytes or larger than one MByte, + * If the buffer size is smaller than 1 byte or larger than one MByte, * do not accept the requested size and leave the current buffer size. */ - if (sz < 10) { + if (sz < 1) { return; } if (sz > (1024 * 1024)) { return; } @@ -6391,14 +6593,15 @@ } } return TCL_OK; } else if ((len > 7) && (optionName[1] == 'b') && (strncmp(optionName, "-buffersize", len) == 0)) { - statePtr->bufSize = atoi(newValue); /* INTL: "C", UTF safe. */ - if ((statePtr->bufSize < 10) || (statePtr->bufSize > (1024 * 1024))) { - statePtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE; - } + int newBufferSize; + if (Tcl_GetInt(interp, newValue, &newBufferSize) == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_SetChannelBufferSize(chan, newBufferSize); } else if ((len > 2) && (optionName[1] == 'e') && (strncmp(optionName, "-encoding", len) == 0)) { Tcl_Encoding encoding; if ((newValue[0] == '\0') || (strcmp(newValue, "binary") == 0)) { @@ -6458,10 +6661,19 @@ } } if (argv != NULL) { ckfree((char *) argv); } + + /* + * [SF Tcl Bug 930851] Reset EOF and BLOCKED flags. Changing + * the character which signals eof can transform a current eof + * condition into a 'go ahead'. Ditto for blocked. + */ + + statePtr->flags &= (~(CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED)); + return TCL_OK; } else if ((len > 1) && (optionName[1] == 't') && (strncmp(optionName, "-translation", len) == 0)) { CONST char *readMode, *writeMode; @@ -6698,10 +6910,26 @@ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); NextChannelHandler nh; Channel* upChanPtr; Tcl_ChannelType* upTypePtr; +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING + /* [SF Tcl Bug 943274] + * For a non-blocking channel without blockmodeproc we keep track + * of actual input coming from the OS so that we can do a credible + * imitation of non-blocking behaviour. + */ + + if ((mask & TCL_READABLE) && + (statePtr->flags & CHANNEL_NONBLOCKING) && + (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) && + !(statePtr->flags & CHANNEL_TIMER_FEV)) { + + statePtr->flags |= CHANNEL_HAS_MORE_DATA; + } +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ + /* * In contrast to the other API functions this procedure walks towards * the top of a stack and not down from it. * * The channel calling this procedure is the one who generated the event, @@ -6848,10 +7076,53 @@ if (!(statePtr->flags & CHANNEL_NEED_MORE_DATA) && (statePtr->inQueueHead != (ChannelBuffer *) NULL) && (statePtr->inQueueHead->nextRemoved < statePtr->inQueueHead->nextAdded)) { mask &= ~TCL_READABLE; + + /* + * Andreas Kupries, April 11, 2003 + * + * Some operating systems (Solaris 2.6 and higher (but not + * Solaris 2.5, go figure)) generate READABLE and + * EXCEPTION events when select()'ing [*] on a plain file, + * even if EOF was not yet reached. This is a problem in + * the following situation: + * + * - An extension asks to get both READABLE and EXCEPTION + * events. + * - It reads data into a buffer smaller than the buffer + * used by Tcl itself. + * - It does not process all events in the event queue, but + * only only one, at least in some situations. + * + * In that case we can get into a situation where + * + * - Tcl drops READABLE here, because it has data in its own + * buffers waiting to be read by the extension. + * - A READABLE event is syntesized via timer. + * - The OS still reports the EXCEPTION condition on the file. + * - And the extension gets the EXCPTION event first, and + * handles this as EOF. + * + * End result ==> Premature end of reading from a file. + * + * The concrete example is 'Expect', and its [expect] + * command (and at the C-level, deep in the bowels of + * Expect, 'exp_get_next_event'. See marker 'SunOS' for + * commentary in that function too). + * + * [*] As the Tcl notifier does. See also for marker + * 'SunOS' in file 'exp_event.c' of Expect. + * + * Our solution here is to drop the interest in the + * EXCEPTION events too. This compiles on all platforms, + * and also passes the testsuite on all of them. + */ + + mask &= ~TCL_EXCEPTION; + if (!statePtr->timer) { statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc, (ClientData) chanPtr); } } @@ -6894,10 +7165,11 @@ */ statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc, (ClientData) chanPtr); +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING /* Set the TIMER flag to notify the higher levels that the * driver might have no data for us. We do this only if we are * in non-blocking mode and the driver has no BlockModeProc * because only then we really don't know if the driver will * block or not. A similar test is done in "PeekAhead". @@ -6905,14 +7177,19 @@ if ((statePtr->flags & CHANNEL_NONBLOCKING) && (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL)) { statePtr->flags |= CHANNEL_TIMER_FEV; } +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ + Tcl_Preserve((ClientData) statePtr); Tcl_NotifyChannel((Tcl_Channel)chanPtr, TCL_READABLE); +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING statePtr->flags &= ~CHANNEL_TIMER_FEV; +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ + Tcl_Release((ClientData) statePtr); } else { statePtr->timer = NULL; UpdateInterest(chanPtr); } @@ -7403,17 +7680,21 @@ inStatePtr = inPtr->state; outStatePtr = outPtr->state; if (inStatePtr->csPtr) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", - Tcl_GetChannelName(inChan), "\" is busy", NULL); + if (interp) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", + Tcl_GetChannelName(inChan), "\" is busy", NULL); + } return TCL_ERROR; } if (outStatePtr->csPtr) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", - Tcl_GetChannelName(outChan), "\" is busy", NULL); + if (interp) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", + Tcl_GetChannelName(outChan), "\" is busy", NULL); + } return TCL_ERROR; } readFlags = inStatePtr->flags; writeFlags = outStatePtr->flags; @@ -7711,11 +7992,11 @@ * Make the callback or return the number of bytes transferred. * The local total is used because StopCopy frees csPtr. */ total = csPtr->total; - if (cmdPtr) { + if (cmdPtr && interp) { /* * Get a private copy of the command so we can mutate it * by adding arguments. Note that StopCopy frees our saved * reference to the original command obj. */ @@ -7735,16 +8016,18 @@ } Tcl_DecrRefCount(cmdPtr); Tcl_Release((ClientData) interp); } else { StopCopy(csPtr); - if (errObj) { - Tcl_SetObjResult(interp, errObj); - result = TCL_ERROR; - } else { - Tcl_ResetResult(interp); - Tcl_SetIntObj(Tcl_GetObjResult(interp), total); + if (interp) { + if (errObj) { + Tcl_SetObjResult(interp, errObj); + result = TCL_ERROR; + } else { + Tcl_ResetResult(interp); + Tcl_SetIntObj(Tcl_GetObjResult(interp), total); + } } } return result; } @@ -8759,10 +9042,12 @@ { if (chanTypePtr->version == TCL_CHANNEL_VERSION_2) { return TCL_CHANNEL_VERSION_2; } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_3) { return TCL_CHANNEL_VERSION_3; + } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_4) { + return TCL_CHANNEL_VERSION_4; } else { /* * In wideSeekProc; } else { return NULL; } } + +/* + *---------------------------------------------------------------------- + * + * Tcl_ChannelThreadActionProc -- + * + * Return the Tcl_DriverThreadActionProc of the channel type. + * + * Results: + * A pointer to the proc. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_DriverThreadActionProc * +Tcl_ChannelThreadActionProc(chanTypePtr) + Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ +{ + if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_4)) { + return chanTypePtr->threadActionProc; + } else { + return NULL; + } +} + +#if 0 +/* For future debugging work, a simple function to print the flags of + * a channel in semi-readable form. + */ + +static int +DumpFlags (str, flags) + char* str; + int flags; +{ + char buf [20]; + int i = 0; + + if (flags & TCL_READABLE) {buf[i] = 'r';} else {buf [i]='_';}; i++; + if (flags & TCL_WRITABLE) {buf[i] = 'w';} else {buf [i]='_';}; i++; + if (flags & CHANNEL_NONBLOCKING) {buf[i] = 'n';} else {buf [i]='_';}; i++; + if (flags & CHANNEL_LINEBUFFERED) {buf[i] = 'l';} else {buf [i]='_';}; i++; + if (flags & CHANNEL_UNBUFFERED) {buf[i] = 'u';} else {buf [i]='_';}; i++; + if (flags & BUFFER_READY) {buf[i] = 'R';} else {buf [i]='_';}; i++; + if (flags & BG_FLUSH_SCHEDULED) {buf[i] = 'F';} else {buf [i]='_';}; i++; + if (flags & CHANNEL_CLOSED) {buf[i] = 'c';} else {buf [i]='_';}; i++; + if (flags & CHANNEL_EOF) {buf[i] = 'E';} else {buf [i]='_';}; i++; + if (flags & CHANNEL_STICKY_EOF) {buf[i] = 'S';} else {buf [i]='_';}; i++; + if (flags & CHANNEL_BLOCKED) {buf[i] = 'B';} else {buf [i]='_';}; i++; + if (flags & INPUT_SAW_CR) {buf[i] = '/';} else {buf [i]='_';}; i++; + if (flags & INPUT_NEED_NL) {buf[i] = '*';} else {buf [i]='_';}; i++; + if (flags & CHANNEL_DEAD) {buf[i] = 'D';} else {buf [i]='_';}; i++; + if (flags & CHANNEL_RAW_MODE) {buf[i] = 'R';} else {buf [i]='_';}; i++; +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING + if (flags & CHANNEL_TIMER_FEV) {buf[i] = 'T';} else {buf [i]='_';}; i++; + if (flags & CHANNEL_HAS_MORE_DATA) {buf[i] = 'H';} else {buf [i]='_';}; i++; +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ + if (flags & CHANNEL_INCLOSE) {buf[i] = 'x';} else {buf [i]='_';}; i++; + buf [i] ='\0'; + + fprintf (stderr,"%s: %s\n", str, buf); fflush(stderr); + return 0; +} +#endif Index: generic/tclIO.h ================================================================== --- generic/tclIO.h +++ generic/tclIO.h @@ -8,11 +8,11 @@ * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIO.h,v 1.5 2002/01/15 17:55:30 dgp Exp $ + * RCS: @(#) $Id: tclIO.h,v 1.5.4.2 2004/07/15 20:46:19 andreas_kupries Exp $ */ /* * Make sure that both EAGAIN and EWOULDBLOCK are defined. This does not * compile on systems where neither is defined. We want both defined so @@ -294,10 +294,11 @@ * When set, file events will not be * delivered for buffered data until * the state of the channel changes. */ #define CHANNEL_RAW_MODE (1<<16) /* When set, notes that the Raw API is * being used. */ +#ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING #define CHANNEL_TIMER_FEV (1<<17) /* When set the event we are * notified by is a fileevent * generated by a timer. We * don't know if the driver * has more data and should @@ -305,10 +306,34 @@ * the system needs more than * is in the buffers out read * routines will simulate a * short read (0 characters * read) */ +#define CHANNEL_HAS_MORE_DATA (1<<18) /* Set by NotifyChannel for a + * channel if and only if the + * channel is configured + * non-blocking, the driver + * for said channel has no + * blockmodeproc, and data has + * arrived for reading at the + * OS level). A GetInput will + * pass reading from the + * driver if the channel is + * non-blocking, without + * blockmode proc and the flag + * has not been set. A read + * will be performed if the + * flag is set. This will + * reset the flag as well. */ +#endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ + +#define CHANNEL_INCLOSE (1<<19) /* Channel is currently being + * closed. Its structures are + * still live and usable, but + * it may not be closed again + * from within the close handler. + */ /* * For each channel handler registered in a call to Tcl_CreateChannelHandler, * there is one record of the following type. All of records for a specific * channel are chained together in a singly linked list which is stored in Index: generic/tclIOCmd.c ================================================================== --- generic/tclIOCmd.c +++ generic/tclIOCmd.c @@ -6,11 +6,11 @@ * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIOCmd.c,v 1.15 2002/02/15 14:28:49 dkf Exp $ + * RCS: @(#) $Id: tclIOCmd.c,v 1.15.2.2 2004/07/16 22:38:37 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -100,11 +100,11 @@ char *arg; int length; arg = Tcl_GetStringFromObj(objv[3], &length); - if (strncmp(arg, "nonewline", (size_t) length) != 0) { + if ((length != 9) || (strncmp(arg, "nonewline", (size_t) length) != 0)) { Tcl_AppendResult(interp, "bad argument \"", arg, "\": should be \"nonewline\"", (char *) NULL); return TCL_ERROR; } @@ -1513,11 +1513,11 @@ if (inChan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((mode & TCL_READABLE) == 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", - Tcl_GetString(objv[1]), + arg, "\" wasn't opened for reading", (char *) NULL); return TCL_ERROR; } arg = Tcl_GetString(objv[2]); outChan = Tcl_GetChannel(interp, arg, &mode); @@ -1524,11 +1524,11 @@ if (outChan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((mode & TCL_WRITABLE) == 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", - Tcl_GetString(objv[1]), + arg, "\" wasn't opened for writing", (char *) NULL); return TCL_ERROR; } toRead = -1; Index: generic/tclIOGT.c ================================================================== --- generic/tclIOGT.c +++ generic/tclIOGT.c @@ -8,11 +8,11 @@ * Copyright (c) 1999-2000 Andreas Kupries (a.kupries@westend.com) * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * CVS: $Id: tclIOGT.c,v 1.7 2002/05/24 21:19:06 dkf Exp $ + * CVS: $Id: tclIOGT.c,v 1.7.2.2 2006/08/30 17:24:07 hobbs Exp $ */ #include "tclInt.h" #include "tclPort.h" #include "tclIO.h" @@ -129,11 +129,11 @@ * transformations. */ static Tcl_ChannelType transformChannelType = { "transform", /* Type name. */ - TCL_CHANNEL_VERSION_2, + TCL_CHANNEL_VERSION_3, TransformCloseProc, /* Close proc. */ TransformInputProc, /* Input proc. */ TransformOutputProc, /* Output proc. */ TransformSeekProc, /* Seek proc. */ TransformSetOptionProc, /* Set option proc. */ @@ -438,11 +438,11 @@ * If an error occured and the current interpreter is defined and not * equal to the interpreter for the callback, then copy the error * message into current interpreter. Don't copy if in preservation mode. */ - res = Tcl_GlobalEvalObj (dataPtr->interp, command); + res = Tcl_EvalObjEx(dataPtr->interp, command, TCL_EVAL_GLOBAL); Tcl_DecrRefCount (command); command = (Tcl_Obj*) NULL; if ((res != TCL_OK) && (interp != NO_INTERP) && (dataPtr->interp != interp) && !preserve) { Index: generic/tclIOUtil.c ================================================================== --- generic/tclIOUtil.c +++ generic/tclIOUtil.c @@ -15,11 +15,11 @@ * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIOUtil.c,v 1.77 2003/03/03 20:22:41 das Exp $ + * RCS: @(#) $Id: tclIOUtil.c,v 1.77.2.34 2007/02/19 23:49:05 hobbs Exp $ */ #include "tclInt.h" #include "tclPort.h" #ifdef MAC_TCL @@ -28,48 +28,90 @@ #ifdef __WIN32__ /* for tclWinProcs->useWide */ #include "tclWinInt.h" #endif -/* - * Prototypes for procedures defined later in this file. +/* + * struct FilesystemRecord -- + * + * A filesystem record is used to keep track of each + * filesystem currently registered with the core, + * in a linked list. Pointers to these structures + * are also kept by each "path" Tcl_Obj, and we must + * retain a refCount on the number of such references. + */ +typedef struct FilesystemRecord { + ClientData clientData; /* Client specific data for the new + * filesystem (can be NULL) */ + Tcl_Filesystem *fsPtr; /* Pointer to filesystem dispatch + * table. */ + int fileRefCount; /* How many Tcl_Obj's use this + * filesystem. */ + struct FilesystemRecord *nextPtr; + /* The next filesystem registered + * to Tcl, or NULL if no more. */ + struct FilesystemRecord *prevPtr; + /* The previous filesystem registered + * to Tcl, or NULL if no more. */ +} FilesystemRecord; + +/* + * The internal TclFS API provides routines for handling and + * manipulating paths efficiently, taking direct advantage of + * the "path" Tcl_Obj type. + * + * These functions are not exported at all at present. */ -static void DupFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, - Tcl_Obj *copyPtr)); -static void FreeFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr)); -static void UpdateStringOfFsPath _ANSI_ARGS_((Tcl_Obj *objPtr)); -static int SetFsPathFromAny _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Obj *objPtr)); -static Tcl_Obj* MakeFsPathFromRelative _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Obj *objPtr, Tcl_Obj *cwdPtr)); -static Tcl_Obj* FSNormalizeAbsolutePath - _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj *pathPtr)); -static int TclNormalizeToUniquePath - _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, - int startAt)); -static int SetFsPathFromAbsoluteNormalized - _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); -static int FindSplitPos _ANSI_ARGS_((char *path, char *separator)); +int TclFSCwdPointerEquals _ANSI_ARGS_((Tcl_Obj* objPtr)); +int TclFSMakePathFromNormalized _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr, ClientData clientData)); +int TclFSNormalizeToUniquePath _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *pathPtr, int startAt, ClientData *clientDataPtr)); +Tcl_Obj* TclFSMakePathRelative _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_Obj *cwdPtr)); +Tcl_Obj* TclFSInternalToNormalized _ANSI_ARGS_(( + Tcl_Filesystem *fromFilesystem, ClientData clientData, + FilesystemRecord **fsRecPtrPtr)); +int TclFSEnsureEpochOk _ANSI_ARGS_((Tcl_Obj* pathObjPtr, + Tcl_Filesystem **fsPtrPtr)); +void TclFSSetPathDetails _ANSI_ARGS_((Tcl_Obj *pathObjPtr, + FilesystemRecord *fsRecPtr, ClientData clientData)); + +/* + * Private variables for use in this file + */ +extern Tcl_Filesystem tclNativeFilesystem; +extern int theFilesystemEpoch; + +/* + * Private functions for use in this file + */ static Tcl_PathType FSGetPathType _ANSI_ARGS_((Tcl_Obj *pathObjPtr, Tcl_Filesystem **filesystemPtrPtr, int *driveNameLengthPtr)); static Tcl_PathType GetPathType _ANSI_ARGS_((Tcl_Obj *pathObjPtr, Tcl_Filesystem **filesystemPtrPtr, int *driveNameLengthPtr, Tcl_Obj **driveNameRef)); - -/* - * Define the 'path' object type, which Tcl uses to represent - * file paths internally. - */ -Tcl_ObjType tclFsPathType = { - "path", /* name */ - FreeFsPathInternalRep, /* freeIntRepProc */ - DupFsPathInternalRep, /* dupIntRepProc */ - UpdateStringOfFsPath, /* updateStringProc */ - SetFsPathFromAny /* setFromAnyProc */ -}; +static Tcl_FSPathInFilesystemProc NativePathInFilesystem; +static Tcl_Obj* TclFSNormalizeAbsolutePath + _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj *pathPtr, + ClientData *clientDataPtr)); +/* + * Prototypes for procedures defined later in this file. + */ + +static FilesystemRecord* FsGetFirstFilesystem(void); +static void FsThrExitProc(ClientData cd); +static Tcl_Obj* FsListMounts _ANSI_ARGS_((Tcl_Obj *pathPtr, + CONST char *pattern)); +static Tcl_Obj* FsAddMountsToGlobResult _ANSI_ARGS_((Tcl_Obj *result, + Tcl_Obj *pathPtr, CONST char *pattern, Tcl_GlobTypeData *types)); + +#ifdef TCL_THREADS +static void FsRecacheFilesystemList(void); +#endif /* * These form part of the native filesystem support. They are needed * here because we have a few native filesystem functions (which are * the same for mac/win/unix) in this file. There is no need to place @@ -100,12 +142,23 @@ if (ret != -1) { #ifndef TCL_WIDE_INT_IS_LONG # define OUT_OF_RANGE(x) \ (((Tcl_WideInt)(x)) < Tcl_LongAsWide(LONG_MIN) || \ ((Tcl_WideInt)(x)) > Tcl_LongAsWide(LONG_MAX)) +#if defined(__GNUC__) && __GNUC__ >= 2 +/* + * Workaround gcc warning of "comparison is always false due to limited range of + * data type" in this macro by checking max type size, and when necessary ANDing + * with the complement of ULONG_MAX instead of the comparison: + */ +# define OUT_OF_URANGE(x) \ + ((((Tcl_WideUInt)(~ (__typeof__(x)) 0)) > (Tcl_WideUInt)ULONG_MAX) && \ + (((Tcl_WideUInt)(x)) & ~(Tcl_WideUInt)ULONG_MAX)) +#else # define OUT_OF_URANGE(x) \ (((Tcl_WideUInt)(x)) > (Tcl_WideUInt)ULONG_MAX) +#endif /* * Perform the result-buffer overflow check manually. * * Note that ino_t/ino64_t is unsigned... @@ -303,30 +356,10 @@ TCL_DECLARE_MUTEX(obsoleteFsHookMutex) #endif /* USE_OBSOLETE_FS_HOOKS */ -/* - * A filesystem record is used to keep track of each - * filesystem currently registered with the core, - * in a linked list. - */ -typedef struct FilesystemRecord { - ClientData clientData; /* Client specific data for the new - * filesystem (can be NULL) */ - Tcl_Filesystem *fsPtr; /* Pointer to filesystem dispatch - * table. */ - int fileRefCount; /* How many Tcl_Obj's use this - * filesystem. */ - struct FilesystemRecord *nextPtr; - /* The next filesystem registered - * to Tcl, or NULL if no more. */ -} FilesystemRecord; - -static FilesystemRecord* GetFilesystemRecord - _ANSI_ARGS_((Tcl_Filesystem *fromFilesystem, int *epoch)); - /* * Declare the native filesystem support. These functions should * be considered private to Tcl, and should really not be called * directly by any code other than this file (i.e. neither by * Tcl's core nor by extensions). Similarly, the old string-based @@ -336,14 +369,12 @@ * which ensure correct and complete virtual filesystem support. * * We cannot make all of these static, since some of them * are implemented in the platform-specific directories. */ -static Tcl_FSPathInFilesystemProc NativePathInFilesystem; static Tcl_FSFilesystemSeparatorProc NativeFilesystemSeparator; static Tcl_FSFreeInternalRepProc NativeFreeInternalRep; -static Tcl_FSDupInternalRepProc NativeDupInternalRep; static Tcl_FSCreateInternalRepProc NativeCreateNativeRep; static Tcl_FSFileAttrStringsProc NativeFileAttrStrings; static Tcl_FSFileAttrsGetProc NativeFileAttrsGet; static Tcl_FSFileAttrsSetProc NativeFileAttrsSet; @@ -381,16 +412,16 @@ * by the functions actually listed within it (or perhaps other * helper functions of them). Anything which is not part of this * 'native filesystem implementation' should not be delving inside * here! */ -static Tcl_Filesystem tclNativeFilesystem = { +Tcl_Filesystem tclNativeFilesystem = { "native", sizeof(Tcl_Filesystem), TCL_FILESYSTEM_VERSION_1, &NativePathInFilesystem, - &NativeDupInternalRep, + &TclNativeDupInternalRep, &NativeFreeInternalRep, &TclpNativeToNormalized, &NativeCreateNativeRep, &TclpObjNormalizePath, &TclpFilesystemPathType, @@ -435,94 +466,53 @@ &tclNativeFilesystem, 1, NULL }; -/* - * The following few variables are protected by the - * filesystemMutex just below. - */ - /* * This is incremented each time we modify the linked list of * filesystems. Any time it changes, all cached filesystem * representations are suspect and must be freed. - */ -static int theFilesystemEpoch = 0; - -/* - * Stores the linked list of filesystems. - */ -static FilesystemRecord *filesystemList = &nativeFilesystemRecord; - -/* - * The number of loops which are currently iterating over the linked - * list. If this is greater than zero, we can't modify the list. - */ -static int filesystemIteratorsInProgress = 0; - -/* - * Someone wants to modify the list of filesystems if this is set. - */ -static int filesystemWantToModify = 0; - -#ifdef TCL_THREADS -static Tcl_Condition filesystemOkToModify = NULL; -#endif + * For multithreading builds, change of the filesystem epoch + * will trigger cache cleanup in all threads. + */ +int theFilesystemEpoch = 0; + +/* + * Stores the linked list of filesystems. A 1:1 copy of this + * list is also maintained in the TSD for each thread. This + * is to avoid synchronization issues. + */ +static FilesystemRecord *filesystemList = &nativeFilesystemRecord; TCL_DECLARE_MUTEX(filesystemMutex) /* - * struct FsPath -- - * - * Internal representation of a Tcl_Obj of "path" type. This - * can be used to represent relative or absolute paths, and has - * certain optimisations when used to represent paths which are - * already normalized and absolute. - * - * Note that 'normPathPtr' can be a circular reference to the - * container Tcl_Obj of this FsPath. - */ -typedef struct FsPath { - Tcl_Obj *translatedPathPtr; /* Name without any ~user sequences. - * If this is NULL, then this is a - * pure normalized, absolute path - * object, in which the parent Tcl_Obj's - * string rep is already both translated - * and normalized. */ - Tcl_Obj *normPathPtr; /* Normalized absolute path, without - * ., .. or ~user sequences. If the - * Tcl_Obj containing - * this FsPath is already normalized, - * this may be a circular reference back - * to the container. If that is NOT the - * case, we have a refCount on the object. */ - Tcl_Obj *cwdPtr; /* If null, path is absolute, else - * this points to the cwd object used - * for this path. We have a refCount - * on the object. */ - int flags; /* Flags to describe interpretation */ - ClientData nativePathPtr; /* Native representation of this path, - * which is filesystem dependent. */ - int filesystemEpoch; /* Used to ensure the path representation - * was generated during the correct - * filesystem epoch. The epoch changes - * when filesystem-mounts are changed. */ - struct FilesystemRecord *fsRecPtr; - /* Pointer to the filesystem record - * entry to use for this path. */ -} FsPath; - -#define TCLPATH_APPENDED 1 -#define TCLPATH_RELATIVE 2 -/* * Used to implement Tcl_FSGetCwd in a file-system independent way. - * This is protected by the cwdMutex below. */ static Tcl_Obj* cwdPathPtr = NULL; +static int cwdPathEpoch = 0; TCL_DECLARE_MUTEX(cwdMutex) +/* + * This structure holds per-thread private copies of + * some global data. This way we avoid most of the + * synchronization calls which boosts performance, at + * cost of having to update this information each + * time the corresponding epoch counter changes. + * + */ +typedef struct ThreadSpecificData { + int initialized; + int cwdPathEpoch; + int filesystemEpoch; + Tcl_Obj *cwdPathPtr; + FilesystemRecord *filesystemList; +} ThreadSpecificData; + +static Tcl_ThreadDataKey dataKey; + /* * Declare fallback support function and * information for Tcl_FSLoadFile */ static Tcl_FSUnloadFileProc FSUnloadTempFile; @@ -543,46 +533,176 @@ ClientData divertedFileNativeRep; } FsDivertLoad; /* Now move on to the basic filesystem implementation */ +static void +FsThrExitProc(cd) + ClientData cd; +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData*)cd; + FilesystemRecord *fsRecPtr = NULL, *tmpFsRecPtr = NULL; + + /* Trash the cwd copy */ + if (tsdPtr->cwdPathPtr != NULL) { + Tcl_DecrRefCount(tsdPtr->cwdPathPtr); + tsdPtr->cwdPathPtr = NULL; + } + /* Trash the filesystems cache */ + fsRecPtr = tsdPtr->filesystemList; + while (fsRecPtr != NULL) { + tmpFsRecPtr = fsRecPtr->nextPtr; + if (--fsRecPtr->fileRefCount <= 0) { + ckfree((char *)fsRecPtr); + } + fsRecPtr = tmpFsRecPtr; + } + tsdPtr->initialized = 0; +} -static int -FsCwdPointerEquals(objPtr) +int +TclFSCwdPointerEquals(objPtr) Tcl_Obj* objPtr; { - Tcl_MutexLock(&cwdMutex); - if (cwdPathPtr == objPtr) { - Tcl_MutexUnlock(&cwdMutex); - return 1; - } else { - Tcl_MutexUnlock(&cwdMutex); - return 0; - } -} - - -static FilesystemRecord* -FsGetIterator(void) { - Tcl_MutexLock(&filesystemMutex); - filesystemIteratorsInProgress++; - Tcl_MutexUnlock(&filesystemMutex); - /* Now we know the list of filesystems cannot be modified */ - return filesystemList; -} - -static void -FsReleaseIterator(void) { - Tcl_MutexLock(&filesystemMutex); - filesystemIteratorsInProgress--; - if (filesystemIteratorsInProgress == 0) { - /* Notify any waiting threads that things are ok now */ - if (filesystemWantToModify > 0) { - Tcl_ConditionNotify(&filesystemOkToModify); - } - } - Tcl_MutexUnlock(&filesystemMutex); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + Tcl_MutexLock(&cwdMutex); + if (tsdPtr->cwdPathPtr == NULL) { + if (cwdPathPtr == NULL) { + tsdPtr->cwdPathPtr = NULL; + } else { + tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr); + Tcl_IncrRefCount(tsdPtr->cwdPathPtr); + } + tsdPtr->cwdPathEpoch = cwdPathEpoch; + } else if (tsdPtr->cwdPathEpoch != cwdPathEpoch) { + Tcl_DecrRefCount(tsdPtr->cwdPathPtr); + if (cwdPathPtr == NULL) { + tsdPtr->cwdPathPtr = NULL; + } else { + tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr); + Tcl_IncrRefCount(tsdPtr->cwdPathPtr); + } + } + Tcl_MutexUnlock(&cwdMutex); + + if (tsdPtr->initialized == 0) { + Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr); + tsdPtr->initialized = 1; + } + return (tsdPtr->cwdPathPtr == objPtr); +} +#ifdef TCL_THREADS + +static void +FsRecacheFilesystemList(void) +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + FilesystemRecord *fsRecPtr, *tmpFsRecPtr = NULL; + + /* Trash the current cache */ + fsRecPtr = tsdPtr->filesystemList; + while (fsRecPtr != NULL) { + tmpFsRecPtr = fsRecPtr->nextPtr; + if (--fsRecPtr->fileRefCount <= 0) { + ckfree((char *)fsRecPtr); + } + fsRecPtr = tmpFsRecPtr; + } + tsdPtr->filesystemList = NULL; + + /* + * Code below operates on shared data. We + * are already called under mutex lock so + * we can safely proceed. + */ + + /* Locate tail of the global filesystem list */ + fsRecPtr = filesystemList; + while (fsRecPtr != NULL) { + tmpFsRecPtr = fsRecPtr; + fsRecPtr = fsRecPtr->nextPtr; + } + + /* Refill the cache honouring the order */ + fsRecPtr = tmpFsRecPtr; + while (fsRecPtr != NULL) { + tmpFsRecPtr = (FilesystemRecord *)ckalloc(sizeof(FilesystemRecord)); + *tmpFsRecPtr = *fsRecPtr; + tmpFsRecPtr->nextPtr = tsdPtr->filesystemList; + tmpFsRecPtr->prevPtr = NULL; + if (tsdPtr->filesystemList) { + tsdPtr->filesystemList->prevPtr = tmpFsRecPtr; + } + tsdPtr->filesystemList = tmpFsRecPtr; + fsRecPtr = fsRecPtr->prevPtr; + } + + /* Make sure the above gets released on thread exit */ + if (tsdPtr->initialized == 0) { + Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr); + tsdPtr->initialized = 1; + } +} +#endif + +static FilesystemRecord * +FsGetFirstFilesystem(void) { + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + FilesystemRecord *fsRecPtr; +#ifndef TCL_THREADS + tsdPtr->filesystemEpoch = theFilesystemEpoch; + fsRecPtr = filesystemList; +#else + Tcl_MutexLock(&filesystemMutex); + if (tsdPtr->filesystemList == NULL + || (tsdPtr->filesystemEpoch != theFilesystemEpoch)) { + FsRecacheFilesystemList(); + tsdPtr->filesystemEpoch = theFilesystemEpoch; + } + Tcl_MutexUnlock(&filesystemMutex); + fsRecPtr = tsdPtr->filesystemList; +#endif + return fsRecPtr; +} + +static void +FsUpdateCwd(cwdObj) + Tcl_Obj *cwdObj; +{ + int len; + char *str = NULL; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + if (cwdObj != NULL) { + str = Tcl_GetStringFromObj(cwdObj, &len); + } + + Tcl_MutexLock(&cwdMutex); + if (cwdPathPtr != NULL) { + Tcl_DecrRefCount(cwdPathPtr); + } + if (cwdObj == NULL) { + cwdPathPtr = NULL; + } else { + /* This MUST be stored as string object! */ + cwdPathPtr = Tcl_NewStringObj(str, len); + Tcl_IncrRefCount(cwdPathPtr); + } + cwdPathEpoch++; + tsdPtr->cwdPathEpoch = cwdPathEpoch; + Tcl_MutexUnlock(&cwdMutex); + + if (tsdPtr->cwdPathPtr) { + Tcl_DecrRefCount(tsdPtr->cwdPathPtr); + } + if (cwdObj == NULL) { + tsdPtr->cwdPathPtr = NULL; + } else { + tsdPtr->cwdPathPtr = Tcl_NewStringObj(str, len); + Tcl_IncrRefCount(tsdPtr->cwdPathPtr); + } } /* *---------------------------------------------------------------------- * @@ -604,45 +724,46 @@ */ void TclFinalizeFilesystem() { + FilesystemRecord *fsRecPtr; + /* * Assumption that only one thread is active now. Otherwise * we would need to put various mutexes around this code. */ if (cwdPathPtr != NULL) { Tcl_DecrRefCount(cwdPathPtr); cwdPathPtr = NULL; + cwdPathEpoch = 0; } /* * Remove all filesystems, freeing any allocated memory * that is no longer needed */ - while (filesystemList != NULL) { - FilesystemRecord *tmpFsRecPtr = filesystemList->nextPtr; - if (filesystemList->fileRefCount > 0) { - /* - * This filesystem must have some path objects still - * around which will be freed later (e.g. when unloading - * any shared libraries). If not, then someone is - * causing us to leak memory. - */ - } else { + + fsRecPtr = filesystemList; + while (fsRecPtr != NULL) { + FilesystemRecord *tmpFsRecPtr = fsRecPtr->nextPtr; + if (fsRecPtr->fileRefCount <= 0) { /* The native filesystem is static, so we don't free it */ - if (filesystemList != &nativeFilesystemRecord) { - ckfree((char *)filesystemList); + if (fsRecPtr->fsPtr != &tclNativeFilesystem) { + ckfree((char *)fsRecPtr); } } - filesystemList = tmpFsRecPtr; + fsRecPtr = tmpFsRecPtr; } + filesystemList = NULL; + /* * Now filesystemList is NULL. This means that any attempt * to use the filesystem is likely to fail. */ + statProcList = NULL; accessProcList = NULL; openFileChannelProcList = NULL; #ifdef __WIN32__ TclWinEncodingsCleanup(); @@ -667,21 +788,17 @@ void TclResetFilesystem() { filesystemList = &nativeFilesystemRecord; + /* * Note, at this point, I believe nativeFilesystemRecord -> * fileRefCount should equal 1 and if not, we should try to track * down the cause. */ - filesystemIteratorsInProgress = 0; - filesystemWantToModify = 0; -#ifdef TCL_THREADS - filesystemOkToModify = NULL; -#endif #ifdef __WIN32__ /* * Cleans up the win32 API filesystem proc lookup table. This must * happen very late in finalization so that deleting of copied * dlls can occur. @@ -754,18 +871,18 @@ * * However, since registering and unregistering filesystems is * a very rare action, this is not a very important point. */ Tcl_MutexLock(&filesystemMutex); - if (filesystemIteratorsInProgress) { - filesystemWantToModify++; - Tcl_ConditionWait(&filesystemOkToModify, &filesystemMutex, NULL); - filesystemWantToModify--; - } newFilesystemPtr->nextPtr = filesystemList; + newFilesystemPtr->prevPtr = NULL; + if (filesystemList) { + filesystemList->prevPtr = newFilesystemPtr; + } filesystemList = newFilesystemPtr; + /* * Increment the filesystem epoch counter, since existing paths * might conceivably now belong to different filesystems. */ theFilesystemEpoch++; @@ -802,32 +919,30 @@ int Tcl_FSUnregister(fsPtr) Tcl_Filesystem *fsPtr; /* The filesystem record to remove. */ { int retVal = TCL_ERROR; - FilesystemRecord *tmpFsRecPtr; - FilesystemRecord *prevFsRecPtr = NULL; + FilesystemRecord *fsRecPtr; Tcl_MutexLock(&filesystemMutex); - if (filesystemIteratorsInProgress) { - filesystemWantToModify++; - Tcl_ConditionWait(&filesystemOkToModify, &filesystemMutex, NULL); - filesystemWantToModify--; - } - tmpFsRecPtr = filesystemList; + /* * Traverse the 'filesystemList' looking for the particular node * whose 'fsPtr' member matches 'fsPtr' and remove that one from * the list. Ensure that the "default" node cannot be removed. */ - while ((retVal == TCL_ERROR) && (tmpFsRecPtr != &nativeFilesystemRecord)) { - if (tmpFsRecPtr->fsPtr == fsPtr) { - if (prevFsRecPtr == NULL) { - filesystemList = filesystemList->nextPtr; + fsRecPtr = filesystemList; + while ((retVal == TCL_ERROR) && (fsRecPtr->fsPtr != &tclNativeFilesystem)) { + if (fsRecPtr->fsPtr == fsPtr) { + if (fsRecPtr->prevPtr) { + fsRecPtr->prevPtr->nextPtr = fsRecPtr->nextPtr; } else { - prevFsRecPtr->nextPtr = tmpFsRecPtr->nextPtr; + filesystemList = fsRecPtr->nextPtr; + } + if (fsRecPtr->nextPtr) { + fsRecPtr->nextPtr->prevPtr = fsRecPtr->prevPtr; } /* * Increment the filesystem epoch counter, since existing * paths might conceivably now belong to different * filesystems. This should also ensure that paths which @@ -835,25 +950,243 @@ * do not reference that filesystem (which would of course * lead to memory exceptions). */ theFilesystemEpoch++; - tmpFsRecPtr->fileRefCount--; - if (tmpFsRecPtr->fileRefCount <= 0) { - ckfree((char *)tmpFsRecPtr); + fsRecPtr->fileRefCount--; + if (fsRecPtr->fileRefCount <= 0) { + ckfree((char *)fsRecPtr); } retVal = TCL_OK; } else { - prevFsRecPtr = tmpFsRecPtr; - tmpFsRecPtr = tmpFsRecPtr->nextPtr; + fsRecPtr = fsRecPtr->nextPtr; } } Tcl_MutexUnlock(&filesystemMutex); return (retVal); } + +/* + *---------------------------------------------------------------------- + * + * Tcl_FSMatchInDirectory -- + * + * This routine is used by the globbing code to search a directory + * for all files which match a given pattern. The appropriate + * function for the filesystem to which pathPtr belongs will be + * called. If pathPtr does not belong to any filesystem and if it + * is NULL or the empty string, then we assume the pattern is to be + * matched in the current working directory. To avoid each + * filesystem's Tcl_FSMatchInDirectoryProc having to deal with this + * issue, we create a pathPtr on the fly (equal to the cwd), and + * then remove it from the results returned. This makes filesystems + * easy to write, since they can assume the pathPtr passed to them + * is an ordinary path. In fact this means we could remove such + * special case handling from Tcl's native filesystems. + * + * If 'pattern' is NULL, then pathPtr is assumed to be a fully + * specified path of a single file/directory which must be + * checked for existence and correct type. + * + * Results: + * + * The return value is a standard Tcl result indicating whether an + * error occurred in globbing. Error messages are placed in + * interp, but good results are placed in the resultPtr given. + * + * Recursive searches, e.g. + * + * glob -dir $dir -join * pkgIndex.tcl + * + * which must recurse through each directory matching '*' are + * handled internally by Tcl, by passing specific flags in a + * modified 'types' parameter. This means the actual filesystem + * only ever sees patterns which match in a single directory. + * + * Side effects: + * The interpreter may have an error message inserted into it. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_FSMatchInDirectory(interp, result, pathPtr, pattern, types) + Tcl_Interp *interp; /* Interpreter to receive error messages. */ + Tcl_Obj *result; /* List object to receive results. */ + Tcl_Obj *pathPtr; /* Contains path to directory to search. */ + CONST char *pattern; /* Pattern to match against. */ + Tcl_GlobTypeData *types; /* Object containing list of acceptable types. + * May be NULL. In particular the directory + * flag is very important. */ +{ + Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); + if (fsPtr != NULL) { + Tcl_FSMatchInDirectoryProc *proc = fsPtr->matchInDirectoryProc; + if (proc != NULL) { + int ret = (*proc)(interp, result, pathPtr, pattern, types); + if (ret == TCL_OK && pattern != NULL) { + result = FsAddMountsToGlobResult(result, pathPtr, + pattern, types); + } + return ret; + } + } else { + Tcl_Obj* cwd; + int ret = -1; + if (pathPtr != NULL) { + int len; + Tcl_GetStringFromObj(pathPtr,&len); + if (len != 0) { + /* + * We have no idea how to match files in a directory + * which belongs to no known filesystem + */ + Tcl_SetErrno(ENOENT); + return -1; + } + } + /* + * We have an empty or NULL path. This is defined to mean we + * must search for files within the current 'cwd'. We + * therefore use that, but then since the proc we call will + * return results which include the cwd we must then trim it + * off the front of each path in the result. We choose to deal + * with this here (in the generic code), since if we don't, + * every single filesystem's implementation of + * Tcl_FSMatchInDirectory will have to deal with it for us. + */ + cwd = Tcl_FSGetCwd(NULL); + if (cwd == NULL) { + if (interp != NULL) { + Tcl_SetResult(interp, "glob couldn't determine " + "the current working directory", TCL_STATIC); + } + return TCL_ERROR; + } + fsPtr = Tcl_FSGetFileSystemForPath(cwd); + if (fsPtr != NULL) { + Tcl_FSMatchInDirectoryProc *proc = fsPtr->matchInDirectoryProc; + if (proc != NULL) { + Tcl_Obj* tmpResultPtr = Tcl_NewListObj(0, NULL); + Tcl_IncrRefCount(tmpResultPtr); + ret = (*proc)(interp, tmpResultPtr, cwd, pattern, types); + if (ret == TCL_OK) { + int resLength; + + tmpResultPtr = FsAddMountsToGlobResult(tmpResultPtr, cwd, + pattern, types); + + ret = Tcl_ListObjLength(interp, tmpResultPtr, &resLength); + if (ret == TCL_OK) { + int i; + + for (i = 0; i < resLength; i++) { + Tcl_Obj *elt; + + Tcl_ListObjIndex(interp, tmpResultPtr, i, &elt); + Tcl_ListObjAppendElement(interp, result, + TclFSMakePathRelative(interp, elt, cwd)); + } + } + } + Tcl_DecrRefCount(tmpResultPtr); + } + } + Tcl_DecrRefCount(cwd); + return ret; + } + Tcl_SetErrno(ENOENT); + return -1; +} + +/* + *---------------------------------------------------------------------- + * + * FsAddMountsToGlobResult -- + * + * This routine is used by the globbing code to take the results + * of a directory listing and add any mounted paths to that + * listing. This is required so that simple things like + * 'glob *' merge mounts and listings correctly. + * + * Results: + * + * The passed in 'result' may be modified (in place, if + * necessary), and the correct list is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static Tcl_Obj* +FsAddMountsToGlobResult(result, pathPtr, pattern, types) + Tcl_Obj *result; /* The current list of matching paths */ + Tcl_Obj *pathPtr; /* The directory in question */ + CONST char *pattern; + Tcl_GlobTypeData *types; +{ + int mLength, gLength, i; + int dir = (types == NULL || (types->type & TCL_GLOB_TYPE_DIR)); + Tcl_Obj *mounts = FsListMounts(pathPtr, pattern); + + if (mounts == NULL) return result; + + if (Tcl_ListObjLength(NULL, mounts, &mLength) != TCL_OK || mLength == 0) { + goto endOfMounts; + } + if (Tcl_ListObjLength(NULL, result, &gLength) != TCL_OK) { + goto endOfMounts; + } + for (i = 0; i < mLength; i++) { + Tcl_Obj *mElt; + int j; + int found = 0; + + Tcl_ListObjIndex(NULL, mounts, i, &mElt); + + for (j = 0; j < gLength; j++) { + Tcl_Obj *gElt; + Tcl_ListObjIndex(NULL, result, j, &gElt); + if (Tcl_FSEqualPaths(mElt, gElt)) { + found = 1; + if (!dir) { + /* We don't want to list this */ + if (Tcl_IsShared(result)) { + Tcl_Obj *newList; + newList = Tcl_DuplicateObj(result); + Tcl_DecrRefCount(result); + result = newList; + } + Tcl_ListObjReplace(NULL, result, j, 1, 0, NULL); + gLength--; + } + /* Break out of for loop */ + break; + } + } + if (!found && dir) { + if (Tcl_IsShared(result)) { + Tcl_Obj *newList; + newList = Tcl_DuplicateObj(result); + Tcl_DecrRefCount(result); + result = newList; + } + Tcl_ListObjAppendElement(NULL, result, mElt); + /* + * No need to increment gLength, since we + * don't want to compare mounts against + * mounts. + */ + } + } + endOfMounts: + Tcl_DecrRefCount(mounts); + return result; +} /* *---------------------------------------------------------------------- * * Tcl_FSMountsChanged -- @@ -944,34 +1277,32 @@ ClientData Tcl_FSData(fsPtr) Tcl_Filesystem *fsPtr; /* The filesystem record to query. */ { ClientData retVal = NULL; - FilesystemRecord *tmpFsRecPtr; + FilesystemRecord *fsRecPtr = FsGetFirstFilesystem(); - tmpFsRecPtr = FsGetIterator(); /* * Traverse the 'filesystemList' looking for the particular node * whose 'fsPtr' member matches 'fsPtr' and remove that one from * the list. Ensure that the "default" node cannot be removed. */ - while ((retVal == NULL) && (tmpFsRecPtr != NULL)) { - if (tmpFsRecPtr->fsPtr == fsPtr) { - retVal = tmpFsRecPtr->clientData; + while ((retVal == NULL) && (fsRecPtr != NULL)) { + if (fsRecPtr->fsPtr == fsPtr) { + retVal = fsRecPtr->clientData; } - tmpFsRecPtr = tmpFsRecPtr->nextPtr; + fsRecPtr = fsRecPtr->nextPtr; } - FsReleaseIterator(); - return (retVal); + return retVal; } /* *--------------------------------------------------------------------------- * - * FSNormalizeAbsolutePath -- + * TclFSNormalizeAbsolutePath -- * * Description: * Takes an absolute path specification and computes a 'normalized' * path from it. * @@ -998,14 +1329,15 @@ * Wippler, with additions from Vince Darley and is copyright * those respective authors. * *--------------------------------------------------------------------------- */ -static Tcl_Obj* -FSNormalizeAbsolutePath(interp, pathPtr) +static Tcl_Obj * +TclFSNormalizeAbsolutePath(interp, pathPtr, clientDataPtr) Tcl_Interp* interp; /* Interpreter to use */ Tcl_Obj *pathPtr; /* Absolute path to normalize */ + ClientData *clientDataPtr; { int splen = 0, nplen, eltLen, i; char *eltName; Tcl_Obj *retVal; Tcl_Obj *split; @@ -1037,10 +1369,12 @@ } else { nplen++; } } if (nplen > 0) { + ClientData clientData = NULL; + retVal = Tcl_FSJoinPath(split, nplen); /* * Now we have an absolute path, with no '..', '.' sequences, * but it still may not be in 'unique' form, depending on the * platform. For instance, Unix is case-sensitive, so the @@ -1050,17 +1384,20 @@ * * Virtual file systems which may be registered may have * other criteria for normalizing a path. */ Tcl_IncrRefCount(retVal); - TclNormalizeToUniquePath(interp, retVal, 0); + TclFSNormalizeToUniquePath(interp, retVal, 0, &clientData); /* * Since we know it is a normalized path, we can - * actually convert this object into an FsPath for + * actually convert this object into an "path" object for * greater efficiency */ - SetFsPathFromAbsoluteNormalized(interp, retVal); + TclFSMakePathFromNormalized(interp, retVal, clientData); + if (clientDataPtr != NULL) { + *clientDataPtr = clientData; + } } else { /* Init to an empty string */ retVal = Tcl_NewStringObj("",0); Tcl_IncrRefCount(retVal); } @@ -1081,11 +1418,11 @@ } /* *--------------------------------------------------------------------------- * - * TclNormalizeToUniquePath -- + * TclFSNormalizeToUniquePath -- * * Description: * Takes a path specification containing no ../, ./ sequences, * and converts it into a unique path for the given platform. * On MacOS, Unix, this means the path must be free of @@ -1111,42 +1448,46 @@ * to a directory separator that we know exists and is already * normalized (so it is important not to point to the char just * after the separator). *--------------------------------------------------------------------------- */ -static int -TclNormalizeToUniquePath(interp, pathPtr, startAt) +int +TclFSNormalizeToUniquePath(interp, pathPtr, startAt, clientDataPtr) Tcl_Interp *interp; Tcl_Obj *pathPtr; int startAt; + ClientData *clientDataPtr; { - FilesystemRecord *fsRecPtr; - + FilesystemRecord *fsRecPtr, *firstFsRecPtr; + /* Ignore this variable */ + (void)clientDataPtr; + /* * Call each of the "normalise path" functions in succession. This is * a special case, in which if we have a native filesystem handler, * we call it first. This is because the root of Tcl's filesystem * is always a native filesystem (i.e. '/' on unix is native). */ - fsRecPtr = FsGetIterator(); + firstFsRecPtr = FsGetFirstFilesystem(); + + fsRecPtr = firstFsRecPtr; while (fsRecPtr != NULL) { - if (fsRecPtr == &nativeFilesystemRecord) { + if (fsRecPtr->fsPtr == &tclNativeFilesystem) { Tcl_FSNormalizePathProc *proc = fsRecPtr->fsPtr->normalizePathProc; if (proc != NULL) { startAt = (*proc)(interp, pathPtr, startAt); } break; } fsRecPtr = fsRecPtr->nextPtr; } - FsReleaseIterator(); - fsRecPtr = FsGetIterator(); + fsRecPtr = firstFsRecPtr; while (fsRecPtr != NULL) { /* Skip the native system next time through */ - if (fsRecPtr != &nativeFilesystemRecord) { + if (fsRecPtr->fsPtr != &tclNativeFilesystem) { Tcl_FSNormalizePathProc *proc = fsRecPtr->fsPtr->normalizePathProc; if (proc != NULL) { startAt = (*proc)(interp, pathPtr, startAt); } /* @@ -1157,13 +1498,12 @@ * but there's not much benefit. */ } fsRecPtr = fsRecPtr->nextPtr; } - FsReleaseIterator(); - return (startAt); + return startAt; } /* *--------------------------------------------------------------------------- * @@ -1226,11 +1566,15 @@ break; case 'w': mode = O_WRONLY|O_CREAT|O_TRUNC; break; case 'a': - mode = O_WRONLY|O_CREAT; + /* [Bug 680143]. + * Added O_APPEND for proper automatic + * seek-to-end-on-write by the OS. + */ + mode = O_WRONLY|O_CREAT|O_APPEND; *seekFlagPtr = 1; break; default: error: if (interp != (Tcl_Interp *) NULL) { @@ -1372,16 +1716,17 @@ Interp *iPtr; char *string; Tcl_Channel chan; Tcl_Obj *objPtr; - if (Tcl_FSGetTranslatedPath(interp, pathPtr) == NULL) { + if (Tcl_FSGetNormalizedPath(interp, pathPtr) == NULL) { return TCL_ERROR; } result = TCL_ERROR; objPtr = Tcl_NewObj(); + Tcl_IncrRefCount(objPtr); if (Tcl_FSStat(pathPtr, &statBuf) == -1) { Tcl_SetErrno(errno); Tcl_AppendResult(interp, "couldn't read file \"", Tcl_GetString(pathPtr), @@ -1416,10 +1761,16 @@ iPtr = (Interp *) interp; oldScriptFile = iPtr->scriptFile; iPtr->scriptFile = pathPtr; Tcl_IncrRefCount(iPtr->scriptFile); string = Tcl_GetStringFromObj(objPtr, &length); + +#ifdef TCL_TIP280 + /* TIP #280 Force the evaluator to open a frame for a sourced + * file. */ + iPtr->evalFlags |= TCL_EVAL_FILE; +#endif result = Tcl_EvalEx(interp, string, length, 0); /* * Now we have to be careful; the script may have changed the * iPtr->scriptFile value, so we must reset it without * assuming it still points to 'pathPtr'. @@ -1523,11 +1874,13 @@ { CONST char *id, *msg; msg = Tcl_ErrnoMsg(errno); id = Tcl_ErrnoId(); - Tcl_SetErrorCode(interp, "POSIX", id, msg, (char *) NULL); + if (interp) { + Tcl_SetErrorCode(interp, "POSIX", id, msg, (char *) NULL); + } return msg; } /* *---------------------------------------------------------------------- @@ -1578,10 +1931,13 @@ statProcPtr = statProcList; while ((retVal == -1) && (statProcPtr != NULL)) { retVal = (*statProcPtr->proc)(path, &oldStyleStatBuffer); statProcPtr = statProcPtr->nextPtr; } + if (transPtr != NULL) { + Tcl_DecrRefCount(transPtr); + } } Tcl_MutexUnlock(&obsoleteFsHookMutex); if (retVal != -1) { /* @@ -1705,10 +2061,13 @@ accessProcPtr = accessProcList; while ((retVal == -1) && (accessProcPtr != NULL)) { retVal = (*accessProcPtr->proc)(path, mode); accessProcPtr = accessProcPtr->nextPtr; } + if (transPtr != NULL) { + Tcl_DecrRefCount(transPtr); + } } Tcl_MutexUnlock(&obsoleteFsHookMutex); if (retVal != -1) { return retVal; @@ -1755,43 +2114,55 @@ * file, with what modes to create * it? */ { Tcl_Filesystem *fsPtr; #ifdef USE_OBSOLETE_FS_HOOKS - OpenFileChannelProc *openFileChannelProcPtr; Tcl_Channel retVal = NULL; - char *path; -#endif /* USE_OBSOLETE_FS_HOOKS */ - Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(interp, pathPtr); - if (transPtr == NULL) { - return NULL; - } -#ifdef USE_OBSOLETE_FS_HOOKS - if (transPtr == NULL) { - path = NULL; - } else { - path = Tcl_GetString(transPtr); - } /* - * Call each of the "Tcl_OpenFileChannel" function in succession. + * Call each of the "Tcl_OpenFileChannel" functions in succession. * A non-NULL return value indicates the particular function has * succeeded. */ Tcl_MutexLock(&obsoleteFsHookMutex); - openFileChannelProcPtr = openFileChannelProcList; - while ((retVal == NULL) && (openFileChannelProcPtr != NULL)) { - retVal = (*openFileChannelProcPtr->proc)(interp, path, - modeString, permissions); - openFileChannelProcPtr = openFileChannelProcPtr->nextPtr; + if (openFileChannelProcList != NULL) { + OpenFileChannelProc *openFileChannelProcPtr; + char *path; + Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(interp, pathPtr); + + if (transPtr == NULL) { + path = NULL; + } else { + path = Tcl_GetString(transPtr); + } + + openFileChannelProcPtr = openFileChannelProcList; + + while ((retVal == NULL) && (openFileChannelProcPtr != NULL)) { + retVal = (*openFileChannelProcPtr->proc)(interp, path, + modeString, permissions); + openFileChannelProcPtr = openFileChannelProcPtr->nextPtr; + } + if (transPtr != NULL) { + Tcl_DecrRefCount(transPtr); + } } Tcl_MutexUnlock(&obsoleteFsHookMutex); if (retVal != NULL) { return retVal; } #endif /* USE_OBSOLETE_FS_HOOKS */ + + /* + * We need this just to ensure we return the correct error messages + * under some circumstances. + */ + if (Tcl_FSGetNormalizedPath(interp, pathPtr) == NULL) { + return NULL; + } + fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSOpenFileChannelProc *proc = fsPtr->openFileChannelProc; if (proc != NULL) { int mode, seekFlag; @@ -1825,375 +2196,10 @@ Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } - -/* - *---------------------------------------------------------------------- - * - * Tcl_FSMatchInDirectory -- - * - * This routine is used by the globbing code to search a directory - * for all files which match a given pattern. The appropriate - * function for the filesystem to which pathPtr belongs will be - * called. If pathPtr does not belong to any filesystem and if it - * is NULL or the empty string, then we assume the pattern is to be - * matched in the current working directory. To avoid each - * filesystem's Tcl_FSMatchInDirectoryProc having to deal with this - * issue, we create a pathPtr on the fly (equal to the cwd), and - * then remove it from the results returned. This makes filesystems - * easy to write, since they can assume the pathPtr passed to them - * is an ordinary path. In fact this means we could remove such - * special case handling from Tcl's native filesystems. - * - * If 'pattern' is NULL, then pathPtr is assumed to be a fully - * specified path of a single file/directory which must be - * checked for existence and correct type. - * - * Results: - * - * The return value is a standard Tcl result indicating whether an - * error occurred in globbing. Error messages are placed in - * interp, but good results are placed in the resultPtr given. - * - * Recursive searches, e.g. - * - * glob -dir $dir -join * pkgIndex.tcl - * - * which must recurse through each directory matching '*' are - * handled internally by Tcl, by passing specific flags in a - * modified 'types' parameter. This means the actual filesystem - * only ever sees patterns which match in a single directory. - * - * Side effects: - * The interpreter may have an error message inserted into it. - * - *---------------------------------------------------------------------- - */ - -int -Tcl_FSMatchInDirectory(interp, result, pathPtr, pattern, types) - Tcl_Interp *interp; /* Interpreter to receive error messages. */ - Tcl_Obj *result; /* List object to receive results. */ - Tcl_Obj *pathPtr; /* Contains path to directory to search. */ - CONST char *pattern; /* Pattern to match against. */ - Tcl_GlobTypeData *types; /* Object containing list of acceptable types. - * May be NULL. In particular the directory - * flag is very important. */ -{ - Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); - if (fsPtr != NULL) { - Tcl_FSMatchInDirectoryProc *proc = fsPtr->matchInDirectoryProc; - if (proc != NULL) { - return (*proc)(interp, result, pathPtr, pattern, types); - } - } else { - Tcl_Obj* cwd; - int ret = -1; - if (pathPtr != NULL) { - int len; - Tcl_GetStringFromObj(pathPtr,&len); - if (len != 0) { - /* - * We have no idea how to match files in a directory - * which belongs to no known filesystem - */ - Tcl_SetErrno(ENOENT); - return -1; - } - } - /* - * We have an empty or NULL path. This is defined to mean we - * must search for files within the current 'cwd'. We - * therefore use that, but then since the proc we call will - * return results which include the cwd we must then trim it - * off the front of each path in the result. We choose to deal - * with this here (in the generic code), since if we don't, - * every single filesystem's implementation of - * Tcl_FSMatchInDirectory will have to deal with it for us. - */ - cwd = Tcl_FSGetCwd(NULL); - if (cwd == NULL) { - if (interp != NULL) { - Tcl_SetResult(interp, "glob couldn't determine " - "the current working directory", TCL_STATIC); - } - return TCL_ERROR; - } - fsPtr = Tcl_FSGetFileSystemForPath(cwd); - if (fsPtr != NULL) { - Tcl_FSMatchInDirectoryProc *proc = fsPtr->matchInDirectoryProc; - if (proc != NULL) { - int cwdLen; - char *cwdStr; - Tcl_Obj* tmpResultPtr = Tcl_NewListObj(0, NULL); - Tcl_IncrRefCount(tmpResultPtr); - /* - * We know the cwd is a normalised object which does - * not end in a directory delimiter, unless the cwd - * is the name of a volume, in which case it will - * end in a delimiter! We handle this situation here. - * A better test than the '!= sep' might be to simply - * check if 'cwd' is a root volume. - * - * Note that if we get this wrong, we will strip off - * either too much or too little below, leading to - * wrong answers returned by glob. - */ - cwdStr = Tcl_GetStringFromObj(cwd, &cwdLen); - /* - * Should we perhaps use 'Tcl_FSPathSeparator'? - * But then what about the Windows special case? - * Perhaps we should just check if cwd is a root - * volume. - */ - switch (tclPlatform) { - case TCL_PLATFORM_UNIX: - if (cwdStr[cwdLen-1] != '/') { - cwdLen++; - } - break; - case TCL_PLATFORM_WINDOWS: - if (cwdStr[cwdLen-1] != '/' - && cwdStr[cwdLen-1] != '\\') { - cwdLen++; - } - break; - case TCL_PLATFORM_MAC: - if (cwdStr[cwdLen-1] != ':') { - cwdLen++; - } - break; - } - ret = (*proc)(interp, tmpResultPtr, cwd, pattern, types); - if (ret == TCL_OK) { - int resLength; - - ret = Tcl_ListObjLength(interp, tmpResultPtr, &resLength); - if (ret == TCL_OK) { - int i; - - for (i = 0; i < resLength; i++) { - Tcl_Obj *cutElt, *elt; - char *eltStr; - int eltLen; - - Tcl_ListObjIndex(interp, tmpResultPtr, i, &elt); - if (elt->typePtr == &tclFsPathType) { - FsPath* fsPathPtr = (FsPath*) - elt->internalRep.otherValuePtr; - if (fsPathPtr->flags != 0 - && fsPathPtr->cwdPtr == cwd) { - Tcl_ListObjAppendElement(interp, result, - MakeFsPathFromRelative(interp, - fsPathPtr->normPathPtr, cwd)); - continue; - } - } - eltStr = Tcl_GetStringFromObj(elt, &eltLen); - cutElt = Tcl_NewStringObj(eltStr + cwdLen, - eltLen - cwdLen); - Tcl_ListObjAppendElement(interp, result, cutElt); - } - } - } - Tcl_DecrRefCount(tmpResultPtr); - } - } - Tcl_DecrRefCount(cwd); - return ret; - } - Tcl_SetErrno(ENOENT); - return -1; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_FSGetCwd -- - * - * This function replaces the library version of getcwd(). - * - * Most VFS's will *not* implement a 'cwdProc'. Tcl now maintains - * its own record (in a Tcl_Obj) of the cwd, and an attempt - * is made to synchronise this with the cwd's containing filesystem, - * if that filesystem provides a cwdProc (e.g. the native filesystem). - * - * Note that if Tcl's cwd is not in the native filesystem, then of - * course Tcl's cwd and the native cwd are different: extensions - * should therefore ensure they only access the cwd through this - * function to avoid confusion. - * - * If a global cwdPathPtr already exists, it is returned, subject - * to a synchronisation attempt in that cwdPathPtr's fs. - * Otherwise, the chain of functions that have been "inserted" - * into the filesystem will be called in succession until either a - * value other than NULL is returned, or the entire list is - * visited. - * - * Results: - * The result is a pointer to a Tcl_Obj specifying the current - * directory, or NULL if the current directory could not be - * determined. If NULL is returned, an error message is left in the - * interp's result. - * - * The result already has its refCount incremented for the caller. - * When it is no longer needed, that refCount should be decremented. - * This is needed for thread-safety purposes, to allow multiple - * threads to access this and related functions, while ensuring the - * results are always valid. - * - * Of course it is probably a bad idea for multiple threads to - * be *setting* the cwd anyway, but we can at least try to - * help the case of multiple reads with occasional sets. - * - * Side effects: - * Various objects may be freed and allocated. - * - *---------------------------------------------------------------------- - */ - -Tcl_Obj* -Tcl_FSGetCwd(interp) - Tcl_Interp *interp; -{ - Tcl_Obj *cwdToReturn; - - if (FsCwdPointerEquals(NULL)) { - FilesystemRecord *fsRecPtr; - Tcl_Obj *retVal = NULL; - - /* - * We've never been called before, try to find a cwd. Call - * each of the "Tcl_GetCwd" function in succession. A non-NULL - * return value indicates the particular function has - * succeeded. - */ - - fsRecPtr = FsGetIterator(); - while ((retVal == NULL) && (fsRecPtr != NULL)) { - Tcl_FSGetCwdProc *proc = fsRecPtr->fsPtr->getCwdProc; - if (proc != NULL) { - retVal = (*proc)(interp); - } - fsRecPtr = fsRecPtr->nextPtr; - } - FsReleaseIterator(); - /* - * Now the 'cwd' may NOT be normalized, at least on some - * platforms. For the sake of efficiency, we want a completely - * normalized cwd at all times. - * - * Finally, if retVal is NULL, we do not have a cwd, which - * could be problematic. - */ - if (retVal != NULL) { - Tcl_Obj *norm = FSNormalizeAbsolutePath(interp, retVal); - if (norm != NULL) { - /* - * We found a cwd, which is now in our global storage. - * We must make a copy. Norm already has a refCount of - * 1. - * - * Threading issue: note that multiple threads at system - * startup could in principle call this procedure - * simultaneously. They will therefore each set the - * cwdPathPtr independently. That behaviour is a bit - * peculiar, but should be fine. Once we have a cwd, - * we'll always be in the 'else' branch below which - * is simpler. - */ - Tcl_MutexLock(&cwdMutex); - /* Just in case the pointer has been set by another - * thread between now and the test above */ - if (cwdPathPtr != NULL) { - Tcl_DecrRefCount(cwdPathPtr); - } - cwdPathPtr = norm; - Tcl_MutexUnlock(&cwdMutex); - } - Tcl_DecrRefCount(retVal); - } - } else { - /* - * We already have a cwd cached, but we want to give the - * filesystem it is in a chance to check whether that cwd - * has changed, or is perhaps no longer accessible. This - * allows an error to be thrown if, say, the permissions on - * that directory have changed. - */ - Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(cwdPathPtr); - /* - * If the filesystem couldn't be found, or if no cwd function - * exists for this filesystem, then we simply assume the cached - * cwd is ok. If we do call a cwd, we must watch for errors - * (if the cwd returns NULL). This ensures that, say, on Unix - * if the permissions of the cwd change, 'pwd' does actually - * throw the correct error in Tcl. (This is tested for in the - * test suite on unix). - */ - if (fsPtr != NULL) { - Tcl_FSGetCwdProc *proc = fsPtr->getCwdProc; - if (proc != NULL) { - Tcl_Obj *retVal = (*proc)(interp); - if (retVal != NULL) { - Tcl_Obj *norm = FSNormalizeAbsolutePath(interp, retVal); - /* - * Check whether cwd has changed from the value - * previously stored in cwdPathPtr. Really 'norm' - * shouldn't be null, but we are careful. - */ - if (norm == NULL) { - /* Do nothing */ - } else if (Tcl_FSEqualPaths(cwdPathPtr, norm)) { - /* - * If the paths were equal, we can be more - * efficient and retain the old path object - * which will probably already be shared. In - * this case we can simply free the normalized - * path we just calculated. - */ - Tcl_DecrRefCount(norm); - } else { - /* The cwd has in fact changed, so we must - * lock down the cwdMutex to modify. */ - Tcl_MutexLock(&cwdMutex); - Tcl_DecrRefCount(cwdPathPtr); - cwdPathPtr = norm; - Tcl_MutexUnlock(&cwdMutex); - } - Tcl_DecrRefCount(retVal); - } else { - /* The 'cwd' function returned an error, so we - * reset the cwd after locking down the mutex. */ - Tcl_MutexLock(&cwdMutex); - Tcl_DecrRefCount(cwdPathPtr); - cwdPathPtr = NULL; - Tcl_MutexUnlock(&cwdMutex); - } - } - } - } - - /* - * The paths all eventually fall through to here. Note that - * we use a bunch of separate mutex locks throughout this - * code to help prevent deadlocks between threads. Really - * the only weirdness will arise if multiple threads are setting - * and reading the cwd, and that behaviour is always going to be - * a little suspect. - */ - Tcl_MutexLock(&cwdMutex); - cwdToReturn = cwdPathPtr; - if (cwdToReturn != NULL) { - Tcl_IncrRefCount(cwdToReturn); - } - Tcl_MutexUnlock(&cwdMutex); - - return (cwdToReturn); -} /* *---------------------------------------------------------------------- * * Tcl_FSUtime -- @@ -2440,10 +2446,164 @@ } /* *---------------------------------------------------------------------- * + * Tcl_FSGetCwd -- + * + * This function replaces the library version of getcwd(). + * + * Most VFS's will *not* implement a 'cwdProc'. Tcl now maintains + * its own record (in a Tcl_Obj) of the cwd, and an attempt + * is made to synchronise this with the cwd's containing filesystem, + * if that filesystem provides a cwdProc (e.g. the native filesystem). + * + * Note that if Tcl's cwd is not in the native filesystem, then of + * course Tcl's cwd and the native cwd are different: extensions + * should therefore ensure they only access the cwd through this + * function to avoid confusion. + * + * If a global cwdPathPtr already exists, it is cached in the thread's + * private data structures and reference to the cached copy is returned, + * subject to a synchronisation attempt in that cwdPathPtr's fs. + * + * Otherwise, the chain of functions that have been "inserted" + * into the filesystem will be called in succession until either a + * value other than NULL is returned, or the entire list is + * visited. + * + * Results: + * The result is a pointer to a Tcl_Obj specifying the current + * directory, or NULL if the current directory could not be + * determined. If NULL is returned, an error message is left in the + * interp's result. + * + * The result already has its refCount incremented for the caller. + * When it is no longer needed, that refCount should be decremented. + * + * Side effects: + * Various objects may be freed and allocated. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj* +Tcl_FSGetCwd(interp) + Tcl_Interp *interp; +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + if (TclFSCwdPointerEquals(NULL)) { + FilesystemRecord *fsRecPtr; + Tcl_Obj *retVal = NULL; + + /* + * We've never been called before, try to find a cwd. Call + * each of the "Tcl_GetCwd" function in succession. A non-NULL + * return value indicates the particular function has + * succeeded. + */ + + fsRecPtr = FsGetFirstFilesystem(); + while ((retVal == NULL) && (fsRecPtr != NULL)) { + Tcl_FSGetCwdProc *proc = fsRecPtr->fsPtr->getCwdProc; + if (proc != NULL) { + retVal = (*proc)(interp); + } + fsRecPtr = fsRecPtr->nextPtr; + } + /* + * Now the 'cwd' may NOT be normalized, at least on some + * platforms. For the sake of efficiency, we want a completely + * normalized cwd at all times. + * + * Finally, if retVal is NULL, we do not have a cwd, which + * could be problematic. + */ + if (retVal != NULL) { + Tcl_Obj *norm = TclFSNormalizeAbsolutePath(interp, retVal, NULL); + if (norm != NULL) { + /* + * We found a cwd, which is now in our global storage. + * We must make a copy. Norm already has a refCount of 1. + * + * Threading issue: note that multiple threads at system + * startup could in principle call this procedure + * simultaneously. They will therefore each set the + * cwdPathPtr independently. That behaviour is a bit + * peculiar, but should be fine. Once we have a cwd, + * we'll always be in the 'else' branch below which + * is simpler. + */ + FsUpdateCwd(norm); + Tcl_DecrRefCount(norm); + } + Tcl_DecrRefCount(retVal); + } + } else { + /* + * We already have a cwd cached, but we want to give the + * filesystem it is in a chance to check whether that cwd + * has changed, or is perhaps no longer accessible. This + * allows an error to be thrown if, say, the permissions on + * that directory have changed. + */ + Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(tsdPtr->cwdPathPtr); + /* + * If the filesystem couldn't be found, or if no cwd function + * exists for this filesystem, then we simply assume the cached + * cwd is ok. If we do call a cwd, we must watch for errors + * (if the cwd returns NULL). This ensures that, say, on Unix + * if the permissions of the cwd change, 'pwd' does actually + * throw the correct error in Tcl. (This is tested for in the + * test suite on unix). + */ + if (fsPtr != NULL) { + Tcl_FSGetCwdProc *proc = fsPtr->getCwdProc; + if (proc != NULL) { + Tcl_Obj *retVal = (*proc)(interp); + if (retVal != NULL) { + Tcl_Obj *norm = TclFSNormalizeAbsolutePath(interp, retVal, NULL); + /* + * Check whether cwd has changed from the value + * previously stored in cwdPathPtr. Really 'norm' + * shouldn't be null, but we are careful. + */ + if (norm == NULL) { + /* Do nothing */ + } else if (Tcl_FSEqualPaths(tsdPtr->cwdPathPtr, norm)) { + /* + * If the paths were equal, we can be more + * efficient and retain the old path object + * which will probably already be shared. In + * this case we can simply free the normalized + * path we just calculated. + */ + Tcl_DecrRefCount(norm); + } else { + FsUpdateCwd(norm); + Tcl_DecrRefCount(norm); + } + Tcl_DecrRefCount(retVal); + } else { + /* The 'cwd' function returned an error; reset the cwd */ + FsUpdateCwd(NULL); + } + } + } + } + + if (tsdPtr->cwdPathPtr != NULL) { + Tcl_IncrRefCount(tsdPtr->cwdPathPtr); + } + + return tsdPtr->cwdPathPtr; +} + +/* + *---------------------------------------------------------------------- + * * Tcl_FSChdir -- * * This function replaces the library version of chdir(). * * The path is normalized and then passed to the filesystem @@ -2465,12 +2625,55 @@ Tcl_Obj *pathPtr; { Tcl_Filesystem *fsPtr; int retVal = -1; +#ifdef WIN32 + /* + * This complete hack addresses the bug tested in winFCmd-16.12, + * where having your HOME as "C:" (IOW, a seemingly path relative + * dir) would cause a crash when you cd'd to it and requested 'pwd'. + * The work-around is to force such a dir into an absolute path by + * tacking on '/'. + * + * We check for '~' specifically because that's what Tcl_CdObjCmd + * passes in that triggers the bug. A direct 'cd C:' call will not + * because that gets the volumerelative pwd. + * + * This is not an issue for 8.5 as that has a more elaborate change + * that requires the use of TCL_FILESYSTEM_VERSION_2. + */ + Tcl_Obj *objPtr = NULL; + if (pathPtr->bytes && pathPtr->length == 1 && pathPtr->bytes[0] == '~') { + int len; + char *str; + + objPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); + if (objPtr == NULL) { + Tcl_SetErrno(ENOENT); + return -1; + } + Tcl_IncrRefCount(objPtr); + str = Tcl_GetStringFromObj(objPtr, &len); + if (len == 2 && str[1] == ':') { + pathPtr = Tcl_NewStringObj(str, len); + Tcl_AppendToObj(pathPtr, "/", 1); + Tcl_IncrRefCount(pathPtr); + Tcl_DecrRefCount(objPtr); + objPtr = pathPtr; + } else { + Tcl_DecrRefCount(objPtr); + objPtr = NULL; + } + } +#endif if (Tcl_FSGetNormalizedPath(NULL, pathPtr) == NULL) { - return TCL_ERROR; +#ifdef WIN32 + if (objPtr) { Tcl_DecrRefCount(objPtr); } +#endif + Tcl_SetErrno(ENOENT); + return -1; } fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSChdirProc *proc = fsPtr->chdirProc; @@ -2497,11 +2700,11 @@ * to the user). If there was no error we must assume that the * cwd was actually changed to the normalized value we * calculated above, and we must therefore cache that * information. */ - if (retVal == TCL_OK) { + if (retVal == 0) { /* * Note that this normalized path may be different to what * we found above (or at least a different object), if the * filesystem epoch changed recently. This can actually * happen with scripted documents very easily. Therefore @@ -2509,29 +2712,25 @@ * will have been cached as a result of the * Tcl_FSGetFileSystemForPath call above anyway). */ Tcl_Obj *normDirName = Tcl_FSGetNormalizedPath(NULL, pathPtr); if (normDirName == NULL) { - return TCL_ERROR; - } - /* - * We will be adding a reference to this object when - * we store it in the cwdPathPtr. - */ - Tcl_IncrRefCount(normDirName); - /* Get a lock on the cwd while we modify it */ - Tcl_MutexLock(&cwdMutex); - /* Free up the previous cwd we stored */ - if (cwdPathPtr != NULL) { - Tcl_DecrRefCount(cwdPathPtr); - } - /* Now remember the current cwd */ - cwdPathPtr = normDirName; - Tcl_MutexUnlock(&cwdMutex); - } - } - +#ifdef WIN32 + if (objPtr) { Tcl_DecrRefCount(objPtr); } +#endif + Tcl_SetErrno(ENOENT); + return -1; + } + FsUpdateCwd(normDirName); + } + } else { + Tcl_SetErrno(ENOENT); + } + +#ifdef WIN32 + if (objPtr) { Tcl_DecrRefCount(objPtr); } +#endif return (retVal); } /* *---------------------------------------------------------------------- @@ -2609,10 +2808,60 @@ Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } +#ifdef TCL_LOAD_FROM_MEMORY + /* + * The platform supports loading code from memory, so ask for a + * buffer of the appropriate size, read the file into it and + * load the code from the buffer: + */ + do { + int ret, size; + void *buffer; + Tcl_StatBuf statBuf; + Tcl_Channel data; + + ret = Tcl_FSStat(pathPtr, &statBuf); + if (ret < 0) { + break; + } + size = (int) statBuf.st_size; + /* Tcl_Read takes an int: check that file size isn't wide */ + if (size != (Tcl_WideInt)statBuf.st_size) { + break; + } + data = Tcl_FSOpenFileChannel(interp, pathPtr, "r", 0666); + if (!data) { + break; + } + buffer = TclpLoadMemoryGetBuffer(interp, size); + if (!buffer) { + Tcl_Close(interp, data); + break; + } + Tcl_SetChannelOption(interp, data, "-translation", "binary"); + ret = Tcl_Read(data, buffer, size); + Tcl_Close(interp, data); + ret = TclpLoadMemory(interp, buffer, size, ret, handlePtr, unloadProcPtr); + if (ret == TCL_OK) { + if (*handlePtr == NULL) { + break; + } + if (sym1 != NULL) { + *proc1Ptr = TclpFindSymbol(interp, *handlePtr, sym1); + } + if (sym2 != NULL) { + *proc2Ptr = TclpFindSymbol(interp, *handlePtr, sym2); + } + return TCL_OK; + } + } while (0); + Tcl_ResetResult(interp); +#endif + /* * Get a temporary filename to use, first to * copy the file into, and then to load. */ copyToPtr = TclpTempFileName(); @@ -2721,11 +2970,11 @@ tvdlPtr->divertedFilesystem = copyFsPtr; tvdlPtr->divertedFileNativeRep = NULL; } else { /* We need the native rep */ tvdlPtr->divertedFileNativeRep = - NativeDupInternalRep(Tcl_FSGetInternalRep(copyToPtr, + TclNativeDupInternalRep(Tcl_FSGetInternalRep(copyToPtr, copyFsPtr)); /* * We don't need or want references to the copied * Tcl_Obj or the filesystem if it is the native * one. @@ -2982,11 +3231,11 @@ * A non-NULL return value indicates the particular function has * succeeded. We call all the functions registered, since we want * a list of all drives from all filesystems. */ - fsRecPtr = FsGetIterator(); + fsRecPtr = FsGetFirstFilesystem(); while (fsRecPtr != NULL) { Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc; if (proc != NULL) { Tcl_Obj *thisFsVolumes = (*proc)(); if (thisFsVolumes != NULL) { @@ -2994,86 +3243,65 @@ Tcl_DecrRefCount(thisFsVolumes); } } fsRecPtr = fsRecPtr->nextPtr; } - FsReleaseIterator(); return resultPtr; } /* - *---------------------------------------------------------------------- - * - * Tcl_FSGetPathType -- - * - * Determines whether a given path is relative to the current - * directory, relative to the current volume, or absolute. - * - * Results: - * Returns one of TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, or - * TCL_PATH_VOLUME_RELATIVE. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tcl_PathType -Tcl_FSGetPathType(pathObjPtr) - Tcl_Obj *pathObjPtr; -{ - return FSGetPathType(pathObjPtr, NULL, NULL); -} - -/* - *---------------------------------------------------------------------- - * - * FSGetPathType -- - * - * Determines whether a given path is relative to the current - * directory, relative to the current volume, or absolute. If the - * caller wishes to know which filesystem claimed the path (in the - * case for which the path is absolute), then a reference to a - * filesystem pointer can be passed in (but passing NULL is - * acceptable). - * - * Results: - * Returns one of TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, or - * TCL_PATH_VOLUME_RELATIVE. The filesystem reference will - * be set if and only if it is non-NULL and the function's - * return value is TCL_PATH_ABSOLUTE. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static Tcl_PathType -FSGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr) - Tcl_Obj *pathObjPtr; - Tcl_Filesystem **filesystemPtrPtr; - int *driveNameLengthPtr; -{ - if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) { - return GetPathType(pathObjPtr, filesystemPtrPtr, - driveNameLengthPtr, NULL); - } else { - FsPath *fsPathPtr = (FsPath*) pathObjPtr->internalRep.otherValuePtr; - if (fsPathPtr->cwdPtr != NULL) { - if (fsPathPtr->flags == 0) { - return TCL_PATH_RELATIVE; - } - return FSGetPathType(fsPathPtr->cwdPtr, filesystemPtrPtr, - driveNameLengthPtr); - } else { - return GetPathType(pathObjPtr, filesystemPtrPtr, - driveNameLengthPtr, NULL); - } - } + *--------------------------------------------------------------------------- + * + * FsListMounts -- + * + * List all mounts within the given directory, which match the + * given pattern. + * + * Results: + * The list of mounts, in a list object which has refCount 0, or + * NULL if we didn't even find any filesystems to try to list + * mounts. + * + * Side effects: + * None + * + *--------------------------------------------------------------------------- + */ + +static Tcl_Obj* +FsListMounts(pathPtr, pattern) + Tcl_Obj *pathPtr; /* Contains path to directory to search. */ + CONST char *pattern; /* Pattern to match against. */ +{ + FilesystemRecord *fsRecPtr; + Tcl_GlobTypeData mountsOnly = { TCL_GLOB_TYPE_MOUNT, 0, NULL, NULL }; + Tcl_Obj *resultPtr = NULL; + + /* + * Call each of the "listMounts" functions in succession. + * A non-NULL return value indicates the particular function has + * succeeded. We call all the functions registered, since we want + * a list from each filesystems. + */ + + fsRecPtr = FsGetFirstFilesystem(); + while (fsRecPtr != NULL) { + if (fsRecPtr->fsPtr != &tclNativeFilesystem) { + Tcl_FSMatchInDirectoryProc *proc = + fsRecPtr->fsPtr->matchInDirectoryProc; + if (proc != NULL) { + if (resultPtr == NULL) { + resultPtr = Tcl_NewObj(); + } + (*proc)(NULL, resultPtr, pathPtr, pattern, &mountsOnly); + } + } + fsRecPtr = fsRecPtr->nextPtr; + } + + return resultPtr; } /* *--------------------------------------------------------------------------- * @@ -3169,192 +3397,33 @@ Tcl_ListObjLength(NULL, result, lenPtr); } return result; } -/* - *--------------------------------------------------------------------------- - * - * Tcl_FSJoinPath -- - * - * This function takes the given Tcl_Obj, which should be a valid - * list, and returns the path object given by considering the - * first 'elements' elements as valid path segments. If elements < 0, - * we use the entire list. - * - * Results: - * Returns object with refCount of zero, (or if non-zero, it has - * references elsewhere in Tcl). Either way, the caller must - * increment its refCount before use. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ +/* Simple helper function */ Tcl_Obj* -Tcl_FSJoinPath(listObj, elements) - Tcl_Obj *listObj; - int elements; -{ - Tcl_Obj *res; - int i; - Tcl_Filesystem *fsPtr = NULL; - - if (elements < 0) { - if (Tcl_ListObjLength(NULL, listObj, &elements) != TCL_OK) { - return NULL; - } - } else { - /* Just make sure it is a valid list */ - int listTest; - if (Tcl_ListObjLength(NULL, listObj, &listTest) != TCL_OK) { - return NULL; - } - /* - * Correct this if it is too large, otherwise we will - * waste our time joining null elements to the path - */ - if (elements > listTest) { - elements = listTest; - } - } - - if (elements == 2) { - /* - * This is a special case where we can be much more - * efficient - */ - Tcl_Obj *base; - - Tcl_ListObjIndex(NULL, listObj, 0, &base); - /* - * There is only any value in doing this if the first object is - * of path type, otherwise we'll never actually get any - * efficiency benefit elsewhere in the code (from re-using the - * normalized representation of the base object). - */ - if (base->typePtr == &tclFsPathType - && !(base->bytes != NULL && base->bytes[0] == '\0')) { - Tcl_Obj *tail; - Tcl_PathType type; - Tcl_ListObjIndex(NULL, listObj, 1, &tail); - type = GetPathType(tail, NULL, NULL, NULL); - if (type == TCL_PATH_RELATIVE) { - CONST char *str; - int len; - str = Tcl_GetStringFromObj(tail,&len); - if (len == 0) { - /* - * This happens if we try to handle the root volume - * '/'. There's no need to return a special path - * object, when the base itself is just fine! - */ - return base; - } - if (str[0] != '.') { - return TclNewFSPathObj(base, str, len); - } - /* - * Otherwise we don't have an easy join, and - * we must let the more general code below handle - * things - */ - } else { - return tail; - } - } - } - - res = Tcl_NewObj(); - - for (i = 0; i < elements; i++) { - Tcl_Obj *elt; - int driveNameLength; - Tcl_PathType type; - char *strElt; - int strEltLen; - int length; - char *ptr; - Tcl_Obj *driveName = NULL; - - Tcl_ListObjIndex(NULL, listObj, i, &elt); - strElt = Tcl_GetStringFromObj(elt, &strEltLen); - type = GetPathType(elt, &fsPtr, &driveNameLength, &driveName); - if (type != TCL_PATH_RELATIVE) { - /* Zero out the current result */ - Tcl_DecrRefCount(res); - if (driveName != NULL) { - res = Tcl_DuplicateObj(driveName); - Tcl_DecrRefCount(driveName); - } else { - res = Tcl_NewStringObj(strElt, driveNameLength); - } - strElt += driveNameLength; - } - - ptr = Tcl_GetStringFromObj(res, &length); - - /* - * Strip off any './' before a tilde, unless this is the - * beginning of the path. - */ - if (length > 0 && strEltLen > 0) { - if ((strElt[0] == '.') && (strElt[1] == '/') - && (strElt[2] == '~')) { - strElt += 2; - } - } - - /* - * A NULL value for fsPtr at this stage basically means - * we're trying to join a relative path onto something - * which is also relative (or empty). There's nothing - * particularly wrong with that. - */ - if (*strElt == '\0') continue; - - if (fsPtr == &tclNativeFilesystem || fsPtr == NULL) { - TclpNativeJoinPath(res, strElt); - } else { - char separator = '/'; - int needsSep = 0; - - if (fsPtr->filesystemSeparatorProc != NULL) { - Tcl_Obj *sep = (*fsPtr->filesystemSeparatorProc)(res); - if (sep != NULL) { - separator = Tcl_GetString(sep)[0]; - } - } - - if (length > 0 && ptr[length -1] != '/') { - Tcl_AppendToObj(res, &separator, 1); - length++; - } - Tcl_SetObjLength(res, length + (int) strlen(strElt)); - - ptr = Tcl_GetString(res) + length; - for (; *strElt != '\0'; strElt++) { - if (*strElt == separator) { - while (strElt[1] == separator) { - strElt++; - } - if (strElt[1] != '\0') { - if (needsSep) { - *ptr++ = separator; - } - } - } else { - *ptr++ = *strElt; - needsSep = 1; - } - } - length = ptr - Tcl_GetString(res); - Tcl_SetObjLength(res, length); - } - } - return res; +TclFSInternalToNormalized(fromFilesystem, clientData, fsRecPtrPtr) + Tcl_Filesystem *fromFilesystem; + ClientData clientData; + FilesystemRecord **fsRecPtrPtr; +{ + FilesystemRecord *fsRecPtr = FsGetFirstFilesystem(); + + while (fsRecPtr != NULL) { + if (fsRecPtr->fsPtr == fromFilesystem) { + *fsRecPtrPtr = fsRecPtr; + break; + } + fsRecPtr = fsRecPtr->nextPtr; + } + + if ((fsRecPtr != NULL) + && (fromFilesystem->internalToNormalizedProc != NULL)) { + return (*fromFilesystem->internalToNormalizedProc)(clientData); + } else { + return NULL; + } } /* *---------------------------------------------------------------------- * @@ -3393,11 +3462,11 @@ * whether the given path is an absolute path on any of the volumes * returned (this is done by checking whether the path's prefix * matches). */ - fsRecPtr = FsGetIterator(); + fsRecPtr = FsGetFirstFilesystem(); while (fsRecPtr != NULL) { Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc; /* * We want to skip the native filesystem in this loop because * otherwise we won't necessarily pass all the Tcl testsuite -- @@ -3467,11 +3536,10 @@ } } } fsRecPtr = fsRecPtr->nextPtr; } - FsReleaseIterator(); if (type != TCL_PATH_ABSOLUTE) { type = TclpGetNativePathType(pathObjPtr, driveNameLengthPtr, driveNameRef); if ((type == TCL_PATH_ABSOLUTE) && (filesystemPtrPtr != NULL)) { @@ -3808,1139 +3876,83 @@ } /* *--------------------------------------------------------------------------- * - * Tcl_FSConvertToPathType -- - * - * This function 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. - * - * The filename may begin with "~" (to indicate current user's - * home directory) or "~" (to indicate any user's home - * directory). - * - * Results: - * Standard Tcl error code. - * - * Side effects: - * The old representation may be freed, and new memory allocated. - * - *--------------------------------------------------------------------------- - */ -int -Tcl_FSConvertToPathType(interp, objPtr) - Tcl_Interp *interp; /* Interpreter in which to store error - * message (if necessary). */ - Tcl_Obj *objPtr; /* Object to convert to a valid, current - * path type. */ -{ - /* - * While it is bad practice to examine an object's type directly, - * this is actually the best thing to do here. The reason is that - * if we are converting this object to FsPath type for the first - * time, we don't need to worry whether the 'cwd' has changed. - * On the other hand, if this object is already of FsPath type, - * and is a relative path, we do have to worry about the cwd. - * If the cwd has changed, we must recompute the path. - */ - if (objPtr->typePtr == &tclFsPathType) { - FsPath *fsPathPtr = (FsPath*) objPtr->internalRep.otherValuePtr; - if (fsPathPtr->filesystemEpoch != theFilesystemEpoch) { - if (objPtr->bytes == NULL) { - UpdateStringOfFsPath(objPtr); - } - FreeFsPathInternalRep(objPtr); - objPtr->typePtr = NULL; - return Tcl_ConvertToType(interp, objPtr, &tclFsPathType); - } - return TCL_OK; - /* - * This code is intentionally never reached. Once fs-optimisation - * is complete, it will be removed/replaced - */ - if (fsPathPtr->cwdPtr == NULL) { - return TCL_OK; - } else { - if (FsCwdPointerEquals(fsPathPtr->cwdPtr)) { - return TCL_OK; - } else { - if (objPtr->bytes == NULL) { - UpdateStringOfFsPath(objPtr); - } - FreeFsPathInternalRep(objPtr); - objPtr->typePtr = NULL; - return Tcl_ConvertToType(interp, objPtr, &tclFsPathType); - } - } - } else { - return Tcl_ConvertToType(interp, objPtr, &tclFsPathType); - } -} - - -/* - * Helper function for SetFsPathFromAny. Returns position of first - * directory delimiter in the path. - */ -static int -FindSplitPos(path, separator) - char *path; - char *separator; -{ - int count = 0; - switch (tclPlatform) { - case TCL_PLATFORM_UNIX: - case TCL_PLATFORM_MAC: - while (path[count] != 0) { - if (path[count] == *separator) { - return count; - } - count++; - } - break; - - case TCL_PLATFORM_WINDOWS: - while (path[count] != 0) { - if (path[count] == *separator || path[count] == '\\') { - return count; - } - count++; - } - break; - } - return count; -} - -/* - *--------------------------------------------------------------------------- - * - * UpdateStringOfFsPath -- - * - * Gives an object a valid string rep. - * - * Results: - * None. - * - * Side effects: - * Memory may be allocated. - * - *--------------------------------------------------------------------------- - */ - -static void -UpdateStringOfFsPath(objPtr) - register Tcl_Obj *objPtr; /* path obj with string rep to update. */ -{ - register FsPath* fsPathPtr = - (FsPath*) objPtr->internalRep.otherValuePtr; - CONST char *cwdStr; - int cwdLen; - Tcl_Obj *copy; - - if (fsPathPtr->flags == 0 || fsPathPtr->cwdPtr == NULL) { - panic("Called UpdateStringOfFsPath with invalid object"); - } - - copy = Tcl_DuplicateObj(fsPathPtr->cwdPtr); - Tcl_IncrRefCount(copy); - - cwdStr = Tcl_GetStringFromObj(copy, &cwdLen); - /* - * Should we perhaps use 'Tcl_FSPathSeparator'? - * But then what about the Windows special case? - * Perhaps we should just check if cwd is a root volume. - * We should never get cwdLen == 0 in this code path. - */ - switch (tclPlatform) { - case TCL_PLATFORM_UNIX: - if (cwdStr[cwdLen-1] != '/') { - Tcl_AppendToObj(copy, "/", 1); - cwdLen++; - } - break; - case TCL_PLATFORM_WINDOWS: - /* - * We need the extra 'cwdLen != 2', and ':' checks because - * a volume relative path doesn't get a '/'. For example - * 'glob C:*cat*.exe' will return 'C:cat32.exe' - */ - if (cwdStr[cwdLen-1] != '/' - && cwdStr[cwdLen-1] != '\\') { - if (cwdLen != 2 || cwdStr[1] != ':') { - Tcl_AppendToObj(copy, "/", 1); - cwdLen++; - } - } - break; - case TCL_PLATFORM_MAC: - if (cwdStr[cwdLen-1] != ':') { - Tcl_AppendToObj(copy, ":", 1); - cwdLen++; - } - break; - } - Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr); - objPtr->bytes = Tcl_GetStringFromObj(copy, &cwdLen); - objPtr->length = cwdLen; - copy->bytes = tclEmptyStringRep; - copy->length = 0; - Tcl_DecrRefCount(copy); -} - -/* - *--------------------------------------------------------------------------- - * - * TclNewFSPathObj -- - * - * Creates a path object whose string representation is - * '[file join dirPtr addStrRep]', but does so in a way that - * allows for more efficient caching of normalized paths. - * - * Assumptions: - * 'dirPtr' must be an absolute path. - * 'len' may not be zero. - * - * Results: - * The new Tcl object. - * - * Side effects: - * Memory is allocated. 'dirPtr' gets an additional refCount. - * - *--------------------------------------------------------------------------- - */ - -Tcl_Obj* -TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len) -{ - FsPath *fsPathPtr; - Tcl_Obj *objPtr; - - objPtr = Tcl_NewObj(); - fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); - - if (tclPlatform == TCL_PLATFORM_MAC) { - /* - * Mac relative paths may begin with a directory separator ':'. - * If present, we need to skip this ':' because we assume that - * we can join dirPtr and addStrRep by concatenating them as - * strings (and we ensure that dirPtr is terminated by a ':'). - */ - if (addStrRep[0] == ':') { - addStrRep++; - len--; - } - } - /* Setup the path */ - fsPathPtr->translatedPathPtr = NULL; - fsPathPtr->normPathPtr = Tcl_NewStringObj(addStrRep, len); - Tcl_IncrRefCount(fsPathPtr->normPathPtr); - fsPathPtr->cwdPtr = dirPtr; - Tcl_IncrRefCount(dirPtr); - fsPathPtr->flags = TCLPATH_RELATIVE | TCLPATH_APPENDED; - fsPathPtr->nativePathPtr = NULL; - fsPathPtr->fsRecPtr = NULL; - fsPathPtr->filesystemEpoch = theFilesystemEpoch; - - objPtr->internalRep.otherValuePtr = (VOID *) fsPathPtr; - objPtr->typePtr = &tclFsPathType; - objPtr->bytes = NULL; - objPtr->length = 0; - return objPtr; -} - -/* - *--------------------------------------------------------------------------- - * - * MakeFsPathFromRelative -- - * - * Like SetFsPathFromAny, but assumes the given object is an - * absolute normalized path. Only for internal use. - * - * Results: - * Standard Tcl error code. - * - * Side effects: - * The old representation may be freed, and new memory allocated. - * - *--------------------------------------------------------------------------- - */ - -static Tcl_Obj* -MakeFsPathFromRelative(interp, objPtr, cwdPtr) - Tcl_Interp *interp; /* Used for error reporting if not NULL. */ - Tcl_Obj *objPtr; /* The object to convert. */ - Tcl_Obj *cwdPtr; /* The object to convert. */ -{ - FsPath *fsPathPtr; - - /* Free old representation */ - if (objPtr->typePtr != NULL) { - if (objPtr->bytes == NULL) { - if (objPtr->typePtr->updateStringProc == NULL) { - if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "can't find object", - "string representation", (char *) NULL); - } - return NULL; - } - objPtr->typePtr->updateStringProc(objPtr); - } - if ((objPtr->typePtr->freeIntRepProc) != NULL) { - (*objPtr->typePtr->freeIntRepProc)(objPtr); - } - } - - fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); - - /* Circular reference, by design */ - fsPathPtr->translatedPathPtr = objPtr; - fsPathPtr->normPathPtr = NULL; - fsPathPtr->flags = 0; - fsPathPtr->cwdPtr = cwdPtr; - Tcl_IncrRefCount(cwdPtr); - fsPathPtr->nativePathPtr = NULL; - fsPathPtr->fsRecPtr = NULL; - fsPathPtr->filesystemEpoch = theFilesystemEpoch; - - objPtr->internalRep.otherValuePtr = (VOID *) fsPathPtr; - objPtr->typePtr = &tclFsPathType; - - return objPtr; -} - -/* - *--------------------------------------------------------------------------- - * - * SetFsPathFromAbsoluteNormalized -- - * - * Like SetFsPathFromAny, but assumes the given object is an - * absolute normalized path. Only for internal use. - * - * Results: - * Standard Tcl error code. - * - * Side effects: - * The old representation may be freed, and new memory allocated. - * - *--------------------------------------------------------------------------- - */ - -static int -SetFsPathFromAbsoluteNormalized(interp, objPtr) - Tcl_Interp *interp; /* Used for error reporting if not NULL. */ - Tcl_Obj *objPtr; /* The object to convert. */ -{ - FsPath *fsPathPtr; - - if (objPtr->typePtr == &tclFsPathType) { - return TCL_OK; - } - - /* Free old representation */ - if (objPtr->typePtr != NULL) { - if (objPtr->bytes == NULL) { - if (objPtr->typePtr->updateStringProc == NULL) { - if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "can't find object", - "string representation", (char *) NULL); - } - return TCL_ERROR; - } - objPtr->typePtr->updateStringProc(objPtr); - } - if ((objPtr->typePtr->freeIntRepProc) != NULL) { - (*objPtr->typePtr->freeIntRepProc)(objPtr); - } - } - - fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); - /* It's a pure normalized absolute path */ - fsPathPtr->translatedPathPtr = NULL; - fsPathPtr->normPathPtr = objPtr; - fsPathPtr->flags = 0; - fsPathPtr->cwdPtr = NULL; - fsPathPtr->nativePathPtr = NULL; - fsPathPtr->fsRecPtr = NULL; - fsPathPtr->filesystemEpoch = theFilesystemEpoch; - - objPtr->internalRep.otherValuePtr = (VOID *) fsPathPtr; - objPtr->typePtr = &tclFsPathType; - - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * SetFsPathFromAny -- - * - * This function tries to convert the given Tcl_Obj to a valid - * Tcl path type. - * - * The filename may begin with "~" (to indicate current user's - * home directory) or "~" (to indicate any user's home - * directory). - * - * Results: - * Standard Tcl error code. - * - * Side effects: - * The old representation may be freed, and new memory allocated. - * - *--------------------------------------------------------------------------- - */ - -static int -SetFsPathFromAny(interp, objPtr) - Tcl_Interp *interp; /* Used for error reporting if not NULL. */ - Tcl_Obj *objPtr; /* The object to convert. */ -{ - int len; - FsPath *fsPathPtr; - Tcl_Obj *transPtr; - char *name; - - if (objPtr->typePtr == &tclFsPathType) { - return TCL_OK; - } - - /* - * First step is to translate the filename. This is similar to - * Tcl_TranslateFilename, but shouldn't convert everything to - * windows backslashes on that platform. The current - * implementation of this piece is a slightly optimised version - * of the various Tilde/Split/Join stuff to avoid multiple - * split/join operations. - * - * We remove any trailing directory separator. - * - * However, the split/join routines are quite complex, and - * one has to make sure not to break anything on Unix, Win - * or MacOS (fCmd.test, fileName.test and cmdAH.test exercise - * most of the code). - */ - name = Tcl_GetStringFromObj(objPtr,&len); - - /* - * Handle tilde substitutions, if needed. - */ - if (name[0] == '~') { - char *expandedUser; - Tcl_DString temp; - int split; - char separator='/'; - - if (tclPlatform==TCL_PLATFORM_MAC) { - if (strchr(name, ':') != NULL) separator = ':'; - } - - split = FindSplitPos(name, &separator); - if (split != len) { - /* We have multiple pieces '~user/foo/bar...' */ - name[split] = '\0'; - } - /* Do some tilde substitution */ - if (name[1] == '\0') { - /* We have just '~' */ - CONST char *dir; - Tcl_DString dirString; - if (split != len) { name[split] = separator; } - - dir = TclGetEnv("HOME", &dirString); - if (dir == NULL) { - if (interp) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't find HOME environment ", - "variable to expand path", (char *) NULL); - } - return TCL_ERROR; - } - Tcl_DStringInit(&temp); - Tcl_JoinPath(1, &dir, &temp); - Tcl_DStringFree(&dirString); - } else { - /* We have a user name '~user' */ - Tcl_DStringInit(&temp); - if (TclpGetUserHome(name+1, &temp) == NULL) { - if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "user \"", (name+1), - "\" doesn't exist", (char *) NULL); - } - Tcl_DStringFree(&temp); - if (split != len) { name[split] = separator; } - return TCL_ERROR; - } - if (split != len) { name[split] = separator; } - } - - expandedUser = Tcl_DStringValue(&temp); - transPtr = Tcl_NewStringObj(expandedUser, Tcl_DStringLength(&temp)); - - if (split != len) { - /* Join up the tilde substitution with the rest */ - if (name[split+1] == separator) { - - /* - * Somewhat tricky case like ~//foo/bar. - * Make use of Split/Join machinery to get it right. - * Assumes all paths beginning with ~ are part of the - * native filesystem. - */ - - int objc; - Tcl_Obj **objv; - Tcl_Obj *parts = TclpNativeSplitPath(objPtr, NULL); - Tcl_ListObjGetElements(NULL, parts, &objc, &objv); - /* Skip '~'. It's replaced by its expansion */ - objc--; objv++; - while (objc--) { - TclpNativeJoinPath(transPtr, Tcl_GetString(*objv++)); - } - Tcl_DecrRefCount(parts); - } else { - /* Simple case. "rest" is relative path. Just join it. */ - Tcl_Obj *rest = Tcl_NewStringObj(name+split+1,-1); - transPtr = Tcl_FSJoinToPath(transPtr, 1, &rest); - } - } - Tcl_DStringFree(&temp); - } else { - transPtr = Tcl_FSJoinToPath(objPtr,0,NULL); - } - - /* - * Now we have a translated filename in 'transPtr'. This will have - * forward slashes on Windows, and will not contain any ~user - * sequences. - */ - - fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); - fsPathPtr->translatedPathPtr = transPtr; - Tcl_IncrRefCount(fsPathPtr->translatedPathPtr); - fsPathPtr->normPathPtr = NULL; - fsPathPtr->flags = 0; - fsPathPtr->cwdPtr = NULL; - fsPathPtr->nativePathPtr = NULL; - fsPathPtr->fsRecPtr = NULL; - fsPathPtr->filesystemEpoch = theFilesystemEpoch; - - /* - * Free old representation before installing our new one. - */ - if (objPtr->typePtr != NULL && objPtr->typePtr->freeIntRepProc != NULL) { - (objPtr->typePtr->freeIntRepProc)(objPtr); - } - objPtr->internalRep.otherValuePtr = (VOID *) fsPathPtr; - objPtr->typePtr = &tclFsPathType; - - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * Tcl_FSNewNativePath -- - * - * This function performs the something like that reverse of the - * usual obj->path->nativerep conversions. If some code retrieves - * a path in native form (from, e.g. readlink 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. - * - * Any memory which is allocated for 'clientData' should be retained - * until clientData is passed to the filesystem's freeInternalRepProc - * when it can be freed. The built in platform-specific filesystems - * use 'ckalloc' to allocate clientData, and ckfree to free it. - * - * Results: - * NULL or a valid path object pointer, with refCount zero. - * - * Side effects: - * New memory may be allocated. - * - *--------------------------------------------------------------------------- - */ - -Tcl_Obj * -Tcl_FSNewNativePath(fromFilesystem, clientData) - Tcl_Filesystem* fromFilesystem; - ClientData clientData; -{ - Tcl_Obj *objPtr; - FsPath *fsPathPtr; - FilesystemRecord *fsFromPtr; - Tcl_FSInternalToNormalizedProc *proc; - int epoch; - - fsFromPtr = GetFilesystemRecord(fromFilesystem, &epoch); - - if (fsFromPtr == NULL) { - return NULL; - } - - proc = fsFromPtr->fsPtr->internalToNormalizedProc; - - if (proc == NULL) { - return NULL; - } - - objPtr = (*proc)(clientData); - if (objPtr == NULL) { - return NULL; - } - - /* - * Free old representation; shouldn't normally be any, - * but best to be safe. - */ - if (objPtr->typePtr != NULL) { - if (objPtr->bytes == NULL) { - if (objPtr->typePtr->updateStringProc == NULL) { - return NULL; - } - objPtr->typePtr->updateStringProc(objPtr); - } - if ((objPtr->typePtr->freeIntRepProc) != NULL) { - (*objPtr->typePtr->freeIntRepProc)(objPtr); - } - } - - fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); - fsPathPtr->translatedPathPtr = NULL; - /* Circular reference, by design */ - fsPathPtr->normPathPtr = objPtr; - fsPathPtr->flags = 0; - fsPathPtr->cwdPtr = NULL; - fsPathPtr->nativePathPtr = clientData; - fsPathPtr->fsRecPtr = fsFromPtr; - /* We must increase the refCount for this filesystem. */ - fsPathPtr->fsRecPtr->fileRefCount++; - fsPathPtr->filesystemEpoch = epoch; - - objPtr->internalRep.otherValuePtr = (VOID *) fsPathPtr; - objPtr->typePtr = &tclFsPathType; - return objPtr; -} - -static void -FreeFsPathInternalRep(pathObjPtr) - Tcl_Obj *pathObjPtr; /* Path object with internal rep to free. */ -{ - register FsPath* fsPathPtr = - (FsPath*) pathObjPtr->internalRep.otherValuePtr; - - if (fsPathPtr->translatedPathPtr != NULL) { - if (fsPathPtr->translatedPathPtr != pathObjPtr) { - Tcl_DecrRefCount(fsPathPtr->translatedPathPtr); - } - } - if (fsPathPtr->normPathPtr != NULL) { - if (fsPathPtr->normPathPtr != pathObjPtr) { - Tcl_DecrRefCount(fsPathPtr->normPathPtr); - } - fsPathPtr->normPathPtr = NULL; - } - if (fsPathPtr->cwdPtr != NULL) { - Tcl_DecrRefCount(fsPathPtr->cwdPtr); - } - if (fsPathPtr->nativePathPtr != NULL) { - if (fsPathPtr->fsRecPtr != NULL) { - if (fsPathPtr->fsRecPtr->fsPtr->freeInternalRepProc != NULL) { - (*fsPathPtr->fsRecPtr->fsPtr - ->freeInternalRepProc)(fsPathPtr->nativePathPtr); - fsPathPtr->nativePathPtr = NULL; - } - } - } - if (fsPathPtr->fsRecPtr != NULL) { - fsPathPtr->fsRecPtr->fileRefCount--; - if (fsPathPtr->fsRecPtr->fileRefCount <= 0) { - /* It has been unregistered already */ - ckfree((char *)fsPathPtr->fsRecPtr); - } - } - - ckfree((char*) fsPathPtr); -} - -static void -DupFsPathInternalRep(srcPtr, copyPtr) - Tcl_Obj *srcPtr; /* Path obj with internal rep to copy. */ - Tcl_Obj *copyPtr; /* Path obj with internal rep to set. */ -{ - register FsPath* srcFsPathPtr = - (FsPath*) srcPtr->internalRep.otherValuePtr; - register FsPath* copyFsPathPtr = - (FsPath*) ckalloc((unsigned)sizeof(FsPath)); - Tcl_FSDupInternalRepProc *dupProc; - - copyPtr->internalRep.otherValuePtr = (VOID *) copyFsPathPtr; - - if (srcFsPathPtr->translatedPathPtr != NULL) { - copyFsPathPtr->translatedPathPtr = srcFsPathPtr->translatedPathPtr; - if (copyFsPathPtr->translatedPathPtr != copyPtr) { - Tcl_IncrRefCount(copyFsPathPtr->translatedPathPtr); - } - } else { - copyFsPathPtr->translatedPathPtr = NULL; - } - - if (srcFsPathPtr->normPathPtr != NULL) { - copyFsPathPtr->normPathPtr = srcFsPathPtr->normPathPtr; - if (copyFsPathPtr->normPathPtr != copyPtr) { - Tcl_IncrRefCount(copyFsPathPtr->normPathPtr); - } - } else { - copyFsPathPtr->normPathPtr = NULL; - } - - if (srcFsPathPtr->cwdPtr != NULL) { - copyFsPathPtr->cwdPtr = srcFsPathPtr->cwdPtr; - Tcl_IncrRefCount(copyFsPathPtr->cwdPtr); - } else { - copyFsPathPtr->cwdPtr = NULL; - } - - copyFsPathPtr->flags = srcFsPathPtr->flags; - - if (srcFsPathPtr->fsRecPtr != NULL - && srcFsPathPtr->nativePathPtr != NULL) { - dupProc = srcFsPathPtr->fsRecPtr->fsPtr->dupInternalRepProc; - if (dupProc != NULL) { - copyFsPathPtr->nativePathPtr = - (*dupProc)(srcFsPathPtr->nativePathPtr); - } else { - copyFsPathPtr->nativePathPtr = NULL; - } - } else { - copyFsPathPtr->nativePathPtr = NULL; - } - copyFsPathPtr->fsRecPtr = srcFsPathPtr->fsRecPtr; - copyFsPathPtr->filesystemEpoch = srcFsPathPtr->filesystemEpoch; - if (copyFsPathPtr->fsRecPtr != NULL) { - copyFsPathPtr->fsRecPtr->fileRefCount++; - } - - copyPtr->typePtr = &tclFsPathType; -} - -/* - *--------------------------------------------------------------------------- - * - * Tcl_FSGetTranslatedPath -- - * - * This function attempts to extract the translated path - * from the given Tcl_Obj. If the translation succeeds (i.e. the - * object is a valid path), then it is returned. Otherwise NULL - * will be returned, and an error message may be left in the - * interpreter (if it is non-NULL) - * - * Results: - * NULL or a valid Tcl_Obj pointer. - * - * Side effects: - * Only those of 'Tcl_FSConvertToPathType' - * - *--------------------------------------------------------------------------- - */ - -Tcl_Obj* -Tcl_FSGetTranslatedPath(interp, pathPtr) - Tcl_Interp *interp; - Tcl_Obj* pathPtr; -{ - register FsPath* srcFsPathPtr; - if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) { - return NULL; - } - srcFsPathPtr = (FsPath*) pathPtr->internalRep.otherValuePtr; - if (srcFsPathPtr->translatedPathPtr == NULL) { - if (srcFsPathPtr->flags != 0) { - return Tcl_FSGetNormalizedPath(interp, pathPtr); - } - /* - * It is a pure absolute, normalized path object. - * This is something like being a 'pure list'. The - * object's string, translatedPath and normalizedPath - * are all identical. - */ - return srcFsPathPtr->normPathPtr; - } else { - /* It is an ordinary path object */ - return srcFsPathPtr->translatedPathPtr; - } -} - -/* - *--------------------------------------------------------------------------- - * - * Tcl_FSGetTranslatedStringPath -- - * - * This function attempts to extract the translated path - * from the given Tcl_Obj. If the translation succeeds (i.e. the - * object is a valid path), then the path is returned. Otherwise NULL - * will be returned, and an error message may be left in the - * interpreter (if it is non-NULL) - * - * Results: - * NULL or a valid string. - * - * Side effects: - * Only those of 'Tcl_FSConvertToPathType' - * - *--------------------------------------------------------------------------- - */ -CONST char* -Tcl_FSGetTranslatedStringPath(interp, pathPtr) - Tcl_Interp *interp; - Tcl_Obj* pathPtr; -{ - Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(interp, pathPtr); - if (transPtr == NULL) { - return NULL; - } else { - return Tcl_GetString(transPtr); - } -} - -/* - *--------------------------------------------------------------------------- - * - * Tcl_FSGetNormalizedPath -- - * - * This important function attempts to extract from the given Tcl_Obj - * a unique normalised path representation, whose string value can - * be used as a unique identifier for the file. - * - * Results: - * NULL or a valid path object pointer. - * - * Side effects: - * New memory may be allocated. The Tcl 'errno' may be modified - * in the process of trying to examine various path possibilities. - * - *--------------------------------------------------------------------------- - */ - -Tcl_Obj* -Tcl_FSGetNormalizedPath(interp, pathObjPtr) - Tcl_Interp *interp; - Tcl_Obj* pathObjPtr; -{ - register FsPath* fsPathPtr; - if (Tcl_FSConvertToPathType(interp, pathObjPtr) != TCL_OK) { - return NULL; - } - fsPathPtr = (FsPath*) pathObjPtr->internalRep.otherValuePtr; - - if (fsPathPtr->flags != 0) { - /* - * This is a special path object which is the result of - * something like 'file join' - */ - Tcl_Obj *dir, *copy; - int cwdLen; - int pathType; - CONST char *cwdStr; - - pathType = Tcl_FSGetPathType(fsPathPtr->cwdPtr); - dir = Tcl_FSGetNormalizedPath(interp, fsPathPtr->cwdPtr); - if (dir == NULL) { - return NULL; - } - if (pathObjPtr->bytes == NULL) { - UpdateStringOfFsPath(pathObjPtr); - } - copy = Tcl_DuplicateObj(dir); - Tcl_IncrRefCount(copy); - Tcl_IncrRefCount(dir); - /* We now own a reference on both 'dir' and 'copy' */ - - cwdStr = Tcl_GetStringFromObj(copy, &cwdLen); - /* - * Should we perhaps use 'Tcl_FSPathSeparator'? - * But then what about the Windows special case? - * Perhaps we should just check if cwd is a root volume. - * We should never get cwdLen == 0 in this code path. - */ - switch (tclPlatform) { - case TCL_PLATFORM_UNIX: - if (cwdStr[cwdLen-1] != '/') { - Tcl_AppendToObj(copy, "/", 1); - cwdLen++; - } - break; - case TCL_PLATFORM_WINDOWS: - if (cwdStr[cwdLen-1] != '/' - && cwdStr[cwdLen-1] != '\\') { - Tcl_AppendToObj(copy, "/", 1); - cwdLen++; - } - break; - case TCL_PLATFORM_MAC: - if (cwdStr[cwdLen-1] != ':') { - Tcl_AppendToObj(copy, ":", 1); - cwdLen++; - } - break; - } - Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr); - /* - * Normalize the combined string, but only starting after - * the end of the previously normalized 'dir'. This should - * be much faster! We use 'cwdLen-1' so that we are - * already pointing at the dir-separator that we know about. - * The normalization code will actually start off directly - * after that separator. - */ - TclNormalizeToUniquePath(interp, copy, cwdLen-1); - /* Now we need to construct the new path object */ - - if (pathType == TCL_PATH_RELATIVE) { - register FsPath* origDirFsPathPtr; - Tcl_Obj *origDir = fsPathPtr->cwdPtr; - origDirFsPathPtr = (FsPath*) origDir->internalRep.otherValuePtr; - - fsPathPtr->cwdPtr = origDirFsPathPtr->cwdPtr; - Tcl_IncrRefCount(fsPathPtr->cwdPtr); - - Tcl_DecrRefCount(fsPathPtr->normPathPtr); - fsPathPtr->normPathPtr = copy; - /* That's our reference to copy used */ - Tcl_DecrRefCount(dir); - Tcl_DecrRefCount(origDir); - } else { - Tcl_DecrRefCount(fsPathPtr->cwdPtr); - fsPathPtr->cwdPtr = NULL; - Tcl_DecrRefCount(fsPathPtr->normPathPtr); - fsPathPtr->normPathPtr = copy; - /* That's our reference to copy used */ - Tcl_DecrRefCount(dir); - } - fsPathPtr->flags = 0; - } - /* Ensure cwd hasn't changed */ - if (fsPathPtr->cwdPtr != NULL) { - if (!FsCwdPointerEquals(fsPathPtr->cwdPtr)) { - if (pathObjPtr->bytes == NULL) { - UpdateStringOfFsPath(pathObjPtr); - } - FreeFsPathInternalRep(pathObjPtr); - pathObjPtr->typePtr = NULL; - if (Tcl_ConvertToType(interp, pathObjPtr, - &tclFsPathType) != TCL_OK) { - return NULL; - } - fsPathPtr = (FsPath*) pathObjPtr->internalRep.otherValuePtr; - } else if (fsPathPtr->normPathPtr == NULL) { - int cwdLen; - Tcl_Obj *copy; - CONST char *cwdStr; - - copy = Tcl_DuplicateObj(fsPathPtr->cwdPtr); - Tcl_IncrRefCount(copy); - cwdStr = Tcl_GetStringFromObj(copy, &cwdLen); - /* - * Should we perhaps use 'Tcl_FSPathSeparator'? - * But then what about the Windows special case? - * Perhaps we should just check if cwd is a root volume. - * We should never get cwdLen == 0 in this code path. - */ - switch (tclPlatform) { - case TCL_PLATFORM_UNIX: - if (cwdStr[cwdLen-1] != '/') { - Tcl_AppendToObj(copy, "/", 1); - cwdLen++; - } - break; - case TCL_PLATFORM_WINDOWS: - if (cwdStr[cwdLen-1] != '/' - && cwdStr[cwdLen-1] != '\\') { - Tcl_AppendToObj(copy, "/", 1); - cwdLen++; - } - break; - case TCL_PLATFORM_MAC: - if (cwdStr[cwdLen-1] != ':') { - Tcl_AppendToObj(copy, ":", 1); - cwdLen++; - } - break; - } - Tcl_AppendObjToObj(copy, pathObjPtr); - /* - * Normalize the combined string, but only starting after - * the end of the previously normalized 'dir'. This should - * be much faster! - */ - TclNormalizeToUniquePath(interp, copy, cwdLen-1); - fsPathPtr->normPathPtr = copy; - } - } - if (fsPathPtr->normPathPtr == NULL) { - int relative = 0; - /* - * Since normPathPtr is NULL, but this is a valid path - * object, we know that the translatedPathPtr cannot be NULL. - */ - Tcl_Obj *absolutePath = fsPathPtr->translatedPathPtr; - char *path = Tcl_GetString(absolutePath); - - /* - * We have to be a little bit careful here to avoid infinite loops - * we're asking Tcl_FSGetPathType to return the path's type, but - * that call can actually result in a lot of other filesystem - * action, which might loop back through here. - */ - if ((path[0] != '\0') && - (Tcl_FSGetPathType(pathObjPtr) == TCL_PATH_RELATIVE)) { - Tcl_Obj *cwd = Tcl_FSGetCwd(interp); - - if (cwd == NULL) { - return NULL; - } - - absolutePath = Tcl_FSJoinToPath(cwd, 1, &absolutePath); - Tcl_IncrRefCount(absolutePath); - Tcl_DecrRefCount(cwd); - - relative = 1; - } - /* Already has refCount incremented */ - fsPathPtr->normPathPtr = FSNormalizeAbsolutePath(interp, absolutePath); - if (!strcmp(Tcl_GetString(fsPathPtr->normPathPtr), - Tcl_GetString(pathObjPtr))) { - /* - * The path was already normalized. - * Get rid of the duplicate. - */ - Tcl_DecrRefCount(fsPathPtr->normPathPtr); - /* - * We do *not* increment the refCount for - * this circular reference - */ - fsPathPtr->normPathPtr = pathObjPtr; - } - if (relative) { - /* This was returned by Tcl_FSJoinToPath above */ - Tcl_DecrRefCount(absolutePath); - - /* Get a quick, temporary lock on the cwd while we copy it */ - Tcl_MutexLock(&cwdMutex); - fsPathPtr->cwdPtr = cwdPathPtr; - Tcl_IncrRefCount(fsPathPtr->cwdPtr); - Tcl_MutexUnlock(&cwdMutex); - } - } - return fsPathPtr->normPathPtr; -} - -/* - *--------------------------------------------------------------------------- - * - * Tcl_FSGetInternalRep -- - * - * Extract the internal representation of a given path object, - * in the given filesystem. If the path object 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 - * 'Tcl_FSCreateInternalRepProc'. - * - * Results: - * NULL or a valid internal representation. - * - * Side effects: - * An attempt may be made to convert the object. - * - *--------------------------------------------------------------------------- - */ - -ClientData -Tcl_FSGetInternalRep(pathObjPtr, fsPtr) - Tcl_Obj* pathObjPtr; - Tcl_Filesystem *fsPtr; -{ - register FsPath* srcFsPathPtr; - - if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) { - return NULL; - } - srcFsPathPtr = (FsPath*) pathObjPtr->internalRep.otherValuePtr; - - /* - * We will only return the native representation for the caller's - * filesystem. Otherwise we will simply return NULL. This means - * that there must be a unique bi-directional mapping between paths - * and filesystems, and that this mapping will not allow 'remapped' - * files -- files which are in one filesystem but mapped into - * another. Another way of putting this is that 'stacked' - * filesystems are not allowed. We recognise that this is a - * potentially useful feature for the future. - * - * Even something simple like a 'pass through' filesystem which - * logs all activity and passes the calls onto the native system - * would be nice, but not easily achievable with the current - * implementation. - */ - if (srcFsPathPtr->fsRecPtr == NULL) { - /* - * This only usually happens in wrappers like TclpStat which - * create a string object and pass it to TclpObjStat. Code - * which calls the Tcl_FS.. functions should always have a - * filesystem already set. Whether this code path is legal or - * not depends on whether we decide to allow external code to - * call the native filesystem directly. It is at least safer - * to allow this sub-optimal routing. - */ - Tcl_FSGetFileSystemForPath(pathObjPtr); - - /* - * If we fail through here, then the path is probably not a - * valid path in the filesystsem, and is most likely to be a - * use of the empty path "" via a direct call to one of the - * objectified interfaces (e.g. from the Tcl testsuite). - */ - srcFsPathPtr = (FsPath*) pathObjPtr->internalRep.otherValuePtr; - if (srcFsPathPtr->fsRecPtr == NULL) { - return NULL; - } - } - - if (fsPtr != srcFsPathPtr->fsRecPtr->fsPtr) { - /* - * There is still one possibility we should consider; if the - * file belongs to a different filesystem, perhaps it is - * actually linked through to a file in our own filesystem - * which we do care about. The way we can check for this - * is we ask what filesystem this path belongs to. - */ - Tcl_Filesystem *actualFs = Tcl_FSGetFileSystemForPath(pathObjPtr); - if (actualFs == fsPtr) { - return Tcl_FSGetInternalRep(pathObjPtr, fsPtr); - } - return NULL; - } - - if (srcFsPathPtr->nativePathPtr == NULL) { - Tcl_FSCreateInternalRepProc *proc; - proc = srcFsPathPtr->fsRecPtr->fsPtr->createInternalRepProc; - - if (proc == NULL) { - return NULL; - } - srcFsPathPtr->nativePathPtr = (*proc)(pathObjPtr); - } - return srcFsPathPtr->nativePathPtr; + * Tcl_FSGetFileSystemForPath -- + * + * This function determines which filesystem to use for a + * particular path object, and returns the filesystem which + * accepts this file. If no filesystem will accept this object + * as a valid file path, then NULL is returned. + * + * Results: +.* NULL or a filesystem which will accept this path. + * + * Side effects: + * The object may be converted to a path type. + * + *--------------------------------------------------------------------------- + */ + +Tcl_Filesystem* +Tcl_FSGetFileSystemForPath(pathObjPtr) + Tcl_Obj* pathObjPtr; +{ + FilesystemRecord *fsRecPtr; + Tcl_Filesystem* retVal = NULL; + + /* + * If the object has a refCount of zero, we reject it. This + * is to avoid possible segfaults or nondeterministic memory + * leaks (i.e. the user doesn't know if they should decrement + * the ref count on return or not). + */ + + if (pathObjPtr->refCount == 0) { + panic("Tcl_FSGetFileSystemForPath called with object with refCount == 0"); + return NULL; + } + + /* + * Check if the filesystem has changed in some way since + * this object's internal representation was calculated. + * Before doing that, assure we have the most up-to-date + * copy of the master filesystem. This is accomplished + * by the FsGetFirstFilesystem() call. + */ + + fsRecPtr = FsGetFirstFilesystem(); + + if (TclFSEnsureEpochOk(pathObjPtr, &retVal) != TCL_OK) { + return NULL; + } + + /* + * Call each of the "pathInFilesystem" functions in succession. A + * non-return value of -1 indicates the particular function has + * succeeded. + */ + + while ((retVal == NULL) && (fsRecPtr != NULL)) { + Tcl_FSPathInFilesystemProc *proc = fsRecPtr->fsPtr->pathInFilesystemProc; + if (proc != NULL) { + ClientData clientData = NULL; + int ret = (*proc)(pathObjPtr, &clientData); + if (ret != -1) { + /* + * We assume the type of pathObjPtr hasn't been changed + * by the above call to the pathInFilesystemProc. + */ + TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData); + retVal = fsRecPtr->fsPtr; + } + } + fsRecPtr = fsRecPtr->nextPtr; + } + + return retVal; } /* *--------------------------------------------------------------------------- * @@ -5005,10 +4017,13 @@ int len; char *str; /* Make sure the normalized path is set */ validPathObjPtr = Tcl_FSGetNormalizedPath(NULL, pathObjPtr); + if (validPathObjPtr == NULL) { + return NULL; + } str = Tcl_GetStringFromObj(validPathObjPtr, &len); #ifdef __WIN32__ Tcl_WinUtfToTChar(str, len, &ds); if (tclWinProcs->useWide) { @@ -5020,11 +4035,11 @@ Tcl_UtfToExternalDString(NULL, str, len, &ds); len = Tcl_DStringLength(&ds) + sizeof(char); #endif nativePathPtr = ckalloc((unsigned) len); memcpy((VOID*)nativePathPtr, (VOID*)Tcl_DStringValue(&ds), (size_t) len); - + Tcl_DStringFree(&ds); return (ClientData)nativePathPtr; } /* @@ -5086,11 +4101,11 @@ /* *--------------------------------------------------------------------------- * - * NativeDupInternalRep -- + * TclNativeDupInternalRep -- * * Duplicate the native representation. * * Results: * The copied native representation, or NULL if it is not possible @@ -5099,12 +4114,12 @@ * Side effects: * None. * *--------------------------------------------------------------------------- */ -static ClientData -NativeDupInternalRep(clientData) +ClientData +TclNativeDupInternalRep(clientData) ClientData clientData; { ClientData copy; size_t len; @@ -5127,47 +4142,10 @@ copy = (ClientData) ckalloc(len); memcpy((VOID*)copy, (VOID*)clientData, len); return copy; } - -/* - *--------------------------------------------------------------------------- - * - * NativePathInFilesystem -- - * - * Any path object is acceptable to the native filesystem, by - * default (we will throw errors when illegal paths are actually - * tried to be used). - * - * However, this behavior means the native filesystem must be - * the last filesystem in the lookup list (otherwise it will - * claim all files belong to it, and other filesystems will - * never get a look in). - * - * Results: - * TCL_OK, to indicate 'yes', -1 to indicate no. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ -static int -NativePathInFilesystem(pathPtr, clientDataPtr) - Tcl_Obj *pathPtr; - ClientData *clientDataPtr; -{ - int len; - Tcl_GetStringFromObj(pathPtr,&len); - if (len == 0) { - return -1; - } else { - /* We accept any path as valid */ - return TCL_OK; - } -} /* *--------------------------------------------------------------------------- * * NativeFreeInternalRep -- @@ -5301,207 +4279,10 @@ separator = ":"; break; } return Tcl_NewStringObj(separator,1); } - -/* - *--------------------------------------------------------------------------- - * - * Tcl_FSGetFileSystemForPath -- - * - * This function determines which filesystem to use for a - * particular path object, and returns the filesystem which - * accepts this file. If no filesystem will accept this object - * as a valid file path, then NULL is returned. - * - * Results: -.* NULL or a filesystem which will accept this path. - * - * Side effects: - * The object may be converted to a path type. - * - *--------------------------------------------------------------------------- - */ - -Tcl_Filesystem* -Tcl_FSGetFileSystemForPath(pathObjPtr) - Tcl_Obj* pathObjPtr; -{ - FilesystemRecord *fsRecPtr; - Tcl_Filesystem* retVal = NULL; - FsPath* srcFsPathPtr; - - /* - * If the object has a refCount of zero, we reject it. This - * is to avoid possible segfaults or nondeterministic memory - * leaks (i.e. the user doesn't know if they should decrement - * the ref count on return or not). - */ - - if (pathObjPtr->refCount == 0) { - panic("Tcl_FSGetFileSystemForPath called with object with refCount == 0"); - return NULL; - } - - /* - * This will ensure the pathObjPtr can be converted into a - * "path" type, and that we are able to generate a complete - * normalized path which is used to determine the filesystem - * match. - */ - - if (Tcl_FSGetNormalizedPath(NULL, pathObjPtr) == NULL) { - return NULL; - } - - /* - * Get a lock on theFilesystemEpoch and the filesystemList - * - * While we don't need the fsRecPtr until the while loop below, we - * do want to make sure the theFilesystemEpoch doesn't change - * between the 'if' and 'while' blocks, getting this iterator will - * ensure that everything is consistent - */ - fsRecPtr = FsGetIterator(); - - /* Make sure pathObjPtr is of the correct epoch */ - - srcFsPathPtr = (FsPath*) pathObjPtr->internalRep.otherValuePtr; - - /* - * Check if the filesystem has changed in some way since - * this object's internal representation was calculated. - */ - if (srcFsPathPtr->filesystemEpoch != theFilesystemEpoch) { - /* - * We have to discard the stale representation and - * recalculate it - */ - if (pathObjPtr->bytes == NULL) { - UpdateStringOfFsPath(pathObjPtr); - } - FreeFsPathInternalRep(pathObjPtr); - pathObjPtr->typePtr = NULL; - if (SetFsPathFromAny(NULL, pathObjPtr) != TCL_OK) { - goto done; - } - srcFsPathPtr = (FsPath*) pathObjPtr->internalRep.otherValuePtr; - } - - /* Check whether the object is already assigned to a fs */ - if (srcFsPathPtr->fsRecPtr != NULL) { - retVal = srcFsPathPtr->fsRecPtr->fsPtr; - goto done; - } - - /* - * Call each of the "pathInFilesystem" functions in succession. A - * non-return value of -1 indicates the particular function has - * succeeded. - */ - - while ((retVal == NULL) && (fsRecPtr != NULL)) { - Tcl_FSPathInFilesystemProc *proc = fsRecPtr->fsPtr->pathInFilesystemProc; - if (proc != NULL) { - ClientData clientData = NULL; - int ret = (*proc)(pathObjPtr, &clientData); - if (ret != -1) { - /* - * We assume the srcFsPathPtr hasn't been changed - * by the above call to the pathInFilesystemProc. - */ - srcFsPathPtr->fsRecPtr = fsRecPtr; - srcFsPathPtr->nativePathPtr = clientData; - srcFsPathPtr->filesystemEpoch = theFilesystemEpoch; - fsRecPtr->fileRefCount++; - retVal = fsRecPtr->fsPtr; - } - } - fsRecPtr = fsRecPtr->nextPtr; - } - - done: - FsReleaseIterator(); - return retVal; -} - -/* Simple helper function */ -static FilesystemRecord* -GetFilesystemRecord(fromFilesystem, epoch) - Tcl_Filesystem *fromFilesystem; - int *epoch; -{ - FilesystemRecord *fsRecPtr = FsGetIterator(); - while (fsRecPtr != NULL) { - if (fsRecPtr->fsPtr == fromFilesystem) { - *epoch = theFilesystemEpoch; - break; - } - fsRecPtr = fsRecPtr->nextPtr; - } - FsReleaseIterator(); - return fsRecPtr; -} - -/* - *--------------------------------------------------------------------------- - * - * Tcl_FSEqualPaths -- - * - * This function tests whether the two paths given are equal path - * objects. If either or both is NULL, 0 is always returned. - * - * Results: - * 1 or 0. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ - -int -Tcl_FSEqualPaths(firstPtr, secondPtr) - Tcl_Obj* firstPtr; - Tcl_Obj* secondPtr; -{ - if (firstPtr == secondPtr) { - return 1; - } else { - char *firstStr, *secondStr; - int firstLen, secondLen, tempErrno; - - if (firstPtr == NULL || secondPtr == NULL) { - return 0; - } - firstStr = Tcl_GetStringFromObj(firstPtr, &firstLen); - secondStr = Tcl_GetStringFromObj(secondPtr, &secondLen); - if ((firstLen == secondLen) && (strcmp(firstStr, secondStr) == 0)) { - return 1; - } - /* - * Try the most thorough, correct method of comparing fully - * normalized paths - */ - - tempErrno = Tcl_GetErrno(); - firstPtr = Tcl_FSGetNormalizedPath(NULL, firstPtr); - secondPtr = Tcl_FSGetNormalizedPath(NULL, secondPtr); - Tcl_SetErrno(tempErrno); - - if (firstPtr == NULL || secondPtr == NULL) { - return 0; - } - firstStr = Tcl_GetStringFromObj(firstPtr, &firstLen); - secondStr = Tcl_GetStringFromObj(secondPtr, &secondLen); - if ((firstLen == secondLen) && (strcmp(firstStr, secondStr) == 0)) { - return 1; - } - } - return 0; -} /* Everything from here on is contained in this obsolete ifdef */ #ifdef USE_OBSOLETE_FS_HOOKS /* @@ -5546,11 +4327,11 @@ retVal = TCL_OK; } } - return (retVal); + return retVal; } /* *---------------------------------------------------------------------- * @@ -5602,11 +4383,12 @@ tmpStatProcPtr = tmpStatProcPtr->nextPtr; } } Tcl_MutexUnlock(&obsoleteFsHookMutex); - return (retVal); + + return retVal; } /* *---------------------------------------------------------------------- * @@ -5650,11 +4432,11 @@ retVal = TCL_OK; } } - return (retVal); + return retVal; } /* *---------------------------------------------------------------------- * @@ -5706,11 +4488,11 @@ tmpAccessProcPtr = tmpAccessProcPtr->nextPtr; } } Tcl_MutexUnlock(&obsoleteFsHookMutex); - return (retVal); + return retVal; } /* *---------------------------------------------------------------------- * @@ -5755,11 +4537,11 @@ retVal = TCL_OK; } } - return (retVal); + return retVal; } /* *---------------------------------------------------------------------- * @@ -5813,8 +4595,1871 @@ tmpOpenFileChannelProcPtr = tmpOpenFileChannelProcPtr->nextPtr; } } Tcl_MutexUnlock(&obsoleteFsHookMutex); - return (retVal); + return retVal; } #endif /* USE_OBSOLETE_FS_HOOKS */ + + +/* + * Prototypes for procedures defined later in this file. + */ + +static void DupFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, + Tcl_Obj *copyPtr)); +static void FreeFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr)); +static void UpdateStringOfFsPath _ANSI_ARGS_((Tcl_Obj *objPtr)); +static int SetFsPathFromAny _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr)); +static int FindSplitPos _ANSI_ARGS_((char *path, char *separator)); + + + +/* + * Define the 'path' object type, which Tcl uses to represent + * file paths internally. + */ +static Tcl_ObjType tclFsPathType = { + "path", /* name */ + FreeFsPathInternalRep, /* freeIntRepProc */ + DupFsPathInternalRep, /* dupIntRepProc */ + UpdateStringOfFsPath, /* updateStringProc */ + SetFsPathFromAny /* setFromAnyProc */ +}; + +/* + * struct FsPath -- + * + * Internal representation of a Tcl_Obj of "path" type. This + * can be used to represent relative or absolute paths, and has + * certain optimisations when used to represent paths which are + * already normalized and absolute. + * + * Note that 'normPathPtr' can be a circular reference to the + * container Tcl_Obj of this FsPath. + */ +typedef struct FsPath { + Tcl_Obj *translatedPathPtr; /* Name without any ~user sequences. + * If this is NULL, then this is a + * pure normalized, absolute path + * object, in which the parent Tcl_Obj's + * string rep is already both translated + * and normalized. */ + Tcl_Obj *normPathPtr; /* Normalized absolute path, without + * ., .. or ~user sequences. If the + * Tcl_Obj containing + * this FsPath is already normalized, + * this may be a circular reference back + * to the container. If that is NOT the + * case, we have a refCount on the object. */ + Tcl_Obj *cwdPtr; /* If null, path is absolute, else + * this points to the cwd object used + * for this path. We have a refCount + * on the object. */ + int flags; /* Flags to describe interpretation */ + ClientData nativePathPtr; /* Native representation of this path, + * which is filesystem dependent. */ + int filesystemEpoch; /* Used to ensure the path representation + * was generated during the correct + * filesystem epoch. The epoch changes + * when filesystem-mounts are changed. */ + struct FilesystemRecord *fsRecPtr; + /* Pointer to the filesystem record + * entry to use for this path. */ +} FsPath; + +/* + * Define some macros to give us convenient access to path-object + * specific fields. + */ +#define PATHOBJ(objPtr) (objPtr->internalRep.otherValuePtr) +#define PATHFLAGS(objPtr) \ + (((FsPath*)(objPtr->internalRep.otherValuePtr))->flags) + +#define TCLPATH_APPENDED 1 +#define TCLPATH_RELATIVE 2 + +/* + *---------------------------------------------------------------------- + * + * Tcl_FSGetPathType -- + * + * Determines whether a given path is relative to the current + * directory, relative to the current volume, or absolute. + * + * Results: + * Returns one of TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, or + * TCL_PATH_VOLUME_RELATIVE. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_PathType +Tcl_FSGetPathType(pathObjPtr) + Tcl_Obj *pathObjPtr; +{ + return FSGetPathType(pathObjPtr, NULL, NULL); +} + +/* + *---------------------------------------------------------------------- + * + * FSGetPathType -- + * + * Determines whether a given path is relative to the current + * directory, relative to the current volume, or absolute. If the + * caller wishes to know which filesystem claimed the path (in the + * case for which the path is absolute), then a reference to a + * filesystem pointer can be passed in (but passing NULL is + * acceptable). + * + * Results: + * Returns one of TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, or + * TCL_PATH_VOLUME_RELATIVE. The filesystem reference will + * be set if and only if it is non-NULL and the function's + * return value is TCL_PATH_ABSOLUTE. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tcl_PathType +FSGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr) + Tcl_Obj *pathObjPtr; + Tcl_Filesystem **filesystemPtrPtr; + int *driveNameLengthPtr; +{ + if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) { + return GetPathType(pathObjPtr, filesystemPtrPtr, + driveNameLengthPtr, NULL); + } else { + FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + if (fsPathPtr->cwdPtr != NULL) { + if (PATHFLAGS(pathObjPtr) == 0) { + return TCL_PATH_RELATIVE; + } + return FSGetPathType(fsPathPtr->cwdPtr, filesystemPtrPtr, + driveNameLengthPtr); + } else { + return GetPathType(pathObjPtr, filesystemPtrPtr, + driveNameLengthPtr, NULL); + } + } +} + +/* + *--------------------------------------------------------------------------- + * + * Tcl_FSJoinPath -- + * + * This function takes the given Tcl_Obj, which should be a valid + * list, and returns the path object given by considering the + * first 'elements' elements as valid path segments. If elements < 0, + * we use the entire list. + * + * Results: + * Returns object with refCount of zero, (or if non-zero, it has + * references elsewhere in Tcl). Either way, the caller must + * increment its refCount before use. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ +Tcl_Obj* +Tcl_FSJoinPath(listObj, elements) + Tcl_Obj *listObj; + int elements; +{ + Tcl_Obj *res; + int i; + Tcl_Filesystem *fsPtr = NULL; + + if (elements < 0) { + if (Tcl_ListObjLength(NULL, listObj, &elements) != TCL_OK) { + return NULL; + } + } else { + /* Just make sure it is a valid list */ + int listTest; + if (Tcl_ListObjLength(NULL, listObj, &listTest) != TCL_OK) { + return NULL; + } + /* + * Correct this if it is too large, otherwise we will + * waste our time joining null elements to the path + */ + if (elements > listTest) { + elements = listTest; + } + } + + res = Tcl_NewObj(); + + for (i = 0; i < elements; i++) { + Tcl_Obj *elt; + int driveNameLength; + Tcl_PathType type; + char *strElt; + int strEltLen; + int length; + char *ptr; + Tcl_Obj *driveName = NULL; + + Tcl_ListObjIndex(NULL, listObj, i, &elt); + + /* + * This is a special case where we can be much more + * efficient, where we are joining a single relative path + * onto an object that is already of path type. The + * 'TclNewFSPathObj' call below creates an object which + * can be normalized more efficiently. Currently we only + * use the special case when we have exactly two elements, + * but we could expand that in the future. + */ + if ((i == (elements-2)) && (i == 0) && (elt->typePtr == &tclFsPathType) + && !(elt->bytes != NULL && (elt->bytes[0] == '\0'))) { + Tcl_Obj *tail; + Tcl_PathType type; + Tcl_ListObjIndex(NULL, listObj, i+1, &tail); + type = GetPathType(tail, NULL, NULL, NULL); + if (type == TCL_PATH_RELATIVE) { + CONST char *str; + int len; + str = Tcl_GetStringFromObj(tail,&len); + if (len == 0) { + /* + * This happens if we try to handle the root volume + * '/'. There's no need to return a special path + * object, when the base itself is just fine! + */ + Tcl_DecrRefCount(res); + return elt; + } + /* + * If it doesn't begin with '.' and is a mac or unix + * path or it a windows path without backslashes, then we + * can be very efficient here. (In fact even a windows + * path with backslashes can be joined efficiently, but + * the path object would not have forward slashes only, + * and this would therefore contradict our 'file join' + * documentation). + */ + if (str[0] != '.' && ((tclPlatform != TCL_PLATFORM_WINDOWS) + || (strchr(str, '\\') == NULL))) { + /* + * Finally, on Windows, 'file join' is defined to + * convert all backslashes to forward slashes, + * so the base part cannot have backslashes either. + */ + if ((tclPlatform != TCL_PLATFORM_WINDOWS) + || (strchr(Tcl_GetString(elt), '\\') == NULL)) { + if (res != NULL) { + TclDecrRefCount(res); + } + return TclNewFSPathObj(elt, str, len); + } + } + /* + * Otherwise we don't have an easy join, and + * we must let the more general code below handle + * things + */ + } else { + if (tclPlatform == TCL_PLATFORM_UNIX) { + Tcl_DecrRefCount(res); + return tail; + } else { + CONST char *str; + int len; + str = Tcl_GetStringFromObj(tail,&len); + if (tclPlatform == TCL_PLATFORM_WINDOWS) { + if (strchr(str, '\\') == NULL) { + Tcl_DecrRefCount(res); + return tail; + } + } else if (tclPlatform == TCL_PLATFORM_MAC) { + if (strchr(str, '/') == NULL) { + Tcl_DecrRefCount(res); + return tail; + } + } + } + } + } + strElt = Tcl_GetStringFromObj(elt, &strEltLen); + type = GetPathType(elt, &fsPtr, &driveNameLength, &driveName); + if (type != TCL_PATH_RELATIVE) { + /* Zero out the current result */ + Tcl_DecrRefCount(res); + if (driveName != NULL) { + res = Tcl_DuplicateObj(driveName); + Tcl_DecrRefCount(driveName); + } else { + res = Tcl_NewStringObj(strElt, driveNameLength); + } + strElt += driveNameLength; + } + + ptr = Tcl_GetStringFromObj(res, &length); + + /* + * Strip off any './' before a tilde, unless this is the + * beginning of the path. + */ + if (length > 0 && strEltLen > 0) { + if ((strElt[0] == '.') && (strElt[1] == '/') + && (strElt[2] == '~')) { + strElt += 2; + } + } + + /* + * A NULL value for fsPtr at this stage basically means + * we're trying to join a relative path onto something + * which is also relative (or empty). There's nothing + * particularly wrong with that. + */ + if (*strElt == '\0') continue; + + if (fsPtr == &tclNativeFilesystem || fsPtr == NULL) { + TclpNativeJoinPath(res, strElt); + } else { + char separator = '/'; + int needsSep = 0; + + if (fsPtr->filesystemSeparatorProc != NULL) { + Tcl_Obj *sep = (*fsPtr->filesystemSeparatorProc)(res); + if (sep != NULL) { + separator = Tcl_GetString(sep)[0]; + } + } + + if (length > 0 && ptr[length -1] != '/') { + Tcl_AppendToObj(res, &separator, 1); + length++; + } + Tcl_SetObjLength(res, length + (int) strlen(strElt)); + + ptr = Tcl_GetString(res) + length; + for (; *strElt != '\0'; strElt++) { + if (*strElt == separator) { + while (strElt[1] == separator) { + strElt++; + } + if (strElt[1] != '\0') { + if (needsSep) { + *ptr++ = separator; + } + } + } else { + *ptr++ = *strElt; + needsSep = 1; + } + } + length = ptr - Tcl_GetString(res); + Tcl_SetObjLength(res, length); + } + } + return res; +} + +/* + *--------------------------------------------------------------------------- + * + * Tcl_FSConvertToPathType -- + * + * This function 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. + * + * The filename may begin with "~" (to indicate current user's + * home directory) or "~" (to indicate any user's home + * directory). + * + * Results: + * Standard Tcl error code. + * + * Side effects: + * The old representation may be freed, and new memory allocated. + * + *--------------------------------------------------------------------------- + */ +int +Tcl_FSConvertToPathType(interp, objPtr) + Tcl_Interp *interp; /* Interpreter in which to store error + * message (if necessary). */ + Tcl_Obj *objPtr; /* Object to convert to a valid, current + * path type. */ +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + /* + * While it is bad practice to examine an object's type directly, + * this is actually the best thing to do here. The reason is that + * if we are converting this object to FsPath type for the first + * time, we don't need to worry whether the 'cwd' has changed. + * On the other hand, if this object is already of FsPath type, + * and is a relative path, we do have to worry about the cwd. + * If the cwd has changed, we must recompute the path. + */ + if (objPtr->typePtr == &tclFsPathType) { + FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr); + if (fsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) { + if (objPtr->bytes == NULL) { + UpdateStringOfFsPath(objPtr); + } + FreeFsPathInternalRep(objPtr); + objPtr->typePtr = NULL; + return Tcl_ConvertToType(interp, objPtr, &tclFsPathType); + } + return TCL_OK; + } else { + return Tcl_ConvertToType(interp, objPtr, &tclFsPathType); + } +} + +/* + * Helper function for SetFsPathFromAny. Returns position of first + * directory delimiter in the path. + */ +static int +FindSplitPos(path, separator) + char *path; + char *separator; +{ + int count = 0; + switch (tclPlatform) { + case TCL_PLATFORM_UNIX: + case TCL_PLATFORM_MAC: + while (path[count] != 0) { + if (path[count] == *separator) { + return count; + } + count++; + } + break; + + case TCL_PLATFORM_WINDOWS: + while (path[count] != 0) { + if (path[count] == *separator || path[count] == '\\') { + return count; + } + count++; + } + break; + } + return count; +} + +/* + *--------------------------------------------------------------------------- + * + * TclNewFSPathObj -- + * + * Creates a path object whose string representation is + * '[file join dirPtr addStrRep]', but does so in a way that + * allows for more efficient caching of normalized paths. + * + * Assumptions: + * 'dirPtr' must be an absolute path. + * 'len' may not be zero. + * + * Results: + * The new Tcl object, with refCount zero. + * + * Side effects: + * Memory is allocated. 'dirPtr' gets an additional refCount. + * + *--------------------------------------------------------------------------- + */ + +Tcl_Obj* +TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len) +{ + FsPath *fsPathPtr; + Tcl_Obj *objPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + objPtr = Tcl_NewObj(); + fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); + + if (tclPlatform == TCL_PLATFORM_MAC) { + /* + * Mac relative paths may begin with a directory separator ':'. + * If present, we need to skip this ':' because we assume that + * we can join dirPtr and addStrRep by concatenating them as + * strings (and we ensure that dirPtr is terminated by a ':'). + */ + if (addStrRep[0] == ':') { + addStrRep++; + len--; + } + } + /* Setup the path */ + fsPathPtr->translatedPathPtr = NULL; + fsPathPtr->normPathPtr = Tcl_NewStringObj(addStrRep, len); + Tcl_IncrRefCount(fsPathPtr->normPathPtr); + fsPathPtr->cwdPtr = dirPtr; + Tcl_IncrRefCount(dirPtr); + fsPathPtr->nativePathPtr = NULL; + fsPathPtr->fsRecPtr = NULL; + fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; + + PATHOBJ(objPtr) = (VOID *) fsPathPtr; + PATHFLAGS(objPtr) = TCLPATH_RELATIVE | TCLPATH_APPENDED; + objPtr->typePtr = &tclFsPathType; + objPtr->bytes = NULL; + objPtr->length = 0; + + return objPtr; +} + +/* + *--------------------------------------------------------------------------- + * + * TclFSMakePathRelative -- + * + * Only for internal use. + * + * Takes a path and a directory, where we _assume_ both path and + * directory are absolute, normalized and that the path lies + * inside the directory. Returns a Tcl_Obj representing filename + * of the path relative to the directory. + * + * In the case where the resulting path would start with a '~', we + * take special care to return an ordinary string. This means to + * use that path (and not have it interpreted as a user name), + * one must prepend './'. This may seem strange, but that is how + * 'glob' is currently defined. + * + * Results: + * NULL on error, otherwise a valid object, typically with + * refCount of zero, which it is assumed the caller will + * increment. + * + * Side effects: + * The old representation may be freed, and new memory allocated. + * + *--------------------------------------------------------------------------- + */ + +Tcl_Obj* +TclFSMakePathRelative(interp, objPtr, cwdPtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + Tcl_Obj *objPtr; /* The object we have. */ + Tcl_Obj *cwdPtr; /* Make it relative to this. */ +{ + int cwdLen, len; + CONST char *tempStr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + if (objPtr->typePtr == &tclFsPathType) { + FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr); + if (PATHFLAGS(objPtr) != 0 + && fsPathPtr->cwdPtr == cwdPtr) { + objPtr = fsPathPtr->normPathPtr; + /* Free old representation */ + if (objPtr->typePtr != NULL) { + if (objPtr->bytes == NULL) { + if (objPtr->typePtr->updateStringProc == NULL) { + if (interp != NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "can't find object", + "string representation", (char *) NULL); + } + return NULL; + } + objPtr->typePtr->updateStringProc(objPtr); + } + if ((objPtr->typePtr->freeIntRepProc) != NULL) { + (*objPtr->typePtr->freeIntRepProc)(objPtr); + } + } + /* Now objPtr is a string object */ + + if (Tcl_GetString(objPtr)[0] == '~') { + /* + * If the first character of the path is a tilde, + * we must just return the path as is, to agree + * with the defined behaviour of 'glob'. + */ + return objPtr; + } + + fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); + + /* Circular reference, by design */ + fsPathPtr->translatedPathPtr = objPtr; + fsPathPtr->normPathPtr = NULL; + fsPathPtr->cwdPtr = cwdPtr; + Tcl_IncrRefCount(cwdPtr); + fsPathPtr->nativePathPtr = NULL; + fsPathPtr->fsRecPtr = NULL; + fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; + + PATHOBJ(objPtr) = (VOID *) fsPathPtr; + PATHFLAGS(objPtr) = 0; + objPtr->typePtr = &tclFsPathType; + + return objPtr; + } + } + /* + * We know the cwd is a normalised object which does + * not end in a directory delimiter, unless the cwd + * is the name of a volume, in which case it will + * end in a delimiter! We handle this situation here. + * A better test than the '!= sep' might be to simply + * check if 'cwd' is a root volume. + * + * Note that if we get this wrong, we will strip off + * either too much or too little below, leading to + * wrong answers returned by glob. + */ + tempStr = Tcl_GetStringFromObj(cwdPtr, &cwdLen); + /* + * Should we perhaps use 'Tcl_FSPathSeparator'? + * But then what about the Windows special case? + * Perhaps we should just check if cwd is a root + * volume. + */ + switch (tclPlatform) { + case TCL_PLATFORM_UNIX: + if (tempStr[cwdLen-1] != '/') { + cwdLen++; + } + break; + case TCL_PLATFORM_WINDOWS: + if (tempStr[cwdLen-1] != '/' + && tempStr[cwdLen-1] != '\\') { + cwdLen++; + } + break; + case TCL_PLATFORM_MAC: + if (tempStr[cwdLen-1] != ':') { + cwdLen++; + } + break; + } + tempStr = Tcl_GetStringFromObj(objPtr, &len); + + return Tcl_NewStringObj(tempStr + cwdLen, len - cwdLen); +} + +/* + *--------------------------------------------------------------------------- + * + * TclFSMakePathFromNormalized -- + * + * Like SetFsPathFromAny, but assumes the given object is an + * absolute normalized path. Only for internal use. + * + * Results: + * Standard Tcl error code. + * + * Side effects: + * The old representation may be freed, and new memory allocated. + * + *--------------------------------------------------------------------------- + */ + +int +TclFSMakePathFromNormalized(interp, objPtr, nativeRep) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + Tcl_Obj *objPtr; /* The object to convert. */ + ClientData nativeRep; /* The native rep for the object, if known + * else NULL. */ +{ + FsPath *fsPathPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + if (objPtr->typePtr == &tclFsPathType) { + return TCL_OK; + } + + /* Free old representation */ + if (objPtr->typePtr != NULL) { + if (objPtr->bytes == NULL) { + if (objPtr->typePtr->updateStringProc == NULL) { + if (interp != NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "can't find object", + "string representation", (char *) NULL); + } + return TCL_ERROR; + } + objPtr->typePtr->updateStringProc(objPtr); + } + if ((objPtr->typePtr->freeIntRepProc) != NULL) { + (*objPtr->typePtr->freeIntRepProc)(objPtr); + } + } + + fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); + /* It's a pure normalized absolute path */ + fsPathPtr->translatedPathPtr = NULL; + fsPathPtr->normPathPtr = objPtr; + fsPathPtr->cwdPtr = NULL; + fsPathPtr->nativePathPtr = nativeRep; + fsPathPtr->fsRecPtr = NULL; + fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; + + PATHOBJ(objPtr) = (VOID *) fsPathPtr; + PATHFLAGS(objPtr) = 0; + objPtr->typePtr = &tclFsPathType; + + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * Tcl_FSNewNativePath -- + * + * This function performs the something like that reverse of the + * usual obj->path->nativerep conversions. If some code retrieves + * a path in native form (from, e.g. readlink 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. + * + * Any memory which is allocated for 'clientData' should be retained + * until clientData is passed to the filesystem's freeInternalRepProc + * when it can be freed. The built in platform-specific filesystems + * use 'ckalloc' to allocate clientData, and ckfree to free it. + * + * Results: + * NULL or a valid path object pointer, with refCount zero. + * + * Side effects: + * New memory may be allocated. + * + *--------------------------------------------------------------------------- + */ + +Tcl_Obj * +Tcl_FSNewNativePath(fromFilesystem, clientData) + Tcl_Filesystem* fromFilesystem; + ClientData clientData; +{ + Tcl_Obj *objPtr; + FsPath *fsPathPtr; + + FilesystemRecord *fsFromPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + objPtr = TclFSInternalToNormalized(fromFilesystem, clientData, &fsFromPtr); + if (objPtr == NULL) { + return NULL; + } + + /* + * Free old representation; shouldn't normally be any, + * but best to be safe. + */ + if (objPtr->typePtr != NULL) { + if (objPtr->bytes == NULL) { + if (objPtr->typePtr->updateStringProc == NULL) { + return NULL; + } + objPtr->typePtr->updateStringProc(objPtr); + } + if ((objPtr->typePtr->freeIntRepProc) != NULL) { + (*objPtr->typePtr->freeIntRepProc)(objPtr); + } + } + + fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); + + fsPathPtr->translatedPathPtr = NULL; + /* Circular reference, by design */ + fsPathPtr->normPathPtr = objPtr; + fsPathPtr->cwdPtr = NULL; + fsPathPtr->nativePathPtr = clientData; + fsPathPtr->fsRecPtr = fsFromPtr; + fsPathPtr->fsRecPtr->fileRefCount++; + fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; + + PATHOBJ(objPtr) = (VOID *) fsPathPtr; + PATHFLAGS(objPtr) = 0; + objPtr->typePtr = &tclFsPathType; + + return objPtr; +} + +/* + *--------------------------------------------------------------------------- + * + * Tcl_FSGetTranslatedPath -- + * + * This function attempts to extract the translated path + * from the given Tcl_Obj. If the translation succeeds (i.e. the + * object is a valid path), then it is returned. Otherwise NULL + * will be returned, and an error message may be left in the + * interpreter (if it is non-NULL) + * + * Results: + * NULL or a valid Tcl_Obj pointer. + * + * Side effects: + * Only those of 'Tcl_FSConvertToPathType' + * + *--------------------------------------------------------------------------- + */ + +Tcl_Obj* +Tcl_FSGetTranslatedPath(interp, pathPtr) + Tcl_Interp *interp; + Tcl_Obj* pathPtr; +{ + Tcl_Obj *retObj = NULL; + FsPath *srcFsPathPtr; + + if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) { + return NULL; + } + srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr); + if (srcFsPathPtr->translatedPathPtr == NULL) { + if (PATHFLAGS(pathPtr) != 0) { + retObj = Tcl_FSGetNormalizedPath(interp, pathPtr); + } else { + /* + * It is a pure absolute, normalized path object. + * This is something like being a 'pure list'. The + * object's string, translatedPath and normalizedPath + * are all identical. + */ + retObj = srcFsPathPtr->normPathPtr; + } + } else { + /* It is an ordinary path object */ + retObj = srcFsPathPtr->translatedPathPtr; + } + + if (retObj) { + Tcl_IncrRefCount(retObj); + } + return retObj; +} + +/* + *--------------------------------------------------------------------------- + * + * Tcl_FSGetTranslatedStringPath -- + * + * This function attempts to extract the translated path + * from the given Tcl_Obj. If the translation succeeds (i.e. the + * object is a valid path), then the path is returned. Otherwise NULL + * will be returned, and an error message may be left in the + * interpreter (if it is non-NULL) + * + * Results: + * NULL or a valid string. + * + * Side effects: + * Only those of 'Tcl_FSConvertToPathType' + * + *--------------------------------------------------------------------------- + */ +CONST char* +Tcl_FSGetTranslatedStringPath(interp, pathPtr) + Tcl_Interp *interp; + Tcl_Obj* pathPtr; +{ + Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(interp, pathPtr); + + if (transPtr != NULL) { + int len; + CONST char *result, *orig; + orig = Tcl_GetStringFromObj(transPtr, &len); + result = (char*) ckalloc((unsigned)(len+1)); + memcpy((VOID*) result, (VOID*) orig, (size_t) (len+1)); + Tcl_DecrRefCount(transPtr); + return result; + } + + return NULL; +} + +/* + *--------------------------------------------------------------------------- + * + * Tcl_FSGetNormalizedPath -- + * + * This important function attempts to extract from the given Tcl_Obj + * a unique normalised path representation, whose string value can + * be used as a unique identifier for the file. + * + * Results: + * NULL or a valid path object pointer. + * + * Side effects: + * New memory may be allocated. The Tcl 'errno' may be modified + * in the process of trying to examine various path possibilities. + * + *--------------------------------------------------------------------------- + */ + +Tcl_Obj* +Tcl_FSGetNormalizedPath(interp, pathObjPtr) + Tcl_Interp *interp; + Tcl_Obj* pathObjPtr; +{ + FsPath *fsPathPtr; + + if (Tcl_FSConvertToPathType(interp, pathObjPtr) != TCL_OK) { + return NULL; + } + fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + + if (PATHFLAGS(pathObjPtr) != 0) { + /* + * This is a special path object which is the result of + * something like 'file join' + */ + Tcl_Obj *dir, *copy; + int cwdLen; + int pathType; + CONST char *cwdStr; + ClientData clientData = NULL; + + pathType = Tcl_FSGetPathType(fsPathPtr->cwdPtr); + dir = Tcl_FSGetNormalizedPath(interp, fsPathPtr->cwdPtr); + if (dir == NULL) { + return NULL; + } + if (pathObjPtr->bytes == NULL) { + UpdateStringOfFsPath(pathObjPtr); + } + copy = Tcl_DuplicateObj(dir); + Tcl_IncrRefCount(copy); + Tcl_IncrRefCount(dir); + /* We now own a reference on both 'dir' and 'copy' */ + + cwdStr = Tcl_GetStringFromObj(copy, &cwdLen); + /* + * Should we perhaps use 'Tcl_FSPathSeparator'? + * But then what about the Windows special case? + * Perhaps we should just check if cwd is a root volume. + * We should never get cwdLen == 0 in this code path. + */ + switch (tclPlatform) { + case TCL_PLATFORM_UNIX: + if (cwdStr[cwdLen-1] != '/') { + Tcl_AppendToObj(copy, "/", 1); + cwdLen++; + } + break; + case TCL_PLATFORM_WINDOWS: + if (cwdStr[cwdLen-1] != '/' + && cwdStr[cwdLen-1] != '\\') { + Tcl_AppendToObj(copy, "/", 1); + cwdLen++; + } + break; + case TCL_PLATFORM_MAC: + if (cwdStr[cwdLen-1] != ':') { + Tcl_AppendToObj(copy, ":", 1); + cwdLen++; + } + break; + } + Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr); + /* + * Normalize the combined string, but only starting after + * the end of the previously normalized 'dir'. This should + * be much faster! We use 'cwdLen-1' so that we are + * already pointing at the dir-separator that we know about. + * The normalization code will actually start off directly + * after that separator. + */ + TclFSNormalizeToUniquePath(interp, copy, cwdLen-1, + (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL)); + /* Now we need to construct the new path object */ + + if (pathType == TCL_PATH_RELATIVE) { + FsPath* origDirFsPathPtr; + Tcl_Obj *origDir = fsPathPtr->cwdPtr; + origDirFsPathPtr = (FsPath*) PATHOBJ(origDir); + + fsPathPtr->cwdPtr = origDirFsPathPtr->cwdPtr; + Tcl_IncrRefCount(fsPathPtr->cwdPtr); + + Tcl_DecrRefCount(fsPathPtr->normPathPtr); + fsPathPtr->normPathPtr = copy; + /* That's our reference to copy used */ + Tcl_DecrRefCount(dir); + Tcl_DecrRefCount(origDir); + } else { + Tcl_DecrRefCount(fsPathPtr->cwdPtr); + fsPathPtr->cwdPtr = NULL; + Tcl_DecrRefCount(fsPathPtr->normPathPtr); + fsPathPtr->normPathPtr = copy; + /* That's our reference to copy used */ + Tcl_DecrRefCount(dir); + } + if (clientData != NULL) { + fsPathPtr->nativePathPtr = clientData; + } + PATHFLAGS(pathObjPtr) = 0; + } + /* Ensure cwd hasn't changed */ + if (fsPathPtr->cwdPtr != NULL) { + if (!TclFSCwdPointerEquals(fsPathPtr->cwdPtr)) { + if (pathObjPtr->bytes == NULL) { + UpdateStringOfFsPath(pathObjPtr); + } + FreeFsPathInternalRep(pathObjPtr); + pathObjPtr->typePtr = NULL; + if (Tcl_ConvertToType(interp, pathObjPtr, + &tclFsPathType) != TCL_OK) { + return NULL; + } + fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + } else if (fsPathPtr->normPathPtr == NULL) { + int cwdLen; + Tcl_Obj *copy; + CONST char *cwdStr; + ClientData clientData = NULL; + + copy = Tcl_DuplicateObj(fsPathPtr->cwdPtr); + Tcl_IncrRefCount(copy); + cwdStr = Tcl_GetStringFromObj(copy, &cwdLen); + /* + * Should we perhaps use 'Tcl_FSPathSeparator'? + * But then what about the Windows special case? + * Perhaps we should just check if cwd is a root volume. + * We should never get cwdLen == 0 in this code path. + */ + switch (tclPlatform) { + case TCL_PLATFORM_UNIX: + if (cwdStr[cwdLen-1] != '/') { + Tcl_AppendToObj(copy, "/", 1); + cwdLen++; + } + break; + case TCL_PLATFORM_WINDOWS: + if (cwdStr[cwdLen-1] != '/' + && cwdStr[cwdLen-1] != '\\') { + Tcl_AppendToObj(copy, "/", 1); + cwdLen++; + } + break; + case TCL_PLATFORM_MAC: + if (cwdStr[cwdLen-1] != ':') { + Tcl_AppendToObj(copy, ":", 1); + cwdLen++; + } + break; + } + Tcl_AppendObjToObj(copy, pathObjPtr); + /* + * Normalize the combined string, but only starting after + * the end of the previously normalized 'dir'. This should + * be much faster! + */ + TclFSNormalizeToUniquePath(interp, copy, cwdLen-1, + (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL)); + fsPathPtr->normPathPtr = copy; + if (clientData != NULL) { + fsPathPtr->nativePathPtr = clientData; + } + } + } + if (fsPathPtr->normPathPtr == NULL) { + ClientData clientData = NULL; + Tcl_Obj *useThisCwd = NULL; + /* + * Since normPathPtr is NULL, but this is a valid path + * object, we know that the translatedPathPtr cannot be NULL. + */ + Tcl_Obj *absolutePath = fsPathPtr->translatedPathPtr; + char *path = Tcl_GetString(absolutePath); + + /* + * We have to be a little bit careful here to avoid infinite loops + * we're asking Tcl_FSGetPathType to return the path's type, but + * that call can actually result in a lot of other filesystem + * action, which might loop back through here. + */ + if (path[0] != '\0') { + Tcl_PathType type = Tcl_FSGetPathType(pathObjPtr); + if (type == TCL_PATH_RELATIVE) { + useThisCwd = Tcl_FSGetCwd(interp); + + if (useThisCwd == NULL) return NULL; + + absolutePath = Tcl_FSJoinToPath(useThisCwd, 1, &absolutePath); + Tcl_IncrRefCount(absolutePath); + /* We have a refCount on the cwd */ +#ifdef __WIN32__ + } else if (type == TCL_PATH_VOLUME_RELATIVE) { + /* + * Only Windows has volume-relative paths. These + * paths are rather rare, but is is nice if Tcl can + * handle them. It is much better if we can + * handle them here, rather than in the native fs code, + * because we really need to have a real absolute path + * just below. + * + * We do not let this block compile on non-Windows + * platforms because the test suite's manual forcing + * of tclPlatform can otherwise cause this code path + * to be executed, causing various errors because + * volume-relative paths really do not exist. + */ + useThisCwd = Tcl_FSGetCwd(interp); + if (useThisCwd == NULL) return NULL; + + if (path[0] == '/') { + /* + * Path of form /foo/bar which is a path in the + * root directory of the current volume. + */ + CONST char *drive = Tcl_GetString(useThisCwd); + absolutePath = Tcl_NewStringObj(drive,2); + Tcl_AppendToObj(absolutePath, path, -1); + Tcl_IncrRefCount(absolutePath); + /* We have a refCount on the cwd */ + } else { + /* + * Path of form C:foo/bar, but this only makes + * sense if the cwd is also on drive C. + */ + CONST char *drive = Tcl_GetString(useThisCwd); + char drive_c = path[0]; + if (drive_c >= 'a') { + drive_c -= ('a' - 'A'); + } + if (drive[0] == drive_c) { + absolutePath = Tcl_DuplicateObj(useThisCwd); + /* We have a refCount on the cwd */ + } else { + Tcl_DecrRefCount(useThisCwd); + useThisCwd = NULL; + /* + * The path is not in the current drive, but + * is volume-relative. The way Tcl 8.3 handles + * this is that it treats such a path as + * relative to the root of the drive. We + * therefore behave the same here. + */ + absolutePath = Tcl_NewStringObj(path, 2); + } + Tcl_IncrRefCount(absolutePath); + Tcl_AppendToObj(absolutePath, "/", 1); + Tcl_AppendToObj(absolutePath, path+2, -1); + } +#endif /* __WIN32__ */ + } + } + /* Already has refCount incremented */ + fsPathPtr->normPathPtr = TclFSNormalizeAbsolutePath(interp, absolutePath, + (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL)); + if (0 && (clientData != NULL)) { + fsPathPtr->nativePathPtr = + (*fsPathPtr->fsRecPtr->fsPtr->dupInternalRepProc)(clientData); + } + if (!strcmp(Tcl_GetString(fsPathPtr->normPathPtr), + Tcl_GetString(pathObjPtr))) { + /* + * The path was already normalized. + * Get rid of the duplicate. + */ + Tcl_DecrRefCount(fsPathPtr->normPathPtr); + /* + * We do *not* increment the refCount for + * this circular reference + */ + fsPathPtr->normPathPtr = pathObjPtr; + } + if (useThisCwd != NULL) { + /* This was returned by Tcl_FSJoinToPath above */ + Tcl_DecrRefCount(absolutePath); + fsPathPtr->cwdPtr = useThisCwd; + } + } + + return fsPathPtr->normPathPtr; +} + +/* + *--------------------------------------------------------------------------- + * + * Tcl_FSGetInternalRep -- + * + * Extract the internal representation of a given path object, + * in the given filesystem. If the path object 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 + * 'Tcl_FSCreateInternalRepProc'. + * + * Results: + * NULL or a valid internal representation. + * + * Side effects: + * An attempt may be made to convert the object. + * + *--------------------------------------------------------------------------- + */ + +ClientData +Tcl_FSGetInternalRep(pathObjPtr, fsPtr) + Tcl_Obj* pathObjPtr; + Tcl_Filesystem *fsPtr; +{ + FsPath *srcFsPathPtr; + + if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) { + return NULL; + } + srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + + /* + * We will only return the native representation for the caller's + * filesystem. Otherwise we will simply return NULL. This means + * that there must be a unique bi-directional mapping between paths + * and filesystems, and that this mapping will not allow 'remapped' + * files -- files which are in one filesystem but mapped into + * another. Another way of putting this is that 'stacked' + * filesystems are not allowed. We recognise that this is a + * potentially useful feature for the future. + * + * Even something simple like a 'pass through' filesystem which + * logs all activity and passes the calls onto the native system + * would be nice, but not easily achievable with the current + * implementation. + */ + if (srcFsPathPtr->fsRecPtr == NULL) { + /* + * This only usually happens in wrappers like TclpStat which + * create a string object and pass it to TclpObjStat. Code + * which calls the Tcl_FS.. functions should always have a + * filesystem already set. Whether this code path is legal or + * not depends on whether we decide to allow external code to + * call the native filesystem directly. It is at least safer + * to allow this sub-optimal routing. + */ + Tcl_FSGetFileSystemForPath(pathObjPtr); + + /* + * If we fail through here, then the path is probably not a + * valid path in the filesystsem, and is most likely to be a + * use of the empty path "" via a direct call to one of the + * objectified interfaces (e.g. from the Tcl testsuite). + */ + srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + if (srcFsPathPtr->fsRecPtr == NULL) { + return NULL; + } + } + + if (fsPtr != srcFsPathPtr->fsRecPtr->fsPtr) { + /* + * There is still one possibility we should consider; if the + * file belongs to a different filesystem, perhaps it is + * actually linked through to a file in our own filesystem + * which we do care about. The way we can check for this + * is we ask what filesystem this path belongs to. + */ + Tcl_Filesystem *actualFs = Tcl_FSGetFileSystemForPath(pathObjPtr); + if (actualFs == fsPtr) { + return Tcl_FSGetInternalRep(pathObjPtr, fsPtr); + } + return NULL; + } + + if (srcFsPathPtr->nativePathPtr == NULL) { + Tcl_FSCreateInternalRepProc *proc; + char *nativePathPtr; + + proc = srcFsPathPtr->fsRecPtr->fsPtr->createInternalRepProc; + if (proc == NULL) { + return NULL; + } + + nativePathPtr = (*proc)(pathObjPtr); + srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + srcFsPathPtr->nativePathPtr = nativePathPtr; + } + + return srcFsPathPtr->nativePathPtr; +} + +/* + *--------------------------------------------------------------------------- + * + * TclFSEnsureEpochOk -- + * + * This will ensure the pathObjPtr is up to date and can be + * converted into a "path" type, and that we are able to generate a + * complete normalized path which is used to determine the + * filesystem match. + * + * Results: + * Standard Tcl return code. + * + * Side effects: + * An attempt may be made to convert the object. + * + *--------------------------------------------------------------------------- + */ + +int +TclFSEnsureEpochOk(pathObjPtr, fsPtrPtr) + Tcl_Obj* pathObjPtr; + Tcl_Filesystem **fsPtrPtr; +{ + FsPath *srcFsPathPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + /* + * SHOULD BE ABLE TO IMPROVE EFFICIENCY HERE. + */ + + if (Tcl_FSGetNormalizedPath(NULL, pathObjPtr) == NULL) { + return TCL_ERROR; + } + + srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + + /* + * Check if the filesystem has changed in some way since + * this object's internal representation was calculated. + */ + if (srcFsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) { + /* + * We have to discard the stale representation and + * recalculate it + */ + if (pathObjPtr->bytes == NULL) { + UpdateStringOfFsPath(pathObjPtr); + } + FreeFsPathInternalRep(pathObjPtr); + pathObjPtr->typePtr = NULL; + if (SetFsPathFromAny(NULL, pathObjPtr) != TCL_OK) { + return TCL_ERROR; + } + srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + } + /* Check whether the object is already assigned to a fs */ + if (srcFsPathPtr->fsRecPtr != NULL) { + *fsPtrPtr = srcFsPathPtr->fsRecPtr->fsPtr; + } + + return TCL_OK; +} + +void +TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData) + Tcl_Obj *pathObjPtr; + FilesystemRecord *fsRecPtr; + ClientData clientData; +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + /* We assume pathObjPtr is already of the correct type */ + FsPath *srcFsPathPtr; + + srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + srcFsPathPtr->fsRecPtr = fsRecPtr; + srcFsPathPtr->nativePathPtr = clientData; + srcFsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; + fsRecPtr->fileRefCount++; +} + +/* + *--------------------------------------------------------------------------- + * + * Tcl_FSEqualPaths -- + * + * This function tests whether the two paths given are equal path + * objects. If either or both is NULL, 0 is always returned. + * + * Results: + * 1 or 0. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +Tcl_FSEqualPaths(firstPtr, secondPtr) + Tcl_Obj* firstPtr; + Tcl_Obj* secondPtr; +{ + if (firstPtr == secondPtr) { + return 1; + } else { + char *firstStr, *secondStr; + int firstLen, secondLen, tempErrno; + + if (firstPtr == NULL || secondPtr == NULL) { + return 0; + } + firstStr = Tcl_GetStringFromObj(firstPtr, &firstLen); + secondStr = Tcl_GetStringFromObj(secondPtr, &secondLen); + if ((firstLen == secondLen) && (strcmp(firstStr, secondStr) == 0)) { + return 1; + } + /* + * Try the most thorough, correct method of comparing fully + * normalized paths + */ + + tempErrno = Tcl_GetErrno(); + firstPtr = Tcl_FSGetNormalizedPath(NULL, firstPtr); + secondPtr = Tcl_FSGetNormalizedPath(NULL, secondPtr); + Tcl_SetErrno(tempErrno); + + if (firstPtr == NULL || secondPtr == NULL) { + return 0; + } + firstStr = Tcl_GetStringFromObj(firstPtr, &firstLen); + secondStr = Tcl_GetStringFromObj(secondPtr, &secondLen); + if ((firstLen == secondLen) && (strcmp(firstStr, secondStr) == 0)) { + return 1; + } + } + + return 0; +} + +/* + *--------------------------------------------------------------------------- + * + * SetFsPathFromAny -- + * + * This function tries to convert the given Tcl_Obj to a valid + * Tcl path type. + * + * The filename may begin with "~" (to indicate current user's + * home directory) or "~" (to indicate any user's home + * directory). + * + * Results: + * Standard Tcl error code. + * + * Side effects: + * The old representation may be freed, and new memory allocated. + * + *--------------------------------------------------------------------------- + */ + +static int +SetFsPathFromAny(interp, objPtr) + Tcl_Interp *interp; /* Used for error reporting if not NULL. */ + Tcl_Obj *objPtr; /* The object to convert. */ +{ + int len; + FsPath *fsPathPtr; + Tcl_Obj *transPtr; + char *name; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + if (objPtr->typePtr == &tclFsPathType) { + return TCL_OK; + } + + /* + * First step is to translate the filename. This is similar to + * Tcl_TranslateFilename, but shouldn't convert everything to + * windows backslashes on that platform. The current + * implementation of this piece is a slightly optimised version + * of the various Tilde/Split/Join stuff to avoid multiple + * split/join operations. + * + * We remove any trailing directory separator. + * + * However, the split/join routines are quite complex, and + * one has to make sure not to break anything on Unix, Win + * or MacOS (fCmd.test, fileName.test and cmdAH.test exercise + * most of the code). + */ + name = Tcl_GetStringFromObj(objPtr,&len); + + /* + * Handle tilde substitutions, if needed. + */ + if (name[0] == '~') { + char *expandedUser; + Tcl_DString temp; + int split; + char separator='/'; + + if (tclPlatform==TCL_PLATFORM_MAC) { + if (strchr(name, ':') != NULL) separator = ':'; + } + + split = FindSplitPos(name, &separator); + if (split != len) { + /* We have multiple pieces '~user/foo/bar...' */ + name[split] = '\0'; + } + /* Do some tilde substitution */ + if (name[1] == '\0') { + /* We have just '~' */ + CONST char *dir; + Tcl_DString dirString; + if (split != len) { name[split] = separator; } + + dir = TclGetEnv("HOME", &dirString); + if (dir == NULL) { + if (interp) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "couldn't find HOME environment ", + "variable to expand path", (char *) NULL); + } + return TCL_ERROR; + } + Tcl_DStringInit(&temp); + Tcl_JoinPath(1, &dir, &temp); + Tcl_DStringFree(&dirString); + } else { + /* We have a user name '~user' */ + Tcl_DStringInit(&temp); + if (TclpGetUserHome(name+1, &temp) == NULL) { + if (interp != NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "user \"", (name+1), + "\" doesn't exist", (char *) NULL); + } + Tcl_DStringFree(&temp); + if (split != len) { name[split] = separator; } + return TCL_ERROR; + } + if (split != len) { name[split] = separator; } + } + + expandedUser = Tcl_DStringValue(&temp); + transPtr = Tcl_NewStringObj(expandedUser, Tcl_DStringLength(&temp)); + + if (split != len) { + /* Join up the tilde substitution with the rest */ + if (name[split+1] == separator) { + + /* + * Somewhat tricky case like ~//foo/bar. + * Make use of Split/Join machinery to get it right. + * Assumes all paths beginning with ~ are part of the + * native filesystem. + */ + + int objc; + Tcl_Obj **objv; + Tcl_Obj *parts = TclpNativeSplitPath(objPtr, NULL); + Tcl_ListObjGetElements(NULL, parts, &objc, &objv); + /* Skip '~'. It's replaced by its expansion */ + objc--; objv++; + while (objc--) { + TclpNativeJoinPath(transPtr, Tcl_GetString(*objv++)); + } + Tcl_DecrRefCount(parts); + } else { + /* Simple case. "rest" is relative path. Just join it. */ + Tcl_Obj *rest = Tcl_NewStringObj(name+split+1,-1); + transPtr = Tcl_FSJoinToPath(transPtr, 1, &rest); + } + } + Tcl_DStringFree(&temp); + } else { + transPtr = Tcl_FSJoinToPath(objPtr,0,NULL); + } + +#if defined(__CYGWIN__) && defined(__WIN32__) + { + extern int cygwin_conv_to_win32_path + _ANSI_ARGS_((CONST char *, char *)); + char winbuf[MAX_PATH+1]; + + /* + * In the Cygwin world, call conv_to_win32_path in order to use the + * mount table to translate the file name into something Windows will + * understand. Take care when converting empty strings! + */ + name = Tcl_GetStringFromObj(transPtr, &len); + if (len > 0) { + cygwin_conv_to_win32_path(name, winbuf); + TclWinNoBackslash(winbuf); + Tcl_SetStringObj(transPtr, winbuf, -1); + } + } +#endif /* __CYGWIN__ && __WIN32__ */ + + /* + * Now we have a translated filename in 'transPtr'. This will have + * forward slashes on Windows, and will not contain any ~user + * sequences. + */ + + fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); + + fsPathPtr->translatedPathPtr = transPtr; + Tcl_IncrRefCount(fsPathPtr->translatedPathPtr); + fsPathPtr->normPathPtr = NULL; + fsPathPtr->cwdPtr = NULL; + fsPathPtr->nativePathPtr = NULL; + fsPathPtr->fsRecPtr = NULL; + fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; + + /* + * Free old representation before installing our new one. + */ + if (objPtr->typePtr != NULL && objPtr->typePtr->freeIntRepProc != NULL) { + (objPtr->typePtr->freeIntRepProc)(objPtr); + } + PATHOBJ(objPtr) = (VOID *) fsPathPtr; + PATHFLAGS(objPtr) = 0; + objPtr->typePtr = &tclFsPathType; + + return TCL_OK; +} + +static void +FreeFsPathInternalRep(pathObjPtr) + Tcl_Obj *pathObjPtr; /* Path object with internal rep to free. */ +{ + FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + + if (fsPathPtr->translatedPathPtr != NULL) { + if (fsPathPtr->translatedPathPtr != pathObjPtr) { + Tcl_DecrRefCount(fsPathPtr->translatedPathPtr); + } + } + if (fsPathPtr->normPathPtr != NULL) { + if (fsPathPtr->normPathPtr != pathObjPtr) { + Tcl_DecrRefCount(fsPathPtr->normPathPtr); + } + fsPathPtr->normPathPtr = NULL; + } + if (fsPathPtr->cwdPtr != NULL) { + Tcl_DecrRefCount(fsPathPtr->cwdPtr); + } + if (fsPathPtr->nativePathPtr != NULL) { + if (fsPathPtr->fsRecPtr != NULL) { + if (fsPathPtr->fsRecPtr->fsPtr->freeInternalRepProc != NULL) { + (*fsPathPtr->fsRecPtr->fsPtr + ->freeInternalRepProc)(fsPathPtr->nativePathPtr); + fsPathPtr->nativePathPtr = NULL; + } + } + } + if (fsPathPtr->fsRecPtr != NULL) { + fsPathPtr->fsRecPtr->fileRefCount--; + if (fsPathPtr->fsRecPtr->fileRefCount <= 0) { + /* It has been unregistered already, so simply free it */ + ckfree((char *)fsPathPtr->fsRecPtr); + } + } + + ckfree((char*) fsPathPtr); +} + + +static void +DupFsPathInternalRep(srcPtr, copyPtr) + Tcl_Obj *srcPtr; /* Path obj with internal rep to copy. */ + Tcl_Obj *copyPtr; /* Path obj with internal rep to set. */ +{ + FsPath *srcFsPathPtr = (FsPath*) PATHOBJ(srcPtr); + FsPath *copyFsPathPtr = (FsPath*) ckalloc((unsigned)sizeof(FsPath)); + + Tcl_FSDupInternalRepProc *dupProc; + + PATHOBJ(copyPtr) = (VOID *) copyFsPathPtr; + + if (srcFsPathPtr->translatedPathPtr != NULL) { + copyFsPathPtr->translatedPathPtr = srcFsPathPtr->translatedPathPtr; + if (copyFsPathPtr->translatedPathPtr != copyPtr) { + Tcl_IncrRefCount(copyFsPathPtr->translatedPathPtr); + } + } else { + copyFsPathPtr->translatedPathPtr = NULL; + } + + if (srcFsPathPtr->normPathPtr != NULL) { + copyFsPathPtr->normPathPtr = srcFsPathPtr->normPathPtr; + if (copyFsPathPtr->normPathPtr != copyPtr) { + Tcl_IncrRefCount(copyFsPathPtr->normPathPtr); + } + } else { + copyFsPathPtr->normPathPtr = NULL; + } + + if (srcFsPathPtr->cwdPtr != NULL) { + copyFsPathPtr->cwdPtr = srcFsPathPtr->cwdPtr; + Tcl_IncrRefCount(copyFsPathPtr->cwdPtr); + } else { + copyFsPathPtr->cwdPtr = NULL; + } + + copyFsPathPtr->flags = srcFsPathPtr->flags; + + if (srcFsPathPtr->fsRecPtr != NULL + && srcFsPathPtr->nativePathPtr != NULL) { + dupProc = srcFsPathPtr->fsRecPtr->fsPtr->dupInternalRepProc; + if (dupProc != NULL) { + copyFsPathPtr->nativePathPtr = + (*dupProc)(srcFsPathPtr->nativePathPtr); + } else { + copyFsPathPtr->nativePathPtr = NULL; + } + } else { + copyFsPathPtr->nativePathPtr = NULL; + } + copyFsPathPtr->fsRecPtr = srcFsPathPtr->fsRecPtr; + copyFsPathPtr->filesystemEpoch = srcFsPathPtr->filesystemEpoch; + if (copyFsPathPtr->fsRecPtr != NULL) { + copyFsPathPtr->fsRecPtr->fileRefCount++; + } + + copyPtr->typePtr = &tclFsPathType; +} + +/* + *--------------------------------------------------------------------------- + * + * UpdateStringOfFsPath -- + * + * Gives an object a valid string rep. + * + * Results: + * None. + * + * Side effects: + * Memory may be allocated. + * + *--------------------------------------------------------------------------- + */ + +static void +UpdateStringOfFsPath(objPtr) + register Tcl_Obj *objPtr; /* path obj with string rep to update. */ +{ + FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr); + CONST char *cwdStr; + int cwdLen; + Tcl_Obj *copy; + + if (PATHFLAGS(objPtr) == 0 || fsPathPtr->cwdPtr == NULL) { + panic("Called UpdateStringOfFsPath with invalid object"); + } + + copy = Tcl_DuplicateObj(fsPathPtr->cwdPtr); + Tcl_IncrRefCount(copy); + + cwdStr = Tcl_GetStringFromObj(copy, &cwdLen); + /* + * Should we perhaps use 'Tcl_FSPathSeparator'? + * But then what about the Windows special case? + * Perhaps we should just check if cwd is a root volume. + * We should never get cwdLen == 0 in this code path. + */ + switch (tclPlatform) { + case TCL_PLATFORM_UNIX: + if (cwdStr[cwdLen-1] != '/') { + Tcl_AppendToObj(copy, "/", 1); + cwdLen++; + } + break; + case TCL_PLATFORM_WINDOWS: + /* + * We need the extra 'cwdLen != 2', and ':' checks because + * a volume relative path doesn't get a '/'. For example + * 'glob C:*cat*.exe' will return 'C:cat32.exe' + */ + if (cwdStr[cwdLen-1] != '/' + && cwdStr[cwdLen-1] != '\\') { + if (cwdLen != 2 || cwdStr[1] != ':') { + Tcl_AppendToObj(copy, "/", 1); + cwdLen++; + } + } + break; + case TCL_PLATFORM_MAC: + if (cwdStr[cwdLen-1] != ':') { + Tcl_AppendToObj(copy, ":", 1); + cwdLen++; + } + break; + } + Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr); + objPtr->bytes = Tcl_GetStringFromObj(copy, &cwdLen); + objPtr->length = cwdLen; + copy->bytes = tclEmptyStringRep; + copy->length = 0; + Tcl_DecrRefCount(copy); +} + +/* + *--------------------------------------------------------------------------- + * + * NativePathInFilesystem -- + * + * Any path object is acceptable to the native filesystem, by + * default (we will throw errors when illegal paths are actually + * tried to be used). + * + * However, this behavior means the native filesystem must be + * the last filesystem in the lookup list (otherwise it will + * claim all files belong to it, and other filesystems will + * never get a look in). + * + * Results: + * TCL_OK, to indicate 'yes', -1 to indicate no. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ +static int +NativePathInFilesystem(pathPtr, clientDataPtr) + Tcl_Obj *pathPtr; + ClientData *clientDataPtr; +{ + /* + * A special case is required to handle the empty path "". + * This is a valid path (i.e. the user should be able + * to do 'file exists ""' without throwing an error), but + * equally the path doesn't exist. Those are the semantics + * of Tcl (at present anyway), so we have to abide by them + * here. + */ + if (pathPtr->typePtr == &tclFsPathType) { + if (pathPtr->bytes != NULL && pathPtr->bytes[0] == '\0') { + /* We reject the empty path "" */ + return -1; + } + /* Otherwise there is no way this path can be empty */ + } else { + /* + * It is somewhat unusual to reach this code path without + * the object being of tclFsPathType. However, we do + * our best to deal with the situation. + */ + int len; + Tcl_GetStringFromObj(pathPtr,&len); + if (len == 0) { + /* We reject the empty path "" */ + return -1; + } + } + /* + * Path is of correct type, or is of non-zero length, + * so we accept it. + */ + return TCL_OK; +} Index: generic/tclIndexObj.c ================================================================== --- generic/tclIndexObj.c +++ generic/tclIndexObj.c @@ -8,11 +8,11 @@ * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIndexObj.c,v 1.16 2002/02/28 05:11:25 dgp Exp $ + * RCS: @(#) $Id: tclIndexObj.c,v 1.16.2.5 2006/04/06 18:57:24 dgp Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -169,11 +169,11 @@ int offset; /* The number of bytes between entries */ CONST char *msg; /* Identifying word to use in error messages. */ int flags; /* 0 or TCL_EXACT */ int *indexPtr; /* Place to store resulting integer index. */ { - int index, length, i, numAbbrev; + int index, i, numAbbrev; char *key, *p1; CONST char *p2; CONST char * CONST *entryPtr; Tcl_Obj *resultPtr; IndexRep *indexRep; @@ -193,22 +193,14 @@ /* * Lookup the value of the object in the table. Accept unique * abbreviations unless TCL_EXACT is set in flags. */ - key = Tcl_GetStringFromObj(objPtr, &length); + key = TclGetString(objPtr); index = -1; numAbbrev = 0; - /* - * The key should not be empty, otherwise it's not a match. - */ - - if (key[0] == '\0') { - goto error; - } - /* * Scan the table looking for one of: * - An exact match (always preferred) * - A single abbreviation (allowed depending on flags) * - Several abbreviations (never allowed, but overridden by exact match) @@ -233,13 +225,13 @@ numAbbrev++; index = i; } } /* - * Check if we were instructed to disallow abbreviations. + * Check if we were instructed to disallow abbreviations. */ - if ((flags & TCL_EXACT) || (numAbbrev != 1)) { + if ((flags & TCL_EXACT) || (key[0] == '\0') || (numAbbrev != 1)) { goto error; } done: /* @@ -269,13 +261,15 @@ if (interp != NULL) { /* * Produce a fancy error message. */ int count; - resultPtr = Tcl_GetObjResult(interp); - Tcl_AppendStringsToObj(resultPtr, - (numAbbrev > 1) ? "ambiguous " : "bad ", msg, " \"", + + TclNewObj(resultPtr); + Tcl_SetObjResult(interp, resultPtr); + Tcl_AppendStringsToObj(resultPtr, (numAbbrev > 1) && + !(flags & TCL_EXACT) ? "ambiguous " : "bad ", msg, " \"", key, "\": must be ", STRING_AT(tablePtr,offset,0), (char*)NULL); for (entryPtr = NEXT_ENTRY(tablePtr, offset), count = 0; *entryPtr != NULL; entryPtr = NEXT_ENTRY(entryPtr, offset), count++) { if (*NEXT_ENTRY(entryPtr, offset) == NULL) { @@ -448,11 +442,12 @@ { Tcl_Obj *objPtr; int i; register IndexRep *indexRep; - objPtr = Tcl_GetObjResult(interp); + TclNewObj(objPtr); + Tcl_SetObjResult(interp, objPtr); Tcl_AppendToObj(objPtr, "wrong # args: should be \"", -1); for (i = 0; i < objc; i++) { /* * If the object is an index type use the index table which allows * for the correct error message even if the subcommand was Index: generic/tclInt.decls ================================================================== --- generic/tclInt.decls +++ generic/tclInt.decls @@ -10,11 +10,11 @@ # Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: tclInt.decls,v 1.59 2003/02/18 02:25:45 hobbs Exp $ +# RCS: @(#) $Id: tclInt.decls,v 1.59.2.7 2007/04/21 19:52:14 kennykb Exp $ library tcl # Define the unsupported generic interfaces. @@ -122,12 +122,12 @@ # Removed in 8.1: # declare 26 generic { # char * TclGetCwd(Tcl_Interp *interp) # } declare 27 generic { - int TclGetDate(char *p, unsigned long now, long zone, - unsigned long *timePtr) + int TclGetDate(char *p, Tcl_WideInt now, long zone, + Tcl_WideInt *timePtr) } declare 28 generic { Tcl_Channel TclpGetDefaultStdChannel(int type) } # Removed in 8.4b2: @@ -310,11 +310,11 @@ declare 77 generic { void TclpGetTime(Tcl_Time *time) } declare 78 generic { - int TclpGetTimeZone(unsigned long time) + int TclpGetTimeZone(Tcl_WideInt time) } # Replaced by Tcl_FSListVolumes in 8.4: #declare 79 generic { # int TclpListVolumes(Tcl_Interp *interp) #} @@ -694,10 +694,23 @@ declare 173 generic { int TclUniCharMatch (CONST Tcl_UniChar *string, int strLen, \ CONST Tcl_UniChar *pattern, int ptnLen, int nocase) } + +# TclpGmtime and TclpLocaltime promoted to the generic interface from unix + +declare 182 generic { + struct tm *TclpLocaltime(TclpTime_t_CONST clock) +} +declare 183 generic { + struct tm *TclpGmtime(TclpTime_t_CONST clock) +} + +declare 199 generic { + int TclMatchIsTrivial(CONST char *pattern) +} ############################################################################## # Define the platform specific internal Tcl interface. These functions are # only available on the designated platform. @@ -925,10 +938,14 @@ # Added in 8.4.2 declare 28 win { void TclWinResetInterfaces(void) } + +declare 29 win { + int TclWinCPUID( unsigned int index, unsigned int *regs ) +} ######################### # Unix specific internals # Pipe channel functions @@ -974,18 +991,21 @@ # Added in 8.4: declare 10 unix { Tcl_DirEntry * TclpReaddir(DIR * dir) } + +# Slots 11 and 12 are forwarders for functions that were promoted to +# generic Stubs declare 11 unix { - struct tm * TclpLocaltime(time_t * clock) + struct tm * TclpLocaltime_unix(TclpTime_t_CONST clock) } declare 12 unix { - struct tm * TclpGmtime(time_t * clock) + struct tm * TclpGmtime_unix(TclpTime_t_CONST clock) } declare 13 unix { char * TclpInetNtoa(struct in_addr addr) } Index: generic/tclInt.h ================================================================== --- generic/tclInt.h +++ generic/tclInt.h @@ -10,11 +10,11 @@ * Copyright (c) 2001, 2002 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInt.h,v 1.118 2003/02/10 10:26:25 vincentdarley Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.118.2.28 2007/05/10 21:32:17 dgp Exp $ */ #ifndef _TCLINT #define _TCLINT @@ -49,10 +49,49 @@ #include "../compat/string.h" #else #include #endif +/* + * Ensure WORDS_BIGENDIAN is defined correcly: + * Needs to happen here in addition to configure to work with fat compiles on + * Darwin (where configure runs only once for multiple architectures). + */ + +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef BYTE_ORDER +# ifdef BIG_ENDIAN +# if BYTE_ORDER == BIG_ENDIAN +# undef WORDS_BIGENDIAN +# define WORDS_BIGENDIAN +# endif +# endif +# ifdef LITTLE_ENDIAN +# if BYTE_ORDER == LITTLE_ENDIAN +# undef WORDS_BIGENDIAN +# endif +# endif +#endif + +/* + * Used to tag functions that are only to be visible within the module being + * built and not outside it (where this is supported by the linker). + */ + +#ifndef MODULE_SCOPE +# ifdef __cplusplus +# define MODULE_SCOPE extern "C" +# else +# define MODULE_SCOPE extern +# endif +#endif + #undef TCL_STORAGE_CLASS #ifdef BUILD_tcl # define TCL_STORAGE_CLASS DLLEXPORT #else # ifdef USE_TCL_STUBS @@ -229,14 +268,17 @@ * allows the namespace resolution code to recognize that the * namespace is "deleted". When the last namespaceName object * in any byte code code unit that refers to the namespace has * been freed (i.e., when the namespace's refCount is 0), the * namespace's storage will be freed. + * NS_KILLED 1 means that TclTeardownNamespace has already been called on + * this namespace and it should not be called again [Bug 1355942] */ #define NS_DYING 0x01 #define NS_DEAD 0x02 +#define NS_KILLED 0x04 /* * Flag passed to TclGetNamespaceForQualName to have it create all namespace * components of a namespace-qualified name that cannot be found. The new * namespaces are created within their specified parent. Note that this @@ -309,10 +351,12 @@ * if no more. */ CommandTrace *nextTracePtr; /* Next trace to check after current * trace procedure returns; if this * trace gets deleted, must update pointer * to avoid using free'd memory. */ + int reverseScan; /* Boolean set true when the traces + * are scanning in reverse order. */ } ActiveCommandTrace; /* * When a variable trace is active (i.e. its associated procedure is * executing), one of the following structures is linked into a list @@ -682,10 +726,12 @@ * if no more. */ Trace *nextTracePtr; /* Next trace to check after current * trace procedure returns; if this * trace gets deleted, must update pointer * to avoid using free'd memory. */ + int reverseScan; /* Boolean set true when the traces + * are scanning in reverse order. */ } ActiveInterpTrace; /* * The structure below defines an entry in the assocData hash table which * is associated with an interpreter. The entry contains a pointer to a @@ -755,10 +801,117 @@ Var* compiledLocals; /* Points to the array of local variables * recognized by the compiler. The compiler * emits code that refers to these variables * using an index into this array. */ } CallFrame; + +#ifdef TCL_TIP280 +/* + * TIP #280 + * The structure below defines a command frame. A command frame + * provides location information for all commands executing a tcl + * script (source, eval, uplevel, procedure bodies, ...). The runtime + * structure essentially contains the stack trace as it would be if + * the currently executing command were to throw an error. + * + * For commands where it makes sense it refers to the associated + * CallFrame as well. + * + * The structures are chained in a single list, with the top of the + * stack anchored in the Interp structure. + * + * Instances can be allocated on the C stack, or the heap, the former + * making cleanup a bit simpler. + */ + +typedef struct CmdFrame { + /* General data. Always available. */ + + int type; /* Values see below */ + int level; /* #Frames in stack, prevent O(n) scan of list */ + int* line; /* Lines the words of the command start on */ + int nline; + + CallFrame* framePtr; /* Procedure activation record, may be NULL */ + struct CmdFrame* nextPtr; /* Link to calling frame */ + + /* Data needed for Eval vs TEBC + * + * EXECUTION CONTEXTS and usage of CmdFrame + * + * Field TEBC EvalEx EvalObjEx + * ======= ==== ====== ========= + * level yes yes yes + * type BC/PREBC SRC/EVAL EVAL_LIST + * line0 yes yes yes + * framePtr yes yes yes + * ======= ==== ====== ========= + * + * ======= ==== ====== ========= union data + * line1 - yes - + * line3 - yes - + * path - yes - + * ------- ---- ------ --------- + * codePtr yes - - + * pc yes - - + * ======= ==== ====== ========= + * + * ======= ==== ====== ========= | union cmd + * listPtr - - yes | + * ------- ---- ------ --------- | + * cmd yes yes - | + * cmdlen yes yes - | + * ------- ---- ------ --------- | + */ + + union { + struct { + Tcl_Obj* path; /* Path of the sourced file the command + * is in. */ + } eval; + struct { + CONST void* codePtr; /* Byte code currently executed */ + CONST char* pc; /* and instruction pointer. */ + } tebc; + } data; + + union { + struct { + CONST char* cmd; /* The executed command, if possible */ + int len; /* And its length */ + } str; + Tcl_Obj* listPtr; /* Tcl_EvalObjEx, cmd list */ + } cmd; + +} CmdFrame; + +/* The following macros define the allowed values for the type field + * of the CmdFrame structure above. Some of the values occur only in + * the extended location data referenced via the 'baseLocPtr'. + * + * TCL_LOCATION_EVAL : Frame is for a script evaluated by EvalEx. + * TCL_LOCATION_EVAL_LIST : Frame is for a script evaluated by the list + * optimization path of EvalObjEx. + * TCL_LOCATION_BC : Frame is for bytecode. + * TCL_LOCATION_PREBC : Frame is for precompiled bytecode. + * TCL_LOCATION_SOURCE : Frame is for a script evaluated by EvalEx, + * from a sourced file. + * TCL_LOCATION_PROC : Frame is for bytecode of a procedure. + * + * A TCL_LOCATION_BC type in a frame can be overridden by _SOURCE and + * _PROC types, per the context of the byte code in execution. + */ + +#define TCL_LOCATION_EVAL (0) /* Location in a dynamic eval script */ +#define TCL_LOCATION_EVAL_LIST (1) /* Location in a dynamic eval script, list-path */ +#define TCL_LOCATION_BC (2) /* Location in byte code */ +#define TCL_LOCATION_PREBC (3) /* Location in precompiled byte code, no location */ +#define TCL_LOCATION_SOURCE (4) /* Location in a file */ +#define TCL_LOCATION_PROC (5) /* Location in a dynamic proc */ + +#define TCL_LOCATION_LAST (6) /* Number of values in the enum */ +#endif /* *---------------------------------------------------------------- * Data structures and procedures related to TclHandles, which * are a very lightweight method of preserving enough information @@ -1113,10 +1266,21 @@ struct ResolverScheme *nextPtr; /* Pointer to next record in linked list. */ } ResolverScheme; +#ifdef TCL_TIP268 +/* + * TIP #268. + * Values for the selection mode, i.e the package require preferences. + */ + +enum PkgPreferOptions { + PKG_PREFER_LATEST, PKG_PREFER_STABLE +}; +#endif + /* *---------------------------------------------------------------- * This structure defines an interpreter, which is a collection of * commands plus other state information related to interpreting * commands, such as variable storage. Primary responsibility for @@ -1304,10 +1468,45 @@ * interp, or NULL if no active traces. */ int tracesForbiddingInline; /* Count of traces (in the list headed by * tracePtr) that forbid inline bytecode * compilation */ +#ifdef TCL_TIP280 + /* TIP #280 */ + CmdFrame* cmdFramePtr; /* Points to the command frame containing + * the location information for the current + * command. */ + CONST CmdFrame* invokeCmdFramePtr; /* Points to the command frame which is the + * invoking context of the bytecode compiler. + * NULL when the byte code compiler is not + * active */ + int invokeWord; /* Index of the word in the command which + * is getting compiled. */ + Tcl_HashTable* linePBodyPtr; + /* This table remembers for each + * statically defined procedure the + * location information for its + * body. It is keyed by the address of + * the Proc structure for a procedure. + */ + Tcl_HashTable* lineBCPtr; + /* This table remembers for each + * ByteCode object the location + * information for its body. It is + * keyed by the address of the Proc + * structure for a procedure. + */ +#endif +#ifdef TCL_TIP268 + /* + * TIP #268. + * The currently active selection mode, + * i.e the package require preferences. + */ + + int packagePrefer; /* Current package selection mode. */ +#endif /* * Statistical information about the bytecode compiler and interpreter's * operation. */ @@ -1327,10 +1526,14 @@ * codes other than these should be turned into errors. */ #define TCL_BRACKET_TERM 1 #define TCL_ALLOW_EXCEPTIONS 4 +#ifdef TCL_TIP280 +#define TCL_EVAL_FILE 2 +#define TCL_EVAL_CTX 8 +#endif /* * Flag bits for Interp structures: * * DELETED: Non-zero means the interpreter has been deleted: @@ -1377,41 +1580,10 @@ #define DONT_COMPILE_CMDS_INLINE 0x20 #define RAND_SEED_INITIALIZED 0x40 #define SAFE_INTERP 0x80 #define USE_EVAL_DIRECT 0x100 #define INTERP_TRACE_IN_PROGRESS 0x200 - -/* - *---------------------------------------------------------------- - * Data structures related to command parsing. These are used in - * tclParse.c and its clients. - *---------------------------------------------------------------- - */ - -/* - * The following data structure is used by various parsing procedures - * to hold information about where to store the results of parsing - * (e.g. the substituted contents of a quoted argument, or the result - * of a nested command). At any given time, the space available - * for output is fixed, but a procedure may be called to expand the - * space available if the current space runs out. - */ - -typedef struct ParseValue { - char *buffer; /* Address of first character in - * output buffer. */ - char *next; /* Place to store next character in - * output buffer. */ - char *end; /* Address of the last usable character - * in the buffer. */ - void (*expandProc) _ANSI_ARGS_((struct ParseValue *pvPtr, int needed)); - /* Procedure to call when space runs out; - * it will make more space. */ - ClientData clientData; /* Arbitrary information for use of - * expandProc. */ -} ParseValue; - /* * Maximum number of levels of nesting permitted in Tcl commands (used * to catch infinite recursion). */ @@ -1528,10 +1700,11 @@ /* * Opaque names for platform specific types. */ typedef struct TclpTime_t_ *TclpTime_t; +typedef struct TclpTime_t_ *CONST TclpTime_t_CONST; /* * The "globParameters" argument of the function TclGlob is an * or'ed combination of the following values: */ @@ -1575,10 +1748,11 @@ extern char * tclNativeExecutableName; extern char * tclDefaultEncodingDir; extern Tcl_ChannelType tclFileChannelType; extern char * tclMemDumpFileName; extern TclPlatformType tclPlatform; +extern Tcl_NotifierProcs tclOriginalNotifier; /* * Variables denoting the Tcl object types defined in the core. */ @@ -1592,13 +1766,11 @@ extern Tcl_ObjType tclProcBodyType; extern Tcl_ObjType tclStringType; extern Tcl_ObjType tclArraySearchType; extern Tcl_ObjType tclIndexType; extern Tcl_ObjType tclNsNameType; -#ifndef TCL_WIDE_INT_IS_LONG extern Tcl_ObjType tclWideIntType; -#endif /* * Variables denoting the hash key types defined in the core. */ @@ -1635,14 +1807,28 @@ * Procedures shared among Tcl modules but not used by the outside * world: *---------------------------------------------------------------- */ +#ifdef TCL_TIP280 +EXTERN void TclAdvanceLines _ANSI_ARGS_((int* line, CONST char* start, + CONST char* end)); +#endif EXTERN int TclArraySet _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *arrayNameObj, Tcl_Obj *arrayElemObj)); EXTERN int TclCheckBadOctal _ANSI_ARGS_((Tcl_Interp *interp, CONST char *value)); +EXTERN void TclDeleteNamespaceVars _ANSI_ARGS_((Namespace *nsPtr)); + +#ifdef TCL_TIP280 +EXTERN int TclEvalObjEx _ANSI_ARGS_((Tcl_Interp *interp, + register Tcl_Obj *objPtr, + int flags, + CONST CmdFrame* invoker, + int word)); +#endif + EXTERN void TclExpandTokenArray _ANSI_ARGS_(( Tcl_Parse *parsePtr)); EXTERN int TclFileAttrsCmd _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int TclFileCopyCmd _ANSI_ARGS_((Tcl_Interp *interp, @@ -1652,25 +1838,32 @@ EXTERN int TclFileMakeDirsCmd _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) ; EXTERN int TclFileRenameCmd _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) ; EXTERN void TclFinalizeAllocSubsystem _ANSI_ARGS_((void)); -EXTERN void TclFinalizeCompExecEnv _ANSI_ARGS_((void)); +EXTERN void TclFinalizeAsync _ANSI_ARGS_((void)); EXTERN void TclFinalizeCompilation _ANSI_ARGS_((void)); EXTERN void TclFinalizeEncodingSubsystem _ANSI_ARGS_((void)); EXTERN void TclFinalizeEnvironment _ANSI_ARGS_((void)); EXTERN void TclFinalizeExecution _ANSI_ARGS_((void)); EXTERN void TclFinalizeIOSubsystem _ANSI_ARGS_((void)); EXTERN void TclFinalizeFilesystem _ANSI_ARGS_((void)); EXTERN void TclResetFilesystem _ANSI_ARGS_((void)); EXTERN void TclFinalizeLoad _ANSI_ARGS_((void)); +EXTERN void TclFinalizeLock _ANSI_ARGS_((void)); EXTERN void TclFinalizeMemorySubsystem _ANSI_ARGS_((void)); EXTERN void TclFinalizeNotifier _ANSI_ARGS_((void)); -EXTERN void TclFinalizeAsync _ANSI_ARGS_((void)); +EXTERN void TclFinalizeObjects _ANSI_ARGS_((void)); +EXTERN void TclFinalizePreserve _ANSI_ARGS_((void)); EXTERN void TclFinalizeSynchronization _ANSI_ARGS_((void)); +EXTERN void TclFinalizeThreadAlloc _ANSI_ARGS_((void)); EXTERN void TclFinalizeThreadData _ANSI_ARGS_((void)); -EXTERN void TclFindEncodings _ANSI_ARGS_((CONST char *argv0)); +EXTERN int TclGetEncodingFromObj _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr)); +#ifdef TCL_TIP280 +EXTERN void TclGetSrcInfoForPc _ANSI_ARGS_((CmdFrame* cfPtr)); +#endif EXTERN int TclGlob _ANSI_ARGS_((Tcl_Interp *interp, char *pattern, Tcl_Obj *unquotedPrefix, int globFlags, Tcl_GlobTypeData* types)); EXTERN void TclInitAlloc _ANSI_ARGS_((void)); EXTERN void TclInitDbCkalloc _ANSI_ARGS_((void)); @@ -1709,10 +1902,13 @@ Tcl_UniChar *resultPtr)); EXTERN int TclParseInteger _ANSI_ARGS_((CONST char *string, int numBytes)); EXTERN int TclParseWhiteSpace _ANSI_ARGS_((CONST char *src, int numBytes, Tcl_Parse *parsePtr, char *typePtr)); +#ifdef TCL_TIP280 +EXTERN int TclWordKnownAtCompileTime _ANSI_ARGS_((Tcl_Token* token)); +#endif EXTERN int TclpObjAccess _ANSI_ARGS_((Tcl_Obj *filename, int mode)); EXTERN int TclpObjLstat _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf)); EXTERN int TclpCheckStackSpace _ANSI_ARGS_((void)); @@ -1721,19 +1917,21 @@ CONST char *addStrRep, int len)); EXTERN int TclpDeleteFile _ANSI_ARGS_((CONST char *path)); EXTERN void TclpFinalizeCondition _ANSI_ARGS_(( Tcl_Condition *condPtr)); EXTERN void TclpFinalizeMutex _ANSI_ARGS_((Tcl_Mutex *mutexPtr)); +EXTERN void TclpFinalizePipes _ANSI_ARGS_((void)); +EXTERN void TclpFinalizeSockets _ANSI_ARGS_((void)); EXTERN void TclpFinalizeThreadData _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr)); EXTERN void TclpFinalizeThreadDataKey _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr)); EXTERN char * TclpFindExecutable _ANSI_ARGS_(( CONST char *argv0)); EXTERN int TclpFindVariable _ANSI_ARGS_((CONST char *name, int *lengthPtr)); -EXTERN void TclpInitLibraryPath _ANSI_ARGS_((CONST char *argv0)); +EXTERN int TclpInitLibraryPath _ANSI_ARGS_((CONST char *argv0)); EXTERN void TclpInitLock _ANSI_ARGS_((void)); EXTERN void TclpInitPlatform _ANSI_ARGS_((void)); EXTERN void TclpInitUnlock _ANSI_ARGS_((void)); EXTERN int TclpLoadFile _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, @@ -1770,21 +1968,20 @@ Tcl_Obj *destPathPtr)); EXTERN int TclpMatchInDirectory _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, CONST char *pattern, Tcl_GlobTypeData *types)); EXTERN Tcl_Obj* TclpObjGetCwd _ANSI_ARGS_((Tcl_Interp *interp)); +EXTERN Tcl_FSDupInternalRepProc TclNativeDupInternalRep; EXTERN Tcl_Obj* TclpObjLink _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkType)); EXTERN int TclpObjChdir _ANSI_ARGS_((Tcl_Obj *pathPtr)); EXTERN Tcl_Obj* TclFileDirname _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj*pathPtr)); EXTERN int TclpObjStat _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf)); EXTERN Tcl_Channel TclpOpenFileChannel _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, int mode, int permissions)); -EXTERN void TclpCutFileChannel _ANSI_ARGS_((Tcl_Channel chan)); -EXTERN void TclpSpliceFileChannel _ANSI_ARGS_((Tcl_Channel chan)); EXTERN void TclpPanic _ANSI_ARGS_(TCL_VARARGS(CONST char *, format)); EXTERN char * TclpReadlink _ANSI_ARGS_((CONST char *fileName, Tcl_DString *linkPtr)); EXTERN void TclpReleaseFile _ANSI_ARGS_((TclFile file)); @@ -1794,10 +1991,15 @@ Tcl_ThreadDataKey *keyPtr)); EXTERN void TclpThreadDataKeyInit _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr)); EXTERN void TclpThreadDataKeySet _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr, VOID *data)); +EXTERN int TclpThreadCreate _ANSI_ARGS_(( + Tcl_ThreadId *idPtr, + Tcl_ThreadCreateProc proc, + ClientData clientData, + int stackSize, int flags)); EXTERN void TclpThreadExit _ANSI_ARGS_((int status)); EXTERN void TclRememberCondition _ANSI_ARGS_((Tcl_Condition *mutex)); EXTERN void TclRememberDataKey _ANSI_ARGS_((Tcl_ThreadDataKey *mutex)); EXTERN VOID TclRememberJoinableThread _ANSI_ARGS_((Tcl_ThreadId id)); EXTERN void TclRememberMutex _ANSI_ARGS_((Tcl_Mutex *mutex)); @@ -1815,10 +2017,19 @@ Tcl_Obj *pathPtr, Tcl_LoadHandle *loadHandle, Tcl_FSUnloadFileProc **unloadProcPtr)); EXTERN int TclpUtime _ANSI_ARGS_((Tcl_Obj *pathPtr, struct utimbuf *tval)); + +#ifdef TCL_LOAD_FROM_MEMORY +EXTERN void* TclpLoadMemoryGetBuffer _ANSI_ARGS_(( + Tcl_Interp *interp, int size)); +EXTERN int TclpLoadMemory _ANSI_ARGS_((Tcl_Interp *interp, + void *buffer, int size, int codeSize, + Tcl_LoadHandle *loadHandle, + Tcl_FSUnloadFileProc **unloadProcPtr)); +#endif /* *---------------------------------------------------------------- * Command procedures in the generic core: *---------------------------------------------------------------- @@ -2105,11 +2316,16 @@ (objPtr)->refCount = 0; \ (objPtr)->bytes = tclEmptyStringRep; \ (objPtr)->length = 0; \ (objPtr)->typePtr = NULL -#define TclDecrRefCount(objPtr) \ + +#ifdef TCL_MEM_DEBUG +# define TclDecrRefCount(objPtr) \ + Tcl_DbDecrRefCount(objPtr, __FILE__, __LINE__) +#else +# define TclDecrRefCount(objPtr) \ if (--(objPtr)->refCount <= 0) { \ if (((objPtr)->typePtr != NULL) \ && ((objPtr)->typePtr->freeIntRepProc != NULL)) { \ (objPtr)->typePtr->freeIntRepProc(objPtr); \ } \ @@ -2118,10 +2334,11 @@ ckfree((char *) (objPtr)->bytes); \ } \ TclFreeObjStorage(objPtr); \ TclIncrObjsFreed(); \ } +#endif #ifdef TCL_MEM_DEBUG # define TclAllocObjStorage(objPtr) \ (objPtr) = (Tcl_Obj *) \ Tcl_DbCkalloc(sizeof(Tcl_Obj), __FILE__, __LINE__) @@ -2163,10 +2380,14 @@ * from per-thread caches. */ EXTERN Tcl_Obj *TclThreadAllocObj _ANSI_ARGS_((void)); EXTERN void TclThreadFreeObj _ANSI_ARGS_((Tcl_Obj *)); +EXTERN void TclFreeAllocCache _ANSI_ARGS_((void *)); +EXTERN void TclpFreeAllocMutex _ANSI_ARGS_((Tcl_Mutex* mutex)); +EXTERN void TclpFreeAllocCache _ANSI_ARGS_((void *)); + # define TclAllocObjStorage(objPtr) \ (objPtr) = TclThreadAllocObj() # define TclFreeObjStorage(objPtr) \ @@ -2237,10 +2458,30 @@ */ #define TclGetString(objPtr) \ ((objPtr)->bytes? (objPtr)->bytes : Tcl_GetString((objPtr))) +/* + *---------------------------------------------------------------- + * Macro used by the Tcl core to get a Tcl_WideInt value out of + * a Tcl_Obj of the "wideInt" type. Different implementation on + * different platforms depending whether TCL_WIDE_INT_IS_LONG. + *---------------------------------------------------------------- + */ + +#ifdef TCL_WIDE_INT_IS_LONG +# define TclGetWide(resultVar, objPtr) \ + (resultVar) = (objPtr)->internalRep.longValue +# define TclGetLongFromWide(resultVar, objPtr) \ + (resultVar) = (objPtr)->internalRep.longValue +#else +# define TclGetWide(resultVar, objPtr) \ + (resultVar) = (objPtr)->internalRep.wideValue +# define TclGetLongFromWide(resultVar, objPtr) \ + (resultVar) = Tcl_WideAsLong((objPtr)->internalRep.wideValue) +#endif + /* *---------------------------------------------------------------- * Macro used by the Tcl core get a unicode char from a utf string. * It checks to see if we have a one-byte utf char before calling * the real Tcl_UtfToUniChar, as this will save a lot of time for Index: generic/tclIntDecls.h ================================================================== --- generic/tclIntDecls.h +++ generic/tclIntDecls.h @@ -9,11 +9,11 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIntDecls.h,v 1.49 2003/02/18 02:25:45 hobbs Exp $ + * RCS: @(#) $Id: tclIntDecls.h,v 1.49.2.9 2007/04/21 19:52:14 kennykb Exp $ */ #ifndef _TCLINTDECLS #define _TCLINTDECLS @@ -113,12 +113,12 @@ EXTERN int TclFormatInt _ANSI_ARGS_((char * buffer, long n)); /* 25 */ EXTERN void TclFreePackageInfo _ANSI_ARGS_((Interp * iPtr)); /* Slot 26 is reserved */ /* 27 */ -EXTERN int TclGetDate _ANSI_ARGS_((char * p, unsigned long now, - long zone, unsigned long * timePtr)); +EXTERN int TclGetDate _ANSI_ARGS_((char * p, Tcl_WideInt now, + long zone, Tcl_WideInt * timePtr)); /* 28 */ EXTERN Tcl_Channel TclpGetDefaultStdChannel _ANSI_ARGS_((int type)); /* Slot 29 is reserved */ /* Slot 30 is reserved */ /* 31 */ @@ -239,11 +239,11 @@ /* 76 */ EXTERN unsigned long TclpGetSeconds _ANSI_ARGS_((void)); /* 77 */ EXTERN void TclpGetTime _ANSI_ARGS_((Tcl_Time * time)); /* 78 */ -EXTERN int TclpGetTimeZone _ANSI_ARGS_((unsigned long time)); +EXTERN int TclpGetTimeZone _ANSI_ARGS_((Tcl_WideInt time)); /* Slot 79 is reserved */ /* Slot 80 is reserved */ /* 81 */ EXTERN char * TclpRealloc _ANSI_ARGS_((char * ptr, unsigned int size)); @@ -501,10 +501,39 @@ /* 173 */ EXTERN int TclUniCharMatch _ANSI_ARGS_(( CONST Tcl_UniChar * string, int strLen, CONST Tcl_UniChar * pattern, int ptnLen, int nocase)); +/* Slot 174 is reserved */ +/* Slot 175 is reserved */ +/* Slot 176 is reserved */ +/* Slot 177 is reserved */ +/* Slot 178 is reserved */ +/* Slot 179 is reserved */ +/* Slot 180 is reserved */ +/* Slot 181 is reserved */ +/* 182 */ +EXTERN struct tm * TclpLocaltime _ANSI_ARGS_((TclpTime_t_CONST clock)); +/* 183 */ +EXTERN struct tm * TclpGmtime _ANSI_ARGS_((TclpTime_t_CONST clock)); +/* Slot 184 is reserved */ +/* Slot 185 is reserved */ +/* Slot 186 is reserved */ +/* Slot 187 is reserved */ +/* Slot 188 is reserved */ +/* Slot 189 is reserved */ +/* Slot 190 is reserved */ +/* Slot 191 is reserved */ +/* Slot 192 is reserved */ +/* Slot 193 is reserved */ +/* Slot 194 is reserved */ +/* Slot 195 is reserved */ +/* Slot 196 is reserved */ +/* Slot 197 is reserved */ +/* Slot 198 is reserved */ +/* 199 */ +EXTERN int TclMatchIsTrivial _ANSI_ARGS_((CONST char * pattern)); typedef struct TclIntStubs { int magic; struct TclIntStubHooks *hooks; @@ -549,11 +578,11 @@ int (*tclFindElement) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * listStr, int listLength, CONST char ** elementPtr, CONST char ** nextPtr, int * sizePtr, int * bracePtr)); /* 22 */ Proc * (*tclFindProc) _ANSI_ARGS_((Interp * iPtr, CONST char * procName)); /* 23 */ int (*tclFormatInt) _ANSI_ARGS_((char * buffer, long n)); /* 24 */ void (*tclFreePackageInfo) _ANSI_ARGS_((Interp * iPtr)); /* 25 */ void *reserved26; - int (*tclGetDate) _ANSI_ARGS_((char * p, unsigned long now, long zone, unsigned long * timePtr)); /* 27 */ + int (*tclGetDate) _ANSI_ARGS_((char * p, Tcl_WideInt now, long zone, Tcl_WideInt * timePtr)); /* 27 */ Tcl_Channel (*tclpGetDefaultStdChannel) _ANSI_ARGS_((int type)); /* 28 */ void *reserved29; void *reserved30; char * (*tclGetExtension) _ANSI_ARGS_((char * name)); /* 31 */ int (*tclGetFrame) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * str, CallFrame ** framePtrPtr)); /* 32 */ @@ -600,11 +629,11 @@ void *reserved73; void (*tclpFree) _ANSI_ARGS_((char * ptr)); /* 74 */ unsigned long (*tclpGetClicks) _ANSI_ARGS_((void)); /* 75 */ unsigned long (*tclpGetSeconds) _ANSI_ARGS_((void)); /* 76 */ void (*tclpGetTime) _ANSI_ARGS_((Tcl_Time * time)); /* 77 */ - int (*tclpGetTimeZone) _ANSI_ARGS_((unsigned long time)); /* 78 */ + int (*tclpGetTimeZone) _ANSI_ARGS_((Tcl_WideInt time)); /* 78 */ void *reserved79; void *reserved80; char * (*tclpRealloc) _ANSI_ARGS_((char * ptr, unsigned int size)); /* 81 */ void *reserved82; void *reserved83; @@ -704,10 +733,36 @@ int (*tclpUtfNcmp2) _ANSI_ARGS_((CONST char * s1, CONST char * s2, unsigned long n)); /* 169 */ int (*tclCheckInterpTraces) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * command, int numChars, Command * cmdPtr, int result, int traceFlags, int objc, Tcl_Obj *CONST objv[])); /* 170 */ int (*tclCheckExecutionTraces) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * command, int numChars, Command * cmdPtr, int result, int traceFlags, int objc, Tcl_Obj *CONST objv[])); /* 171 */ int (*tclInThreadExit) _ANSI_ARGS_((void)); /* 172 */ int (*tclUniCharMatch) _ANSI_ARGS_((CONST Tcl_UniChar * string, int strLen, CONST Tcl_UniChar * pattern, int ptnLen, int nocase)); /* 173 */ + void *reserved174; + void *reserved175; + void *reserved176; + void *reserved177; + void *reserved178; + void *reserved179; + void *reserved180; + void *reserved181; + struct tm * (*tclpLocaltime) _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 182 */ + struct tm * (*tclpGmtime) _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 183 */ + void *reserved184; + void *reserved185; + void *reserved186; + void *reserved187; + void *reserved188; + void *reserved189; + void *reserved190; + void *reserved191; + void *reserved192; + void *reserved193; + void *reserved194; + void *reserved195; + void *reserved196; + void *reserved197; + void *reserved198; + int (*tclMatchIsTrivial) _ANSI_ARGS_((CONST char * pattern)); /* 199 */ } TclIntStubs; #ifdef __cplusplus extern "C" { #endif @@ -1314,11 +1369,46 @@ #endif #ifndef TclUniCharMatch #define TclUniCharMatch \ (tclIntStubsPtr->tclUniCharMatch) /* 173 */ #endif +/* Slot 174 is reserved */ +/* Slot 175 is reserved */ +/* Slot 176 is reserved */ +/* Slot 177 is reserved */ +/* Slot 178 is reserved */ +/* Slot 179 is reserved */ +/* Slot 180 is reserved */ +/* Slot 181 is reserved */ +#ifndef TclpLocaltime +#define TclpLocaltime \ + (tclIntStubsPtr->tclpLocaltime) /* 182 */ +#endif +#ifndef TclpGmtime +#define TclpGmtime \ + (tclIntStubsPtr->tclpGmtime) /* 183 */ +#endif +/* Slot 184 is reserved */ +/* Slot 185 is reserved */ +/* Slot 186 is reserved */ +/* Slot 187 is reserved */ +/* Slot 188 is reserved */ +/* Slot 189 is reserved */ +/* Slot 190 is reserved */ +/* Slot 191 is reserved */ +/* Slot 192 is reserved */ +/* Slot 193 is reserved */ +/* Slot 194 is reserved */ +/* Slot 195 is reserved */ +/* Slot 196 is reserved */ +/* Slot 197 is reserved */ +/* Slot 198 is reserved */ +#ifndef TclMatchIsTrivial +#define TclMatchIsTrivial \ + (tclIntStubsPtr->tclMatchIsTrivial) /* 199 */ +#endif #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ /* !END!: Do not edit above this line. */ #endif /* _TCLINTDECLS */ Index: generic/tclIntPlatDecls.h ================================================================== --- generic/tclIntPlatDecls.h +++ generic/tclIntPlatDecls.h @@ -7,11 +7,11 @@ * versions. Use at your own risk. * * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. * - * RCS: @(#) $Id: tclIntPlatDecls.h,v 1.19 2002/12/06 23:22:59 hobbs Exp $ + * RCS: @(#) $Id: tclIntPlatDecls.h,v 1.19.2.7 2007/04/21 19:52:14 kennykb Exp $ */ #ifndef _TCLINTPLATDECLS #define _TCLINTPLATDECLS @@ -60,13 +60,14 @@ EXTERN TclFile TclpCreateTempFile _ANSI_ARGS_(( CONST char * contents)); /* 10 */ EXTERN Tcl_DirEntry * TclpReaddir _ANSI_ARGS_((DIR * dir)); /* 11 */ -EXTERN struct tm * TclpLocaltime _ANSI_ARGS_((time_t * clock)); +EXTERN struct tm * TclpLocaltime_unix _ANSI_ARGS_(( + TclpTime_t_CONST clock)); /* 12 */ -EXTERN struct tm * TclpGmtime _ANSI_ARGS_((time_t * clock)); +EXTERN struct tm * TclpGmtime_unix _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 13 */ EXTERN char * TclpInetNtoa _ANSI_ARGS_((struct in_addr addr)); #endif /* UNIX */ #ifdef __WIN32__ /* 0 */ @@ -137,10 +138,13 @@ EXTERN void TclWinSetInterfaces _ANSI_ARGS_((int wide)); /* 27 */ EXTERN void TclWinFlushDirtyChannels _ANSI_ARGS_((void)); /* 28 */ EXTERN void TclWinResetInterfaces _ANSI_ARGS_((void)); +/* 29 */ +EXTERN int TclWinCPUID _ANSI_ARGS_((unsigned int index, + unsigned int * regs)); #endif /* __WIN32__ */ #ifdef MAC_TCL /* 0 */ EXTERN VOID * TclpSysAlloc _ANSI_ARGS_((long size, int isBin)); /* 1 */ @@ -227,12 +231,12 @@ TclFile (*tclpMakeFile) _ANSI_ARGS_((Tcl_Channel channel, int direction)); /* 6 */ TclFile (*tclpOpenFile) _ANSI_ARGS_((CONST char * fname, int mode)); /* 7 */ int (*tclUnixWaitForFile) _ANSI_ARGS_((int fd, int mask, int timeout)); /* 8 */ TclFile (*tclpCreateTempFile) _ANSI_ARGS_((CONST char * contents)); /* 9 */ Tcl_DirEntry * (*tclpReaddir) _ANSI_ARGS_((DIR * dir)); /* 10 */ - struct tm * (*tclpLocaltime) _ANSI_ARGS_((time_t * clock)); /* 11 */ - struct tm * (*tclpGmtime) _ANSI_ARGS_((time_t * clock)); /* 12 */ + struct tm * (*tclpLocaltime_unix) _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 11 */ + struct tm * (*tclpGmtime_unix) _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 12 */ char * (*tclpInetNtoa) _ANSI_ARGS_((struct in_addr addr)); /* 13 */ #endif /* UNIX */ #ifdef __WIN32__ void (*tclWinConvertError) _ANSI_ARGS_((DWORD errCode)); /* 0 */ void (*tclWinConvertWSAError) _ANSI_ARGS_((DWORD errCode)); /* 1 */ @@ -261,10 +265,11 @@ char * (*tclWinNoBackslash) _ANSI_ARGS_((char * path)); /* 24 */ TclPlatformType * (*tclWinGetPlatform) _ANSI_ARGS_((void)); /* 25 */ void (*tclWinSetInterfaces) _ANSI_ARGS_((int wide)); /* 26 */ void (*tclWinFlushDirtyChannels) _ANSI_ARGS_((void)); /* 27 */ void (*tclWinResetInterfaces) _ANSI_ARGS_((void)); /* 28 */ + int (*tclWinCPUID) _ANSI_ARGS_((unsigned int index, unsigned int * regs)); /* 29 */ #endif /* __WIN32__ */ #ifdef MAC_TCL VOID * (*tclpSysAlloc) _ANSI_ARGS_((long size, int isBin)); /* 0 */ void (*tclpSysFree) _ANSI_ARGS_((VOID * ptr)); /* 1 */ VOID * (*tclpSysRealloc) _ANSI_ARGS_((VOID * cp, unsigned int size)); /* 2 */ @@ -349,17 +354,17 @@ #endif #ifndef TclpReaddir #define TclpReaddir \ (tclIntPlatStubsPtr->tclpReaddir) /* 10 */ #endif -#ifndef TclpLocaltime -#define TclpLocaltime \ - (tclIntPlatStubsPtr->tclpLocaltime) /* 11 */ +#ifndef TclpLocaltime_unix +#define TclpLocaltime_unix \ + (tclIntPlatStubsPtr->tclpLocaltime_unix) /* 11 */ #endif -#ifndef TclpGmtime -#define TclpGmtime \ - (tclIntPlatStubsPtr->tclpGmtime) /* 12 */ +#ifndef TclpGmtime_unix +#define TclpGmtime_unix \ + (tclIntPlatStubsPtr->tclpGmtime_unix) /* 12 */ #endif #ifndef TclpInetNtoa #define TclpInetNtoa \ (tclIntPlatStubsPtr->tclpInetNtoa) /* 13 */ #endif @@ -464,10 +469,14 @@ #endif #ifndef TclWinResetInterfaces #define TclWinResetInterfaces \ (tclIntPlatStubsPtr->tclWinResetInterfaces) /* 28 */ #endif +#ifndef TclWinCPUID +#define TclWinCPUID \ + (tclIntPlatStubsPtr->tclWinCPUID) /* 29 */ +#endif #endif /* __WIN32__ */ #ifdef MAC_TCL #ifndef TclpSysAlloc #define TclpSysAlloc \ (tclIntPlatStubsPtr->tclpSysAlloc) /* 0 */ Index: generic/tclInterp.c ================================================================== --- generic/tclInterp.c +++ generic/tclInterp.c @@ -7,11 +7,11 @@ * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInterp.c,v 1.20 2002/11/27 02:54:00 hobbs Exp $ + * RCS: @(#) $Id: tclInterp.c,v 1.20.2.3 2006/11/28 22:20:02 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclPort.h" #include @@ -459,11 +459,13 @@ } if (slavePtr != NULL) { Tcl_WrongNumArgs(interp, 2, objv, "?-safe? ?--? ?path?"); return TCL_ERROR; } - slavePtr = objv[i]; + if (i < objc) { + slavePtr = objv[i]; + } } buf[0] = '\0'; if (slavePtr == NULL) { /* * Create an anonymous interpreter -- we choose its name and @@ -1442,11 +1444,11 @@ Tcl_Obj *CONST objv[]; /* Argument vector. */ { #define ALIAS_CMDV_PREALLOC 10 Tcl_Interp *targetInterp; Alias *aliasPtr; - int result, prefc, cmdc; + int result, prefc, cmdc, i; Tcl_Obj **prefv, **cmdv; Tcl_Obj *cmdArr[ALIAS_CMDV_PREALLOC]; aliasPtr = (Alias *) clientData; targetInterp = aliasPtr->targetInterp; @@ -1470,17 +1472,23 @@ memcpy((VOID *) (cmdv+prefc), (VOID *) (objv+1), (size_t) ((objc-1) * sizeof(Tcl_Obj *))); Tcl_ResetResult(targetInterp); + for (i=0; icmdFramePtr,0); +#endif } else { objPtr = Tcl_ConcatObj(objc, objv); Tcl_IncrRefCount(objPtr); result = Tcl_EvalObjEx(slaveInterp, objPtr, 0); Tcl_DecrRefCount(objPtr); Index: generic/tclLink.c ================================================================== --- generic/tclLink.c +++ generic/tclLink.c @@ -11,11 +11,11 @@ * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclLink.c,v 1.8 2002/08/05 03:24:41 dgp Exp $ + * RCS: @(#) $Id: tclLink.c,v 1.8.2.2 2007/05/10 18:23:58 dgp Exp $ */ #include "tclInt.h" /* @@ -93,11 +93,11 @@ * to varName. */ int type; /* Type of C variable: TCL_LINK_INT, etc. * Also may have TCL_LINK_READ_ONLY * OR'ed in. */ { - Tcl_Obj *objPtr; + Tcl_Obj *objPtr, *resPtr; Link *linkPtr; int code; linkPtr = (Link *) ckalloc(sizeof(Link)); linkPtr->interp = interp; @@ -109,14 +109,16 @@ linkPtr->flags = LINK_READ_ONLY; } else { linkPtr->flags = 0; } objPtr = ObjValue(linkPtr); - if (Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, objPtr, - TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { + Tcl_IncrRefCount(objPtr); + resPtr = Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, objPtr, + TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG); + Tcl_DecrRefCount(objPtr); + if (resPtr == NULL) { Tcl_DecrRefCount(linkPtr->varName); - Tcl_DecrRefCount(objPtr); ckfree((char *) linkPtr); return TCL_ERROR; } code = Tcl_TraceVar(interp, varName, TCL_GLOBAL_ONLY|TCL_TRACE_READS |TCL_TRACE_WRITES|TCL_TRACE_UNSETS, LinkTraceProc, @@ -189,20 +191,23 @@ Tcl_Interp *interp; /* Interpreter containing variable. */ CONST char *varName; /* Name of global variable that is linked. */ { Link *linkPtr; int savedFlag; + Tcl_Obj *objPtr; linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY, LinkTraceProc, (ClientData) NULL); if (linkPtr == NULL) { return; } savedFlag = linkPtr->flags & LINK_BEING_UPDATED; linkPtr->flags |= LINK_BEING_UPDATED; - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), - TCL_GLOBAL_ONLY); + objPtr = ObjValue(linkPtr); + Tcl_IncrRefCount(objPtr); + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, objPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(objPtr); linkPtr->flags = (linkPtr->flags & ~LINK_BEING_UPDATED) | savedFlag; } /* *---------------------------------------------------------------------- @@ -235,24 +240,27 @@ { Link *linkPtr = (Link *) clientData; int changed, valueLength; CONST char *value; char **pp, *result; - Tcl_Obj *objPtr, *valueObj; + Tcl_Obj *objPtr, *valueObj, *tmpPtr; /* * If the variable is being unset, then just re-create it (with a * trace) unless the whole interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { - if (flags & TCL_INTERP_DESTROYED) { + if (Tcl_InterpDeleted(interp)) { Tcl_DecrRefCount(linkPtr->varName); ckfree((char *) linkPtr); } else if (flags & TCL_TRACE_DESTROYED) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + tmpPtr = ObjValue(linkPtr); + Tcl_IncrRefCount(tmpPtr); + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(tmpPtr); Tcl_TraceVar(interp, Tcl_GetString(linkPtr->varName), TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES |TCL_TRACE_UNSETS, LinkTraceProc, (ClientData) linkPtr); } return NULL; @@ -291,12 +299,15 @@ break; default: return "internal error: bad linked variable type"; } if (changed) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + tmpPtr = ObjValue(linkPtr); + Tcl_IncrRefCount(tmpPtr); + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(tmpPtr); } return NULL; } /* @@ -307,12 +318,15 @@ * and restore the interpreter's result, since the variable access * could occur when the result has been partially set. */ if (linkPtr->flags & LINK_READ_ONLY) { - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + tmpPtr = ObjValue(linkPtr); + Tcl_IncrRefCount(tmpPtr); + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(tmpPtr); return "linked variable is read-only"; } valueObj = Tcl_ObjGetVar2(interp, linkPtr->varName,NULL, TCL_GLOBAL_ONLY); if (valueObj == NULL) { /* @@ -329,12 +343,15 @@ switch (linkPtr->type) { case TCL_LINK_INT: if (Tcl_GetIntFromObj(interp, valueObj, &linkPtr->lastValue.i) != TCL_OK) { Tcl_SetObjResult(interp, objPtr); - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + tmpPtr = ObjValue(linkPtr); + Tcl_IncrRefCount(tmpPtr); + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(tmpPtr); result = "variable must have integer value"; goto end; } *(int *)(linkPtr->addr) = linkPtr->lastValue.i; break; @@ -341,12 +358,15 @@ case TCL_LINK_WIDE_INT: if (Tcl_GetWideIntFromObj(interp, valueObj, &linkPtr->lastValue.w) != TCL_OK) { Tcl_SetObjResult(interp, objPtr); - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + tmpPtr = ObjValue(linkPtr); + Tcl_IncrRefCount(tmpPtr); + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(tmpPtr); result = "variable must have integer value"; goto end; } *(Tcl_WideInt *)(linkPtr->addr) = linkPtr->lastValue.w; break; @@ -353,12 +373,15 @@ case TCL_LINK_DOUBLE: if (Tcl_GetDoubleFromObj(interp, valueObj, &linkPtr->lastValue.d) != TCL_OK) { Tcl_SetObjResult(interp, objPtr); - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + tmpPtr = ObjValue(linkPtr); + Tcl_IncrRefCount(tmpPtr); + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(tmpPtr); result = "variable must have real value"; goto end; } *(double *)(linkPtr->addr) = linkPtr->lastValue.d; break; @@ -365,12 +388,15 @@ case TCL_LINK_BOOLEAN: if (Tcl_GetBooleanFromObj(interp, valueObj, &linkPtr->lastValue.i) != TCL_OK) { Tcl_SetObjResult(interp, objPtr); - Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr), + tmpPtr = ObjValue(linkPtr); + Tcl_IncrRefCount(tmpPtr); + Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(tmpPtr); result = "variable must have boolean value"; goto end; } *(int *)(linkPtr->addr) = linkPtr->lastValue.i; break; Index: generic/tclListObj.c ================================================================== --- generic/tclListObj.c +++ generic/tclListObj.c @@ -9,11 +9,11 @@ * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclListObj.c,v 1.13 2002/01/07 23:09:13 dgp Exp $ + * RCS: @(#) $Id: tclListObj.c,v 1.13.4.2 2005/08/25 22:27:08 dkf Exp $ */ #include "tclInt.h" /* @@ -678,21 +678,13 @@ numAfterLast = (numElems - start); shift = (objc - count); /* numNewElems - numDeleted */ if ((numAfterLast > 0) && (shift != 0)) { Tcl_Obj **src, **dst; - if (shift < 0) { - for (src = elemPtrs + start, dst = src + shift; - numAfterLast > 0; numAfterLast--, src++, dst++) { - *dst = *src; - } - } else { - for (src = elemPtrs + numElems - 1, dst = src + shift; - numAfterLast > 0; numAfterLast--, src--, dst--) { - *dst = *src; - } - } + src = elemPtrs + start; dst = src + shift; + memmove((VOID*) dst, (VOID*) src, + (size_t) (numAfterLast * sizeof(Tcl_Obj*))); } /* * Insert the new elements into elemPtrs before "first". */ @@ -1629,10 +1621,16 @@ listPtr->length = 1; for (i = 0; i < numElems; i++) { elem = Tcl_GetStringFromObj(listRepPtr->elements[i], &length); listPtr->length += Tcl_ScanCountedElement(elem, length, &flagPtr[i]) + 1; + /* + * Check for continued sanity. [Bug 1267380] + */ + if (listPtr->length < 1) { + Tcl_Panic("string representation size exceeds sane bounds"); + } } /* * Pass 2: copy into string rep buffer. */ Index: generic/tclMain.c ================================================================== --- generic/tclMain.c +++ generic/tclMain.c @@ -8,11 +8,11 @@ * Copyright (c) 2000 Ajuba Solutions. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMain.c,v 1.20 2002/05/29 22:59:33 dgp Exp $ + * RCS: @(#) $Id: tclMain.c,v 1.20.2.3 2006/05/05 18:08:58 dgp Exp $ */ #include "tcl.h" #include "tclInt.h" @@ -202,19 +202,17 @@ /* Application-specific initialization * procedure to call after most * initialization but before starting to * execute commands. */ { - Tcl_Obj *resultPtr; - Tcl_Obj *commandPtr = NULL; - char buffer[TCL_INTEGER_SPACE + 5], *args; + Tcl_Obj *resultPtr, *argvPtr, *commandPtr = NULL; PromptType prompt = PROMPT_START; - int code, length, tty; - int exitCode = 0; + int code, length, tty, exitCode = 0; Tcl_Channel inChannel, outChannel, errChannel; Tcl_Interp *interp; - Tcl_DString argString; + Tcl_DString appName; + Tcl_Obj *objPtr; Tcl_FindExecutable(argv[0]); interp = Tcl_CreateInterp(); Tcl_InitMemory(interp); @@ -231,32 +229,37 @@ argc--; argv++; } } - /* - * The CONST casting is safe, and better we do it here than force - * all callers of Tcl_Main to do it. (Those callers are likely - * in a main() that can't easily change its signature.) - */ - - args = Tcl_Merge(argc-1, (CONST char **)argv+1); - Tcl_ExternalToUtfDString(NULL, args, -1, &argString); - Tcl_SetVar(interp, "argv", Tcl_DStringValue(&argString), TCL_GLOBAL_ONLY); - Tcl_DStringFree(&argString); - ckfree(args); - if (TclGetStartupScriptPath() == NULL) { - Tcl_ExternalToUtfDString(NULL, argv[0], -1, &argString); + Tcl_ExternalToUtfDString(NULL, argv[0], -1, &appName); } else { TclSetStartupScriptFileName(Tcl_ExternalToUtfDString(NULL, - TclGetStartupScriptFileName(), -1, &argString)); + TclGetStartupScriptFileName(), -1, &appName)); } + Tcl_SetVar(interp, "argv0", Tcl_DStringValue(&appName), TCL_GLOBAL_ONLY); + Tcl_DStringFree(&appName); + argc--; + argv++; - TclFormatInt(buffer, (long) argc-1); - Tcl_SetVar(interp, "argc", buffer, TCL_GLOBAL_ONLY); - Tcl_SetVar(interp, "argv0", Tcl_DStringValue(&argString), TCL_GLOBAL_ONLY); + objPtr = Tcl_NewIntObj(argc); + Tcl_IncrRefCount(objPtr); + Tcl_SetVar2Ex(interp, "argc", NULL, objPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(objPtr); + + argvPtr = Tcl_NewListObj(0, NULL); + while (argc--) { + Tcl_DString ds; + Tcl_ExternalToUtfDString(NULL, *argv++, -1, &ds); + Tcl_ListObjAppendElement(NULL, argvPtr, Tcl_NewStringObj( + Tcl_DStringValue(&ds), Tcl_DStringLength(&ds))); + Tcl_DStringFree(&ds); + } + Tcl_IncrRefCount(argvPtr); + Tcl_SetVar2Ex(interp, "argv", NULL, argvPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(argvPtr); /* * Set the "tcl_interactive" variable. */ @@ -306,11 +309,10 @@ } exitCode = 1; } goto done; } - Tcl_DStringFree(&argString); /* * We're running interactively. Source a user-specific startup * file if the application specified one and if the file exists. */ @@ -331,88 +333,88 @@ */ Tcl_LinkVar(interp, "tcl_interactive", (char *) &tty, TCL_LINK_BOOLEAN); inChannel = Tcl_GetStdChannel(TCL_STDIN); outChannel = Tcl_GetStdChannel(TCL_STDOUT); while ((inChannel != (Tcl_Channel) NULL) && !Tcl_InterpDeleted(interp)) { - if (tty) { - Prompt(interp, &prompt); - if (Tcl_InterpDeleted(interp)) { - break; - } - inChannel = Tcl_GetStdChannel(TCL_STDIN); - if (inChannel == (Tcl_Channel) NULL) { - break; - } - } - if (Tcl_IsShared(commandPtr)) { - Tcl_DecrRefCount(commandPtr); - commandPtr = Tcl_DuplicateObj(commandPtr); - Tcl_IncrRefCount(commandPtr); - } - length = Tcl_GetsObj(inChannel, commandPtr); - if (length < 0) { - if (Tcl_InputBlocked(inChannel)) { - - /* - * This can only happen if stdin has been set to - * non-blocking. In that case cycle back and try - * again. This sets up a tight polling loop (since - * we have no event loop running). If this causes - * bad CPU hogging, we might try toggling the blocking - * on stdin instead. - */ - - continue; - } - - /* - * Either EOF, or an error on stdin; we're done - */ - - break; - } - - /* - * Add the newline removed by Tcl_GetsObj back to the string. - */ - - if (Tcl_IsShared(commandPtr)) { - Tcl_DecrRefCount(commandPtr); - commandPtr = Tcl_DuplicateObj(commandPtr); - Tcl_IncrRefCount(commandPtr); - } - Tcl_AppendToObj(commandPtr, "\n", 1); - if (!TclObjCommandComplete(commandPtr)) { - prompt = PROMPT_CONTINUE; - continue; - } - - prompt = PROMPT_START; - code = Tcl_RecordAndEvalObj(interp, commandPtr, TCL_EVAL_GLOBAL); - inChannel = Tcl_GetStdChannel(TCL_STDIN); - outChannel = Tcl_GetStdChannel(TCL_STDOUT); - errChannel = Tcl_GetStdChannel(TCL_STDERR); - Tcl_DecrRefCount(commandPtr); - commandPtr = Tcl_NewObj(); - Tcl_IncrRefCount(commandPtr); - if (code != TCL_OK) { - if (errChannel) { - Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); - Tcl_WriteChars(errChannel, "\n", 1); - } - } else if (tty) { - resultPtr = Tcl_GetObjResult(interp); - Tcl_IncrRefCount(resultPtr); - Tcl_GetStringFromObj(resultPtr, &length); - if ((length > 0) && outChannel) { - Tcl_WriteObj(outChannel, resultPtr); - Tcl_WriteChars(outChannel, "\n", 1); - } - Tcl_DecrRefCount(resultPtr); - } - if (mainLoopProc != NULL) { - + if (mainLoopProc == NULL) { + if (tty) { + Prompt(interp, &prompt); + if (Tcl_InterpDeleted(interp)) { + break; + } + inChannel = Tcl_GetStdChannel(TCL_STDIN); + if (inChannel == (Tcl_Channel) NULL) { + break; + } + } + if (Tcl_IsShared(commandPtr)) { + Tcl_DecrRefCount(commandPtr); + commandPtr = Tcl_DuplicateObj(commandPtr); + Tcl_IncrRefCount(commandPtr); + } + length = Tcl_GetsObj(inChannel, commandPtr); + if (length < 0) { + if (Tcl_InputBlocked(inChannel)) { + + /* + * This can only happen if stdin has been set to + * non-blocking. In that case cycle back and try + * again. This sets up a tight polling loop (since + * we have no event loop running). If this causes + * bad CPU hogging, we might try toggling the blocking + * on stdin instead. + */ + + continue; + } + + /* + * Either EOF, or an error on stdin; we're done + */ + + break; + } + + /* + * Add the newline removed by Tcl_GetsObj back to the string. + */ + + if (Tcl_IsShared(commandPtr)) { + Tcl_DecrRefCount(commandPtr); + commandPtr = Tcl_DuplicateObj(commandPtr); + Tcl_IncrRefCount(commandPtr); + } + Tcl_AppendToObj(commandPtr, "\n", 1); + if (!TclObjCommandComplete(commandPtr)) { + prompt = PROMPT_CONTINUE; + continue; + } + + prompt = PROMPT_START; + code = Tcl_RecordAndEvalObj(interp, commandPtr, TCL_EVAL_GLOBAL); + inChannel = Tcl_GetStdChannel(TCL_STDIN); + outChannel = Tcl_GetStdChannel(TCL_STDOUT); + errChannel = Tcl_GetStdChannel(TCL_STDERR); + Tcl_DecrRefCount(commandPtr); + commandPtr = Tcl_NewObj(); + Tcl_IncrRefCount(commandPtr); + if (code != TCL_OK) { + if (errChannel) { + Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); + Tcl_WriteChars(errChannel, "\n", 1); + } + } else if (tty) { + resultPtr = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(resultPtr); + Tcl_GetStringFromObj(resultPtr, &length); + if ((length > 0) && outChannel) { + Tcl_WriteObj(outChannel, resultPtr); + Tcl_WriteChars(outChannel, "\n", 1); + } + Tcl_DecrRefCount(resultPtr); + } + } else { /* (mainLoopProc != NULL) */ /* * If a main loop has been defined while running interactively, * we want to start a fileevent based prompt by establishing a * channel handler for stdin. */ @@ -494,10 +496,11 @@ * users can replace "exit" with some other command to do additional * cleanup on exit. The Tcl_Eval call should never return. */ if (!Tcl_InterpDeleted(interp)) { + char buffer[TCL_INTEGER_SPACE + 5]; sprintf(buffer, "exit %d", exitCode); Tcl_Eval(interp, buffer); /* * If Tcl_Eval returns, trying to eval [exit], something Index: generic/tclNamesp.c ================================================================== --- generic/tclNamesp.c +++ generic/tclNamesp.c @@ -17,11 +17,11 @@ * mmclennan@lucent.com * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclNamesp.c,v 1.31 2002/07/15 22:18:07 msofer Exp $ + * RCS: @(#) $Id: tclNamesp.c,v 1.31.2.14 2007/05/15 18:32:18 dgp Exp $ */ #include "tclInt.h" /* @@ -349,11 +349,10 @@ Tcl_PopCallFrame(interp) Tcl_Interp* interp; /* Interpreter with call frame to pop. */ { register Interp *iPtr = (Interp *) interp; register CallFrame *framePtr = iPtr->framePtr; - int saveErrFlag; Namespace *nsPtr; /* * It's important to remove the call frame from the interpreter's stack * of call frames before deleting local variables, so that traces @@ -362,36 +361,19 @@ */ iPtr->framePtr = framePtr->callerPtr; iPtr->varFramePtr = framePtr->callerVarPtr; - /* - * Delete the local variables. As a hack, we save then restore the - * ERR_IN_PROGRESS flag in the interpreter. The problem is that there - * could be unset traces on the variables, which cause scripts to be - * evaluated. This will clear the ERR_IN_PROGRESS flag, losing stack - * trace information if the procedure was exiting with an error. The - * code below preserves the flag. Unfortunately, that isn't really - * enough: we really should preserve the errorInfo variable too - * (otherwise a nested error in the trace script will trash errorInfo). - * What's really needed is a general-purpose mechanism for saving and - * restoring interpreter state. - */ - - saveErrFlag = (iPtr->flags & ERR_IN_PROGRESS); - if (framePtr->varTablePtr != NULL) { TclDeleteVars(iPtr, framePtr->varTablePtr); ckfree((char *) framePtr->varTablePtr); framePtr->varTablePtr = NULL; } if (framePtr->numCompiledLocals > 0) { TclDeleteCompiledLocalVars(iPtr, framePtr); } - iPtr->flags |= saveErrFlag; - /* * Decrement the namespace's count of active call frames. If the * namespace is "dying" and there are no more active call frames, * call Tcl_DeleteNamespace to destroy it. */ @@ -628,17 +610,21 @@ if (entryPtr != NULL) { Tcl_DeleteHashEntry(entryPtr); } } nsPtr->parentPtr = NULL; - } else { + } else if (!(nsPtr->flags & NS_KILLED)) { /* * Delete the namespace and everything in it. If this is the global * namespace, then clear it but don't free its storage unless the - * interpreter is being torn down. + * interpreter is being torn down. Set the NS_KILLED flag to avoid + * recursive calls here - if the namespace is really in the process of + * being deleted, ignore any second call. */ + nsPtr->flags |= (NS_DYING|NS_KILLED); + TclTeardownNamespace(nsPtr); if ((nsPtr != globalNsPtr) || (iPtr->flags & DELETED)) { /* * If this is the global namespace, then it may have residual @@ -645,11 +631,11 @@ * "errorInfo" and "errorCode" variables for errors that * occurred while it was being torn down. Try to clear the * variable list one last time. */ - TclDeleteVars((Interp *) nsPtr->interp, &nsPtr->varTable); + TclDeleteNamespaceVars(nsPtr); Tcl_DeleteHashTable(&nsPtr->childTable); Tcl_DeleteHashTable(&nsPtr->cmdTable); /* @@ -660,11 +646,17 @@ if (nsPtr->refCount == 0) { NamespaceFree(nsPtr); } else { nsPtr->flags |= NS_DEAD; } - } + } else { + /* + * We didn't really kill it, so remove the KILLED marks, so + * it can get killed later, avoiding mem leaks + */ + nsPtr->flags &= ~(NS_DYING|NS_KILLED); + } } } /* *---------------------------------------------------------------------- @@ -711,59 +703,66 @@ * since variables might trigger traces. */ if (nsPtr == globalNsPtr) { /* - * This is the global namespace, so be careful to preserve the - * "errorInfo" and "errorCode" variables. These might be needed - * later on if errors occur while deleting commands. We are careful - * to destroy and recreate the "errorInfo" and "errorCode" - * variables, in case they had any traces on them. + * This is the global namespace. Tearing it down will destroy the + * ::errorInfo and ::errorCode variables. We save and restore them + * in case there are any errors in progress, so the error details + * they contain will not be lost. See test namespace-8.5 */ - CONST char *str; - char *errorInfoStr, *errorCodeStr; - - str = Tcl_GetVar((Tcl_Interp *) iPtr, "errorInfo", TCL_GLOBAL_ONLY); - if (str != NULL) { - errorInfoStr = ckalloc((unsigned) (strlen(str)+1)); - strcpy(errorInfoStr, str); - } else { - errorInfoStr = NULL; - } - - str = Tcl_GetVar((Tcl_Interp *) iPtr, "errorCode", TCL_GLOBAL_ONLY); - if (str != NULL) { - errorCodeStr = ckalloc((unsigned) (strlen(str)+1)); - strcpy(errorCodeStr, str); - } else { - errorCodeStr = NULL; - } - - TclDeleteVars(iPtr, &nsPtr->varTable); + Tcl_Obj *errorInfo = Tcl_GetVar2Ex(nsPtr->interp, "errorInfo", + NULL, TCL_GLOBAL_ONLY); + Tcl_Obj *errorCode = Tcl_GetVar2Ex(nsPtr->interp, "errorCode", + NULL, TCL_GLOBAL_ONLY); + + if (errorInfo) { + Tcl_IncrRefCount(errorInfo); + } + if (errorCode) { + Tcl_IncrRefCount(errorCode); + } + + TclDeleteNamespaceVars(nsPtr); Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS); - if (errorInfoStr != NULL) { - Tcl_SetVar((Tcl_Interp *) iPtr, "errorInfo", errorInfoStr, - TCL_GLOBAL_ONLY); - ckfree(errorInfoStr); - } - if (errorCodeStr != NULL) { - Tcl_SetVar((Tcl_Interp *) iPtr, "errorCode", errorCodeStr, - TCL_GLOBAL_ONLY); - ckfree(errorCodeStr); - } + if (errorInfo) { + Tcl_SetVar2Ex(nsPtr->interp, "errorInfo", NULL, + errorInfo, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(errorInfo); + } + if (errorCode) { + Tcl_SetVar2Ex(nsPtr->interp, "errorCode", NULL, + errorCode, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(errorCode); + } } else { /* * Variable table should be cleared but not freed! TclDeleteVars * frees it, so we reinitialize it afterwards. */ - TclDeleteVars(iPtr, &nsPtr->varTable); + TclDeleteNamespaceVars(nsPtr); Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS); } + /* + * Delete all commands in this namespace. Be careful when traversing the + * hash table: when each command is deleted, it removes itself from the + * command table. + */ + + for (entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); + entryPtr != NULL; + entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search)) { + cmd = (Tcl_Command) Tcl_GetHashValue(entryPtr); + Tcl_DeleteCommandFromToken((Tcl_Interp *) iPtr, cmd); + } + Tcl_DeleteHashTable(&nsPtr->cmdTable); + Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS); + /* * Remove the namespace from its parent's child hashtable. */ if (nsPtr->parentPtr != NULL) { @@ -789,25 +788,10 @@ entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search)) { childNsPtr = (Tcl_Namespace *) Tcl_GetHashValue(entryPtr); Tcl_DeleteNamespace(childNsPtr); } - /* - * Delete all commands in this namespace. Be careful when traversing the - * hash table: when each command is deleted, it removes itself from the - * command table. - */ - - for (entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); - entryPtr != NULL; - entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search)) { - cmd = (Tcl_Command) Tcl_GetHashValue(entryPtr); - Tcl_DeleteCommandFromToken((Tcl_Interp *) iPtr, cmd); - } - Tcl_DeleteHashTable(&nsPtr->cmdTable); - Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS); - /* * Free the namespace's export pattern array. */ if (nsPtr->exportArrayPtr != NULL) { @@ -906,13 +890,11 @@ * to export. This pattern may not include * any namespace qualifiers; only commands * in the specified namespace may be * exported. */ int resetListFirst; /* If nonzero, resets the namespace's - * export list before appending. - * If 0, return an error if an imported - * cmd conflicts with an existing one. */ + * export list before appending. */ { #define INIT_EXPORT_PATTERNS 5 Namespace *nsPtr, *exportNsPtr, *dummyPtr; Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); CONST char *simplePattern; @@ -949,12 +931,12 @@ /* * Check that the pattern doesn't have namespace qualifiers. */ TclGetNamespaceForQualName(interp, pattern, nsPtr, - /*flags*/ TCL_LEAVE_ERR_MSG, &exportNsPtr, &dummyPtr, - &dummyPtr, &simplePattern); + /*flags*/ (TCL_LEAVE_ERR_MSG | TCL_NAMESPACE_ONLY), + &exportNsPtr, &dummyPtr, &dummyPtr, &simplePattern); if ((exportNsPtr != nsPtr) || (strcmp(pattern, simplePattern) != 0)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "invalid export pattern \"", pattern, "\": pattern can't specify a namespace", @@ -1117,11 +1099,11 @@ Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); CONST char *simplePattern; char *cmdName; register Tcl_HashEntry *hPtr; Tcl_HashSearch search; - Command *cmdPtr, *realCmdPtr; + Command *cmdPtr; ImportRef *refPtr; Tcl_Command autoCmd, importedCmd; ImportedCmdData *dataPtr; int wasExported, i, result; @@ -1177,12 +1159,12 @@ Tcl_SetStringObj(Tcl_GetObjResult(interp), "empty import pattern", -1); return TCL_ERROR; } TclGetNamespaceForQualName(interp, pattern, nsPtr, - /*flags*/ TCL_LEAVE_ERR_MSG, &importNsPtr, &dummyPtr, - &dummyPtr, &simplePattern); + /*flags*/ (TCL_LEAVE_ERR_MSG | TCL_NAMESPACE_ONLY), + &importNsPtr, &dummyPtr, &dummyPtr, &simplePattern); if (importNsPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown namespace in import pattern \"", pattern, "\"", (char *) NULL); @@ -1217,10 +1199,11 @@ /* * The command cmdName in the source namespace matches the * pattern. Check whether it was exported. If it wasn't, * we ignore it. */ + Tcl_HashEntry *found; wasExported = 0; for (i = 0; i < importNsPtr->numExportPatterns; i++) { if (Tcl_StringMatch(cmdName, importNsPtr->exportArrayPtr[i])) { @@ -1234,13 +1217,13 @@ /* * Unless there is a name clash, create an imported command * in the current namespace that refers to cmdPtr. */ - - if ((Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName) == NULL) - || allowOverwrite) { + + found = Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName); + if ((found == NULL) || allowOverwrite) { /* * Create the imported command and its client data. * To create the new command in the current namespace, * generate a fully qualified name for it. */ @@ -1254,29 +1237,34 @@ } Tcl_DStringAppend(&ds, cmdName, -1); /* * Check whether creating the new imported command in the - * current namespace would create a cycle of imported->real - * command references that also would destroy an existing - * "real" command already in the current namespace. + * current namespace would create a cycle of imported + * command references. */ cmdPtr = (Command *) Tcl_GetHashValue(hPtr); - if (cmdPtr->deleteProc == DeleteImportedCmd) { - realCmdPtr = (Command *) TclGetOriginalCommand( - (Tcl_Command) cmdPtr); - if ((realCmdPtr != NULL) - && (realCmdPtr->nsPtr == currNsPtr) - && (Tcl_FindHashEntry(&currNsPtr->cmdTable, - cmdName) != NULL)) { - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "import pattern \"", pattern, - "\" would create a loop containing command \"", - Tcl_DStringValue(&ds), "\"", (char *) NULL); - Tcl_DStringFree(&ds); - return TCL_ERROR; + if ((found != NULL) + && cmdPtr->deleteProc == DeleteImportedCmd) { + + Command *overwrite = (Command *) Tcl_GetHashValue(found); + Command *link = cmdPtr; + while (link->deleteProc == DeleteImportedCmd) { + ImportedCmdData *dataPtr; + + dataPtr = (ImportedCmdData *) link->objClientData; + link = dataPtr->realCmdPtr; + if (overwrite == link) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "import pattern \"", pattern, + "\" would create a loop containing ", + "command \"", Tcl_DStringValue(&ds), + "\"", (char *) NULL); + Tcl_DStringFree(&ds); + return TCL_ERROR; + } } } dataPtr = (ImportedCmdData *) ckalloc(sizeof(ImportedCmdData)); @@ -1297,10 +1285,20 @@ refPtr = (ImportRef *) ckalloc(sizeof(ImportRef)); refPtr->importedCmdPtr = (Command *) importedCmd; refPtr->nextPtr = cmdPtr->importRefPtr; cmdPtr->importRefPtr = refPtr; } else { + Command *overwrite = (Command *) Tcl_GetHashValue(found); + if (overwrite->deleteProc == DeleteImportedCmd) { + ImportedCmdData *dataPtr = + (ImportedCmdData *) overwrite->objClientData; + if (dataPtr->realCmdPtr + == (Command *) Tcl_GetHashValue(hPtr)) { + /* Repeated import of same command -- acceptable */ + return TCL_OK; + } + } Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't import command \"", cmdName, "\": already exists", (char *) NULL); return TCL_ERROR; } @@ -1312,21 +1310,26 @@ /* *---------------------------------------------------------------------- * * Tcl_ForgetImport -- * - * Deletes previously imported commands. Given a pattern that may - * include the name of an exporting namespace, this procedure first - * finds all matching exported commands. It then looks in the namespace - * specified by namespacePtr for any corresponding previously imported - * commands, which it deletes. If namespacePtr is NULL, commands are - * deleted from the current namespace. + * Deletes commands previously imported into the namespace indicated. The + * by namespacePtr, or the current namespace of interp, when + * namespacePtr is NULL. The pattern controls which imported commands + * are deleted. A simple pattern, one without namespace separators, + * matches the current command names of imported commands in the + * namespace. Matching imported commands are deleted. A qualified + * pattern is interpreted as deletion selection on the basis of where + * the command is imported from. The original command and "first link" + * command for each imported command are determined, and they are matched + * against the pattern. A match leads to deletion of the imported + * command. * * Results: - * Returns TCL_OK if successful. If there is an error, returns - * TCL_ERROR and puts an error message in the interpreter's result - * object. + * Returns TCL_ERROR and records an error message in the interp + * result if a namespace qualified pattern refers to a namespace + * that does not exist. Otherwise, returns TCL_OK. * * Side effects: * May delete commands. * *---------------------------------------------------------------------- @@ -1337,21 +1340,17 @@ Tcl_Interp *interp; /* Current interpreter. */ Tcl_Namespace *namespacePtr; /* Points to the namespace from which * previously imported commands should be * removed. NULL for current namespace. */ CONST char *pattern; /* String pattern indicating which imported - * commands to remove. This pattern should - * be qualified by the name of the - * namespace from which the command(s) were - * imported. */ + * commands to remove. */ { - Namespace *nsPtr, *importNsPtr, *dummyPtr, *actualCtxPtr; + Namespace *nsPtr, *sourceNsPtr, *dummyPtr; CONST char *simplePattern; char *cmdName; register Tcl_HashEntry *hPtr; Tcl_HashSearch search; - Command *cmdPtr; /* * If the specified namespace is NULL, use the current namespace. */ @@ -1360,46 +1359,78 @@ } else { nsPtr = (Namespace *) namespacePtr; } /* - * From the pattern, find the namespace from which we are importing - * and get the simple pattern (no namespace qualifiers or ::'s) at - * the end. + * Parse the pattern into its namespace-qualification (if any) + * and the simple pattern. */ TclGetNamespaceForQualName(interp, pattern, nsPtr, - /*flags*/ TCL_LEAVE_ERR_MSG, &importNsPtr, &dummyPtr, - &actualCtxPtr, &simplePattern); + /*flags*/ (TCL_LEAVE_ERR_MSG | TCL_NAMESPACE_ONLY), + &sourceNsPtr, &dummyPtr, &dummyPtr, &simplePattern); - if (importNsPtr == NULL) { + if (sourceNsPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown namespace in namespace forget pattern \"", pattern, "\"", (char *) NULL); return TCL_ERROR; } - /* - * Scan through the command table in the source namespace and look for - * exported commands that match the string pattern. If the current - * namespace has an imported command that refers to one of those real - * commands, delete it. - */ - - for (hPtr = Tcl_FirstHashEntry(&importNsPtr->cmdTable, &search); - (hPtr != NULL); - hPtr = Tcl_NextHashEntry(&search)) { - cmdName = Tcl_GetHashKey(&importNsPtr->cmdTable, hPtr); - if (Tcl_StringMatch(cmdName, simplePattern)) { - hPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName); - if (hPtr != NULL) { /* cmd of same name in current namespace */ - cmdPtr = (Command *) Tcl_GetHashValue(hPtr); - if (cmdPtr->deleteProc == DeleteImportedCmd) { - Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr); - } - } - } + if (strcmp(pattern, simplePattern) == 0) { + /* + * The pattern is simple. + * Delete any imported commands that match it. + */ + + for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); + (hPtr != NULL); + hPtr = Tcl_NextHashEntry(&search)) { + Command *cmdPtr = (Command *) Tcl_GetHashValue(hPtr); + if (cmdPtr->deleteProc != DeleteImportedCmd) { + continue; + } + cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, hPtr); + if (Tcl_StringMatch(cmdName, simplePattern)) { + Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr); + } + } + return TCL_OK; + } + + /* The pattern was namespace-qualified */ + + for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); (hPtr != NULL); + hPtr = Tcl_NextHashEntry(&search)) { + Tcl_CmdInfo info; + Tcl_Command token = (Tcl_Command) Tcl_GetHashValue(hPtr); + Tcl_Command origin = TclGetOriginalCommand(token); + + if (Tcl_GetCommandInfoFromToken(origin, &info) == 0) { + continue; /* Not an imported command */ + } + if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) { + /* + * Original not in namespace we're matching. + * Check the first link in the import chain. + */ + Command *cmdPtr = (Command *) token; + ImportedCmdData *dataPtr = + (ImportedCmdData *) cmdPtr->objClientData; + Tcl_Command firstToken = (Tcl_Command) dataPtr->realCmdPtr; + if (firstToken == origin) { + continue; + } + Tcl_GetCommandInfoFromToken(firstToken, &info); + if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) { + continue; + } + origin = firstToken; + } + if (Tcl_StringMatch(Tcl_GetCommandName(NULL, origin), simplePattern)) { + Tcl_DeleteCommandFromToken(interp, token); + } } return TCL_OK; } /* @@ -1619,12 +1650,11 @@ CONST char *qualName; /* A namespace-qualified name of an * command, variable, or namespace. */ Namespace *cxtNsPtr; /* The namespace in which to start the * search for qualName's namespace. If NULL * start from the current namespace. - * Ignored if TCL_GLOBAL_ONLY or - * TCL_NAMESPACE_ONLY are set. */ + * Ignored if TCL_GLOBAL_ONLY is set. */ int flags; /* Flags controlling the search: an OR'd * combination of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY, * CREATE_NS_IF_UNKNOWN, and * FIND_ONLY_NS. */ @@ -1663,21 +1693,18 @@ Tcl_DString buffer; int len; /* * Determine the context namespace nsPtr in which to start the primary - * search. If TCL_NAMESPACE_ONLY or FIND_ONLY_NS was specified, search - * from the current namespace. If the qualName name starts with a "::" - * or TCL_GLOBAL_ONLY was specified, search from the global - * namespace. Otherwise, use the given namespace given in cxtNsPtr, or - * if that is NULL, use the current namespace context. Note that we - * always treat two or more adjacent ":"s as a namespace separator. + * search. If the qualName name starts with a "::" or TCL_GLOBAL_ONLY + * was specified, search from the global namespace. Otherwise, use the + * namespace given in cxtNsPtr, or if that is NULL, use the current + * namespace context. Note that we always treat two or more + * adjacent ":"s as a namespace separator. */ - if (flags & (TCL_NAMESPACE_ONLY | FIND_ONLY_NS)) { - nsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); - } else if (flags & TCL_GLOBAL_ONLY) { + if (flags & TCL_GLOBAL_ONLY) { nsPtr = globalNsPtr; } else if (nsPtr == NULL) { if (iPtr->varFramePtr != NULL) { nsPtr = iPtr->varFramePtr->nsPtr; } else { @@ -2029,15 +2056,16 @@ cmdPtr = NULL; for (search = 0; (search < 2) && (cmdPtr == NULL); search++) { if ((nsPtr[search] != NULL) && (simpleName != NULL)) { entryPtr = Tcl_FindHashEntry(&nsPtr[search]->cmdTable, simpleName); - if (entryPtr != NULL) { - cmdPtr = (Command *) Tcl_GetHashValue(entryPtr); - } - } + if (entryPtr != NULL) { + cmdPtr = (Command *) Tcl_GetHashValue(entryPtr); + } + } } + if (cmdPtr != NULL) { return (Tcl_Command) cmdPtr; } else if (flags & TCL_LEAVE_ERR_MSG) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), @@ -2868,11 +2896,11 @@ for (i = 2; i < objc; i++) { name = Tcl_GetString(objv[i]); namespacePtr = Tcl_FindNamespace(interp, name, (Tcl_Namespace *) NULL, /*flags*/ 0); - if (namespacePtr == NULL) { + if (namespacePtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown namespace \"", Tcl_GetString(objv[i]), "\" in namespace delete command", (char *) NULL); return TCL_ERROR; } @@ -2973,19 +3001,30 @@ } frame.objc = objc; frame.objv = objv; /* ref counts do not need to be incremented here */ if (objc == 4) { +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[3], 0); +#else + /* TIP #280 : Make invoker available to eval'd script */ + Interp* iPtr = (Interp*) interp; + result = TclEvalObjEx(interp, objv[3], 0, iPtr->cmdFramePtr,3); +#endif } else { /* * More than one argument: concatenate them together with spaces * between, then evaluate the result. Tcl_EvalObjEx will delete * the object when it decrements its refcount after eval'ing it. */ objPtr = Tcl_ConcatObj(objc-3, objv+3); +#ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_DIRECT); +#else + /* TIP #280. Make invoking context available to eval'd script */ + result = TclEvalObjEx(interp, objPtr, TCL_EVAL_DIRECT, NULL, 0); +#endif } if (result == TCL_ERROR) { char msg[256 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (in namespace eval \"%.200s\" script line %d)", Index: generic/tclNotify.c ================================================================== --- generic/tclNotify.c +++ generic/tclNotify.c @@ -12,11 +12,11 @@ * Copyright (c) 2003 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclNotify.c,v 1.11 2003/02/15 20:24:10 kennykb Exp $ + * RCS: @(#) $Id: tclNotify.c,v 1.11.2.2 2005/04/26 00:46:02 das Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -66,10 +66,11 @@ /* Pointer to first event source in * list of event sources for this thread. */ Tcl_ThreadId threadId; /* Thread that owns this notifier instance. */ ClientData clientData; /* Opaque handle for platform specific * notifier. */ + int initialized; /* 1 if notifier has been initialized. */ struct ThreadSpecificData *nextPtr; /* Next notifier in global list of notifiers. * Access is controlled by the listLock global * mutex. */ } ThreadSpecificData; @@ -116,10 +117,11 @@ Tcl_MutexLock(&listLock); tsdPtr->threadId = Tcl_GetCurrentThread(); tsdPtr->clientData = tclStubs.tcl_InitNotifier(); + tsdPtr->initialized = 1; tsdPtr->nextPtr = firstNotifierPtr; firstNotifierPtr = tsdPtr; Tcl_MutexUnlock(&listLock); } @@ -135,11 +137,19 @@ * Results: * None. * * Side effects: * Removes the notifier associated with the current thread from - * the global notifier list. + * the global notifier list. This is done only if the notifier + * was initialized for this thread by call to TclInitNotifier(). + * This is always true for threads which have been seeded with + * an Tcl interpreter, since the call to Tcl_CreateInterp will, + * among other things, call TclInitializeSubsystems() and this + * one will, in turn, call the TclInitNotifier() for the thread. + * For threads created without the Tcl interpreter, though, + * nobody is explicitly nor implicitly calling the TclInitNotifier + * hence, TclFinalizeNotifier should not be performed at all. * *---------------------------------------------------------------------- */ void @@ -146,10 +156,14 @@ TclFinalizeNotifier() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); ThreadSpecificData **prevPtrPtr; Tcl_Event *evPtr, *hold; + + if (!tsdPtr->initialized) { + return; /* Notifier not initialized for the current thread */ + } Tcl_MutexLock(&(tsdPtr->queueMutex)); for (evPtr = tsdPtr->firstEventPtr; evPtr != (Tcl_Event *) NULL; ) { hold = evPtr; evPtr = evPtr->nextPtr; @@ -170,10 +184,11 @@ if (*prevPtrPtr == tsdPtr) { *prevPtrPtr = tsdPtr->nextPtr; break; } } + tsdPtr->initialized = 0; Tcl_MutexUnlock(&listLock); } /* @@ -862,11 +877,11 @@ /* * Ask Tcl to service a queued event, if there are any. */ if (Tcl_ServiceEvent(flags)) { - result = 1; + result = 1; break; } /* * If TCL_DONT_WAIT is set, be sure to poll rather than Index: generic/tclObj.c ================================================================== --- generic/tclObj.c +++ generic/tclObj.c @@ -9,11 +9,11 @@ * Copyright (c) 2001 by ActiveState Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclObj.c,v 1.42 2003/01/17 22:11:02 mdejong Exp $ + * RCS: @(#) $Id: tclObj.c,v 1.42.2.14 2005/11/29 14:02:04 dkf Exp $ */ #include "tclInt.h" #include "tclCompile.h" #include "tclPort.h" @@ -58,16 +58,19 @@ Tcl_Obj *objPtr)); static int SetDoubleFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static int SetIntFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); +static int SetIntOrWideFromAny _ANSI_ARGS_((Tcl_Interp* interp, + Tcl_Obj *objPtr)); static void UpdateStringOfBoolean _ANSI_ARGS_((Tcl_Obj *objPtr)); static void UpdateStringOfDouble _ANSI_ARGS_((Tcl_Obj *objPtr)); static void UpdateStringOfInt _ANSI_ARGS_((Tcl_Obj *objPtr)); -#ifndef TCL_WIDE_INT_IS_LONG static int SetWideIntFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); + +#ifndef TCL_WIDE_INT_IS_LONG static void UpdateStringOfWideInt _ANSI_ARGS_((Tcl_Obj *objPtr)); #endif /* * Prototypes for the array hash key methods. @@ -124,19 +127,21 @@ (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */ UpdateStringOfInt, /* updateStringProc */ SetIntFromAny /* setFromAnyProc */ }; -#ifndef TCL_WIDE_INT_IS_LONG Tcl_ObjType tclWideIntType = { "wideInt", /* name */ (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */ (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */ +#ifdef TCL_WIDE_INT_IS_LONG + UpdateStringOfInt, /* updateStringProc */ +#else /* !TCL_WIDE_INT_IS_LONG */ UpdateStringOfWideInt, /* updateStringProc */ +#endif SetWideIntFromAny /* setFromAnyProc */ }; -#endif /* * The structure below defines the Tcl obj hash key type. */ Tcl_HashKeyType tclObjHashKeyType = { @@ -152,10 +157,17 @@ * The structure below defines the command name Tcl object type by means of * procedures that can be invoked by generic object code. Objects of this * type cache the Command pointer that results from looking up command names * in the command hashtable. Such objects appear as the zeroth ("command * name") argument in a Tcl command. + * + * NOTE: the ResolvedCmdName that gets cached is stored in the + * twoPtrValue.ptr1 field, and the twoPtrValue.ptr2 field is unused. + * You might think you could use the simpler otherValuePtr field to + * store the single ResolvedCmdName pointer, but DO NOT DO THIS. It + * seems that some extensions use the second internal pointer field + * of the twoPtrValue field for their own purposes. */ static Tcl_ObjType tclCmdNameType = { "cmdName", /* name */ FreeCmdNameInternalRep, /* freeIntRepProc */ @@ -231,13 +243,11 @@ Tcl_RegisterObjType(&tclBooleanType); Tcl_RegisterObjType(&tclByteArrayType); Tcl_RegisterObjType(&tclDoubleType); Tcl_RegisterObjType(&tclEndOffsetType); Tcl_RegisterObjType(&tclIntType); -#ifndef TCL_WIDE_INT_IS_LONG Tcl_RegisterObjType(&tclWideIntType); -#endif Tcl_RegisterObjType(&tclStringType); Tcl_RegisterObjType(&tclListType); Tcl_RegisterObjType(&tclByteCodeType); Tcl_RegisterObjType(&tclProcBodyType); Tcl_RegisterObjType(&tclArraySearchType); @@ -260,40 +270,42 @@ } /* *---------------------------------------------------------------------- * - * TclFinalizeCompExecEnv -- + * TclFinalizeObjects -- * - * This procedure is called by Tcl_Finalize to clean up the Tcl - * compilation and execution environment so it can later be properly - * reinitialized. + * This procedure is called by Tcl_Finalize to clean up all + * registered Tcl_ObjType's and to reset the tclFreeObjList. * * Results: * None. * * Side effects: - * Cleans up the compilation and execution environment + * None. * *---------------------------------------------------------------------- */ void -TclFinalizeCompExecEnv() +TclFinalizeObjects() { Tcl_MutexLock(&tableMutex); if (typeTableInitialized) { Tcl_DeleteHashTable(&typeTable); typeTableInitialized = 0; } Tcl_MutexUnlock(&tableMutex); + + /* + * All we do here is reset the head pointer of the linked list of + * free Tcl_Obj's to NULL; the memory finalization will take care + * of releasing memory for us. + */ Tcl_MutexLock(&tclObjMutex); tclFreeObjList = NULL; Tcl_MutexUnlock(&tclObjMutex); - - TclFinalizeCompilation(); - TclFinalizeExecution(); } /* *-------------------------------------------------------------- * @@ -317,30 +329,14 @@ Tcl_RegisterObjType(typePtr) Tcl_ObjType *typePtr; /* Information about object type; * storage must be statically * allocated (must live forever). */ { - register Tcl_HashEntry *hPtr; int new; - - /* - * If there's already an object type with the given name, remove it. - */ Tcl_MutexLock(&tableMutex); - hPtr = Tcl_FindHashEntry(&typeTable, typePtr->name); - if (hPtr != (Tcl_HashEntry *) NULL) { - Tcl_DeleteHashEntry(hPtr); - } - - /* - * Now insert the new object type. - */ - - hPtr = Tcl_CreateHashEntry(&typeTable, typePtr->name, &new); - if (new) { - Tcl_SetHashValue(hPtr, typePtr); - } + Tcl_SetHashValue( + Tcl_CreateHashEntry(&typeTable, typePtr->name, &new), typePtr); Tcl_MutexUnlock(&tableMutex); } /* *---------------------------------------------------------------------- @@ -374,27 +370,31 @@ * name of each registered type is appended * as a list element. */ { register Tcl_HashEntry *hPtr; Tcl_HashSearch search; - Tcl_ObjType *typePtr; - int result; - + int objc; + Tcl_Obj **objv; + + /* + * Get the test for a valid list out of the way first. + */ + + if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { + return TCL_ERROR; + } + /* - * This code assumes that types names do not contain embedded NULLs. + * Type names are NUL-terminated, not counted strings. + * This code relies on that. */ Tcl_MutexLock(&tableMutex); for (hPtr = Tcl_FirstHashEntry(&typeTable, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - typePtr = (Tcl_ObjType *) Tcl_GetHashValue(hPtr); - result = Tcl_ListObjAppendElement(interp, objPtr, - Tcl_NewStringObj(typePtr->name, -1)); - if (result == TCL_ERROR) { - Tcl_MutexUnlock(&tableMutex); - return result; - } + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewStringObj(Tcl_GetHashKey(&typeTable, hPtr), -1)); } Tcl_MutexUnlock(&tableMutex); return TCL_OK; } @@ -419,21 +419,19 @@ Tcl_ObjType * Tcl_GetObjType(typeName) CONST char *typeName; /* Name of Tcl object type to look up. */ { register Tcl_HashEntry *hPtr; - Tcl_ObjType *typePtr; + Tcl_ObjType *typePtr = NULL; Tcl_MutexLock(&tableMutex); hPtr = Tcl_FindHashEntry(&typeTable, typeName); if (hPtr != (Tcl_HashEntry *) NULL) { typePtr = (Tcl_ObjType *) Tcl_GetHashValue(hPtr); - Tcl_MutexUnlock(&tableMutex); - return typePtr; } Tcl_MutexUnlock(&tableMutex); - return NULL; + return typePtr; } /* *---------------------------------------------------------------------- * @@ -617,11 +615,14 @@ /* * This has been noted by Purify to be a potential leak. The problem is * that Tcl, when not TCL_MEM_DEBUG compiled, keeps around all allocated * Tcl_Obj's, pointed to by tclFreeObjList, when freed instead of - * actually freeing the memory. These never do get freed properly. + * actually freeing the memory. TclFinalizeObjects() does not ckfree() + * this memory, but leaves it to Tcl's memory subsystem finalziation to + * release it. Purify apparently can't figure that out, and fires a + * false alarm. */ basePtr = (char *) ckalloc(bytesToAlloc); memset(basePtr, 0, bytesToAlloc); @@ -875,11 +876,11 @@ *---------------------------------------------------------------------- * * Tcl_NewBooleanObj -- * * This procedure is normally called when not debugging: i.e., when - * TCL_MEM_DEBUG is not defined. It creates a new boolean object and + * TCL_MEM_DEBUG is not defined. It creates a new Tcl_Obj and * initializes it from the argument boolean value. A nonzero * "boolValue" is coerced to 1. * * When TCL_MEM_DEBUG is defined, this procedure just returns the * result of calling the debugging version Tcl_DbNewBooleanObj. @@ -1105,14 +1106,12 @@ if (objPtr->typePtr == &tclIntType) { newBool = (objPtr->internalRep.longValue != 0); } else if (objPtr->typePtr == &tclDoubleType) { newBool = (objPtr->internalRep.doubleValue != 0.0); -#ifndef TCL_WIDE_INT_IS_LONG } else if (objPtr->typePtr == &tclWideIntType) { - newBool = (objPtr->internalRep.wideValue != Tcl_LongAsWide(0)); -#endif /* TCL_WIDE_INT_IS_LONG */ + newBool = (objPtr->internalRep.wideValue != 0); } else { /* * Copy the string converting its characters to lower case. */ @@ -1735,36 +1734,95 @@ Tcl_GetIntFromObj(interp, objPtr, intPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object from which to get a int. */ register int *intPtr; /* Place to store resulting int. */ { - register long l; int result; - - if (objPtr->typePtr != &tclIntType) { - result = SetIntFromAny(interp, objPtr); + Tcl_WideInt w = 0; + + /* + * If the object isn't already an integer of any width, try to + * convert it to one. + */ + + if (objPtr->typePtr != &tclIntType && objPtr->typePtr != &tclWideIntType) { + result = SetIntOrWideFromAny(interp, objPtr); if (result != TCL_OK) { return result; } } - l = objPtr->internalRep.longValue; - if (((long)((int)l)) == l) { - *intPtr = (int)objPtr->internalRep.longValue; - return TCL_OK; - } - if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendToObj(Tcl_GetObjResult(interp), - "integer value too large to represent as non-long integer", -1); - } - return TCL_ERROR; + + /* + * Object should now be either int or wide. Get its value. + */ + +#ifndef TCL_WIDE_INT_IS_LONG + if (objPtr->typePtr == &tclWideIntType) { + w = objPtr->internalRep.wideValue; + } else +#endif + { + w = Tcl_LongAsWide(objPtr->internalRep.longValue); + } + + if ((LLONG_MAX > UINT_MAX) + && ((w > UINT_MAX) || (w < -(Tcl_WideInt)UINT_MAX))) { + if (interp != NULL) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "integer value too large to represent as non-long integer", + -1)); + } + return TCL_ERROR; + } + *intPtr = (int)w; + return TCL_OK; } /* *---------------------------------------------------------------------- * * SetIntFromAny -- + * + * Attempts to force the internal representation for a Tcl object + * to tclIntType, specifically. + * + * Results: + * The return value is a standard object Tcl result. If an + * error occurs during conversion, an error message is left in + * the interpreter's result unless "interp" is NULL. + * + *---------------------------------------------------------------------- + */ + +static int +SetIntFromAny( Tcl_Interp* interp, + /* Tcl interpreter */ + Tcl_Obj* objPtr ) + /* Pointer to the object to convert */ +{ + int result; + + result = SetIntOrWideFromAny( interp, objPtr ); + if ( result != TCL_OK ) { + return result; + } + if ( objPtr->typePtr != &tclIntType ) { + if ( interp != NULL ) { + char *s = "integer value too large to represent"; + Tcl_ResetResult(interp); + Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1); + Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *) NULL); + } + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * SetIntOrWideFromAny -- * * Attempt to generate an integer internal form for the Tcl object * "objPtr". * * Results: @@ -1778,19 +1836,21 @@ * *---------------------------------------------------------------------- */ static int -SetIntFromAny(interp, objPtr) +SetIntOrWideFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { Tcl_ObjType *oldTypePtr = objPtr->typePtr; char *string, *end; int length; register char *p; - long newLong; + unsigned long newLong; + int isNegative = 0; + int isWide = 0; /* * Get the string representation. Make it up-to-date if necessary. */ @@ -1803,25 +1863,20 @@ * unsigned numbers, but don't depend on strtoul to handle sign * characters; it won't in some implementations. */ errno = 0; -#ifdef TCL_STRTOUL_SIGN_CHECK for ( ; isspace(UCHAR(*p)); p++) { /* INTL: ISO space. */ /* Empty loop body. */ } if (*p == '-') { p++; - newLong = -((long)strtoul(p, &end, 0)); + isNegative = 1; } else if (*p == '+') { p++; - newLong = strtoul(p, &end, 0); - } else -#else - newLong = strtoul(p, &end, 0); -#endif - if (end == p) { + } + if (!isdigit(UCHAR(*p))) { badInteger: if (interp != NULL) { /* * Must copy string before resetting the result in case a caller * is trying to convert the interpreter's result to an int. @@ -1832,10 +1887,14 @@ Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1); TclCheckBadOctal(interp, string); } return TCL_ERROR; + } + newLong = strtoul(p, &end, 0); + if (end == p) { + goto badInteger; } if (errno == ERANGE) { if (interp != NULL) { char *s = "integer value too large to represent"; Tcl_ResetResult(interp); @@ -1855,10 +1914,22 @@ } if (end != (string+length)) { goto badInteger; } + /* + * If the resulting integer will exceed the range of a long, + * put it into a wide instead. (Tcl Bug #868489) + */ + +#ifndef TCL_WIDE_INT_IS_LONG + if ((isNegative && newLong > (unsigned long) (LONG_MAX) + 1) + || (!isNegative && newLong > LONG_MAX)) { + isWide = 1; + } +#endif + /* * The conversion to int succeeded. Free the old internalRep before * setting the new one. We do this as late as possible to allow the * conversion code, in particular Tcl_GetStringFromObj, to use that old * internalRep. @@ -1866,12 +1937,19 @@ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } - objPtr->internalRep.longValue = newLong; - objPtr->typePtr = &tclIntType; + if (isWide) { + objPtr->internalRep.wideValue = + (isNegative ? -(Tcl_WideInt)newLong : (Tcl_WideInt)newLong); + objPtr->typePtr = &tclWideIntType; + } else { + objPtr->internalRep.longValue = + (isNegative ? -(long)newLong : (long)newLong); + objPtr->typePtr = &tclIntType; + } return TCL_OK; } /* *---------------------------------------------------------------------- @@ -2100,19 +2178,45 @@ register Tcl_Obj *objPtr; /* The object from which to get a long. */ register long *longPtr; /* Place to store resulting long. */ { register int result; - if (objPtr->typePtr == &tclIntType) { - *longPtr = objPtr->internalRep.longValue; - return TCL_OK; - } - result = SetIntFromAny(interp, objPtr); - if (result == TCL_OK) { - *longPtr = objPtr->internalRep.longValue; - } - return result; + if (objPtr->typePtr != &tclIntType && objPtr->typePtr != &tclWideIntType) { + result = SetIntOrWideFromAny(interp, objPtr); + if (result != TCL_OK) { + return result; + } + } + +#ifndef TCL_WIDE_INT_IS_LONG + if (objPtr->typePtr == &tclWideIntType) { + /* + * If the object is already a wide integer, don't convert it. + * This code allows for any integer in the range -ULONG_MAX to + * ULONG_MAX to be converted to a long, ignoring overflow. + * The rule preserves existing semantics for conversion of + * integers on input, but avoids inadvertent demotion of + * wide integers to 32-bit ones in the internal rep. + */ + + Tcl_WideInt w = objPtr->internalRep.wideValue; + if (w >= -(Tcl_WideInt)(ULONG_MAX) && w <= (Tcl_WideInt)(ULONG_MAX)) { + *longPtr = Tcl_WideAsLong(w); + return TCL_OK; + } else { + if (interp != NULL) { + Tcl_ResetResult(interp); + Tcl_AppendToObj(Tcl_GetObjResult(interp), + "integer value too large to represent", -1); + } + return TCL_ERROR; + } + } +#endif + + *longPtr = objPtr->internalRep.longValue; + return TCL_OK; } /* *---------------------------------------------------------------------- * @@ -2131,16 +2235,16 @@ * representation. * *---------------------------------------------------------------------- */ -#ifndef TCL_WIDE_INT_IS_LONG static int SetWideIntFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { +#ifndef TCL_WIDE_INT_IS_LONG Tcl_ObjType *oldTypePtr = objPtr->typePtr; char *string, *end; int length; register char *p; Tcl_WideInt newWide; @@ -2222,14 +2326,18 @@ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.wideValue = newWide; +#else + if (TCL_ERROR == SetIntFromAny(interp, objPtr)) { + return TCL_ERROR; + } +#endif objPtr->typePtr = &tclWideIntType; return TCL_OK; } -#endif /* *---------------------------------------------------------------------- * * UpdateStringOfWideInt -- @@ -2312,22 +2420,18 @@ Tcl_Obj * Tcl_NewWideIntObj(wideValue) register Tcl_WideInt wideValue; /* Wide integer used to initialize * the new object. */ { -#ifdef TCL_WIDE_INT_IS_LONG - return Tcl_NewLongObj(wideValue); -#else register Tcl_Obj *objPtr; TclNewObj(objPtr); objPtr->bytes = NULL; objPtr->internalRep.wideValue = wideValue; objPtr->typePtr = &tclWideIntType; return objPtr; -#endif /* TCL_WIDE_INT_IS_LONG */ } #endif /* if TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- @@ -2373,22 +2477,18 @@ * calling this procedure; used for * debugging. */ int line; /* Line number in the source file; * used for debugging. */ { -#ifdef TCL_WIDE_INT_IS_LONG - return Tcl_DbNewLongObj(wideValue, file, line); -#else register Tcl_Obj *objPtr; TclDbNewObj(objPtr, file, line); objPtr->bytes = NULL; objPtr->internalRep.wideValue = wideValue; objPtr->typePtr = &tclWideIntType; return objPtr; -#endif } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * @@ -2427,13 +2527,10 @@ Tcl_SetWideIntObj(objPtr, wideValue) register Tcl_Obj *objPtr; /* Object w. internal rep to init. */ register Tcl_WideInt wideValue; /* Wide integer used to initialize * the object's value. */ { -#ifdef TCL_WIDE_INT_IS_LONG - Tcl_SetLongObj(objPtr, wideValue); -#else register Tcl_ObjType *oldTypePtr = objPtr->typePtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_SetWideIntObj called with shared object"); } @@ -2443,11 +2540,10 @@ } objPtr->internalRep.wideValue = wideValue; objPtr->typePtr = &tclWideIntType; Tcl_InvalidateStringRep(objPtr); -#endif } /* *---------------------------------------------------------------------- * @@ -2473,28 +2569,32 @@ Tcl_GetWideIntFromObj(interp, objPtr, wideIntPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* Object from which to get a wide int. */ register Tcl_WideInt *wideIntPtr; /* Place to store resulting long. */ { -#ifdef TCL_WIDE_INT_IS_LONG - /* - * Next line is type-safe because we only do this when long = Tcl_WideInt - */ - return Tcl_GetLongFromObj(interp, objPtr, wideIntPtr); -#else register int result; if (objPtr->typePtr == &tclWideIntType) { + gotWide: *wideIntPtr = objPtr->internalRep.wideValue; return TCL_OK; + } + if (objPtr->typePtr == &tclIntType) { + /* + * This cast is safe; all valid ints/longs are wides. + */ + + objPtr->internalRep.wideValue = + Tcl_LongAsWide(objPtr->internalRep.longValue); + objPtr->typePtr = &tclWideIntType; + goto gotWide; } result = SetWideIntFromAny(interp, objPtr); if (result == TCL_OK) { *wideIntPtr = objPtr->internalRep.wideValue; } return result; -#endif } /* *---------------------------------------------------------------------- * @@ -2721,13 +2821,13 @@ /* * Don't use Tcl_GetStringFromObj as it would prevent l1 and l2 being * in a register. */ - p1 = Tcl_GetString (objPtr1); + p1 = TclGetString(objPtr1); l1 = objPtr1->length; - p2 = Tcl_GetString (objPtr2); + p2 = TclGetString(objPtr2); l2 = objPtr2->length; /* * Only compare if the string representations are of the same length. */ @@ -2793,18 +2893,15 @@ HashObjKey(tablePtr, keyPtr) Tcl_HashTable *tablePtr; /* Hash table. */ VOID *keyPtr; /* Key from which to compute hash value. */ { Tcl_Obj *objPtr = (Tcl_Obj *) keyPtr; - register CONST char *string; - register int length; - register unsigned int result; - register int c; - - string = Tcl_GetString (objPtr); - length = objPtr->length; - + CONST char *string = TclGetString(objPtr); + int length = objPtr->length; + unsigned int result; + int i; + /* * I tried a zillion different hash functions and asked many other * people for advice. Many people had their own favorite functions, * all different, but no-one had much idea why they were good ones. * I chose the one below (multiply by 9 and add new character) @@ -2818,18 +2915,12 @@ * the high-order bits to fill out the hash value. This seems * works well both for decimal and non-decimal strings. */ result = 0; - while (length) { - c = *string; - string++; - length--; - if (length == 0) { - break; - } - result += (result<<3) + c; + for (i=0 ; ivarFramePtr = savedFramePtr; return (Tcl_Command) NULL; } } - resPtr = (ResolvedCmdName *) objPtr->internalRep.otherValuePtr; + resPtr = (ResolvedCmdName *) objPtr->internalRep.twoPtrValue.ptr1; /* * Get the current namespace. */ @@ -2933,11 +3024,11 @@ result = tclCmdNameType.setFromAnyProc(interp, objPtr); if (result != TCL_OK) { iPtr->varFramePtr = savedFramePtr; return (Tcl_Command) NULL; } - resPtr = (ResolvedCmdName *) objPtr->internalRep.otherValuePtr; + resPtr = (ResolvedCmdName *) objPtr->internalRep.twoPtrValue.ptr1; if (resPtr != NULL) { cmdPtr = resPtr->cmdPtr; } } iPtr->varFramePtr = savedFramePtr; @@ -3034,11 +3125,11 @@ FreeCmdNameInternalRep(objPtr) register Tcl_Obj *objPtr; /* CmdName object with internal * representation to free. */ { register ResolvedCmdName *resPtr = - (ResolvedCmdName *) objPtr->internalRep.otherValuePtr; + (ResolvedCmdName *) objPtr->internalRep.twoPtrValue.ptr1; if (resPtr != NULL) { /* * Decrement the reference count of the ResolvedCmdName structure. * If there are no more uses, free the ResolvedCmdName structure. @@ -3083,11 +3174,11 @@ DupCmdNameInternalRep(srcPtr, copyPtr) Tcl_Obj *srcPtr; /* Object with internal rep to copy. */ register Tcl_Obj *copyPtr; /* Object with internal rep to set. */ { register ResolvedCmdName *resPtr = - (ResolvedCmdName *) srcPtr->internalRep.otherValuePtr; + (ResolvedCmdName *) srcPtr->internalRep.twoPtrValue.ptr1; copyPtr->internalRep.twoPtrValue.ptr1 = (VOID *) resPtr; copyPtr->internalRep.twoPtrValue.ptr2 = NULL; if (resPtr != NULL) { resPtr->refCount++; Index: generic/tclPanic.c ================================================================== --- generic/tclPanic.c +++ generic/tclPanic.c @@ -10,11 +10,11 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclPanic.c,v 1.4 2001/06/17 03:48:19 dgp Exp $ + * RCS: @(#) $Id: tclPanic.c,v 1.4.12.2 2006/03/09 23:11:23 dgp Exp $ */ #include "tclInt.h" #include "tclPort.h" Index: generic/tclParse.c ================================================================== --- generic/tclParse.c +++ generic/tclParse.c @@ -11,11 +11,11 @@ * Contributions from Don Porter, NIST, 2002. (not subject to US copyright) * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclParse.c,v 1.25 2003/02/16 01:36:32 msofer Exp $ + * RCS: @(#) $Id: tclParse.c,v 1.25.2.1 2006/09/24 21:15:10 msofer Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -236,11 +236,11 @@ * of a command. */ CONST char *termPtr; /* Set by Tcl_ParseBraces/QuotedString to * point to char after terminating one. */ int scanned; - if ((string == NULL) && (numBytes>0)) { + if ((string == NULL) && (numBytes!=0)) { if (interp != NULL) { Tcl_SetResult(interp, "can't parse a NULL pointer", TCL_STATIC); } return TCL_ERROR; } Index: generic/tclParseExpr.c ================================================================== --- generic/tclParseExpr.c +++ generic/tclParseExpr.c @@ -11,11 +11,11 @@ * Contributions from Don Porter, NIST, 2002. (not subject to US copyright) * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclParseExpr.c,v 1.17 2003/02/16 01:36:32 msofer Exp $ + * RCS: @(#) $Id: tclParseExpr.c,v 1.17.2.2 2005/05/20 17:19:10 vasiljevic Exp $ */ #include "tclInt.h" /* @@ -1179,10 +1179,11 @@ case LITERAL: /* * Int or double number. */ + tokenizeLiteral: if (parsePtr->numTokens == parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; tokenPtr->type = TCL_TOKEN_TEXT; @@ -1366,52 +1367,58 @@ tokenPtr->size = exprTokenPtr->size; tokenPtr->numComponents = exprTokenPtr->numComponents-1; } break; - case FUNC_NAME: + case STREQ: + case STRNEQ: + case FUNC_NAME: { /* * math_func '(' expr {',' expr} ')' */ - - if (parsePtr->numTokens == parsePtr->tokensAvailable) { - TclExpandTokenArray(parsePtr); - } - tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; - tokenPtr->type = TCL_TOKEN_OPERATOR; - tokenPtr->start = infoPtr->start; - tokenPtr->size = infoPtr->size; - tokenPtr->numComponents = 0; - parsePtr->numTokens++; + + ParseInfo savedInfo = *infoPtr; code = GetLexeme(infoPtr); /* skip over function name */ if (code != TCL_OK) { return code; } if (infoPtr->lexeme != OPEN_PAREN) { + int code; + Tcl_DString functionName; + Tcl_HashEntry *hPtr; + Interp *iPtr = (Interp *) infoPtr->parsePtr->interp; + Tcl_Obj *objPtr = Tcl_NewStringObj(savedInfo.start, savedInfo.size); + + /* Check for boolean literals (true, false, yes, no, on, off) */ + Tcl_IncrRefCount(objPtr); + code = Tcl_ConvertToType(NULL, objPtr, &tclBooleanType); + Tcl_DecrRefCount(objPtr); + if (code == TCL_OK) { + *infoPtr = savedInfo; + goto tokenizeLiteral; + } + /* * Guess what kind of error we have by trying to tell * whether we have a function or variable name here. * Alas, this makes the parser more tightly bound with the * rest of the interpreter, but that is the only way to * give a sensible message here. Still, it is not too * serious as this is only done when generating an error. */ - Interp *iPtr = (Interp *) infoPtr->parsePtr->interp; - Tcl_DString functionName; - Tcl_HashEntry *hPtr; /* * Look up the name as a function name. We need a writable * copy (DString) so we can terminate it with a NULL for * the benefit of Tcl_FindHashEntry which operates on * NULL-terminated string keys. */ Tcl_DStringInit(&functionName); hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, - Tcl_DStringAppend(&functionName, tokenPtr->start, - tokenPtr->size)); + Tcl_DStringAppend(&functionName, + savedInfo.start, savedInfo.size)); Tcl_DStringFree(&functionName); /* * Assume that we have an attempted variable reference * unless we've got a function name, as the set of @@ -1424,10 +1431,21 @@ LogSyntaxError(infoPtr, "variable references require preceding $"); } return TCL_ERROR; } + + if (parsePtr->numTokens == parsePtr->tokensAvailable) { + TclExpandTokenArray(parsePtr); + } + tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; + tokenPtr->type = TCL_TOKEN_OPERATOR; + tokenPtr->start = savedInfo.start; + tokenPtr->size = savedInfo.size; + tokenPtr->numComponents = 0; + parsePtr->numTokens++; + code = GetLexeme(infoPtr); /* skip over '(' */ if (code != TCL_OK) { return code; } @@ -1451,10 +1469,11 @@ exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; exprTokenPtr->size = (infoPtr->next - exprTokenPtr->start); exprTokenPtr->numComponents = parsePtr->numTokens - firstIndex; break; + } case COMMA: LogSyntaxError(infoPtr, "commas can only separate function arguments"); return TCL_ERROR; @@ -1842,54 +1861,10 @@ c = UCHAR(ch); } infoPtr->size = (src - infoPtr->start); infoPtr->next = src; parsePtr->term = infoPtr->next; - /* - * Check for boolean literals (true, false, yes, no, on, off) - */ - switch (infoPtr->start[0]) { - case 'f': - if (infoPtr->size == 5 && - strncmp("false", infoPtr->start, 5) == 0) { - infoPtr->lexeme = LITERAL; - return TCL_OK; - } - break; - case 'n': - if (infoPtr->size == 2 && - strncmp("no", infoPtr->start, 2) == 0) { - infoPtr->lexeme = LITERAL; - return TCL_OK; - } - break; - case 'o': - if (infoPtr->size == 3 && - strncmp("off", infoPtr->start, 3) == 0) { - infoPtr->lexeme = LITERAL; - return TCL_OK; - } else if (infoPtr->size == 2 && - strncmp("on", infoPtr->start, 2) == 0) { - infoPtr->lexeme = LITERAL; - return TCL_OK; - } - break; - case 't': - if (infoPtr->size == 4 && - strncmp("true", infoPtr->start, 4) == 0) { - infoPtr->lexeme = LITERAL; - return TCL_OK; - } - break; - case 'y': - if (infoPtr->size == 3 && - strncmp("yes", infoPtr->start, 3) == 0) { - infoPtr->lexeme = LITERAL; - return TCL_OK; - } - break; - } return TCL_OK; } infoPtr->lexeme = UNKNOWN_CHAR; return TCL_OK; } Index: generic/tclPipe.c ================================================================== --- generic/tclPipe.c +++ generic/tclPipe.c @@ -8,11 +8,11 @@ * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclPipe.c,v 1.7 2002/12/17 02:47:39 davygrvy Exp $ + * RCS: @(#) $Id: tclPipe.c,v 1.7.2.5 2006/03/16 00:35:58 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -66,17 +66,17 @@ static TclFile FileForRedirect(interp, spec, atOK, arg, nextArg, flags, skipPtr, closePtr, releasePtr) Tcl_Interp *interp; /* Intepreter to use for error reporting. */ - CONST char *spec; /* Points to character just after + CONST char *spec; /* Points to character just after * redirection character. */ - CONST char *arg; /* Pointer to entire argument containing - * spec: used for error reporting. */ int atOK; /* Non-zero means that '@' notation can be * used to specify a channel, zero means that * it isn't. */ + CONST char *arg; /* Pointer to entire argument containing + * spec: used for error reporting. */ CONST char *nextArg; /* Next argument in argc/argv array, if needed * for file name or channel name. May be * NULL. */ int flags; /* Flags to use for opening file or to * specify mode for channel. */ @@ -105,13 +105,13 @@ if (chan == (Tcl_Channel) NULL) { return NULL; } file = TclpMakeFile(chan, writing ? TCL_WRITABLE : TCL_READABLE); if (file == NULL) { - Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan), - "\" wasn't opened for ", - ((writing) ? "writing" : "reading"), (char *) NULL); + Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan), + "\" wasn't opened for ", + ((writing) ? "writing" : "reading"), (char *) NULL); return NULL; } *releasePtr = 1; if (writing) { @@ -133,15 +133,14 @@ goto badLastArg; } *skipPtr = 2; } name = Tcl_TranslateFileName(interp, spec, &nameString); - if (name != NULL) { - file = TclpOpenFile(name, flags); - } else { - file = NULL; + if (name == NULL) { + return NULL; } + file = TclpOpenFile(name, flags); Tcl_DStringFree(&nameString); if (file == NULL) { Tcl_AppendResult(interp, "couldn't ", ((writing) ? "write" : "read"), " file \"", spec, "\": ", Tcl_PosixError(interp), (char *) NULL); @@ -506,11 +505,12 @@ * stderr. */ int errorClose = 0; /* If non-zero, then errorFile should be * closed when cleaning up. */ int errorRelease = 0; CONST char *p; - int skip, lastBar, lastArg, i, j, atOK, flags, errorToOutput; + CONST char *nextArg; + int skip, lastBar, lastArg, i, j, atOK, flags, needCmd, errorToOutput = 0; Tcl_DString execBuffer; TclFile pipeIn; TclFile curInFile, curOutFile, curErrFile; Tcl_Channel channel; @@ -544,12 +544,14 @@ * entire pipe may appear at the very end of the argument list. */ lastBar = -1; cmdCount = 1; + needCmd = 1; for (i = 0; i < argc; i++) { - skip = 0; + errorToOutput = 0; + skip = 0; p = argv[i]; switch (*p++) { case '|': if (*p == '&') { p++; @@ -562,10 +564,11 @@ goto error; } } lastBar = i; cmdCount++; + needCmd = 1; break; case '<': if (inputClose != 0) { inputClose = 0; @@ -578,36 +581,42 @@ if (*p == '<') { inputFile = NULL; inputLiteral = p + 1; skip = 1; if (*inputLiteral == '\0') { - inputLiteral = argv[i + 1]; + inputLiteral = ((i + 1) == argc) ? NULL : argv[i + 1]; if (inputLiteral == NULL) { Tcl_AppendResult(interp, "can't specify \"", argv[i], "\" as last word in command", (char *) NULL); goto error; } skip = 2; } } else { + nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; inputLiteral = NULL; inputFile = FileForRedirect(interp, p, 1, argv[i], - argv[i + 1], O_RDONLY, &skip, &inputClose, &inputRelease); + nextArg, O_RDONLY, &skip, &inputClose, &inputRelease); if (inputFile == NULL) { goto error; } } break; case '>': atOK = 1; flags = O_WRONLY | O_CREAT | O_TRUNC; - errorToOutput = 0; if (*p == '>') { p++; atOK = 0; - flags = O_WRONLY | O_CREAT; + + /* + * Note that the O_APPEND flag only has an effect on POSIX + * platforms. On Windows, we just have to carry on regardless. + */ + + flags = O_WRONLY | O_CREAT | O_APPEND; } if (*p == '&') { if (errorClose != 0) { errorClose = 0; TclpCloseFile(errorFile); @@ -635,12 +644,13 @@ errorRelease = 1; } else { TclpReleaseFile(outputFile); } } + nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; outputFile = FileForRedirect(interp, p, atOK, argv[i], - argv[i + 1], flags, &skip, &outputClose, &outputRelease); + nextArg, flags, &skip, &outputClose, &outputRelease); if (outputFile == NULL) { goto error; } if (errorToOutput) { if (errorClose != 0) { @@ -673,16 +683,38 @@ } if (errorRelease != 0) { errorRelease = 0; TclpReleaseFile(errorFile); } - errorFile = FileForRedirect(interp, p, atOK, argv[i], - argv[i + 1], flags, &skip, &errorClose, &errorRelease); - if (errorFile == NULL) { - goto error; + if (atOK && p[0] == '@' && p[1] == '1' && p[2] == '\0') { + /* + * Special case handling of 2>@1 to redirect stderr to the + * exec/open output pipe as well. This is meant for the end + * of the command string, otherwise use |& between commands. + */ + if (i != argc - 1) { + Tcl_AppendResult(interp, "must specify \"", argv[i], + "\" as last word in command", (char *) NULL); + goto error; + } + errorFile = outputFile; + errorToOutput = 2; + skip = 1; + } else { + nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; + errorFile = FileForRedirect(interp, p, atOK, argv[i], + nextArg, flags, &skip, &errorClose, &errorRelease); + if (errorFile == NULL) { + goto error; + } } break; + + default: + /* Got a command word, not a redirection */ + needCmd = 0; + break; } if (skip != 0) { for (j = i + skip; j < argc; j++) { argv[j - skip] = argv[j]; @@ -689,10 +721,19 @@ } argc -= skip; i -= 1; } } + + if (needCmd) { + /* We had a bar followed only by redirections. */ + + Tcl_SetResult(interp, + "illegal use of | or |& in command", + TCL_STATIC); + goto error; + } if (inputFile == NULL) { if (inputLiteral != NULL) { /* * The input for the first process is immediate data coming from @@ -763,11 +804,16 @@ } } } if (errorFile == NULL) { - if (errFilePtr != NULL) { + if (errorToOutput == 2) { + /* + * Handle 2>@1 special case at end of cmd line + */ + errorFile = outputFile; + } else if (errFilePtr != NULL) { /* * Set up the standard error output sink for the pipeline, if * requested. Use a temporary file which is opened, then deleted. * Could potentially just use pipe, but if it filled up it could * cause the pipeline to deadlock: we'd be waiting for processes @@ -835,21 +881,21 @@ joinThisError = 1; break; } } } - argv[lastArg] = NULL; /* * If this is the last segment, use the specified outputFile. * Otherwise create an intermediate pipe. pipeIn will become the * curInFile for the next segment of the pipe. */ - if (lastArg == argc) { + if (lastArg == argc) { curOutFile = outputFile; } else { + argv[lastArg] = NULL; if (TclpCreatePipe(&pipeIn, &curOutFile) == 0) { Tcl_AppendResult(interp, "couldn't create pipe: ", Tcl_PosixError(interp), (char *) NULL); goto error; } Index: generic/tclPkg.c ================================================================== --- generic/tclPkg.c +++ generic/tclPkg.c @@ -3,15 +3,20 @@ * * This file implements package and version control for Tcl via * the "package" command and a few C APIs. * * Copyright (c) 1996 Sun Microsystems, Inc. + * Copyright (c) 2006 Andreas Kupries * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclPkg.c,v 1.9 2002/02/22 22:36:09 dgp Exp $ + * RCS: @(#) $Id: tclPkg.c,v 1.9.2.9 2007/03/19 17:06:26 dgp Exp $ + * + * TIP #268. + * Heavily rewritten to handle the extend version numbers, and extended + * package requirements. */ #include "tclInt.h" /* @@ -48,17 +53,38 @@ /* * Prototypes for procedures defined in this file: */ +#ifndef TCL_TIP268 static int CheckVersion _ANSI_ARGS_((Tcl_Interp *interp, CONST char *string)); static int ComparePkgVersions _ANSI_ARGS_((CONST char *v1, CONST char *v2, int *satPtr)); static Package * FindPackage _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name)); +#else +static int CheckVersionAndConvert(Tcl_Interp *interp, CONST char *string, + char** internal, int* stable); +static int CompareVersions(CONST char *v1i, CONST char *v2i, + int *isMajorPtr); +static int CheckRequirement(Tcl_Interp *interp, CONST char *string); +static int CheckAllRequirements(Tcl_Interp* interp, + int reqc, Tcl_Obj *CONST reqv[]); +static int RequirementSatisfied(CONST char *havei, CONST char *req); +static int AllRequirementsSatisfied(CONST char *havei, + int reqc, Tcl_Obj *CONST reqv[]); +static void AddRequirementsToResult(Tcl_Interp* interp, + int reqc, Tcl_Obj *CONST reqv[]); +static void AddRequirementsToDString(Tcl_DString* dstring, + int reqc, Tcl_Obj *CONST reqv[]); +static Package * FindPackage(Tcl_Interp *interp, CONST char *name); +static Tcl_Obj* ExactRequirement(CONST char* version); +static void VersionCleanupProc(ClientData clientData, + Tcl_Interp *interp); +#endif /* *---------------------------------------------------------------------- * * Tcl_PkgProvide / Tcl_PkgProvideEx -- @@ -81,51 +107,71 @@ *---------------------------------------------------------------------- */ int Tcl_PkgProvide(interp, name, version) - Tcl_Interp *interp; /* Interpreter in which package is now + Tcl_Interp *interp; /* Interpreter in which package is now * available. */ - CONST char *name; /* Name of package. */ - CONST char *version; /* Version string for package. */ + CONST char *name; /* Name of package. */ + CONST char *version; /* Version string for package. */ { return Tcl_PkgProvideEx(interp, name, version, (ClientData) NULL); } int Tcl_PkgProvideEx(interp, name, version, clientData) - Tcl_Interp *interp; /* Interpreter in which package is now + Tcl_Interp *interp; /* Interpreter in which package is now * available. */ - CONST char *name; /* Name of package. */ - CONST char *version; /* Version string for package. */ - ClientData clientData; /* clientdata for this package (normally - * used for C callback function table) */ + CONST char *name; /* Name of package. */ + CONST char *version; /* Version string for package. */ + ClientData clientData; /* clientdata for this package (normally + * used for C callback function table) */ { Package *pkgPtr; +#ifdef TCL_TIP268 + char* pvi; + char* vi; + int res; +#endif pkgPtr = FindPackage(interp, name); if (pkgPtr->version == NULL) { pkgPtr->version = ckalloc((unsigned) (strlen(version) + 1)); strcpy(pkgPtr->version, version); pkgPtr->clientData = clientData; return TCL_OK; } +#ifndef TCL_TIP268 if (ComparePkgVersions(pkgPtr->version, version, (int *) NULL) == 0) { +#else + if (CheckVersionAndConvert (interp, pkgPtr->version, &pvi, NULL) != TCL_OK) { + return TCL_ERROR; + } else if (CheckVersionAndConvert (interp, version, &vi, NULL) != TCL_OK) { + Tcl_Free (pvi); + return TCL_ERROR; + } + + res = CompareVersions(pvi, vi, NULL); + Tcl_Free (pvi); + Tcl_Free (vi); + + if (res == 0) { +#endif if (clientData != NULL) { pkgPtr->clientData = clientData; } return TCL_OK; } Tcl_AppendResult(interp, "conflicting versions provided for package \"", - name, "\": ", pkgPtr->version, ", then ", version, (char *) NULL); + name, "\": ", pkgPtr->version, ", then ", version, (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * - * Tcl_PkgRequire / Tcl_PkgRequireEx -- + * Tcl_PkgRequire / Tcl_PkgRequireEx / Tcl_PkgRequireProc -- * * This procedure is called by code that depends on a particular * version of a particular package. If the package is not already * provided in the interpreter, this procedure invokes a Tcl script * to provide it. If the package is already provided, this @@ -146,47 +192,68 @@ * The script from some previous "package ifneeded" command may * be invoked to provide the package. * *---------------------------------------------------------------------- */ + +#ifndef TCL_TIP268 +/* + * Empty definition for Stubs when TIP 268 is not activated. + */ +int +Tcl_PkgRequireProc(interp,name,reqc,reqv,clientDataPtr) + Tcl_Interp *interp; /* Interpreter in which package is now + * available. */ + CONST char *name; /* Name of desired package. */ + int reqc; /* Requirements constraining the desired version. */ + Tcl_Obj *CONST reqv[]; /* 0 means to use the latest version available. */ + ClientData *clientDataPtr; +{ + return TCL_ERROR; +} +#endif CONST char * Tcl_PkgRequire(interp, name, version, exact) - Tcl_Interp *interp; /* Interpreter in which package is now - * available. */ - CONST char *name; /* Name of desired package. */ - CONST char *version; /* Version string for desired version; - * NULL means use the latest version - * available. */ - int exact; /* Non-zero means that only the particular - * version given is acceptable. Zero means - * use the latest compatible version. */ + Tcl_Interp *interp; /* Interpreter in which package is now + * available. */ + CONST char *name; /* Name of desired package. */ + CONST char *version; /* Version string for desired version; NULL + * means use the latest version available. */ + int exact; /* Non-zero means that only the particular + * version given is acceptable. Zero means use + * the latest compatible version. */ { return Tcl_PkgRequireEx(interp, name, version, exact, (ClientData *) NULL); } CONST char * Tcl_PkgRequireEx(interp, name, version, exact, clientDataPtr) - Tcl_Interp *interp; /* Interpreter in which package is now + Tcl_Interp *interp; /* Interpreter in which package is now * available. */ - CONST char *name; /* Name of desired package. */ - CONST char *version; /* Version string for desired version; + CONST char *name; /* Name of desired package. */ + CONST char *version; /* Version string for desired version; * NULL means use the latest version * available. */ - int exact; /* Non-zero means that only the particular + int exact; /* Non-zero means that only the particular * version given is acceptable. Zero means * use the latest compatible version. */ - ClientData *clientDataPtr; /* Used to return the client data for this + ClientData *clientDataPtr; /* Used to return the client data for this * package. If it is NULL then the client * data is not returned. This is unchanged * if this call fails for any reason. */ { +#ifndef TCL_TIP268 Package *pkgPtr; PkgAvail *availPtr, *bestPtr; char *script; int code, satisfies, result, pass; Tcl_DString command; +#else + Tcl_Obj *ov; + int res; +#endif /* * If an attempt is being made to load this into a standalone executable * on a platform where backlinking is not supported then this must be * a shared version of Tcl (Otherwise the load would have failed). @@ -255,80 +322,416 @@ * incomplete. */ tclEmptyStringRep = &tclEmptyString; Tcl_AppendResult(interp, "Cannot load package \"", name, - "\" in standalone executable: This package is not ", - "compiled with stub support", NULL); + "\" in standalone executable: This package is not ", + "compiled with stub support", NULL); return NULL; } +#ifdef TCL_TIP268 + /* Translate between old and new API, and defer to the new function. */ + + if (version == NULL) { + res = Tcl_PkgRequireProc(interp, name, 0, NULL, clientDataPtr); + } else { + if (exact) { + ov = ExactRequirement (version); + } else { + ov = Tcl_NewStringObj (version,-1); + } + + Tcl_IncrRefCount (ov); + res = Tcl_PkgRequireProc(interp, name, 1, &ov, clientDataPtr); + Tcl_DecrRefCount (ov); + } + + if (res != TCL_OK) { + return NULL; + } + + /* This function returns the version string explictly, and leaves the + * interpreter result empty. However "Tcl_PkgRequireProc" above returned + * the version through the interpreter result. Simply resetting the result + * now potentially deletes the string (obj), and the pointer to its string + * rep we have, as our result, may be dangling due to this. Our solution + * is to remember the object in interp associated data, with a proper + * reference count, and then reset the result. Now pointers will not + * dangle. It will be a leak however if nothing is done. So the next time + * we come through here we delete the object remembered by this call, as + * we can then be sure that there is no pointer to its string around + * anymore. Beyond that we have a deletion function which cleans up the last + * remembered object which was not cleaned up directly, here. + */ + + ov = (Tcl_Obj*) Tcl_GetAssocData (interp, "tcl/Tcl_PkgRequireEx", NULL); + if (ov != NULL) { + Tcl_DecrRefCount (ov); + } + + ov = Tcl_GetObjResult (interp); + Tcl_IncrRefCount (ov); + Tcl_SetAssocData(interp, "tcl/Tcl_PkgRequireEx", VersionCleanupProc, + (ClientData) ov); + Tcl_ResetResult (interp); + + return Tcl_GetString (ov); +} + +int +Tcl_PkgRequireProc(interp,name,reqc,reqv,clientDataPtr) + Tcl_Interp *interp; /* Interpreter in which package is now + * available. */ + CONST char *name; /* Name of desired package. */ + int reqc; /* Requirements constraining the desired version. */ + Tcl_Obj *CONST reqv[]; /* 0 means to use the latest version available. */ + ClientData *clientDataPtr; +{ + Interp *iPtr = (Interp *) interp; + Package *pkgPtr; + PkgAvail *availPtr, *bestPtr, *bestStablePtr; + char *availVersion, *bestVersion; /* Internal rep. of versions */ + int availStable; + char *script; + int code, satisfies, pass; + Tcl_DString command; + char* pkgVersionI; + +#endif /* - * It can take up to three passes to find the package: one pass to - * run the "package unknown" script, one to run the "package ifneeded" - * script for a specific version, and a final pass to lookup the - * package loaded by the "package ifneeded" script. + * It can take up to three passes to find the package: one pass to run the + * "package unknown" script, one to run the "package ifneeded" script for + * a specific version, and a final pass to lookup the package loaded by + * the "package ifneeded" script. */ for (pass = 1; ; pass++) { pkgPtr = FindPackage(interp, name); if (pkgPtr->version != NULL) { break; } + + /* + * Check whether we're already attempting to load some version + * of this package (circular dependency detection). + */ + + if (pkgPtr->clientData != NULL) { + Tcl_AppendResult(interp, "circular package dependency: ", + "attempt to provide ", name, " ", + (char *)(pkgPtr->clientData), " requires ", name, NULL); +#ifndef TCL_TIP268 + if (version != NULL) { + Tcl_AppendResult(interp, " ", version, NULL); + } + return NULL; +#else + AddRequirementsToResult (interp, reqc, reqv); + return TCL_ERROR; +#endif + } /* - * The package isn't yet present. Search the list of available + * The package isn't yet present. Search the list of available * versions and invoke the script for the best available version. + * + * For TIP 268 we are actually locating the best, and the best stable + * version. One of them is then chosen based on the selection mode. */ - +#ifndef TCL_TIP268 bestPtr = NULL; for (availPtr = pkgPtr->availPtr; availPtr != NULL; availPtr = availPtr->nextPtr) { if ((bestPtr != NULL) && (ComparePkgVersions(availPtr->version, bestPtr->version, (int *) NULL) <= 0)) { +#else + bestPtr = NULL; + bestStablePtr = NULL; + bestVersion = NULL; + + for (availPtr = pkgPtr->availPtr; + availPtr != NULL; + availPtr = availPtr->nextPtr) { + if (CheckVersionAndConvert (interp, availPtr->version, + &availVersion, &availStable) != TCL_OK) { + /* The provided version number is has invalid syntax. This + * should not happen. This should have been caught by the + * 'package ifneeded' registering the package. + */ +#endif continue; } +#ifndef TCL_TIP268 if (version != NULL) { result = ComparePkgVersions(availPtr->version, version, &satisfies); if ((result != 0) && exact) { +#else + if (bestPtr != NULL) { + int res = CompareVersions (availVersion, bestVersion, NULL); + /* Note: Use internal reps! */ + if (res <= 0) { + /* The version of the package sought is not as good as the + * currently selected version. Ignore it. */ + Tcl_Free (availVersion); + availVersion = NULL; +#endif continue; } +#ifdef TCL_TIP268 + } + + /* We have found a version which is better than our max. */ + + if (reqc > 0) { + /* Check satisfaction of requirements */ + satisfies = AllRequirementsSatisfied (availVersion, reqc, reqv); +#endif if (!satisfies) { +#ifdef TCL_TIP268 + Tcl_Free (availVersion); + availVersion = NULL; +#endif continue; } } bestPtr = availPtr; +#ifdef TCL_TIP268 + if (bestVersion != NULL) Tcl_Free (bestVersion); + bestVersion = availVersion; + availVersion = NULL; + + /* If this new best version is stable then it also has to be + * better than the max stable version found so far. + */ + + if (availStable) { + bestStablePtr = availPtr; + } + } + + if (bestVersion != NULL) { + Tcl_Free (bestVersion); + } + + /* Now choose a version among the two best. For 'latest' we simply + * take (actually keep) the best. For 'stable' we take the best + * stable, if there is any, or the best if there is nothing stable. + */ + + if ((iPtr->packagePrefer == PKG_PREFER_STABLE) && (bestStablePtr != NULL)) { + bestPtr = bestStablePtr; +#endif } if (bestPtr != NULL) { /* - * We found an ifneeded script for the package. Be careful while - * executing it: this could cause reentrancy, so (a) protect the + * We found an ifneeded script for the package. Be careful while + * executing it: this could cause reentrancy, so (a) protect the * script itself from deletion and (b) don't assume that bestPtr * will still exist when the script completes. */ - + + CONST char *versionToProvide = bestPtr->version; script = bestPtr->script; + pkgPtr->clientData = (ClientData) versionToProvide; Tcl_Preserve((ClientData) script); - code = Tcl_GlobalEval(interp, script); + Tcl_Preserve((ClientData) versionToProvide); + code = Tcl_EvalEx(interp, script, -1, TCL_EVAL_GLOBAL); Tcl_Release((ClientData) script); - if (code != TCL_OK) { - if (code == TCL_ERROR) { - Tcl_AddErrorInfo(interp, - "\n (\"package ifneeded\" script)"); - } - return NULL; - } - Tcl_ResetResult(interp); pkgPtr = FindPackage(interp, name); + if (code == TCL_OK) { +#ifdef TCL_TIP268 + Tcl_ResetResult(interp); +#endif + if (pkgPtr->version == NULL) { +#ifndef TCL_TIP268 + Tcl_ResetResult(interp); +#endif + code = TCL_ERROR; + Tcl_AppendResult(interp, "attempt to provide package ", + name, " ", versionToProvide, + " failed: no version of package ", name, + " provided", NULL); +#ifndef TCL_TIP268 + } else if (0 != ComparePkgVersions( + pkgPtr->version, versionToProvide, NULL)) { + /* At this point, it is clear that a prior + * [package ifneeded] command lied to us. It said + * that to get a particular version of a particular + * package, we needed to evaluate a particular script. + * However, we evaluated that script and got a different + * version than we were told. This is an error, and we + * ought to report it. + * + * However, we've been letting this type of error slide + * for a long time, and as a result, a lot of packages + * suffer from them. + * + * It's a bit too harsh to make a large number of + * existing packages start failing by releasing a + * new patch release, so we forgive this type of error + * for the rest of the Tcl 8.4 series. + * + * We considered reporting a warning, but in practice + * even that appears too harsh a change for a patch release. + * + * We limit the error reporting to only + * the situation where a broken ifneeded script leads + * to a failure to satisfy the requirement. + */ + if (version) { + result = ComparePkgVersions( + pkgPtr->version, version, &satisfies); + if (result && (exact || !satisfies)) { + Tcl_ResetResult(interp); + code = TCL_ERROR; + Tcl_AppendResult(interp, + "attempt to provide package ", name, " ", + versionToProvide, " failed: package ", + name, " ", pkgPtr->version, + " provided instead", NULL); +#else + } else { + char* pvi; + char* vi; + int res; + + if (CheckVersionAndConvert (interp, pkgPtr->version, &pvi, NULL) != TCL_OK) { + code = TCL_ERROR; + } else if (CheckVersionAndConvert (interp, versionToProvide, &vi, NULL) != TCL_OK) { + Tcl_Free (pvi); + code = TCL_ERROR; + } else { + res = CompareVersions(pvi, vi, NULL); + Tcl_Free (vi); + + if (res != 0) { + /* At this point, it is clear that a prior + * [package ifneeded] command lied to us. It said + * that to get a particular version of a particular + * package, we needed to evaluate a particular script. + * However, we evaluated that script and got a different + * version than we were told. This is an error, and we + * ought to report it. + * + * However, we've been letting this type of error slide + * for a long time, and as a result, a lot of packages + * suffer from them. + * + * It's a bit too harsh to make a large number of + * existing packages start failing by releasing a + * new patch release, so we forgive this type of error + * for the rest of the Tcl 8.4 series. + * + * We considered reporting a warning, but in practice + * even that appears too harsh a change for a patch release. + * + * We limit the error reporting to only + * the situation where a broken ifneeded script leads + * to a failure to satisfy the requirement. + */ + + if (reqc > 0) { + satisfies = AllRequirementsSatisfied (pvi, reqc, reqv); + if (!satisfies) { + Tcl_ResetResult(interp); + code = TCL_ERROR; + Tcl_AppendResult(interp, + "attempt to provide package ", name, " ", + versionToProvide, " failed: package ", + name, " ", pkgPtr->version, + " provided instead", NULL); + } + } + /* + * Warning generation now disabled + if (code == TCL_OK) { + Tcl_Obj *msg = Tcl_NewStringObj( + "attempt to provide package ", -1); + Tcl_Obj *cmdPtr = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(NULL, cmdPtr, + Tcl_NewStringObj("tclLog", -1)); + Tcl_AppendStringsToObj(msg, name, " ", versionToProvide, + " failed: package ", name, " ", + pkgPtr->version, " provided instead", NULL); + Tcl_ListObjAppendElement(NULL, cmdPtr, msg); + Tcl_IncrRefCount(cmdPtr); + Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(cmdPtr); + Tcl_ResetResult(interp); + } + */ +#endif + } +#ifdef TCL_TIP268 + Tcl_Free (pvi); +#endif + } +#ifndef TCL_TIP268 + /* + * Warning generation now disabled + if (code == TCL_OK) { + Tcl_Obj *msg = Tcl_NewStringObj( + "attempt to provide package ", -1); + Tcl_Obj *cmdPtr = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(NULL, cmdPtr, + Tcl_NewStringObj("tclLog", -1)); + Tcl_AppendStringsToObj(msg, name, " ", versionToProvide, + " failed: package ", name, " ", + pkgPtr->version, " provided instead", NULL); + Tcl_ListObjAppendElement(NULL, cmdPtr, msg); + Tcl_IncrRefCount(cmdPtr); + Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(cmdPtr); + Tcl_ResetResult(interp); + } + */ +#endif + } + } 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: ", Tcl_GetString(codePtr), NULL); + Tcl_DecrRefCount(codePtr); + code = TCL_ERROR; + } + Tcl_Release((ClientData) versionToProvide); + + if (code != TCL_OK) { + /* + * Take a non-TCL_OK code from the script as an + * indication the package wasn't loaded properly, + * so the package system should not remember an + * improper load. + * + * This is consistent with our returning NULL. + * If we're not willing to tell our caller we + * got a particular version, we shouldn't store + * that version for telling future callers either. + */ + Tcl_AddErrorInfo(interp, "\n (\"package ifneeded\" script)"); + if (pkgPtr->version != NULL) { + ckfree(pkgPtr->version); + pkgPtr->version = NULL; + } + pkgPtr->clientData = NULL; +#ifndef TCL_TIP268 + return NULL; +#else + return TCL_ERROR; +#endif + } break; } /* - * Package not in the database. If there is a "package unknown" - * command, invoke it (but only on the first pass; after that, - * we should not get here in the first place). + * The package is not in the database. If there is a "package unknown" + * command, invoke it (but only on the first pass; after that, we + * should not get here in the first place). */ if (pass > 1) { break; } @@ -335,60 +738,103 @@ script = ((Interp *) interp)->packageUnknown; if (script != NULL) { Tcl_DStringInit(&command); Tcl_DStringAppend(&command, script, -1); Tcl_DStringAppendElement(&command, name); +#ifndef TCL_TIP268 Tcl_DStringAppend(&command, " ", 1); Tcl_DStringAppend(&command, (version != NULL) ? version : "{}", -1); if (exact) { Tcl_DStringAppend(&command, " -exact", 7); } - code = Tcl_GlobalEval(interp, Tcl_DStringValue(&command)); +#else + AddRequirementsToDString(&command, reqc, reqv); +#endif + code = Tcl_EvalEx(interp, Tcl_DStringValue(&command), + Tcl_DStringLength(&command), TCL_EVAL_GLOBAL); Tcl_DStringFree(&command); - if (code != TCL_OK) { - if (code == TCL_ERROR) { - Tcl_AddErrorInfo(interp, - "\n (\"package unknown\" script)"); - } + if ((code != TCL_OK) && (code != TCL_ERROR)) { + Tcl_Obj *codePtr = Tcl_NewIntObj(code); + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "bad return code: ", + Tcl_GetString(codePtr), NULL); + Tcl_DecrRefCount(codePtr); + code = TCL_ERROR; + } + if (code == TCL_ERROR) { + Tcl_AddErrorInfo(interp, "\n (\"package unknown\" script)"); +#ifndef TCL_TIP268 return NULL; +#else + return TCL_ERROR; +#endif } Tcl_ResetResult(interp); } } if (pkgPtr->version == NULL) { - Tcl_AppendResult(interp, "can't find package ", name, - (char *) NULL); + Tcl_AppendResult(interp, "can't find package ", name, (char *) NULL); +#ifndef TCL_TIP268 if (version != NULL) { Tcl_AppendResult(interp, " ", version, (char *) NULL); } return NULL; +#else + AddRequirementsToResult(interp, reqc, reqv); + return TCL_ERROR; +#endif } /* - * At this point we know that the package is present. Make sure that the - * provided version meets the current requirement. + * At this point we know that the package is present. Make sure that the + * provided version meets the current requirements. */ +#ifndef TCL_TIP268 if (version == NULL) { if (clientDataPtr) { *clientDataPtr = pkgPtr->clientData; } return pkgPtr->version; +#else + if (reqc == 0) { + satisfies = 1; + } else { + CheckVersionAndConvert (interp, pkgPtr->version, &pkgVersionI, NULL); + satisfies = AllRequirementsSatisfied (pkgVersionI, reqc, reqv); + + Tcl_Free (pkgVersionI); +#endif } +#ifndef TCL_TIP268 result = ComparePkgVersions(pkgPtr->version, version, &satisfies); if ((satisfies && !exact) || (result == 0)) { +#else + if (satisfies) { +#endif if (clientDataPtr) { *clientDataPtr = pkgPtr->clientData; } +#ifndef TCL_TIP268 return pkgPtr->version; +#else + Tcl_SetObjResult (interp, Tcl_NewStringObj (pkgPtr->version, -1)); + return TCL_OK; +#endif } Tcl_AppendResult(interp, "version conflict for package \"", - name, "\": have ", pkgPtr->version, ", need ", version, - (char *) NULL); + name, "\": have ", pkgPtr->version, +#ifndef TCL_TIP268 + ", need ", version, (char *) NULL); return NULL; +#else + ", need", (char*) NULL); + AddRequirementsToResult (interp, reqc, reqv); + return TCL_ERROR; +#endif } /* *---------------------------------------------------------------------- * @@ -411,35 +857,35 @@ *---------------------------------------------------------------------- */ CONST char * Tcl_PkgPresent(interp, name, version, exact) - Tcl_Interp *interp; /* Interpreter in which package is now + Tcl_Interp *interp; /* Interpreter in which package is now * available. */ - CONST char *name; /* Name of desired package. */ - CONST char *version; /* Version string for desired version; + CONST char *name; /* Name of desired package. */ + CONST char *version; /* Version string for desired version; * NULL means use the latest version * available. */ - int exact; /* Non-zero means that only the particular + int exact; /* Non-zero means that only the particular * version given is acceptable. Zero means * use the latest compatible version. */ { return Tcl_PkgPresentEx(interp, name, version, exact, (ClientData *) NULL); } CONST char * Tcl_PkgPresentEx(interp, name, version, exact, clientDataPtr) - Tcl_Interp *interp; /* Interpreter in which package is now + Tcl_Interp *interp; /* Interpreter in which package is now * available. */ - CONST char *name; /* Name of desired package. */ - CONST char *version; /* Version string for desired version; + CONST char *name; /* Name of desired package. */ + CONST char *version; /* Version string for desired version; * NULL means use the latest version * available. */ - int exact; /* Non-zero means that only the particular + int exact; /* Non-zero means that only the particular * version given is acceptable. Zero means * use the latest compatible version. */ - ClientData *clientDataPtr; /* Used to return the client data for this + ClientData *clientDataPtr; /* Used to return the client data for this * package. If it is NULL then the client * data is not returned. This is unchanged * if this call fails for any reason. */ { Interp *iPtr = (Interp *) interp; @@ -449,10 +895,15 @@ hPtr = Tcl_FindHashEntry(&iPtr->packageTable, name); if (hPtr) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { +#ifdef TCL_TIP268 + char* pvi; + char* vi; + int thisIsMajor; +#endif /* * At this point we know that the package is present. Make sure * that the provided version meets the current requirement. */ @@ -462,11 +913,24 @@ *clientDataPtr = pkgPtr->clientData; } return pkgPtr->version; } +#ifndef TCL_TIP268 result = ComparePkgVersions(pkgPtr->version, version, &satisfies); +#else + if (CheckVersionAndConvert (interp, pkgPtr->version, &pvi, NULL) != TCL_OK) { + return NULL; + } else if (CheckVersionAndConvert (interp, version, &vi, NULL) != TCL_OK) { + Tcl_Free (pvi); + return NULL; + } + result = CompareVersions(pvi, vi, &thisIsMajor); + Tcl_Free (pvi); + Tcl_Free (vi); + satisfies = (result == 0) || ((result == 1) && !thisIsMajor); +#endif if ((satisfies && !exact) || (result == 0)) { if (clientDataPtr) { *clientDataPtr = pkgPtr->clientData; } @@ -504,25 +968,32 @@ * See the user documentation. * *---------------------------------------------------------------------- */ - /* ARGSUSED */ +/* ARGSUSED */ int Tcl_PackageObjCmd(dummy, interp, objc, objv) - ClientData dummy; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int objc; /* Number of arguments. */ - Tcl_Obj *CONST objv[]; /* Argument objects. */ + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { static CONST char *pkgOptions[] = { - "forget", "ifneeded", "names", "present", "provide", "require", - "unknown", "vcompare", "versions", "vsatisfies", (char *) NULL + "forget", "ifneeded", "names", +#ifdef TCL_TIP268 + "prefer", +#endif + "present", "provide", "require", "unknown", "vcompare", + "versions", "vsatisfies", (char *) NULL }; enum pkgOptions { - PKG_FORGET, PKG_IFNEEDED, PKG_NAMES, PKG_PRESENT, - PKG_PROVIDE, PKG_REQUIRE, PKG_UNKNOWN, PKG_VCOMPARE, + PKG_FORGET, PKG_IFNEEDED, PKG_NAMES, +#ifdef TCL_TIP268 + PKG_PREFER, +#endif + PKG_PRESENT, PKG_PROVIDE, PKG_REQUIRE, PKG_UNKNOWN, PKG_VCOMPARE, PKG_VERSIONS, PKG_VSATISFIES }; Interp *iPtr = (Interp *) interp; int optionIndex, exact, i, satisfies; PkgAvail *availPtr, *prevPtr; @@ -530,21 +1001,26 @@ Tcl_HashEntry *hPtr; Tcl_HashSearch search; Tcl_HashTable *tablePtr; CONST char *version; char *argv2, *argv3, *argv4; +#ifdef TCL_TIP268 + char* iva = NULL; + char* ivb = NULL; +#endif if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], pkgOptions, "option", 0, - &optionIndex) != TCL_OK) { + &optionIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum pkgOptions) optionIndex) { +#ifndef TCL_TIP268 case PKG_FORGET: { char *keyString; for (i = 2; i < objc; i++) { keyString = Tcl_GetString(objv[i]); hPtr = Tcl_FindHashEntry(&iPtr->packageTable, keyString); @@ -557,34 +1033,109 @@ ckfree(pkgPtr->version); } while (pkgPtr->availPtr != NULL) { availPtr = pkgPtr->availPtr; pkgPtr->availPtr = availPtr->nextPtr; - ckfree(availPtr->version); + Tcl_EventuallyFree((ClientData)availPtr->version, TCL_DYNAMIC); Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC); ckfree((char *) availPtr); } ckfree((char *) pkgPtr); } break; +#else + case PKG_FORGET: { + char *keyString; + for (i = 2; i < objc; i++) { + keyString = Tcl_GetString(objv[i]); + hPtr = Tcl_FindHashEntry(&iPtr->packageTable, keyString); + if (hPtr == NULL) { + continue; + } + pkgPtr = (Package *) Tcl_GetHashValue(hPtr); + Tcl_DeleteHashEntry(hPtr); + if (pkgPtr->version != NULL) { + ckfree(pkgPtr->version); + } + while (pkgPtr->availPtr != NULL) { + availPtr = pkgPtr->availPtr; + pkgPtr->availPtr = availPtr->nextPtr; + Tcl_EventuallyFree((ClientData)availPtr->version, TCL_DYNAMIC); + Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC); + ckfree((char *) availPtr); + } + ckfree((char *) pkgPtr); + } + break; + } + case PKG_IFNEEDED: { + int length; + char* argv3i; + char* avi; + int res; + + if ((objc != 4) && (objc != 5)) { + Tcl_WrongNumArgs(interp, 2, objv, "package version ?script?"); + return TCL_ERROR; + } + argv3 = Tcl_GetString(objv[3]); + if (CheckVersionAndConvert(interp, argv3, &argv3i, NULL) != TCL_OK) { + return TCL_ERROR; +#endif } +#ifndef TCL_TIP268 case PKG_IFNEEDED: { int length; if ((objc != 4) && (objc != 5)) { Tcl_WrongNumArgs(interp, 2, objv, "package version ?script?"); return TCL_ERROR; +#else + argv2 = Tcl_GetString(objv[2]); + if (objc == 4) { + hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2); + if (hPtr == NULL) { + Tcl_Free (argv3i); + return TCL_OK; +#endif } +#ifndef TCL_TIP268 argv3 = Tcl_GetString(objv[3]); if (CheckVersion(interp, argv3) != TCL_OK) { +#else + pkgPtr = (Package *) Tcl_GetHashValue(hPtr); + } else { + pkgPtr = FindPackage(interp, argv2); + } + argv3 = Tcl_GetStringFromObj(objv[3], &length); + + for (availPtr = pkgPtr->availPtr, prevPtr = NULL; + availPtr != NULL; + prevPtr = availPtr, availPtr = availPtr->nextPtr) { + + if (CheckVersionAndConvert (interp, availPtr->version, &avi, NULL) != TCL_OK) { + Tcl_Free (argv3i); +#endif return TCL_ERROR; } +#ifndef TCL_TIP268 argv2 = Tcl_GetString(objv[2]); if (objc == 4) { hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2); if (hPtr == NULL) { +#else + + res = CompareVersions(avi, argv3i, NULL); + Tcl_Free (avi); + + if (res == 0){ + if (objc == 4) { + Tcl_Free (argv3i); + Tcl_SetResult(interp, availPtr->script, TCL_VOLATILE); +#endif return TCL_OK; } +#ifndef TCL_TIP268 pkgPtr = (Package *) Tcl_GetHashValue(hPtr); } else { pkgPtr = FindPackage(interp, argv2); } argv3 = Tcl_GetStringFromObj(objv[3], &length); @@ -600,11 +1151,16 @@ break; } } if (objc == 4) { return TCL_OK; +#else + Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC); + break; +#endif } +#ifndef TCL_TIP268 if (availPtr == NULL) { availPtr = (PkgAvail *) ckalloc(sizeof(PkgAvail)); availPtr->version = ckalloc((unsigned) (length + 1)); strcpy(availPtr->version, argv3); if (prevPtr == NULL) { @@ -612,44 +1168,173 @@ pkgPtr->availPtr = availPtr; } else { availPtr->nextPtr = prevPtr->nextPtr; prevPtr->nextPtr = availPtr; } +#else + } + Tcl_Free (argv3i); + if (objc == 4) { + return TCL_OK; + } + if (availPtr == NULL) { + availPtr = (PkgAvail *) ckalloc(sizeof(PkgAvail)); + availPtr->version = ckalloc((unsigned) (length + 1)); + strcpy(availPtr->version, argv3); + if (prevPtr == NULL) { + availPtr->nextPtr = pkgPtr->availPtr; + pkgPtr->availPtr = availPtr; + } else { + availPtr->nextPtr = prevPtr->nextPtr; + prevPtr->nextPtr = availPtr; +#endif } +#ifndef TCL_TIP268 argv4 = Tcl_GetStringFromObj(objv[4], &length); availPtr->script = ckalloc((unsigned) (length + 1)); strcpy(availPtr->script, argv4); break; +#endif } +#ifndef TCL_TIP268 case PKG_NAMES: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); +#else + argv4 = Tcl_GetStringFromObj(objv[4], &length); + availPtr->script = ckalloc((unsigned) (length + 1)); + strcpy(availPtr->script, argv4); + break; + } + case PKG_NAMES: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + tablePtr = &iPtr->packageTable; + for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; + hPtr = Tcl_NextHashEntry(&search)) { + pkgPtr = (Package *) Tcl_GetHashValue(hPtr); + if ((pkgPtr->version != NULL) || (pkgPtr->availPtr != NULL)) { + Tcl_AppendElement(interp, Tcl_GetHashKey(tablePtr, hPtr)); + } + } + break; + } + case PKG_PRESENT: { + if (objc < 3) { + presentSyntax: + Tcl_WrongNumArgs(interp, 2, objv, "?-exact? package ?version?"); + return TCL_ERROR; + } + argv2 = Tcl_GetString(objv[2]); + if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) { + exact = 1; + } else { + exact = 0; + } + version = NULL; + if (objc == (4 + exact)) { + version = Tcl_GetString(objv[3 + exact]); + if (CheckVersionAndConvert(interp, version, NULL, NULL) != TCL_OK) { +#endif return TCL_ERROR; } +#ifndef TCL_TIP268 tablePtr = &iPtr->packageTable; for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { +#else + } else if ((objc != 3) || exact) { + goto presentSyntax; + } + if (exact) { + argv3 = Tcl_GetString(objv[3]); + version = Tcl_PkgPresent(interp, argv3, version, exact); + } else { + version = Tcl_PkgPresent(interp, argv2, version, exact); + } + if (version == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult( interp, Tcl_NewStringObj( version, -1 ) ); + break; + } + case PKG_PROVIDE: { + if ((objc != 3) && (objc != 4)) { + Tcl_WrongNumArgs(interp, 2, objv, "package ?version?"); + return TCL_ERROR; + } + argv2 = Tcl_GetString(objv[2]); + if (objc == 3) { + hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2); + if (hPtr != NULL) { +#endif pkgPtr = (Package *) Tcl_GetHashValue(hPtr); +#ifndef TCL_TIP268 if ((pkgPtr->version != NULL) || (pkgPtr->availPtr != NULL)) { Tcl_AppendElement(interp, Tcl_GetHashKey(tablePtr, hPtr)); +#else + if (pkgPtr->version != NULL) { + Tcl_SetResult(interp, pkgPtr->version, TCL_VOLATILE); +#endif } } +#ifndef TCL_TIP268 break; +#else + return TCL_OK; +#endif } +#ifndef TCL_TIP268 case PKG_PRESENT: { if (objc < 3) { presentSyntax: Tcl_WrongNumArgs(interp, 2, objv, "?-exact? package ?version?"); return TCL_ERROR; +#else + argv3 = Tcl_GetString(objv[3]); + if (CheckVersionAndConvert(interp, argv3, NULL, NULL) != TCL_OK) { + return TCL_ERROR; + } + return Tcl_PkgProvide(interp, argv2, argv3); + } + case PKG_REQUIRE: { + if (objc < 3) { + requireSyntax: + Tcl_WrongNumArgs(interp, 2, objv, "?-exact? package ?requirement...?"); + return TCL_ERROR; + } + version = NULL; + argv2 = Tcl_GetString(objv[2]); + if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) { + Tcl_Obj* ov; + int res; + + if (objc != 5) { + goto requireSyntax; +#endif } +#ifndef TCL_TIP268 argv2 = Tcl_GetString(objv[2]); if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) { exact = 1; } else { exact = 0; +#else + version = Tcl_GetString(objv[4]); + if (CheckVersionAndConvert(interp, version, NULL, NULL) != TCL_OK) { + return TCL_ERROR; +#endif } +#ifdef TCL_TIP268 + /* Create a new-style requirement for the exact version. */ + + ov = ExactRequirement (version); +#endif version = NULL; +#ifndef TCL_TIP268 if (objc == (4 + exact)) { version = Tcl_GetString(objv[3 + exact]); if (CheckVersion(interp, version) != TCL_OK) { return TCL_ERROR; } @@ -661,20 +1346,78 @@ version = Tcl_PkgPresent(interp, argv3, version, exact); } else { version = Tcl_PkgPresent(interp, argv2, version, exact); } if (version == NULL) { +#else + argv3 = Tcl_GetString(objv[3]); + + Tcl_IncrRefCount (ov); + res = Tcl_PkgRequireProc(interp, argv3, 1, &ov, NULL); + Tcl_DecrRefCount (ov); + return res; + } else { + if (CheckAllRequirements (interp, objc-3, objv+3) != TCL_OK) { +#endif return TCL_ERROR; } +#ifndef TCL_TIP268 Tcl_SetObjResult( interp, Tcl_NewStringObj( version, -1 ) ); break; +#else + return Tcl_PkgRequireProc(interp, argv2, objc-3, objv+3, NULL); +#endif } +#ifndef TCL_TIP268 case PKG_PROVIDE: { if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 2, objv, "package ?version?"); +#else + break; + } + case PKG_UNKNOWN: { + int length; + if (objc == 2) { + if (iPtr->packageUnknown != NULL) { + Tcl_SetResult(interp, iPtr->packageUnknown, TCL_VOLATILE); + } + } else if (objc == 3) { + if (iPtr->packageUnknown != NULL) { + ckfree(iPtr->packageUnknown); + } + argv2 = Tcl_GetStringFromObj(objv[2], &length); + if (argv2[0] == 0) { + iPtr->packageUnknown = NULL; + } else { + iPtr->packageUnknown = (char *) ckalloc((unsigned) + (length + 1)); + strcpy(iPtr->packageUnknown, argv2); + } + } else { + Tcl_WrongNumArgs(interp, 2, objv, "?command?"); + return TCL_ERROR; + } + break; + } + case PKG_PREFER: { + /* See tclInt.h for the enum, just before Interp */ + static CONST char *pkgPreferOptions[] = { + "latest", "stable", NULL + }; + + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?latest|stable?"); + return TCL_ERROR; + } else if (objc == 3) { + /* Set value. */ + int new; + if (Tcl_GetIndexFromObj(interp, objv[2], pkgPreferOptions, "preference", 0, + &new) != TCL_OK) { +#endif return TCL_ERROR; } +#ifndef TCL_TIP268 argv2 = Tcl_GetString(objv[2]); if (objc == 3) { hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2); if (hPtr != NULL) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); @@ -681,17 +1424,24 @@ if (pkgPtr->version != NULL) { Tcl_SetResult(interp, pkgPtr->version, TCL_VOLATILE); } } return TCL_OK; +#else + if (new < iPtr->packagePrefer) { + iPtr->packagePrefer = new; +#endif } +#ifndef TCL_TIP268 argv3 = Tcl_GetString(objv[3]); if (CheckVersion(interp, argv3) != TCL_OK) { return TCL_ERROR; } return Tcl_PkgProvide(interp, argv2, argv3); +#endif } +#ifndef TCL_TIP268 case PKG_REQUIRE: { if (objc < 3) { requireSyntax: Tcl_WrongNumArgs(interp, 2, objv, "?-exact? package ?version?"); return TCL_ERROR; @@ -720,11 +1470,22 @@ if (version == NULL) { return TCL_ERROR; } Tcl_SetObjResult( interp, Tcl_NewStringObj( version, -1 ) ); break; +#else + /* Always return current value. */ + Tcl_SetObjResult(interp, Tcl_NewStringObj (pkgPreferOptions [iPtr->packagePrefer], -1)); + break; + } + case PKG_VCOMPARE: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "version1 version2"); + return TCL_ERROR; +#endif } +#ifndef TCL_TIP268 case PKG_UNKNOWN: { int length; if (objc == 2) { if (iPtr->packageUnknown != NULL) { Tcl_SetResult(interp, iPtr->packageUnknown, TCL_VOLATILE); @@ -744,11 +1505,21 @@ } else { Tcl_WrongNumArgs(interp, 2, objv, "?command?"); return TCL_ERROR; } break; +#else + argv3 = Tcl_GetString(objv[3]); + argv2 = Tcl_GetString(objv[2]); + if ((CheckVersionAndConvert (interp, argv2, &iva, NULL) != TCL_OK) || + (CheckVersionAndConvert (interp, argv3, &ivb, NULL) != TCL_OK)) { + if (iva != NULL) { Tcl_Free (iva); } + /* ivb cannot be set in this branch */ + return TCL_ERROR; +#endif } +#ifndef TCL_TIP268 case PKG_VCOMPARE: { if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "version1 version2"); return TCL_ERROR; } @@ -759,16 +1530,40 @@ return TCL_ERROR; } Tcl_SetIntObj(Tcl_GetObjResult(interp), ComparePkgVersions(argv2, argv3, (int *) NULL)); break; +#else + + /* Comparison is done on the internal representation */ + Tcl_SetObjResult(interp,Tcl_NewIntObj(CompareVersions(iva, ivb, NULL))); + Tcl_Free (iva); + Tcl_Free (ivb); + break; + } + case PKG_VERSIONS: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "package"); + return TCL_ERROR; +#endif } +#ifndef TCL_TIP268 case PKG_VERSIONS: { if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "package"); return TCL_ERROR; +#else + argv2 = Tcl_GetString(objv[2]); + hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2); + if (hPtr != NULL) { + pkgPtr = (Package *) Tcl_GetHashValue(hPtr); + for (availPtr = pkgPtr->availPtr; availPtr != NULL; + availPtr = availPtr->nextPtr) { + Tcl_AppendElement(interp, availPtr->version); +#endif } +#ifndef TCL_TIP268 argv2 = Tcl_GetString(objv[2]); hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2); if (hPtr != NULL) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); for (availPtr = pkgPtr->availPtr; availPtr != NULL; @@ -775,11 +1570,13 @@ availPtr = availPtr->nextPtr) { Tcl_AppendElement(interp, availPtr->version); } } break; +#endif } +#ifndef TCL_TIP268 case PKG_VSATISFIES: { if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "version1 version2"); return TCL_ERROR; } @@ -790,14 +1587,46 @@ return TCL_ERROR; } ComparePkgVersions(argv2, argv3, &satisfies); Tcl_SetIntObj(Tcl_GetObjResult(interp), satisfies); break; +#else + break; + } + case PKG_VSATISFIES: { + char* argv2i = NULL; + + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, "version requirement requirement..."); + return TCL_ERROR; +#endif } +#ifndef TCL_TIP268 default: { panic("Tcl_PackageObjCmd: bad option index to pkgOptions"); +#else + + argv2 = Tcl_GetString(objv[2]); + if ((CheckVersionAndConvert(interp, argv2, &argv2i, NULL) != TCL_OK)) { + return TCL_ERROR; + } else if (CheckAllRequirements (interp, objc-3, objv+3) != TCL_OK) { + Tcl_Free (argv2i); + return TCL_ERROR; +#endif } +#ifdef TCL_TIP268 + + satisfies = AllRequirementsSatisfied (argv2i, objc-3, objv+3); + Tcl_Free (argv2i); + + Tcl_SetIntObj(Tcl_GetObjResult(interp), satisfies); + break; + } + default: { + panic("Tcl_PackageObjCmd: bad option index to pkgOptions"); + } +#endif } return TCL_OK; } /* @@ -819,12 +1648,12 @@ *---------------------------------------------------------------------- */ static Package * FindPackage(interp, name) - Tcl_Interp *interp; /* Interpreter to use for package lookup. */ - CONST char *name; /* Name of package to fine. */ + Tcl_Interp *interp; /* Interpreter to use for package lookup. */ + CONST char *name; /* Name of package to fine. */ { Interp *iPtr = (Interp *) interp; Tcl_HashEntry *hPtr; int new; Package *pkgPtr; @@ -860,27 +1689,27 @@ *---------------------------------------------------------------------- */ void TclFreePackageInfo(iPtr) - Interp *iPtr; /* Interpereter that is being deleted. */ + Interp *iPtr; /* Interpreter that is being deleted. */ { Package *pkgPtr; Tcl_HashSearch search; Tcl_HashEntry *hPtr; PkgAvail *availPtr; for (hPtr = Tcl_FirstHashEntry(&iPtr->packageTable, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { ckfree(pkgPtr->version); } while (pkgPtr->availPtr != NULL) { availPtr = pkgPtr->availPtr; pkgPtr->availPtr = availPtr->nextPtr; - ckfree(availPtr->version); + Tcl_EventuallyFree((ClientData)availPtr->version, TCL_DYNAMIC); Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC); ckfree((char *) availPtr); } ckfree((char *) pkgPtr); } @@ -891,11 +1720,11 @@ } /* *---------------------------------------------------------------------- * - * CheckVersion -- + * CheckVersion / CheckVersionAndConvert -- * * This procedure checks to see whether a version number has * valid syntax. * * Results: @@ -908,45 +1737,118 @@ * *---------------------------------------------------------------------- */ static int +#ifndef TCL_TIP268 CheckVersion(interp, string) Tcl_Interp *interp; /* Used for error reporting. */ CONST char *string; /* Supposedly a version number, which is * groups of decimal digits separated * by dots. */ +#else +CheckVersionAndConvert(interp, string, internal, stable) + Tcl_Interp *interp; /* Used for error reporting. */ + CONST char *string; /* Supposedly a version number, which is + * groups of decimal digits separated by + * dots. */ + char** internal; /* Internal normalized representation */ + int* stable; /* Flag: Version is (un)stable. */ +#endif { CONST char *p = string; char prevChar; - +#ifdef TCL_TIP268 + int hasunstable = 0; + /* 4* assuming that each char is a separator (a,b become ' -x '). + * 4+ to have spce for an additional -2 at the end + */ + char* ibuf = ckalloc (4+4*strlen(string)); + char* ip = ibuf; + + /* Basic rules + * (1) First character has to be a digit. + * (2) All other characters have to be a digit or '.' + * (3) Two '.'s may not follow each other. + + * TIP 268, Modified rules + * (1) s.a. + * (2) All other characters have to be a digit, 'a', 'b', or '.' + * (3) s.a. + * (4) Only one of 'a' or 'b' may occur. + * (5) Neither 'a', nor 'b' may occur before or after a '.' + */ + +#endif if (!isdigit(UCHAR(*p))) { /* INTL: digit */ goto error; } +#ifdef TCL_TIP268 + *ip++ = *p; +#endif for (prevChar = *p, p++; *p != 0; p++) { +#ifndef TCL_TIP268 if (!isdigit(UCHAR(*p)) && ((*p != '.') || (prevChar == '.'))) { /* INTL: digit */ +#else + if ( + (!isdigit(UCHAR(*p))) && + (((*p != '.') && (*p != 'a') && (*p != 'b')) || + ((hasunstable && ((*p == 'a') || (*p == 'b'))) || + (((prevChar == 'a') || (prevChar == 'b') || (prevChar == '.')) && (*p == '.')) || + (((*p == 'a') || (*p == 'b') || (*p == '.')) && (prevChar == '.')))) + ) { + /* INTL: digit */ +#endif goto error; } +#ifdef TCL_TIP268 + if ((*p == 'a') || (*p == 'b')) { hasunstable = 1 ; } + + /* Translation to the internal rep. Regular version chars are copied + * as is. The separators are translated to numerics. The new separator + * for all parts is space. */ + + if (*p == '.') { *ip++ = ' '; *ip++ = '0'; *ip++ = ' '; } + else if (*p == 'a') { *ip++ = ' '; *ip++ = '-'; *ip++ = '2'; *ip++ = ' '; } + else if (*p == 'b') { *ip++ = ' '; *ip++ = '-'; *ip++ = '1'; *ip++ = ' '; } + else { *ip++ = *p; } +#endif prevChar = *p; } +#ifndef TCL_TIP268 if (prevChar != '.') { +#else + if ((prevChar != '.') && (prevChar != 'a') && (prevChar != 'b')) { + *ip = '\0'; + if (internal != NULL) { + *internal = ibuf; + } else { + Tcl_Free (ibuf); + } + if (stable != NULL) { + *stable = !hasunstable; + } +#endif return TCL_OK; } - error: + error: +#ifdef TCL_TIP268 + ckfree (ibuf); +#endif Tcl_AppendResult(interp, "expected version number but got \"", string, "\"", (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * - * ComparePkgVersions -- + * ComparePkgVersions / CompareVersions -- * - * This procedure compares two version numbers. + * This procedure compares two version numbers. (268: in internal rep). * * Results: * The return value is -1 if v1 is less than v2, 0 if the two * version numbers are the same, and 1 if v1 is greater than v2. * If *satPtr is non-NULL, the word it points to is filled in @@ -958,48 +1860,85 @@ * *---------------------------------------------------------------------- */ static int +#ifndef TCL_TIP268 ComparePkgVersions(v1, v2, satPtr) CONST char *v1; CONST char *v2; /* Versions strings, of form 2.1.3 (any * number of version numbers). */ int *satPtr; /* If non-null, the word pointed to is * filled in with a 0/1 value. 1 means * v1 "satisfies" v2: v1 is greater than * or equal to v2 and both version numbers * have the same major number. */ +#else +CompareVersions(v1, v2, isMajorPtr) + CONST char *v1; /* Versions strings, of form 2.1.3 (any number */ + CONST char *v2; /* of version numbers). */ + int *isMajorPtr; /* If non-null, the word pointed to is filled + * in with a 0/1 value. 1 means that the difference + * occured in the first element. */ +#endif { int thisIsMajor, n1, n2; +#ifdef TCL_TIP268 + int res, flip; +#endif /* - * Each iteration of the following loop processes one number from - * each string, terminated by a ".". If those numbers don't match - * then the comparison is over; otherwise, we loop back for the - * next number. + * Each iteration of the following loop processes one number from each + * string, terminated by a " " (space). If those numbers don't match then the + * comparison is over; otherwise, we loop back for the next number. + * + * TIP 268. + * This is identical the function 'ComparePkgVersion', but using the new + * space separator as used by the internal rep of version numbers. The + * special separators 'a' and 'b' have already been dealt with in + * 'CheckVersionAndConvert', they were translated into numbers as + * well. This keeps the comparison sane. Otherwise we would have to + * compare numerics, the separators, and also deal with the special case + * of end-of-string compared to separators. The semi-list rep we get here + * is much easier to handle, as it is still regular. */ thisIsMajor = 1; while (1) { /* * Parse one decimal number from the front of each string. */ n1 = n2 = 0; +#ifndef TCL_TIP268 while ((*v1 != 0) && (*v1 != '.')) { +#else + flip = 0; + while ((*v1 != 0) && (*v1 != ' ')) { + if (*v1 == '-') {flip = 1 ; v1++ ; continue;} +#endif n1 = 10*n1 + (*v1 - '0'); v1++; } +#ifndef TCL_TIP268 while ((*v2 != 0) && (*v2 != '.')) { +#else + if (flip) n1 = -n1; + flip = 0; + while ((*v2 != 0) && (*v2 != ' ')) { + if (*v2 == '-') {flip = 1; v2++ ; continue;} +#endif n2 = 10*n2 + (*v2 - '0'); v2++; } +#ifdef TCL_TIP268 + if (flip) n2 = -n2; +#endif /* - * Compare and go on to the next version number if the - * current numbers match. + * Compare and go on to the next version number if the current numbers + * match. */ if (n1 != n2) { break; } @@ -1011,16 +1950,455 @@ if (*v2 != 0) { v2++; } thisIsMajor = 0; } +#ifndef TCL_TIP268 if (satPtr != NULL) { *satPtr = (n1 == n2) || ((n1 > n2) && !thisIsMajor); } +#endif if (n1 > n2) { +#ifndef TCL_TIP268 return 1; +#else + res = 1; +#endif } else if (n1 == n2) { +#ifndef TCL_TIP268 return 0; +#else + res = 0; +#endif } else { +#ifndef TCL_TIP268 return -1; +#else + res = -1; + } + + if (isMajorPtr != NULL) { + *isMajorPtr = thisIsMajor; + } + + return res; +} + +/* + *---------------------------------------------------------------------- + * + * CheckAllRequirements -- + * + * This function checks to see whether all requirements in a set + * have valid syntax. + * + * Results: + * TCL_OK is returned if all requirements are valid. + * Otherwise TCL_ERROR is returned and an error message + * is left in the interp's result. + * + * Side effects: + * May modify the interpreter result. + * + *---------------------------------------------------------------------- + */ + +static int +CheckAllRequirements(interp, reqc, reqv) + Tcl_Interp* interp; + int reqc; /* Requirements to check. */ + Tcl_Obj *CONST reqv[]; +{ + int i; + for (i = 0; i < reqc; i++) { + if ((CheckRequirement(interp, Tcl_GetString(reqv[i])) != TCL_OK)) { + return TCL_ERROR; + } + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * CheckRequirement -- + * + * This function checks to see whether a requirement has valid syntax. + * + * Results: + * If string is a properly formed requirement then TCL_OK is returned. + * Otherwise TCL_ERROR is returned and an error message is left in the + * interp's result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +CheckRequirement(interp, string) + Tcl_Interp *interp; /* Used for error reporting. */ + CONST char *string; /* Supposedly a requirement. */ +{ + /* Syntax of requirement = version + * = version-version + * = version- + */ + + char* dash = NULL; + char* buf; + + dash = strchr (string, '-'); + if (dash == NULL) { + /* no dash found, has to be a simple version */ + return CheckVersionAndConvert (interp, string, NULL, NULL); + } + if (strchr (dash+1, '-') != NULL) { + /* More dashes found after the first. This is wrong. */ + Tcl_AppendResult(interp, "expected versionMin-versionMax but got \"", string, + "\"", NULL); + return TCL_ERROR; +#endif + } +#ifdef TCL_TIP268 + + /* Exactly one dash is present. Copy the string, split at the location of + * dash and check that both parts are versions. Note that the max part can + * be empty. + */ + + buf = strdup (string); + dash = buf + (dash - string); + *dash = '\0'; /* buf now <=> min part */ + dash ++; /* dash now <=> max part */ + + if ((CheckVersionAndConvert(interp, buf, NULL, NULL) != TCL_OK) || + ((*dash != '\0') && + (CheckVersionAndConvert(interp, dash, NULL, NULL) != TCL_OK))) { + free (buf); + return TCL_ERROR; + } + + free (buf); + return TCL_OK; +#endif +} +#ifdef TCL_TIP268 + +/* + *---------------------------------------------------------------------- + * + * AddRequirementsToResult -- + * + * This function accumulates requirements in the interpreter result. + * + * Results: + * None. + * + * Side effects: + * The interpreter result is extended. + * + *---------------------------------------------------------------------- + */ + +static void +AddRequirementsToResult(interp, reqc, reqv) + Tcl_Interp* interp; + int reqc; /* Requirements constraining the desired version. */ + Tcl_Obj *CONST reqv[]; /* 0 means to use the latest version available. */ +{ + if (reqc > 0) { + int i; + for (i = 0; i < reqc; i++) { + Tcl_AppendResult(interp, " ", TclGetString(reqv[i]), NULL); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * AddRequirementsToDString -- + * + * This function accumulates requirements in a DString. + * + * Results: + * None. + * + * Side effects: + * The DString argument is extended. + * + *---------------------------------------------------------------------- + */ + +static void +AddRequirementsToDString(dstring, reqc, reqv) + Tcl_DString* dstring; + int reqc; /* Requirements constraining the desired version. */ + Tcl_Obj *CONST reqv[]; /* 0 means to use the latest version available. */ +{ + if (reqc > 0) { + int i; + for (i = 0; i < reqc; i++) { + Tcl_DStringAppend(dstring, " ", 1); + Tcl_DStringAppend(dstring, TclGetString(reqv[i]), -1); + } + } else { + Tcl_DStringAppend(dstring, " 0-", -1); + } +} + +/* + *---------------------------------------------------------------------- + * + * AllRequirementSatisfied -- + * + * This function checks to see whether a version satisfies at + * least one of a set of requirements. + * + * Results: + * If the requirements are satisfied 1 is returned. + * Otherwise 0 is returned. The function assumes + * that all pieces have valid syntax. And is allowed + * to make that assumption. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +AllRequirementsSatisfied(availVersionI, reqc, reqv) + CONST char* availVersionI; /* Candidate version to check against the requirements */ + int reqc; /* Requirements constraining the desired version. */ + Tcl_Obj *CONST reqv[]; /* 0 means to use the latest version available. */ +{ + int i, satisfies; + + for (satisfies = i = 0; i < reqc; i++) { + satisfies = RequirementSatisfied(availVersionI, Tcl_GetString(reqv[i])); + if (satisfies) break; + } + return satisfies; +} + +/* + *---------------------------------------------------------------------- + * + * RequirementSatisfied -- + * + * This function checks to see whether a version satisfies a requirement. + * + * Results: + * If the requirement is satisfied 1 is returned. + * Otherwise 0 is returned. The function assumes + * that all pieces have valid syntax. And is allowed + * to make that assumption. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +RequirementSatisfied(havei, req) + CONST char *havei; /* Version string, of candidate package we have */ + CONST char *req; /* Requirement string the candidate has to satisfy */ +{ + /* The have candidate is already in internal rep. */ + + int satisfied, res; + char* dash = NULL; + char* buf, *min, *max; + + dash = strchr (req, '-'); + if (dash == NULL) { + /* No dash found, is a simple version, fallback to regular check. + * The 'CheckVersionAndConvert' cannot fail. We pad the requirement with + * 'a0', i.e '-2' before doing the comparison to properly accept + * unstables as well. + */ + + char* reqi = NULL; + int thisIsMajor; + + CheckVersionAndConvert (NULL, req, &reqi, NULL); + strcat (reqi, " -2"); + res = CompareVersions(havei, reqi, &thisIsMajor); + satisfied = (res == 0) || ((res == 1) && !thisIsMajor); + Tcl_Free (reqi); + return satisfied; + } + + /* Exactly one dash is present (Assumption of valid syntax). Copy the req, + * split at the location of dash and check that both parts are + * versions. Note that the max part can be empty. + */ + + buf = strdup (req); + dash = buf + (dash - req); + *dash = '\0'; /* buf now <=> min part */ + dash ++; /* dash now <=> max part */ + + if (*dash == '\0') { + /* We have a min, but no max. For the comparison we generate the + * internal rep, padded with 'a0' i.e. '-2'. + */ + + /* No max part, unbound */ + + CheckVersionAndConvert (NULL, buf, &min, NULL); + strcat (min, " -2"); + satisfied = (CompareVersions(havei, min, NULL) >= 0); + Tcl_Free (min); + free (buf); + return satisfied; + } + + /* We have both min and max, and generate their internal reps. + * When identical we compare as is, otherwise we pad with 'a0' + * to ove the range a bit. + */ + + CheckVersionAndConvert (NULL, buf, &min, NULL); + CheckVersionAndConvert (NULL, dash, &max, NULL); + + if (CompareVersions(min, max, NULL) == 0) { + satisfied = (CompareVersions(min, havei, NULL) == 0); + } else { + strcat (min, " -2"); + strcat (max, " -2"); + satisfied = ((CompareVersions(min, havei, NULL) <= 0) && + (CompareVersions(havei, max, NULL) < 0)); + } + + Tcl_Free (min); + Tcl_Free (max); + free (buf); + return satisfied; +} + +/* + *---------------------------------------------------------------------- + * + * ExactRequirement -- + * + * This function is the core for the translation of -exact requests. + * It translates the request of the version into a range of versions. + * The translation was chosen for backwards compatibility. + * + * Results: + * A Tcl_Obj containing the version range as string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tcl_Obj* +ExactRequirement(version) + CONST char* version; +{ + /* A -exact request for a version X.y is translated into the range + * X.y-X.(y+1). For example -exact 8.4 means the range "8.4-8.5". + * + * This translation was chosen to prevent packages which currently use a + * 'package require -exact tclversion' from being affected by the core now + * registering itself as 8.4.x (patchlevel) instead of 8.4 + * (version). Examples are tbcload, compiler, and ITcl. + * + * Translating -exact 8.4 to the range "8.4-8.4" instead would require us + * and everyone else to rebuild these packages to require -exact 8.4.14, + * or whatever the exact current patchlevel is. A backward compatibility + * issue with effects similar to the bugfix made in 8.5 now requiring + * ifneeded and provided versions to match. Instead we have chosen to + * interpret exactness to not be exactly equal, but to be exact only + * within the specified level, and allowing variation in the deeper + * level. More examples: + * + * -exact 8 => "8-9" + * -exact 8.4 => "8.4-8.5" + * -exact 8.4.14 => "8.4.14-8.4.15" + * -exact 8.0a2 => "8.0a2-8.0a3" + */ + + char* iv; + int lc, i; + CONST char** lv; + char buf [30]; + Tcl_Obj* o = Tcl_NewStringObj (version,-1); + Tcl_AppendStringsToObj (o, "-", NULL); + + /* Assuming valid syntax here */ + CheckVersionAndConvert (NULL, version, &iv, NULL); + + /* Split the list into components */ + Tcl_SplitList (NULL, iv, &lc, &lv); + + /* Iterate over the components and make them parts of the result. Except + * for the last, which is handled separately, to allow the + * incrementation. + */ + + for (i=0; i < (lc-1); i++) { + /* Regular component */ + Tcl_AppendStringsToObj (o, lv[i], NULL); + /* Separator component */ + i ++; + if (0 == strcmp ("-1", lv[i])) { + Tcl_AppendStringsToObj (o, "b", NULL); + } else if (0 == strcmp ("-2", lv[i])) { + Tcl_AppendStringsToObj (o, "a", NULL); + } else { + Tcl_AppendStringsToObj (o, ".", NULL); + } + } + /* Regular component, last */ + sprintf (buf, "%d", atoi (lv [lc-1]) + 1); + Tcl_AppendStringsToObj (o, buf, NULL); + + ckfree ((char*) lv); + return o; +} + +/* + *---------------------------------------------------------------------- + * + * VersionCleanupProc -- + * + * This function is called to delete the last remember package version + * string for an interpreter when the interpreter is deleted. It gets + * invoked via the Tcl AssocData mechanism. + * + * Results: + * None. + * + * Side effects: + * Storage for the version object for interp get deleted. + * + *---------------------------------------------------------------------- + */ + +static void +VersionCleanupProc ( + ClientData clientData, /* Pointer to remembered version string object + * for interp. */ + Tcl_Interp *interp) /* Interpreter that is being deleted. */ +{ + Tcl_Obj* ov = (Tcl_Obj*) clientData; + if (ov != NULL) { + Tcl_DecrRefCount (ov); } } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ +#endif Index: generic/tclPlatDecls.h ================================================================== --- generic/tclPlatDecls.h +++ generic/tclPlatDecls.h @@ -4,11 +4,11 @@ * Declarations of platform specific Tcl APIs. * * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. * - * RCS: @(#) $Id: tclPlatDecls.h,v 1.18 2002/09/27 00:50:10 hobbs Exp $ + * RCS: @(#) $Id: tclPlatDecls.h,v 1.18.2.5 2004/06/10 17:17:45 andreas_kupries Exp $ */ #ifndef _TCLPLATDECLS #define _TCLPLATDECLS @@ -80,10 +80,16 @@ /* 0 */ EXTERN int Tcl_MacOSXOpenBundleResources _ANSI_ARGS_(( Tcl_Interp * interp, CONST char * bundleName, int hasResourceFile, int maxPathLen, char * libraryPath)); +/* 1 */ +EXTERN int Tcl_MacOSXOpenVersionedBundleResources _ANSI_ARGS_(( + Tcl_Interp * interp, CONST char * bundleName, + CONST char * bundleVersion, + int hasResourceFile, int maxPathLen, + char * libraryPath)); #endif /* MAC_OSX_TCL */ typedef struct TclPlatStubs { int magic; struct TclPlatStubHooks *hooks; @@ -103,10 +109,11 @@ int (*strncasecmp) _ANSI_ARGS_((CONST char * s1, CONST char * s2, size_t n)); /* 7 */ int (*strcasecmp) _ANSI_ARGS_((CONST char * s1, CONST char * s2)); /* 8 */ #endif /* MAC_TCL */ #ifdef MAC_OSX_TCL int (*tcl_MacOSXOpenBundleResources) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * bundleName, int hasResourceFile, int maxPathLen, char * libraryPath)); /* 0 */ + int (*tcl_MacOSXOpenVersionedBundleResources) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * bundleName, CONST char * bundleVersion, int hasResourceFile, int maxPathLen, char * libraryPath)); /* 1 */ #endif /* MAC_OSX_TCL */ } TclPlatStubs; #ifdef __cplusplus extern "C" { @@ -173,14 +180,18 @@ #ifdef MAC_OSX_TCL #ifndef Tcl_MacOSXOpenBundleResources #define Tcl_MacOSXOpenBundleResources \ (tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */ #endif +#ifndef Tcl_MacOSXOpenVersionedBundleResources +#define Tcl_MacOSXOpenVersionedBundleResources \ + (tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */ +#endif #endif /* MAC_OSX_TCL */ #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ /* !END!: Do not edit above this line. */ #endif /* _TCLPLATDECLS */ Index: generic/tclPort.h ================================================================== --- generic/tclPort.h +++ generic/tclPort.h @@ -8,11 +8,11 @@ * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclPort.h,v 1.6 2002/02/15 14:28:49 dkf Exp $ + * RCS: @(#) $Id: tclPort.h,v 1.6.2.1 2003/04/16 23:31:46 dgp Exp $ */ #ifndef _TCLPORT #define _TCLPORT @@ -26,18 +26,22 @@ # else # include "../unix/tclUnixPort.h" # endif #endif -#if !defined(TCL_WIDE_INT_IS_LONG) && !defined(LLONG_MIN) -# ifdef LLONG_BIT -# define LLONG_MIN ((Tcl_WideInt)(Tcl_LongAsWide(1)<<(LLONG_BIT-1))) +#if !defined(LLONG_MIN) +# ifdef TCL_WIDE_INT_IS_LONG +# define LLONG_MIN LONG_MIN # else +# ifdef LLONG_BIT +# define LLONG_MIN ((Tcl_WideInt)(Tcl_LongAsWide(1)<<(LLONG_BIT-1))) +# else /* Assume we're on a system with a 64-bit 'long long' type */ -# define LLONG_MIN ((Tcl_WideInt)(Tcl_LongAsWide(1)<<63)) +# define LLONG_MIN ((Tcl_WideInt)(Tcl_LongAsWide(1)<<63)) +# endif # endif /* Assume that if LLONG_MIN is undefined, then so is LLONG_MAX */ # define LLONG_MAX (~LLONG_MIN) #endif #endif /* _TCLPORT */ Index: generic/tclPreserve.c ================================================================== --- generic/tclPreserve.c +++ generic/tclPreserve.c @@ -10,11 +10,11 @@ * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclPreserve.c,v 1.3 1999/04/16 00:46:52 stanton Exp $ + * RCS: @(#) $Id: tclPreserve.c,v 1.3.34.2 2005/06/24 18:21:41 kennykb Exp $ */ #include "tclInt.h" /* @@ -64,21 +64,15 @@ int refCount; /* Number of TclHandlePreserve() calls in * effect on this handle. */ } HandleStruct; -/* - * Static routines in this file: - */ - -static void PreserveExitProc _ANSI_ARGS_((ClientData clientData)); - /* *---------------------------------------------------------------------- * - * PreserveExitProc -- + * TclFinalizePreserve -- * * Called during exit processing to clean up the reference array. * * Results: * None. @@ -88,13 +82,12 @@ * *---------------------------------------------------------------------- */ /* ARGSUSED */ -static void -PreserveExitProc(clientData) - ClientData clientData; /* NULL -Unused. */ +void +TclFinalizePreserve() { Tcl_MutexLock(&preserveMutex); if (spaceAvl != 0) { ckfree((char *) refArray); refArray = (Reference *) NULL; @@ -149,12 +142,10 @@ * bigger if it is full. */ if (inUse == spaceAvl) { if (spaceAvl == 0) { - Tcl_CreateExitHandler((Tcl_ExitProc *) PreserveExitProc, - (ClientData) NULL); refArray = (Reference *) ckalloc((unsigned) (INITIAL_SIZE*sizeof(Reference))); spaceAvl = INITIAL_SIZE; } else { Reference *new; @@ -231,12 +222,11 @@ inUse--; if (i < inUse) { refArray[i] = refArray[inUse]; } if (mustFree) { - if ((freeProc == TCL_DYNAMIC) || - (freeProc == (Tcl_FreeProc *) free)) { + if (freeProc == TCL_DYNAMIC) { ckfree((char *) clientData); } else { Tcl_MutexUnlock(&preserveMutex); (*freeProc)((char *) clientData); return; @@ -304,12 +294,11 @@ /* * No reference for this block. Free it now. */ - if ((freeProc == TCL_DYNAMIC) - || (freeProc == (Tcl_FreeProc *) free)) { + if (freeProc == TCL_DYNAMIC) { ckfree((char *) clientData); } else { (*freeProc)((char *)clientData); } } Index: generic/tclProc.c ================================================================== --- generic/tclProc.c +++ generic/tclProc.c @@ -8,11 +8,11 @@ * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclProc.c,v 1.44 2002/12/11 21:29:52 dgp Exp $ + * RCS: @(#) $Id: tclProc.c,v 1.44.2.6 2006/11/28 22:20:02 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclCompile.h" @@ -23,10 +23,14 @@ static void ProcBodyDup _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *dupPtr)); static void ProcBodyFree _ANSI_ARGS_((Tcl_Obj *objPtr)); static int ProcBodySetFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static void ProcBodyUpdateString _ANSI_ARGS_((Tcl_Obj *objPtr)); +static int ProcCompileProc _ANSI_ARGS_((Tcl_Interp *interp, + Proc *procPtr, Tcl_Obj *bodyPtr, Namespace *nsPtr, + CONST char *description, CONST char *procName, + Proc **procPtrPtr)); static int ProcessProcResultCode _ANSI_ARGS_((Tcl_Interp *interp, char *procName, int nameLen, int returnCode)); static int TclCompileNoOp _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); @@ -146,10 +150,69 @@ * namespace if the proc was renamed into a different namespace. */ procPtr->cmdPtr = (Command *) cmd; +#ifdef TCL_TIP280 + /* TIP #280 Remember the line the procedure body is starting on. In a + * Byte code context we ask the engine to provide us with the necessary + * information. This is for the initialization of the byte code compiler + * when the body is used for the first time. + */ + + if (iPtr->cmdFramePtr) { + CmdFrame context = *iPtr->cmdFramePtr; + + if (context.type == TCL_LOCATION_BC) { + TclGetSrcInfoForPc (&context); + /* May get path in context */ + } else if (context.type == TCL_LOCATION_SOURCE) { + /* context now holds another reference */ + Tcl_IncrRefCount (context.data.eval.path); + } + + /* type == TCL_LOCATION_PREBC implies that 'line' is NULL here! We + * cannot assume that 'line' is valid here, we have to check. If the + * outer context is an eval (bc, prebc, eval) we do not save any + * information. Counting relative to the beginning of the proc body is + * more sensible than counting relative to the outer eval block. + */ + + if ((context.type == TCL_LOCATION_SOURCE) && + context.line && + (context.nline >= 4) && + (context.line [3] >= 0)) { + int new; + CmdFrame* cfPtr = (CmdFrame*) ckalloc (sizeof (CmdFrame)); + + cfPtr->level = -1; + cfPtr->type = context.type; + cfPtr->line = (int*) ckalloc (sizeof (int)); + cfPtr->line [0] = context.line [3]; + cfPtr->nline = 1; + cfPtr->framePtr = NULL; + cfPtr->nextPtr = NULL; + + if (context.type == TCL_LOCATION_SOURCE) { + cfPtr->data.eval.path = context.data.eval.path; + /* Transfer of reference. The reference going away (release of + * the context) is replaced by the reference in the + * constructed cmdframe */ + } else { + cfPtr->type = TCL_LOCATION_EVAL; + cfPtr->data.eval.path = NULL; + } + + cfPtr->cmd.str.cmd = NULL; + cfPtr->cmd.str.len = 0; + + Tcl_SetHashValue (Tcl_CreateHashEntry (iPtr->linePBodyPtr, + (char*) procPtr, &new), + cfPtr); + } + } +#endif /* * Optimize for noop procs: if the body is not precompiled (like a TclPro * procbody), and the argument list is just "args" and the body is empty, * define a compileProc to compile a noop. @@ -900,19 +963,18 @@ int objc; /* Count of number of arguments to this * procedure. */ Tcl_Obj *CONST objv[]; /* Argument value objects. */ { Interp *iPtr = (Interp *) interp; - register Proc *procPtr = (Proc *) clientData; + Proc *procPtr = (Proc *) clientData; Namespace *nsPtr = procPtr->cmdPtr->nsPtr; CallFrame frame; register CallFrame *framePtr = &frame; register Var *varPtr; register CompiledLocal *localPtr; char *procName; int nameLen, localCt, numArgs, argCt, i, result; - Tcl_Obj *objResult = Tcl_GetObjResult(interp); /* * This procedure generates an array "compiledLocals" that holds the * storage for local variables. It starts out with stack-allocated space * but uses dynamically-allocated storage if needed. @@ -934,12 +996,12 @@ * variables. Note that compiling the body might increase * procPtr->numCompiledLocals if new local variables are found * while compiling. */ - result = TclProcCompileProc(interp, procPtr, procPtr->bodyPtr, nsPtr, - "body of proc", procName); + result = ProcCompileProc(interp, procPtr, procPtr->bodyPtr, nsPtr, + "body of proc", procName, &procPtr); if (result != TCL_OK) { return result; } @@ -1035,17 +1097,36 @@ } varPtr++; localPtr = localPtr->nextPtr; } if (argCt > 0) { + Tcl_Obj *objResult; + int len, flags; + incorrectArgs: /* * Build up equivalent to Tcl_WrongNumArgs message for proc */ + Tcl_ResetResult(interp); - Tcl_AppendStringsToObj(objResult, - "wrong # args: should be \"", procName, (char *) NULL); + objResult = Tcl_GetObjResult(interp); + Tcl_AppendToObj(objResult, "wrong # args: should be \"", -1); + + /* + * Quote the proc name if it contains spaces (Bug 942757). + */ + + len = Tcl_ScanCountedElement(procName, nameLen, &flags); + if (len != nameLen) { + char *procName1 = ckalloc((unsigned) len); + len = Tcl_ConvertCountedElement(procName, nameLen, procName1, flags); + Tcl_AppendToObj(objResult, procName1, len); + ckfree(procName1); + } else { + Tcl_AppendToObj(objResult, procName, len); + } + localPtr = procPtr->firstLocalPtr; for (i = 1; i <= numArgs; i++) { if (localPtr->defValuePtr != NULL) { Tcl_AppendStringsToObj(objResult, " ?", localPtr->name, "?", (char *) NULL); @@ -1077,11 +1158,19 @@ } #endif /*TCL_COMPILE_DEBUG*/ iPtr->returnCode = TCL_OK; procPtr->refCount++; +#ifndef TCL_TIP280 result = TclCompEvalObj(interp, procPtr->bodyPtr); +#else + /* TIP #280: No need to set the invoking context here. The body has + * already been compiled, so the part of CompEvalObj using it is bypassed. + */ + + result = TclCompEvalObj(interp, procPtr->bodyPtr, NULL, 0); +#endif procPtr->refCount--; if (procPtr->refCount <= 0) { TclProcCleanupProc(procPtr); } @@ -1132,16 +1221,36 @@ * but could be any code fragment compiled * in the context of this procedure.) */ Namespace *nsPtr; /* Namespace containing procedure. */ CONST char *description; /* string describing this body of code. */ CONST char *procName; /* Name of this procedure. */ +{ + return ProcCompileProc(interp, procPtr, bodyPtr, nsPtr, + description, procName, NULL); +} + +static int +ProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description, + procName, procPtrPtr) + Tcl_Interp *interp; /* Interpreter containing procedure. */ + Proc *procPtr; /* Data associated with procedure. */ + Tcl_Obj *bodyPtr; /* Body of proc. (Usually procPtr->bodyPtr, + * but could be any code fragment compiled + * in the context of this procedure.) */ + Namespace *nsPtr; /* Namespace containing procedure. */ + CONST char *description; /* string describing this body of code. */ + CONST char *procName; /* Name of this procedure. */ + Proc **procPtrPtr; /* points to storage where a replacement + * (Proc *) value may be written, when + * appropriate */ { Interp *iPtr = (Interp*)interp; - int result; + int i, result; Tcl_CallFrame frame; Proc *saveProcPtr; ByteCode *codePtr = (ByteCode *) bodyPtr->internalRep.otherValuePtr; + CompiledLocal *localPtr; /* * If necessary, compile the procedure's body. The compiler will * allocate frame slots for the procedure's non-argument local * variables. If the ByteCode already exists, make sure it hasn't been @@ -1203,19 +1312,94 @@ * * TRICKY NOTE: Be careful to push a call frame with the * proper namespace context, so that the byte codes are * compiled in the appropriate class context. */ - + saveProcPtr = iPtr->compiledProcPtr; + + if (procPtrPtr != NULL && procPtr->refCount > 1) { + Tcl_Command token; + Tcl_CmdInfo info; + Proc *new = (Proc *) ckalloc(sizeof(Proc)); + + new->iPtr = procPtr->iPtr; + new->refCount = 1; + new->cmdPtr = procPtr->cmdPtr; + token = (Tcl_Command) new->cmdPtr; + new->bodyPtr = Tcl_DuplicateObj(bodyPtr); + bodyPtr = new->bodyPtr; + Tcl_IncrRefCount(bodyPtr); + new->numArgs = procPtr->numArgs; + + new->numCompiledLocals = new->numArgs; + new->firstLocalPtr = NULL; + new->lastLocalPtr = NULL; + localPtr = procPtr->firstLocalPtr; + for (i = 0; i < new->numArgs; i++, localPtr = localPtr->nextPtr) { + CompiledLocal *copy = (CompiledLocal *) ckalloc((unsigned) + (sizeof(CompiledLocal) -sizeof(localPtr->name) + + localPtr->nameLength + 1)); + if (new->firstLocalPtr == NULL) { + new->firstLocalPtr = new->lastLocalPtr = copy; + } else { + new->lastLocalPtr->nextPtr = copy; + new->lastLocalPtr = copy; + } + copy->nextPtr = NULL; + copy->nameLength = localPtr->nameLength; + copy->frameIndex = localPtr->frameIndex; + copy->flags = localPtr->flags; + copy->defValuePtr = localPtr->defValuePtr; + if (copy->defValuePtr) { + Tcl_IncrRefCount(copy->defValuePtr); + } + copy->resolveInfo = localPtr->resolveInfo; + strcpy(copy->name, localPtr->name); + } + + + /* Reset the ClientData */ + Tcl_GetCommandInfoFromToken(token, &info); + if (info.objClientData == (ClientData) procPtr) { + info.objClientData = (ClientData) new; + } + if (info.clientData == (ClientData) procPtr) { + info.clientData = (ClientData) new; + } + if (info.deleteData == (ClientData) procPtr) { + info.deleteData = (ClientData) new; + } + Tcl_SetCommandInfoFromToken(token, &info); + + procPtr->refCount--; + *procPtrPtr = procPtr = new; + } iPtr->compiledProcPtr = procPtr; result = Tcl_PushCallFrame(interp, &frame, (Tcl_Namespace*)nsPtr, /* isProcCallFrame */ 0); if (result == TCL_OK) { +#ifdef TCL_TIP280 + /* TIP #280. We get the invoking context from the cmdFrame + * which was saved by 'Tcl_ProcObjCmd' (using linePBodyPtr). + */ + + Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->linePBodyPtr, (char *) procPtr); + + /* Constructed saved frame has body as word 0. See Tcl_ProcObjCmd. + */ + iPtr->invokeWord = 0; + iPtr->invokeCmdFramePtr = (hePtr + ? (CmdFrame*) Tcl_GetHashValue (hePtr) + : NULL); +#endif result = tclByteCodeType.setFromAnyProc(interp, bodyPtr); +#ifdef TCL_TIP280 + iPtr->invokeCmdFramePtr = NULL; +#endif Tcl_PopCallFrame(interp); } iPtr->compiledProcPtr = saveProcPtr; @@ -1227,19 +1411,26 @@ ellipsis = ""; if (numChars > 50) { numChars = 50; ellipsis = "..."; } + while ( (procName[numChars] & 0xC0) == 0x80 ) { + /* + * Back up truncation point so that we don't truncate + * in the middle of a multi-byte character (in UTF-8) + */ + numChars--; + ellipsis = "..."; + } sprintf(buf, "\n (compiling %s \"%.*s%s\", line %d)", description, numChars, procName, ellipsis, interp->errorLine); Tcl_AddObjErrorInfo(interp, buf, -1); } return result; } } else if (codePtr->nsEpoch != nsPtr->resolverEpoch) { - register CompiledLocal *localPtr; /* * The resolver epoch has changed, but we only need to invalidate * the resolver cache. */ @@ -1310,10 +1501,18 @@ : "invoked \"continue\" outside of a loop"), -1); } if (nameLen > 60) { nameLen = 60; ellipsis = "..."; + } + while ( (procName[nameLen] & 0xC0) == 0x80 ) { + /* + * Back up truncation point so that we don't truncate in the + * middle of a multi-byte character (in UTF-8) + */ + nameLen--; + ellipsis = "..."; } sprintf(msg, "\n (procedure \"%.*s%s\" line %d)", nameLen, procName, ellipsis, iPtr->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); return TCL_ERROR; @@ -1375,10 +1574,15 @@ { register CompiledLocal *localPtr; Tcl_Obj *bodyPtr = procPtr->bodyPtr; Tcl_Obj *defPtr; Tcl_ResolvedVarInfo *resVarInfo; +#ifdef TCL_TIP280 + Tcl_HashEntry* hePtr = NULL; + CmdFrame* cfPtr = NULL; + Interp* iPtr = procPtr->iPtr; +#endif if (bodyPtr != NULL) { Tcl_DecrRefCount(bodyPtr); } for (localPtr = procPtr->firstLocalPtr; localPtr != NULL; ) { @@ -1399,10 +1603,32 @@ } ckfree((char *) localPtr); localPtr = nextPtr; } ckfree((char *) procPtr); + +#ifdef TCL_TIP280 + /* TIP #280. Release the location data associated with this Proc + * structure, if any. The interpreter may not exist (For example for + * procbody structurues created by tbcload. + */ + + if (!iPtr) return; + + hePtr = Tcl_FindHashEntry (iPtr->linePBodyPtr, (char *) procPtr); + if (!hePtr) return; + + cfPtr = (CmdFrame*) Tcl_GetHashValue (hePtr); + + if (cfPtr->type == TCL_LOCATION_SOURCE) { + Tcl_DecrRefCount (cfPtr->data.eval.path); + cfPtr->data.eval.path = NULL; + } + ckfree ((char*) cfPtr->line); cfPtr->line = NULL; + ckfree ((char*) cfPtr); + Tcl_DeleteHashEntry (hePtr); +#endif } /* *---------------------------------------------------------------------- * @@ -1428,23 +1654,28 @@ Interp *iPtr; /* Interpreter for which TCL_RETURN * exception is being processed. */ { int code; char *errorCode; + Tcl_Obj *objPtr; code = iPtr->returnCode; iPtr->returnCode = TCL_OK; if (code == TCL_ERROR) { errorCode = ((iPtr->errorCode != NULL) ? iPtr->errorCode : "NONE"); + objPtr = Tcl_NewStringObj(errorCode, -1); + Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorCode, - NULL, Tcl_NewStringObj(errorCode, -1), - TCL_GLOBAL_ONLY); + NULL, objPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(objPtr); iPtr->flags |= ERROR_CODE_SET; if (iPtr->errorInfo != NULL) { + objPtr = Tcl_NewStringObj(iPtr->errorInfo, -1); + Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorInfo, - NULL, Tcl_NewStringObj(iPtr->errorInfo, -1), - TCL_GLOBAL_ONLY); + NULL, objPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(objPtr); iPtr->flags |= ERR_IN_PROGRESS; } } return code; } @@ -1699,8 +1930,14 @@ } envPtr->currStackDepth = savedStackDepth; TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0), envPtr); return TCL_OK; } - - + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ Index: generic/tclRegexp.c ================================================================== --- generic/tclRegexp.c +++ generic/tclRegexp.c @@ -8,11 +8,11 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclRegexp.c,v 1.14 2002/01/17 03:03:12 dgp Exp $ + * RCS: @(#) $Id: tclRegexp.c,v 1.14.4.2 2006/04/07 01:14:28 hobbs Exp $ */ #include "tclInt.h" #include "tclPort.h" #include "tclRegexp.h" @@ -103,11 +103,11 @@ /* * The regular expression Tcl object type. This serves as a cache * of the compiled form of the regular expression. */ -Tcl_ObjType tclRegexpType = { +static Tcl_ObjType tclRegexpType = { "regexp", /* name */ FreeRegexpInternalRep, /* freeIntRepProc */ DupRegexpInternalRep, /* dupIntRepProc */ NULL, /* updateStringProc */ SetRegexpFromAny /* setFromAnyProc */ @@ -1022,7 +1022,13 @@ regexpPtr = tsdPtr->regexps[i]; if (--(regexpPtr->refCount) <= 0) { FreeRegexp(regexpPtr); } ckfree(tsdPtr->patterns[i]); + tsdPtr->patterns[i] = NULL; } + /* + * We may find ourselves reinitialized if another finalization routine + * invokes regexps. + */ + tsdPtr->initialized = 0; } Index: generic/tclResult.c ================================================================== --- generic/tclResult.c +++ generic/tclResult.c @@ -6,11 +6,11 @@ * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclResult.c,v 1.5 2002/01/25 20:40:55 dgp Exp $ + * RCS: @(#) $Id: tclResult.c,v 1.5.2.2 2004/09/30 22:45:15 dgp Exp $ */ #include "tclInt.h" /* @@ -196,12 +196,11 @@ TclDecrRefCount(statePtr->objResultPtr); if (statePtr->result == statePtr->appendResult) { ckfree(statePtr->appendResult); } else if (statePtr->freeProc) { - if ((statePtr->freeProc == TCL_DYNAMIC) - || (statePtr->freeProc == (Tcl_FreeProc *) free)) { + if (statePtr->freeProc == TCL_DYNAMIC) { ckfree(statePtr->result); } else { (*statePtr->freeProc)(statePtr->result); } } @@ -263,12 +262,11 @@ * here, rather than at the beginning, in case the new result value * was part of the old result value. */ if (oldFreeProc != 0) { - if ((oldFreeProc == TCL_DYNAMIC) - || (oldFreeProc == (Tcl_FreeProc *) free)) { + if (oldFreeProc == TCL_DYNAMIC) { ckfree(oldResult); } else { (*oldFreeProc)(oldResult); } } @@ -357,12 +355,11 @@ /* * Reset the string result since we just set the result object. */ if (iPtr->freeProc != NULL) { - if ((iPtr->freeProc == TCL_DYNAMIC) - || (iPtr->freeProc == (Tcl_FreeProc *) free)) { + if (iPtr->freeProc == TCL_DYNAMIC) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; @@ -411,12 +408,11 @@ objResultPtr = iPtr->objResultPtr; length = strlen(iPtr->result); TclInitStringRep(objResultPtr, iPtr->result, length); if (iPtr->freeProc != NULL) { - if ((iPtr->freeProc == TCL_DYNAMIC) - || (iPtr->freeProc == (Tcl_FreeProc *) free)) { + if (iPtr->freeProc == TCL_DYNAMIC) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; @@ -749,12 +745,11 @@ register Tcl_Interp *interp; /* Interpreter for which to free result. */ { register Interp *iPtr = (Interp *) interp; if (iPtr->freeProc != NULL) { - if ((iPtr->freeProc == TCL_DYNAMIC) - || (iPtr->freeProc == (Tcl_FreeProc *) free)) { + if (iPtr->freeProc == TCL_DYNAMIC) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; @@ -789,12 +784,11 @@ { register Interp *iPtr = (Interp *) interp; ResetObjResult(iPtr); if (iPtr->freeProc != NULL) { - if ((iPtr->freeProc == TCL_DYNAMIC) - || (iPtr->freeProc == (Tcl_FreeProc *) free)) { + if (iPtr->freeProc == TCL_DYNAMIC) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; @@ -1033,20 +1027,23 @@ Tcl_ResetResult(targetInterp); objPtr = Tcl_GetVar2Ex(sourceInterp, "errorInfo", NULL, TCL_GLOBAL_ONLY); - Tcl_SetVar2Ex(targetInterp, "errorInfo", NULL, objPtr, - TCL_GLOBAL_ONLY); + if (objPtr) { + Tcl_SetVar2Ex(targetInterp, "errorInfo", NULL, objPtr, + TCL_GLOBAL_ONLY); + ((Interp *) targetInterp)->flags |= ERR_IN_PROGRESS; + } objPtr = Tcl_GetVar2Ex(sourceInterp, "errorCode", NULL, TCL_GLOBAL_ONLY); - Tcl_SetVar2Ex(targetInterp, "errorCode", NULL, objPtr, - TCL_GLOBAL_ONLY); + if (objPtr) { + Tcl_SetObjErrorCode(targetInterp, objPtr); + } - ((Interp *) targetInterp)->flags |= (ERR_IN_PROGRESS | ERROR_CODE_SET); } ((Interp *) targetInterp)->returnCode = ((Interp *) sourceInterp)->returnCode; Tcl_SetObjResult(targetInterp, Tcl_GetObjResult(sourceInterp)); Tcl_ResetResult(sourceInterp); } Index: generic/tclScan.c ================================================================== --- generic/tclScan.c +++ generic/tclScan.c @@ -6,11 +6,11 @@ * Copyright (c) 1998 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclScan.c,v 1.12 2002/02/25 15:23:02 dkf Exp $ + * RCS: @(#) $Id: tclScan.c,v 1.12.2.2 2005/10/23 22:01:30 msofer Exp $ */ #include "tclInt.h" /* * For strtoll() and strtoull() declarations on some platforms... @@ -369,13 +369,11 @@ */ switch (ch) { case 'l': case 'L': -#ifndef TCL_WIDE_INT_IS_LONG flags |= SCAN_LONGER; -#endif case 'h': format += Tcl_UtfToUniChar(format, &ch); } if (!(flags & SCAN_SUPPRESS) && numVars && (objIndex >= numVars)) { @@ -702,13 +700,11 @@ */ switch (ch) { case 'l': case 'L': -#ifndef TCL_WIDE_INT_IS_LONG flags |= SCAN_LONGER; -#endif /* * Fall through so we skip to the next character. */ case 'h': format += Tcl_UtfToUniChar(format, &ch); @@ -1038,16 +1034,15 @@ #endif /* !TCL_WIDE_INT_IS_LONG */ value = (long) (*fn)(buf, NULL, base); if ((flags & SCAN_UNSIGNED) && (value < 0)) { sprintf(buf, "%lu", value); /* INTL: ISO digit */ objPtr = Tcl_NewStringObj(buf, -1); + } else if ((flags & SCAN_LONGER) + || (unsigned long) value > UINT_MAX) { + objPtr = Tcl_NewLongObj(value); } else { - if ((unsigned long) value > UINT_MAX) { - objPtr = Tcl_NewLongObj(value); - } else { - objPtr = Tcl_NewIntObj(value); - } + objPtr = Tcl_NewIntObj(value); } #ifndef TCL_WIDE_INT_IS_LONG } #endif Tcl_IncrRefCount(objPtr); @@ -1171,19 +1166,21 @@ /* * In this case, variables were specified (classic scan) */ for (i = 0; i < totalVars; i++) { if (objs[i] != NULL) { + Tcl_Obj *tmpPtr; + result++; - if (Tcl_ObjSetVar2(interp, objv[i+3], NULL, - objs[i], 0) == NULL) { + tmpPtr = Tcl_ObjSetVar2(interp, objv[i+3], NULL, objs[i], 0); + Tcl_DecrRefCount(objs[i]); + if (tmpPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "couldn't set variable \"", Tcl_GetString(objv[i+3]), "\"", (char *) NULL); code = TCL_ERROR; } - Tcl_DecrRefCount(objs[i]); } } } else { /* * Here no vars were specified, we want a list returned (inline scan) Index: generic/tclStringObj.c ================================================================== --- generic/tclStringObj.c +++ generic/tclStringObj.c @@ -31,11 +31,11 @@ * Copyright (c) 1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclStringObj.c,v 1.32 2003/02/19 16:43:28 das Exp $ */ + * RCS: @(#) $Id: tclStringObj.c,v 1.32.2.2 2006/09/24 21:15:11 msofer Exp $ */ #include "tclInt.h" /* * Prototypes for procedures defined later in this file: @@ -103,12 +103,14 @@ * 'uallocated' field above. */ } String; #define STRING_UALLOC(numChars) \ (numChars * sizeof(Tcl_UniChar)) -#define STRING_SIZE(ualloc) \ - ((unsigned) (sizeof(String) - sizeof(Tcl_UniChar) + ualloc)) +#define STRING_SIZE(ualloc) \ + ((unsigned) ((ualloc) \ + ? sizeof(String) - sizeof(Tcl_UniChar) + (ualloc) \ + : sizeof(String))) #define GET_STRING(objPtr) \ ((String *) (objPtr)->internalRep.otherValuePtr) #define SET_STRING(objPtr, stringPtr) \ (objPtr)->internalRep.otherValuePtr = (VOID *) (stringPtr) @@ -640,11 +642,11 @@ */ stringPtr = GET_STRING(objPtr); } - if (stringPtr->numChars == objPtr->length) { + if (objPtr->bytes && stringPtr->numChars == objPtr->length) { char *str = Tcl_GetString(objPtr); /* * All of the characters in the Utf string are 1 byte chars, * so we don't store the unicode char. Create a new string Index: generic/tclStubInit.c ================================================================== --- generic/tclStubInit.c +++ generic/tclStubInit.c @@ -6,11 +6,11 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclStubInit.c,v 1.79 2003/02/18 02:25:45 hobbs Exp $ + * RCS: @(#) $Id: tclStubInit.c,v 1.79.2.10 2006/09/22 01:26:23 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -33,10 +33,33 @@ #undef Tcl_ValidateAllMemory #if TCL_PRESERVE_BINARY_COMPATABILITY # undef Tcl_FindHashEntry # undef Tcl_CreateHashEntry #endif + +/* + * Keep a record of the original Notifier procedures, created in the + * same compilation unit as the stub tables so we can later do reliable, + * portable comparisons to see whether a Tcl_SetNotifier() call swapped + * new routines into the stub table. + */ + +Tcl_NotifierProcs tclOriginalNotifier = { + Tcl_SetTimer, + Tcl_WaitForEvent, +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + Tcl_CreateFileHandler, + Tcl_DeleteFileHandler, +#else + NULL, + NULL, +#endif + NULL, + NULL, + NULL, + NULL +}; /* * WARNING: The contents of this file is automatically generated by the * tools/genStubs.tcl script. Any modifications to the function declarations * below should be made in the generic/tcl.decls script. @@ -243,10 +266,36 @@ TclpUtfNcmp2, /* 169 */ TclCheckInterpTraces, /* 170 */ TclCheckExecutionTraces, /* 171 */ TclInThreadExit, /* 172 */ TclUniCharMatch, /* 173 */ + NULL, /* 174 */ + NULL, /* 175 */ + NULL, /* 176 */ + NULL, /* 177 */ + NULL, /* 178 */ + NULL, /* 179 */ + NULL, /* 180 */ + NULL, /* 181 */ + TclpLocaltime, /* 182 */ + TclpGmtime, /* 183 */ + NULL, /* 184 */ + NULL, /* 185 */ + NULL, /* 186 */ + NULL, /* 187 */ + NULL, /* 188 */ + NULL, /* 189 */ + NULL, /* 190 */ + NULL, /* 191 */ + NULL, /* 192 */ + NULL, /* 193 */ + NULL, /* 194 */ + NULL, /* 195 */ + NULL, /* 196 */ + NULL, /* 197 */ + NULL, /* 198 */ + TclMatchIsTrivial, /* 199 */ }; TclIntPlatStubs tclIntPlatStubs = { TCL_STUB_MAGIC, NULL, @@ -260,12 +309,12 @@ TclpMakeFile, /* 6 */ TclpOpenFile, /* 7 */ TclUnixWaitForFile, /* 8 */ TclpCreateTempFile, /* 9 */ TclpReaddir, /* 10 */ - TclpLocaltime, /* 11 */ - TclpGmtime, /* 12 */ + TclpLocaltime_unix, /* 11 */ + TclpGmtime_unix, /* 12 */ TclpInetNtoa, /* 13 */ #endif /* UNIX */ #ifdef __WIN32__ TclWinConvertError, /* 0 */ TclWinConvertWSAError, /* 1 */ @@ -294,10 +343,11 @@ TclWinNoBackslash, /* 24 */ TclWinGetPlatform, /* 25 */ TclWinSetInterfaces, /* 26 */ TclWinFlushDirtyChannels, /* 27 */ TclWinResetInterfaces, /* 28 */ + TclWinCPUID, /* 29 */ #endif /* __WIN32__ */ #ifdef MAC_TCL TclpSysAlloc, /* 0 */ TclpSysFree, /* 1 */ TclpSysRealloc, /* 2 */ @@ -346,10 +396,11 @@ strncasecmp, /* 7 */ strcasecmp, /* 8 */ #endif /* MAC_TCL */ #ifdef MAC_OSX_TCL Tcl_MacOSXOpenBundleResources, /* 0 */ + Tcl_MacOSXOpenVersionedBundleResources, /* 1 */ #endif /* MAC_OSX_TCL */ }; static TclStubHooks tclStubHooks = { &tclPlatStubs, @@ -900,8 +951,88 @@ Tcl_SetWideIntObj, /* 489 */ Tcl_AllocStatBuf, /* 490 */ Tcl_Seek, /* 491 */ Tcl_Tell, /* 492 */ Tcl_ChannelWideSeekProc, /* 493 */ + NULL, /* 494 */ + NULL, /* 495 */ + NULL, /* 496 */ + NULL, /* 497 */ + NULL, /* 498 */ + NULL, /* 499 */ + NULL, /* 500 */ + NULL, /* 501 */ + NULL, /* 502 */ + NULL, /* 503 */ + NULL, /* 504 */ + NULL, /* 505 */ + NULL, /* 506 */ + NULL, /* 507 */ + NULL, /* 508 */ + NULL, /* 509 */ + NULL, /* 510 */ + NULL, /* 511 */ + NULL, /* 512 */ + NULL, /* 513 */ + NULL, /* 514 */ + NULL, /* 515 */ + NULL, /* 516 */ + NULL, /* 517 */ + NULL, /* 518 */ + NULL, /* 519 */ + NULL, /* 520 */ + NULL, /* 521 */ + NULL, /* 522 */ + NULL, /* 523 */ + NULL, /* 524 */ + NULL, /* 525 */ + NULL, /* 526 */ + NULL, /* 527 */ + NULL, /* 528 */ + NULL, /* 529 */ + NULL, /* 530 */ + NULL, /* 531 */ + NULL, /* 532 */ + NULL, /* 533 */ + NULL, /* 534 */ + NULL, /* 535 */ + NULL, /* 536 */ + NULL, /* 537 */ + NULL, /* 538 */ + NULL, /* 539 */ + NULL, /* 540 */ + NULL, /* 541 */ + NULL, /* 542 */ + NULL, /* 543 */ + NULL, /* 544 */ + NULL, /* 545 */ + NULL, /* 546 */ + NULL, /* 547 */ + NULL, /* 548 */ + NULL, /* 549 */ + NULL, /* 550 */ + NULL, /* 551 */ + NULL, /* 552 */ + NULL, /* 553 */ + Tcl_ChannelThreadActionProc, /* 554 */ + NULL, /* 555 */ + NULL, /* 556 */ + NULL, /* 557 */ + NULL, /* 558 */ + NULL, /* 559 */ + NULL, /* 560 */ + NULL, /* 561 */ + NULL, /* 562 */ + NULL, /* 563 */ + NULL, /* 564 */ + NULL, /* 565 */ + NULL, /* 566 */ + NULL, /* 567 */ + NULL, /* 568 */ + NULL, /* 569 */ + NULL, /* 570 */ + NULL, /* 571 */ + NULL, /* 572 */ + Tcl_PkgRequireProc, /* 573 */ }; /* !END!: Do not edit above this line. */ Index: generic/tclStubLib.c ================================================================== --- generic/tclStubLib.c +++ generic/tclStubLib.c @@ -8,11 +8,11 @@ * Copyright (c) 1998 Paul Duffin. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclStubLib.c,v 1.6 2002/12/04 07:07:59 hobbs Exp $ + * RCS: @(#) $Id: tclStubLib.c,v 1.6.2.1 2005/11/20 18:23:03 jenglish Exp $ */ /* * We need to ensure that we use the stub macros so that this file contains * no references to any of the stub functions. This will make it possible @@ -31,13 +31,10 @@ /* * Ensure that Tcl_InitStubs is built as an exported symbol. The other stub * functions should be built as non-exported symbols. */ -#undef TCL_STORAGE_CLASS -#define TCL_STORAGE_CLASS DLLEXPORT - TclStubs *tclStubsPtr = NULL; TclPlatStubs *tclPlatStubsPtr = NULL; TclIntStubs *tclIntStubsPtr = NULL; TclIntPlatStubs *tclIntPlatStubsPtr = NULL; @@ -85,11 +82,11 @@ Tcl_Interp *interp; CONST char *version; int exact; { CONST char *actualVersion = NULL; - TclStubs *tmp; + ClientData pkgData = NULL; /* * We can't optimize this check by caching tclStubsPtr because * that prevents apps from being able to load/unload Tcl dynamically * multiple times. [Bug 615304] @@ -98,16 +95,15 @@ tclStubsPtr = HasStubSupport(interp); if (!tclStubsPtr) { return NULL; } - actualVersion = Tcl_PkgRequireEx(interp, "Tcl", version, exact, - (ClientData *) &tmp); + actualVersion = Tcl_PkgRequireEx(interp, "Tcl", version, exact, &pkgData); if (actualVersion == NULL) { - tclStubsPtr = NULL; return NULL; } + tclStubsPtr = (TclStubs*)pkgData; if (tclStubsPtr->hooks) { tclPlatStubsPtr = tclStubsPtr->hooks->tclPlatStubs; tclIntStubsPtr = tclStubsPtr->hooks->tclIntStubs; tclIntPlatStubsPtr = tclStubsPtr->hooks->tclIntPlatStubs; Index: generic/tclTest.c ================================================================== --- generic/tclTest.c +++ generic/tclTest.c @@ -12,11 +12,11 @@ * Copyright (c) 2003 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclTest.c,v 1.62 2003/02/18 10:13:25 vincentdarley Exp $ + * RCS: @(#) $Id: tclTest.c,v 1.62.2.13 2006/09/22 01:26:23 andreas_kupries Exp $ */ #define TCL_TEST #include "tclInt.h" #include "tclPort.h" @@ -206,12 +206,10 @@ Tcl_Interp *interp, int argc, CONST char **argv)); static int TestcmdtokenCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestcmdtraceCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); -static int TestchmodCmd _ANSI_ARGS_((ClientData dummy, - Tcl_Interp *interp, int argc, CONST char **argv)); static int TestcreatecommandCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestdcallCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestdelCmd _ANSI_ARGS_((ClientData dummy, @@ -312,10 +310,12 @@ Tcl_Obj *CONST objv[])); static void TestsaveresultFree _ANSI_ARGS_((char *blockPtr)); static int TestsetassocdataCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestsetCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int argc, CONST char **argv)); +static int TestseterrorcodeCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestsetobjerrorcodeCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestopenfilechannelprocCmd _ANSI_ARGS_(( @@ -418,10 +418,13 @@ int mode, int permissions)); static Tcl_Obj* SimpleListVolumes _ANSI_ARGS_ ((void)); static int SimplePathInFilesystem _ANSI_ARGS_ (( Tcl_Obj *pathPtr, ClientData *clientDataPtr)); static Tcl_Obj* SimpleCopy _ANSI_ARGS_ ((Tcl_Obj *pathPtr)); +static int TestNumUtfCharsCmd _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[])); static Tcl_Filesystem testReportingFilesystem = { "reporting", sizeof(Tcl_Filesystem), TCL_FILESYSTEM_VERSION_1, @@ -543,11 +546,16 @@ static CONST char *specialOptions[] = { "-appinitprocerror", "-appinitprocdeleteinterp", "-appinitprocclosestderr", "-appinitprocsetrcfile", (char *) NULL }; +#ifndef TCL_TIP268 if (Tcl_PkgProvide(interp, "Tcltest", TCL_VERSION) == TCL_ERROR) { +#else + /* TIP #268: Full patchlevel instead of just major.minor */ + if (Tcl_PkgProvide(interp, "Tcltest", TCL_PATCH_LEVEL) == TCL_ERROR) { +#endif return TCL_ERROR; } /* * Create additional commands and math functions for testing Tcl. @@ -573,12 +581,10 @@ Tcl_CreateCommand(interp, "testasync", TestasyncCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testchannel", TestChannelCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testchannelevent", TestChannelEventCmd, - (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateCommand(interp, "testchmod", TestchmodCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testcmdtoken", TestcmdtokenCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testcmdinfo", TestcmdinfoCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); @@ -649,12 +655,17 @@ (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testsetnoerr", TestsetCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testseterr", TestsetCmd, (ClientData) TCL_LEAVE_ERR_MSG, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, "testseterrorcode", TestseterrorcodeCmd, + (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testsetobjerrorcode", TestsetobjerrorcodeCmd, (ClientData) 0, + (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "testnumutfchars", + TestNumUtfCharsCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testsetplatform", TestsetplatformCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "teststaticpkg", TeststaticpkgCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); @@ -1121,10 +1132,22 @@ */ cmdTrace = Tcl_CreateTrace(interp, 50000, (Tcl_CmdTraceProc *) CmdTraceDeleteProc, (ClientData) NULL); Tcl_Eval(interp, argv[2]); + } else if (strcmp(argv[1], "leveltest") == 0) { + Interp *iPtr = (Interp *) interp; + Tcl_DStringInit(&buffer); + cmdTrace = Tcl_CreateTrace(interp, iPtr->numLevels + 4, + (Tcl_CmdTraceProc *) CmdTraceProc, (ClientData) &buffer); + result = Tcl_Eval(interp, argv[2]); + if (result == TCL_OK) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), NULL); + } + Tcl_DeleteTrace(interp, cmdTrace); + Tcl_DStringFree(&buffer); } else if ( strcmp(argv[1], "resulttest" ) == 0 ) { /* Create an object-based trace, then eval a script. This is used * to test return codes other than TCL_OK from the trace engine. */ static int deleteCalled; @@ -1965,11 +1988,12 @@ "tail", "mark", NULL }; int posIndex; /* Index of the chosen position */ - static CONST int posNum[] = { /* Interpretation of the chosen position */ + static CONST Tcl_QueuePosition posNum[] = { + /* Interpretation of the chosen position */ TCL_QUEUE_HEAD, TCL_QUEUE_TAIL, TCL_QUEUE_MARK }; TestEvent* ev; /* Event to be queued */ @@ -2793,18 +2817,16 @@ double d0 = i0; double d1 = args[1].doubleValue; resultPtr->type = TCL_DOUBLE; resultPtr->doubleValue = ((d0 > d1)? d0 : d1); -#ifndef TCL_WIDE_INT_IS_LONG } else if (args[1].type == TCL_WIDE_INT) { Tcl_WideInt w0 = Tcl_LongAsWide(i0); Tcl_WideInt w1 = args[1].wideValue; resultPtr->type = TCL_WIDE_INT; resultPtr->wideValue = ((w0 > w1)? w0 : w1); -#endif } else { Tcl_SetResult(interp, "T3: wrong type for arg 2", TCL_STATIC); result = TCL_ERROR; } } else if (args[0].type == TCL_DOUBLE) { @@ -2818,22 +2840,19 @@ } else if (args[1].type == TCL_DOUBLE) { double d1 = args[1].doubleValue; resultPtr->type = TCL_DOUBLE; resultPtr->doubleValue = ((d0 > d1)? d0 : d1); -#ifndef TCL_WIDE_INT_IS_LONG } else if (args[1].type == TCL_WIDE_INT) { double d1 = Tcl_WideAsDouble(args[1].wideValue); resultPtr->type = TCL_DOUBLE; resultPtr->doubleValue = ((d0 > d1)? d0 : d1); -#endif } else { Tcl_SetResult(interp, "T3: wrong type for arg 2", TCL_STATIC); result = TCL_ERROR; } -#ifndef TCL_WIDE_INT_IS_LONG } else if (args[0].type == TCL_WIDE_INT) { Tcl_WideInt w0 = args[0].wideValue; if (args[1].type == TCL_INT) { Tcl_WideInt w1 = Tcl_LongAsWide(args[1].intValue); @@ -2853,11 +2872,10 @@ resultPtr->wideValue = ((w0 > w1)? w0 : w1); } else { Tcl_SetResult(interp, "T3: wrong type for arg 2", TCL_STATIC); result = TCL_ERROR; } -#endif } else { Tcl_SetResult(interp, "T3: wrong type for arg 1", TCL_STATIC); result = TCL_ERROR; } return result; @@ -3337,16 +3355,30 @@ Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); if (objc > 2 && (cflags®_EXPECT) && indices) { char *varName; CONST char *value; int start, end; - char info[TCL_INTEGER_SPACE * 2]; + char resinfo[TCL_INTEGER_SPACE * 2]; varName = Tcl_GetString(objv[2]); TclRegExpRangeUniChar(regExpr, -1, &start, &end); - sprintf(info, "%d %d", start, end-1); - value = Tcl_SetVar(interp, varName, info, 0); + sprintf(resinfo, "%d %d", start, end-1); + value = Tcl_SetVar(interp, varName, resinfo, 0); + if (value == NULL) { + Tcl_AppendResult(interp, "couldn't set variable \"", + varName, "\"", (char *) NULL); + return TCL_ERROR; + } + } else if (cflags & TCL_REG_CANMATCH) { + char *varName; + CONST char *value; + char resinfo[TCL_INTEGER_SPACE * 2]; + + Tcl_RegExpGetInfo(regExpr, &info); + varName = Tcl_GetString(objv[2]); + sprintf(resinfo, "%ld", info.extendStart); + value = Tcl_SetVar(interp, varName, resinfo, 0); if (value == NULL) { Tcl_AppendResult(interp, "couldn't set variable \"", varName, "\"", (char *) NULL); return TCL_ERROR; } @@ -3404,13 +3436,14 @@ } else { newPtr = Tcl_GetRange(objPtr, info.matches[ii].start, info.matches[ii].end - 1); } } + Tcl_IncrRefCount(newPtr); valuePtr = Tcl_ObjSetVar2(interp, varPtr, NULL, newPtr, 0); + Tcl_DecrRefCount(newPtr); if (valuePtr == NULL) { - Tcl_DecrRefCount(newPtr); Tcl_AppendResult(interp, "couldn't set variable \"", Tcl_GetString(varPtr), "\"", (char *) NULL); return TCL_ERROR; } } @@ -3460,10 +3493,14 @@ break; } case 'b': { cflags &= ~REG_ADVANCED; break; + } + case 'c': { + cflags |= TCL_REG_CANMATCH; + break; } case 'e': { cflags &= ~REG_ADVANCED; cflags |= REG_EXTENDED; break; @@ -3778,15 +3815,50 @@ } /* *---------------------------------------------------------------------- * + * TestseterrorcodeCmd -- + * + * This procedure implements the "testseterrorcodeCmd". + * This tests up to five elements passed to the + * Tcl_SetErrorCode command. + * + * Results: + * A standard Tcl result. Always returns TCL_ERROR so that + * the error code can be tested. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +TestseterrorcodeCmd(dummy, interp, argc, argv) + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + CONST char **argv; /* Argument strings. */ +{ + if (argc > 6) { + Tcl_SetResult(interp, "too many args", TCL_STATIC); + return TCL_ERROR; + } + Tcl_SetErrorCode(interp, argv[1], argv[2], argv[3], argv[4], + argv[5], NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * * TestsetobjerrorcodeCmd -- * * This procedure implements the "testsetobjerrorcodeCmd". - * This tests up to five elements passed to the - * Tcl_SetObjErrorCode command. + * This tests the Tcl_SetObjErrorCode function. * * Results: * A standard Tcl result. Always returns TCL_ERROR so that * the error code can be tested. * @@ -3926,69 +3998,10 @@ ckfree((char *)argString); return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * TestchmodCmd -- - * - * Implements the "testchmod" cmd. Used when testing "file" - * command. The only attribute used by the Mac and Windows platforms - * is the user write flag; if this is not set, the file is - * made read-only. Otehrwise, the file is made read-write. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Changes permissions of specified files. - * - *--------------------------------------------------------------------------- - */ - -static int -TestchmodCmd(dummy, interp, argc, argv) - ClientData dummy; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - CONST char **argv; /* Argument strings. */ -{ - int i, mode; - char *rest; - - if (argc < 2) { - usage: - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " mode file ?file ...?", (char *) NULL); - return TCL_ERROR; - } - - mode = (int) strtol(argv[1], &rest, 8); - if ((rest == argv[1]) || (*rest != '\0')) { - goto usage; - } - - for (i = 2; i < argc; i++) { - Tcl_DString buffer; - CONST char *translated; - - translated = Tcl_TranslateFileName(interp, argv[i], &buffer); - if (translated == NULL) { - return TCL_ERROR; - } - if (chmod(translated, (unsigned) mode) != 0) { - Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp), - (char *) NULL); - return TCL_ERROR; - } - Tcl_DStringFree(&buffer); - } - return TCL_OK; -} - static int TestfileCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ @@ -4012,11 +4025,11 @@ if (argc - i > 2) { return TCL_ERROR; } for (j = i; j < argc; j++) { - if (Tcl_FSGetTranslatedPath(interp, argv[j]) == NULL) { + if (Tcl_FSGetNormalizedPath(interp, argv[j]) == NULL) { return TCL_ERROR; } } subcmd = Tcl_GetString(argv[1]); @@ -4642,12 +4655,23 @@ Tcl_DecrRefCount(pathPtr); if (ret != -1) { # define OUT_OF_RANGE(x) \ (((Tcl_WideInt)(x)) < Tcl_LongAsWide(LONG_MIN) || \ ((Tcl_WideInt)(x)) > Tcl_LongAsWide(LONG_MAX)) +#if defined(__GNUC__) && __GNUC__ >= 2 +/* + * Workaround gcc warning of "comparison is always false due to limited range of + * data type" in this macro by checking max type size, and when necessary ANDing + * with the complement of ULONG_MAX instead of the comparison: + */ +# define OUT_OF_URANGE(x) \ + ((((Tcl_WideUInt)(~ (__typeof__(x)) 0)) > (Tcl_WideUInt)ULONG_MAX) && \ + (((Tcl_WideUInt)(x)) & ~(Tcl_WideUInt)ULONG_MAX)) +#else # define OUT_OF_URANGE(x) \ (((Tcl_WideUInt)(x)) > (Tcl_WideUInt)ULONG_MAX) +#endif /* * Perform the result-buffer overflow check manually. * * Note that ino_t/ino64_t is unsigned... @@ -6089,20 +6113,25 @@ } static int TestReportMatchInDirectory(interp, resultPtr, dirPtr, pattern, types) Tcl_Interp *interp; /* Interpreter to receive results. */ - Tcl_Obj *resultPtr; /* Directory separators to pass to TclDoGlob. */ + Tcl_Obj *resultPtr; /* Object to lappend results. */ Tcl_Obj *dirPtr; /* Contains path to directory to search. */ CONST char *pattern; /* Pattern to match against. */ Tcl_GlobTypeData *types; /* Object containing list of acceptable types. * May be NULL. */ { - TestReport("matchindirectory",dirPtr, NULL); - return Tcl_FSMatchInDirectory(interp, resultPtr, - TestReportGetNativePath(dirPtr), pattern, - types); + if (types != NULL && types->type & TCL_GLOB_TYPE_MOUNT) { + TestReport("matchmounts",dirPtr, NULL); + return TCL_OK; + } else { + TestReport("matchindirectory",dirPtr, NULL); + return Tcl_FSMatchInDirectory(interp, resultPtr, + TestReportGetNativePath(dirPtr), pattern, + types); + } } static int TestReportChdir(dirName) Tcl_Obj *dirName; { @@ -6427,6 +6456,26 @@ retVal = Tcl_NewStringObj("simplefs:/",-1); Tcl_IncrRefCount(retVal); return retVal; } - + +/* + * Used to check correct string-length determining in Tcl_NumUtfChars + */ +static int +TestNumUtfCharsCmd(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +{ + if (objc > 1) { + int len = -1; + if (objc > 2) { + (void) Tcl_GetStringFromObj(objv[1], &len); + } + len = Tcl_NumUtfChars(Tcl_GetString(objv[1]), len); + Tcl_SetObjResult(interp, Tcl_NewIntObj(len)); + } + return TCL_OK; +} Index: generic/tclThread.c ================================================================== --- generic/tclThread.c +++ generic/tclThread.c @@ -7,11 +7,11 @@ * Copyright (c) 1998 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclThread.c,v 1.6 2002/12/10 00:34:15 hobbs Exp $ + * RCS: @(#) $Id: tclThread.c,v 1.6.2.1 2004/05/06 01:02:59 davygrvy Exp $ */ #include "tclInt.h" /* @@ -28,13 +28,13 @@ int num; /* Number of objects remembered */ int max; /* Max size of the array */ char **list; /* List of pointers */ } SyncObjRecord; -static SyncObjRecord keyRecord; -static SyncObjRecord mutexRecord; -static SyncObjRecord condRecord; +static SyncObjRecord keyRecord = {0, 0, NULL}; +static SyncObjRecord mutexRecord = {0, 0, NULL}; +static SyncObjRecord condRecord = {0, 0, NULL}; /* * Prototypes of functions used only in this file */ Index: generic/tclThreadAlloc.c ================================================================== --- generic/tclThreadAlloc.c +++ generic/tclThreadAlloc.c @@ -9,15 +9,16 @@ * Portions created by AOL are Copyright (C) 1999 America Online, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclThreadAlloc.c,v 1.4 2002/08/26 13:05:56 msofer Exp $ */ - -#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) + * RCS: @(#) $Id: tclThreadAlloc.c,v 1.4.2.7 2005/12/20 22:16:34 dkf Exp $ + */ #include "tclInt.h" + +#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG) #ifdef WIN32 #include "tclWinInt.h" #else extern Tcl_Mutex *TclpNewAllocMutex(void); @@ -87,16 +88,16 @@ * various accounting and statistics information. */ typedef struct Bucket { Block *firstPtr; - int nfree; - int nget; - int nput; - int nwait; - int nlock; - int nrequest; + long nfree; + long nget; + long nput; + long nwait; + long nlock; + long nrequest; } Bucket; /* * The following structure defines a cache of buckets and objs. */ @@ -274,15 +275,11 @@ nextPtrPtr = &(*nextPtrPtr)->nextPtr; } *nextPtrPtr = cachePtr->nextPtr; cachePtr->nextPtr = NULL; Tcl_MutexUnlock(listLockPtr); -#ifdef WIN32 - TlsFree((DWORD) cachePtr); -#else free(cachePtr); -#endif } /* *---------------------------------------------------------------------- @@ -638,12 +635,12 @@ } else { sprintf(buf, "thread%d", (int) cachePtr->owner); Tcl_DStringAppendElement(dsPtr, buf); } for (n = 0; n < NBUCKETS; ++n) { - sprintf(buf, "%d %d %d %d %d %d %d", - (int) binfo[n].blocksize, + sprintf(buf, "%lu %ld %ld %ld %ld %ld %ld", + (unsigned long) binfo[n].blocksize, cachePtr->buckets[n].nfree, cachePtr->buckets[n].nget, cachePtr->buckets[n].nput, cachePtr->buckets[n].nrequest, cachePtr->buckets[n].nlock, @@ -949,7 +946,67 @@ } blockPtr->b_next = NULL; } return 1; } + +/* + *---------------------------------------------------------------------- + * + * TclFinalizeThreadAlloc -- + * + * This procedure is used to destroy all private resources used in + * this file. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TclFinalizeThreadAlloc() +{ + int i; + for (i = 0; i < NBUCKETS; ++i) { + TclpFreeAllocMutex(binfo[i].lockPtr); + binfo[i].lockPtr = NULL; + } + + TclpFreeAllocMutex(objLockPtr); + objLockPtr = NULL; + + TclpFreeAllocMutex(listLockPtr); + listLockPtr = NULL; + + TclpFreeAllocCache(NULL); +} + +#else /* ! defined(TCL_THREADS) && ! defined(USE_THREAD_ALLOC) */ + +/* + *---------------------------------------------------------------------- + * + * TclFinalizeThreadAlloc -- + * + * This procedure is used to destroy all private resources used in + * this file. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TclFinalizeThreadAlloc() +{ + Tcl_Panic("TclFinalizeThreadAlloc called when threaded memory allocator not in use."); +} #endif /* TCL_THREADS */ Index: generic/tclThreadTest.c ================================================================== --- generic/tclThreadTest.c +++ generic/tclThreadTest.c @@ -9,11 +9,11 @@ * Copyright (c) 1998 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclThreadTest.c,v 1.16 2002/01/26 01:10:08 dgp Exp $ + * RCS: @(#) $Id: tclThreadTest.c,v 1.16.2.2 2006/09/22 14:48:52 dkf Exp $ */ #include "tclInt.h" #ifdef TCL_THREADS @@ -419,11 +419,11 @@ Tcl_MutexLock(&threadMutex); if (Tcl_CreateThread(&id, NewTestThread, (ClientData) &ctrl, TCL_THREAD_STACK_DEFAULT, joinable) != TCL_OK) { Tcl_MutexUnlock(&threadMutex); - Tcl_AppendResult(interp,"can't create a new thread",0); + Tcl_AppendResult(interp,"can't create a new thread",NULL); ckfree((void*)ctrl.script); return TCL_ERROR; } /* @@ -866,17 +866,17 @@ Tcl_CreateThreadExitHandler(ThreadFreeProc, (ClientData) threadEventPtr->script); code = Tcl_GlobalEval(interp, threadEventPtr->script); Tcl_DeleteThreadExitHandler(ThreadFreeProc, (ClientData) threadEventPtr->script); - result = Tcl_GetStringResult(interp); if (code != TCL_OK) { errorCode = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY); errorInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); } else { errorCode = errorInfo = NULL; } + result = Tcl_GetStringResult(interp); } ckfree(threadEventPtr->script); if (resultPtr) { Tcl_MutexLock(&threadMutex); resultPtr->code = code; Index: generic/tclTimer.c ================================================================== --- generic/tclTimer.c +++ generic/tclTimer.c @@ -7,11 +7,11 @@ * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclTimer.c,v 1.6 2002/03/01 06:22:31 hobbs Exp $ + * RCS: @(#) $Id: tclTimer.c,v 1.6.2.4 2005/11/09 21:46:20 kennykb Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -301,13 +301,16 @@ Tcl_DeleteTimerHandler(token) Tcl_TimerToken token; /* Result previously returned by * Tcl_DeleteTimerHandler. */ { register TimerHandler *timerHandlerPtr, *prevPtr; - ThreadSpecificData *tsdPtr; + ThreadSpecificData *tsdPtr = InitTimer(); - tsdPtr = InitTimer(); + if (token == NULL) { + return; + } + for (timerHandlerPtr = tsdPtr->firstTimerHandlerPtr, prevPtr = NULL; timerHandlerPtr != NULL; prevPtr = timerHandlerPtr, timerHandlerPtr = timerHandlerPtr->nextPtr) { if (timerHandlerPtr->token != token) { continue; @@ -730,21 +733,18 @@ */ /* ARGSUSED */ int Tcl_AfterObjCmd(clientData, interp, objc, objv) - ClientData clientData; /* Points to the "tclAfter" assocData for - * this interpreter, or NULL if the assocData - * hasn't been created yet.*/ + ClientData clientData; /* Unused */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int ms; AfterInfo *afterPtr; - AfterAssocData *assocPtr = (AfterAssocData *) clientData; - Tcl_CmdInfo cmdInfo; + AfterAssocData *assocPtr; int length; char *argString; int index; char buf[16 + TCL_INTEGER_SPACE]; static CONST char *afterSubCmds[] = { @@ -758,29 +758,20 @@ return TCL_ERROR; } /* * Create the "after" information associated for this interpreter, - * if it doesn't already exist. Associate it with the command too, - * so that it will be passed in as the ClientData argument in the - * future. + * if it doesn't already exist. */ + assocPtr = Tcl_GetAssocData( interp, "tclAfter", NULL ); if (assocPtr == NULL) { assocPtr = (AfterAssocData *) ckalloc(sizeof(AfterAssocData)); assocPtr->interp = interp; assocPtr->firstAfterPtr = NULL; Tcl_SetAssocData(interp, "tclAfter", AfterCleanupProc, (ClientData) assocPtr); - cmdInfo.proc = NULL; - cmdInfo.clientData = (ClientData) NULL; - cmdInfo.objProc = Tcl_AfterObjCmd; - cmdInfo.objClientData = (ClientData) assocPtr; - cmdInfo.deleteProc = NULL; - cmdInfo.deleteData = (ClientData) assocPtr; - Tcl_SetCommandInfo(interp, Tcl_GetStringFromObj(objv[0], &length), - &cmdInfo); } /* * First lets see if the command was passed a number as the first argument. */ @@ -788,11 +779,12 @@ if (objv[1]->typePtr == &tclIntType) { ms = (int) objv[1]->internalRep.longValue; goto processInteger; } argString = Tcl_GetStringFromObj(objv[1], &length); - if (isdigit(UCHAR(argString[0]))) { /* INTL: digit */ + if (argString[0] == '+' || argString[0] == '-' + || isdigit(UCHAR(argString[0]))) { /* INTL: digit */ if (Tcl_GetIntFromObj(interp, objv[1], &ms) != TCL_OK) { return TCL_ERROR; } processInteger: if (ms < 0) { Index: generic/tclUtf.c ================================================================== --- generic/tclUtf.c +++ generic/tclUtf.c @@ -6,11 +6,11 @@ * Copyright (c) 1997-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUtf.c,v 1.30 2003/02/18 02:25:45 hobbs Exp $ + * RCS: @(#) $Id: tclUtf.c,v 1.30.2.3 2005/09/07 14:35:56 dgp Exp $ */ #include "tclInt.h" /* @@ -167,49 +167,51 @@ { if ((ch > 0) && (ch < UNICODE_SELF)) { str[0] = (char) ch; return 1; } - if (ch <= 0x7FF) { - str[1] = (char) ((ch | 0x80) & 0xBF); - str[0] = (char) ((ch >> 6) | 0xC0); - return 2; - } - if (ch <= 0xFFFF) { + if (ch >= 0) { + if (ch <= 0x7FF) { + str[1] = (char) ((ch | 0x80) & 0xBF); + str[0] = (char) ((ch >> 6) | 0xC0); + return 2; + } + if (ch <= 0xFFFF) { three: - str[2] = (char) ((ch | 0x80) & 0xBF); - str[1] = (char) (((ch >> 6) | 0x80) & 0xBF); - str[0] = (char) ((ch >> 12) | 0xE0); - return 3; - } + str[2] = (char) ((ch | 0x80) & 0xBF); + str[1] = (char) (((ch >> 6) | 0x80) & 0xBF); + str[0] = (char) ((ch >> 12) | 0xE0); + return 3; + } #if TCL_UTF_MAX > 3 - if (ch <= 0x1FFFFF) { - str[3] = (char) ((ch | 0x80) & 0xBF); - str[2] = (char) (((ch >> 6) | 0x80) & 0xBF); - str[1] = (char) (((ch >> 12) | 0x80) & 0xBF); - str[0] = (char) ((ch >> 18) | 0xF0); - return 4; - } - if (ch <= 0x3FFFFFF) { - str[4] = (char) ((ch | 0x80) & 0xBF); - str[3] = (char) (((ch >> 6) | 0x80) & 0xBF); - str[2] = (char) (((ch >> 12) | 0x80) & 0xBF); - str[1] = (char) (((ch >> 18) | 0x80) & 0xBF); - str[0] = (char) ((ch >> 24) | 0xF8); - return 5; - } - if (ch <= 0x7FFFFFFF) { - str[5] = (char) ((ch | 0x80) & 0xBF); - str[4] = (char) (((ch >> 6) | 0x80) & 0xBF); - str[3] = (char) (((ch >> 12) | 0x80) & 0xBF); - str[2] = (char) (((ch >> 18) | 0x80) & 0xBF); - str[1] = (char) (((ch >> 24) | 0x80) & 0xBF); - str[0] = (char) ((ch >> 30) | 0xFC); - return 6; - } + if (ch <= 0x1FFFFF) { + str[3] = (char) ((ch | 0x80) & 0xBF); + str[2] = (char) (((ch >> 6) | 0x80) & 0xBF); + str[1] = (char) (((ch >> 12) | 0x80) & 0xBF); + str[0] = (char) ((ch >> 18) | 0xF0); + return 4; + } + if (ch <= 0x3FFFFFF) { + str[4] = (char) ((ch | 0x80) & 0xBF); + str[3] = (char) (((ch >> 6) | 0x80) & 0xBF); + str[2] = (char) (((ch >> 12) | 0x80) & 0xBF); + str[1] = (char) (((ch >> 18) | 0x80) & 0xBF); + str[0] = (char) ((ch >> 24) | 0xF8); + return 5; + } + if (ch <= 0x7FFFFFFF) { + str[5] = (char) ((ch | 0x80) & 0xBF); + str[4] = (char) (((ch >> 6) | 0x80) & 0xBF); + str[3] = (char) (((ch >> 12) | 0x80) & 0xBF); + str[2] = (char) (((ch >> 18) | 0x80) & 0xBF); + str[1] = (char) (((ch >> 24) | 0x80) & 0xBF); + str[0] = (char) ((ch >> 30) | 0xFC); + return 6; + } #endif + } ch = 0xFFFD; goto three; } @@ -499,15 +501,12 @@ * the single-byte char case specially. */ i = 0; if (len < 0) { - while (1) { + while (*str != '\0') { str += TclUtfToUniChar(str, chPtr); - if (ch == '\0') { - break; - } i++; } } else { register int n; @@ -1292,13 +1291,16 @@ CONST Tcl_UniChar *cs; /* Unicode string to compare to ct. */ CONST Tcl_UniChar *ct; /* Unicode string cs is compared to. */ unsigned long n; /* Number of unichars to compare. */ { for ( ; n != 0; n--, cs++, ct++) { - if ((*cs != *ct) && - (Tcl_UniCharToLower(*cs) != Tcl_UniCharToLower(*ct))) { - return (*cs - *ct); + if (*cs != *ct) { + Tcl_UniChar lcs = Tcl_UniCharToLower(*cs); + Tcl_UniChar lct = Tcl_UniCharToLower(*ct); + if (lcs != lct) { + return (lcs - lct); + } } } return 0; } Index: generic/tclUtil.c ================================================================== --- generic/tclUtil.c +++ generic/tclUtil.c @@ -9,11 +9,11 @@ * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUtil.c,v 1.36 2002/11/19 02:34:50 hobbs Exp $ + * RCS: @(#) $Id: tclUtil.c,v 1.36.2.8 2007/05/10 18:23:58 dgp Exp $ */ #include "tclInt.h" #include "tclPort.h" @@ -434,19 +434,30 @@ * space for both the array of pointers and also for a copy of * the list. To estimate the number of pointers needed, count * the number of space characters in the list. */ - for (size = 1, l = list; *l != 0; l++) { + for (size = 2, l = list; *l != 0; l++) { if (isspace(UCHAR(*l))) { /* INTL: ISO space. */ size++; + /* Consecutive space can only count as a single list delimiter */ + while (1) { + char next = *(l + 1); + if (next == '\0') { + break; + } + ++l; + if (isspace(UCHAR(next))) { + continue; + } + break; + } } } - size++; /* Leave space for final NULL pointer. */ + length = l - list; argv = (CONST char **) ckalloc((unsigned) - ((size * sizeof(char *)) + (l - list) + 1)); - length = strlen(list); + ((size * sizeof(char *)) + length + 1)); for (i = 0, p = ((char *) argv) + size*sizeof(char *); *list != 0; i++) { CONST char *prevList = list; result = TclFindElement(interp, list, length, &element, @@ -1393,10 +1404,47 @@ } /* *---------------------------------------------------------------------- * + * TclMatchIsTrivial -- + * + * Test whether a particular glob pattern is a trivial pattern. + * (i.e. where matching is the same as equality testing). + * + * Results: + * A boolean indicating whether the pattern is free of all of the + * glob special chars. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclMatchIsTrivial(pattern) + CONST char *pattern; +{ + CONST char *p = pattern; + + while (1) { + switch (*p++) { + case '\0': + return 1; + case '*': + case '?': + case '[': + case '\\': + return 0; + } + } +} + +/* + *---------------------------------------------------------------------- + * * Tcl_DStringInit -- * * Initializes a dynamic string, discarding any previous contents * of the string (Tcl_DStringFree should have been called already * if the dynamic string was previously in use). @@ -1742,12 +1790,11 @@ TCL_VOLATILE); } dsPtr->length = strlen(iPtr->result); if (iPtr->freeProc != NULL) { - if ((iPtr->freeProc == TCL_DYNAMIC) - || (iPtr->freeProc == (Tcl_FreeProc *) free)) { + if (iPtr->freeProc == TCL_DYNAMIC) { dsPtr->string = iPtr->result; dsPtr->spaceAvl = dsPtr->length+1; } else { dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length+1)); strcpy(dsPtr->string, iPtr->result); @@ -1921,11 +1968,11 @@ /* * If the variable is unset, then recreate the trace. */ if (flags & TCL_TRACE_UNSETS) { - if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { + if ((flags & TCL_TRACE_DESTROYED) && !Tcl_InterpDeleted(interp)) { Tcl_TraceVar2(interp, name1, name2, TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES |TCL_TRACE_UNSETS, TclPrecTraceProc, clientData); } return (char *) NULL; @@ -2000,46 +2047,68 @@ TclNeedSpace(start, end) CONST char *start; /* First character in string. */ CONST char *end; /* End of string (place where space will * be added, if appropriate). */ { - Tcl_UniChar ch; - - /* - * A space is needed unless either - * (a) we're at the start of the string, or - * (b) the trailing characters of the string consist of one or more - * open curly braces preceded by a space or extending back to - * the beginning of the string. - * (c) the trailing characters of the string consist of a space - * preceded by a character other than backslash. - */ - - if (end == start) { - return 0; - } - end = Tcl_UtfPrev(end, start); - if (*end != '{') { - Tcl_UtfToUniChar(end, &ch); - /* - * Direct char comparison on next line is safe as it is with - * a character in the ASCII subset, and so single-byte in UTF8. - */ - if (Tcl_UniCharIsSpace(ch) && ((end == start) || (end[-1] != '\\'))) { - return 0; - } - return 1; - } - do { - if (end == start) { - return 0; - } - end = Tcl_UtfPrev(end, start); - } while (*end == '{'); - Tcl_UtfToUniChar(end, &ch); - if (Tcl_UniCharIsSpace(ch)) { - return 0; + /* + * A space is needed unless either + * (a) we're at the start of the string, or + */ + if (end == start) { + return 0; + } + + /* + * (b) we're at the start of a nested list-element, quoted with an + * open curly brace; we can be nested arbitrarily deep, so long + * as the first curly brace starts an element, so backtrack over + * open curly braces that are trailing characters of the string; and + */ + + end = Tcl_UtfPrev(end, start); + while (*end == '{') { + if (end == start) { + return 0; + } + end = Tcl_UtfPrev(end, start); + } + + /* + * (c) the trailing character of the string is already a list-element + * separator (according to TclFindElement); that is, one of these + * characters: + * \u0009 \t TAB + * \u000A \n NEWLINE + * \u000B \v VERTICAL TAB + * \u000C \f FORM FEED + * \u000D \r CARRIAGE RETURN + * \u0020 SPACE + * with the condition that the penultimate character is not a + * backslash. + */ + + if (*end > 0x20) { + /* + * Performance tweak. All ASCII spaces are <= 0x20. So get + * a quick answer for most characters before comparing against + * all spaces in the switch below. + * + * NOTE: Remove this if other Unicode spaces ever get accepted + * as list-element separators. + */ + return 1; + } + switch (*end) { + case ' ': + case '\t': + case '\n': + case '\r': + case '\v': + case '\f': + if ((end == start) || (end[-1] != '\\')) { + return 0; + } } return 1; } /* @@ -2216,83 +2285,29 @@ int endValue; /* The value to be stored at "indexPtr" if * "objPtr" holds "end". */ int *indexPtr; /* Location filled in with an integer * representing an index. */ { - char *bytes; - int offset; -#ifndef TCL_WIDE_INT_IS_LONG - Tcl_WideInt wideOffset; -#endif - - /* - * If the object is already an integer, use it. - */ - - if (objPtr->typePtr == &tclIntType) { - *indexPtr = (int)objPtr->internalRep.longValue; - return TCL_OK; - } - - /* - * If the object is already a wide-int, and it is not out of range - * for an integer, use it. [Bug #526717] - */ -#ifndef TCL_WIDE_INT_IS_LONG - if (objPtr->typePtr == &tclWideIntType) { - Tcl_WideInt wideOffset = objPtr->internalRep.wideValue; - if (wideOffset >= Tcl_LongAsWide(INT_MIN) - && wideOffset <= Tcl_LongAsWide(INT_MAX)) { - *indexPtr = (int) Tcl_WideAsLong(wideOffset); - return TCL_OK; - } - } -#endif /* TCL_WIDE_INT_IS_LONG */ + if (Tcl_GetIntFromObj(NULL, objPtr, indexPtr) == TCL_OK) { + return TCL_OK; + } if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) { /* * If the object is already an offset from the end of the * list, or can be converted to one, use it. */ *indexPtr = endValue + objPtr->internalRep.longValue; -#ifdef TCL_WIDE_INT_IS_LONG - } else if (Tcl_GetIntFromObj(NULL, objPtr, &offset) == TCL_OK) { - /* - * If the object can be converted to an integer, use that. - */ - - *indexPtr = offset; - -#else /* !TCL_WIDE_INT_IS_LONG */ - } else if (Tcl_GetWideIntFromObj(NULL, objPtr, &wideOffset) == TCL_OK) { - /* - * If the object can be converted to a wide integer, use - * that. [Bug #526717] - */ - - offset = (int) Tcl_WideAsLong(wideOffset); - if (Tcl_LongAsWide(offset) == wideOffset) { - /* - * But it is representable as a narrow integer, so we - * prefer that (so preserving old behaviour in the - * majority of cases.) - */ - objPtr->typePtr = &tclIntType; - objPtr->internalRep.longValue = offset; - } - *indexPtr = offset; - -#endif /* TCL_WIDE_INT_IS_LONG */ } else { /* * Report a parse error. */ if (interp != NULL) { - bytes = Tcl_GetString(objPtr); + char *bytes = Tcl_GetString(objPtr); /* * 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. */ Index: generic/tclVar.c ================================================================== --- generic/tclVar.c +++ generic/tclVar.c @@ -13,15 +13,16 @@ * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclVar.c,v 1.69 2002/11/12 02:23:03 hobbs Exp $ + * RCS: @(#) $Id: tclVar.c,v 1.69.2.14 2007/05/10 18:23:58 dgp Exp $ */ #include "tclInt.h" #include "tclPort.h" + /* * The strings below are used to indicate what went wrong when a * variable access is denied. */ @@ -53,21 +54,23 @@ static void DisposeTraceResult _ANSI_ARGS_((int flags, char *result)); static int ObjMakeUpvar _ANSI_ARGS_((Tcl_Interp *interp, CallFrame *framePtr, Tcl_Obj *otherP1Ptr, CONST char *otherP2, CONST int otherFlags, - CONST char *myName, CONST int myFlags, int index)); + CONST char *myName, int myFlags, int index)); static Var * NewVar _ANSI_ARGS_((void)); static ArraySearch * ParseSearchId _ANSI_ARGS_((Tcl_Interp *interp, CONST Var *varPtr, CONST char *varName, Tcl_Obj *handleObj)); static void VarErrMsg _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, CONST char *operation, CONST char *reason)); static int SetArraySearchObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); - +static void UnsetVarStruct _ANSI_ARGS_((Var *varPtr, Var *arrayPtr, + Interp *iPtr, CONST char *part1, CONST char *part2, + int flags)); /* * Functions defined in this file that may be exported in the future * for use by the bytecode compiler and engine or to the public interface. */ @@ -106,21 +109,21 @@ * twoPtrValue.ptr2 = pointer to the element name string * (owned by this Tcl_Obj), or NULL if * it is a scalar variable */ -Tcl_ObjType tclLocalVarNameType = { +static Tcl_ObjType tclLocalVarNameType = { "localVarName", FreeLocalVarName, DupLocalVarName, UpdateLocalVarName, NULL }; -Tcl_ObjType tclNsVarNameType = { +static Tcl_ObjType tclNsVarNameType = { "namespaceVarName", FreeNsVarName, DupNsVarName, NULL, NULL }; -Tcl_ObjType tclParsedVarNameType = { +static Tcl_ObjType tclParsedVarNameType = { "parsedVarName", FreeParsedVarName, DupParsedVarName, UpdateParsedVarName, NULL }; /* @@ -548,18 +551,30 @@ part1Ptr->typePtr = &tclLocalVarNameType; procPtr->refCount++; part1Ptr->internalRep.twoPtrValue.ptr1 = (VOID *) procPtr; part1Ptr->internalRep.twoPtrValue.ptr2 = (VOID *) index; +#if 0 + /* + * TEMPORARYLY DISABLED tclNsVarNameType + * + * This optimisation will hopefully be turned back on soon. + * Miguel Sofer, 2004-05-22 + */ + } else if (index > -3) { + /* + * A cacheable namespace or global variable. + */ Namespace *nsPtr; nsPtr = ((index == -1)? iPtr->globalNsPtr : varFramePtr->nsPtr); varPtr->refCount++; part1Ptr->typePtr = &tclNsVarNameType; part1Ptr->internalRep.twoPtrValue.ptr1 = (VOID *) nsPtr; part1Ptr->internalRep.twoPtrValue.ptr2 = (VOID *) varPtr; +#endif } else { /* * At least mark part1Ptr as already parsed. */ part1Ptr->typePtr = &tclParsedVarNameType; @@ -593,10 +608,20 @@ flags, msg, createPart1, createPart2, varPtr); } return varPtr; } +/* + * This flag bit should not interfere with TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, + * or TCL_LEAVE_ERR_MSG; it signals that the variable lookup is performed for + * upvar (or similar) purposes, with slightly different rules: + * - Bug #696893 - variable is either proc-local or in the current + * namespace; never follow the second (global) resolution path + * - Bug #631741 - do not use special namespace or interp resolvers + */ +#define LOOKUP_FOR_UPVAR 0x40000 + /* *---------------------------------------------------------------------- * * TclLookupSimpleVar -- * @@ -640,11 +665,12 @@ TclLookupSimpleVar(interp, varName, flags, create, errMsgPtr, indexPtr) Tcl_Interp *interp; /* Interpreter to use for lookup. */ CONST char *varName; /* This is a simple variable name that could * representa scalar or an array. */ int flags; /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, - * and TCL_LEAVE_ERR_MSG bits matter. */ + * LOOKUP_FOR_UPVAR and TCL_LEAVE_ERR_MSG bits + * matter. */ CONST int create; /* If 1, create hash table entry for varname, * if it doesn't already exist. If 0, return * error if it doesn't exist. */ CONST char **errMsgPtr; int *indexPtr; @@ -666,24 +692,26 @@ int new, i, result; varPtr = NULL; varNsPtr = NULL; /* set non-NULL if a nonlocal variable */ *indexPtr = -3; + + if ((flags & TCL_GLOBAL_ONLY) || iPtr->varFramePtr == NULL) { + cxtNsPtr = iPtr->globalNsPtr; + } else { + cxtNsPtr = iPtr->varFramePtr->nsPtr; + } /* * If this namespace has a variable resolver, then give it first * crack at the variable resolution. It may return a Tcl_Var * value, it may signal to continue onward, or it may signal * an error. */ - if ((flags & TCL_GLOBAL_ONLY) || iPtr->varFramePtr == NULL) { - cxtNsPtr = iPtr->globalNsPtr; - } else { - cxtNsPtr = iPtr->varFramePtr->nsPtr; - } - if (cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) { + if ((cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) + && !(flags & LOOKUP_FOR_UPVAR)) { resPtr = iPtr->resolverPtr; if (cxtNsPtr->varResProc) { result = (*cxtNsPtr->varResProc)(interp, varName, (Tcl_Namespace *) cxtNsPtr, flags, &var); @@ -734,14 +762,19 @@ lookGlobal = (flags & TCL_GLOBAL_ONLY) || (cxtNsPtr == iPtr->globalNsPtr) || ((*varName == ':') && (*(varName+1) == ':')); if (lookGlobal) { *indexPtr = -1; - flags = (flags | TCL_GLOBAL_ONLY) & ~TCL_NAMESPACE_ONLY; - } else if (flags & TCL_NAMESPACE_ONLY) { - *indexPtr = -2; - } + flags = (flags | TCL_GLOBAL_ONLY) & ~(TCL_NAMESPACE_ONLY|LOOKUP_FOR_UPVAR); + } else { + if (flags & LOOKUP_FOR_UPVAR) { + flags = (flags | TCL_NAMESPACE_ONLY) & ~LOOKUP_FOR_UPVAR; + } + if (flags & TCL_NAMESPACE_ONLY) { + *indexPtr = -2; + } + } /* * Don't pass TCL_LEAVE_ERR_MSG, we may yet create the variable, * or otherwise generate our own error! */ @@ -1065,18 +1098,14 @@ int flags; /* OR-ed combination of TCL_GLOBAL_ONLY, * and TCL_LEAVE_ERR_MSG bits. */ { Var *varPtr, *arrayPtr; - /* - * We need a special flag check to see if we want to create part 1, - * because commands like lappend require read traces to trigger for - * previously non-existent values. - */ + /* Filter to pass through only the flags this interface supports. */ + flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); varPtr = TclLookupVar(interp, part1, part2, flags, "read", - /*createPart1*/ (flags & TCL_TRACE_READS), - /*createPart2*/ 1, &arrayPtr); + /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } return TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags); @@ -1122,18 +1151,14 @@ char *part1, *part2; part1 = Tcl_GetString(part1Ptr); part2 = ((part2Ptr == NULL) ? NULL : Tcl_GetString(part2Ptr)); - /* - * We need a special flag check to see if we want to create part 1, - * because commands like lappend require read traces to trigger for - * previously non-existent values. - */ + /* Filter to pass through only the flags this interface supports. */ + flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "read", - /*createPart1*/ (flags & TCL_TRACE_READS), - /*createPart2*/ 1, &arrayPtr); + /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } return TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags); @@ -1425,10 +1450,13 @@ * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE, * TCL_LIST_ELEMENT or TCL_LEAVE_ERR_MSG. */ { Var *varPtr, *arrayPtr; + /* Filter to pass through only the flags this interface supports. */ + flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG + |TCL_APPEND_VALUE|TCL_LIST_ELEMENT); varPtr = TclLookupVar(interp, part1, part2, flags, "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } @@ -1481,10 +1509,13 @@ char *part1, *part2; part1 = TclGetString(part1Ptr); part2 = ((part2Ptr == NULL) ? NULL : Tcl_GetString(part2Ptr)); + /* Filter to pass through only the flags this interface supports. */ + flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG + |TCL_APPEND_VALUE|TCL_LIST_ELEMENT); varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } @@ -1529,11 +1560,11 @@ CONST char *part1; /* Name of an array (if part2 is non-NULL) * or the name of a variable. */ CONST char *part2; /* If non-NULL, gives the name of an element * in the array part1. */ Tcl_Obj *newValuePtr; /* New value for variable. */ - CONST int flags; /* OR-ed combination of TCL_GLOBAL_ONLY, + CONST int flags; /* OR-ed combination of TCL_GLOBAL_ONLY, * and TCL_LEAVE_ERR_MSG bits. */ { Interp *iPtr = (Interp *) interp; Tcl_Obj *oldValuePtr; Tcl_Obj *resultPtr = NULL; @@ -1569,11 +1600,12 @@ return NULL; } /* * Invoke any read traces that have been set for the variable if it - * is requested; this is only done in the core when lappending. + * is requested; this is only done in the core by the INST_LAPPEND_* + * instructions. */ if ((flags & TCL_TRACE_READS) && ((varPtr->tracePtr != NULL) || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL)))) { if (TCL_ERROR == CallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, @@ -1588,12 +1620,15 @@ * appending, then if the variable's old value is unshared we can modify * it directly, otherwise we must create a new copy to modify: this is * "copy on write". */ + if (flags & TCL_LIST_ELEMENT && !(flags & TCL_APPEND_VALUE)) { + TclSetVarUndefined(varPtr); + } oldValuePtr = varPtr->value.objPtr; - if (flags & TCL_APPEND_VALUE) { + if (flags & (TCL_APPEND_VALUE|TCL_LIST_ELEMENT)) { if (TclIsVarUndefined(varPtr) && (oldValuePtr != NULL)) { Tcl_DecrRefCount(oldValuePtr); /* discard old value */ varPtr->value.objPtr = NULL; oldValuePtr = NULL; } @@ -1818,21 +1853,13 @@ createdNewObj = 0; if (Tcl_IsShared(varValuePtr)) { varValuePtr = Tcl_DuplicateObj(varValuePtr); createdNewObj = 1; } -#ifdef TCL_WIDE_INT_IS_LONG - if (Tcl_GetLongFromObj(interp, varValuePtr, &i) != TCL_OK) { - if (createdNewObj) { - Tcl_DecrRefCount(varValuePtr); /* free unneeded copy */ - } - return NULL; - } - Tcl_SetLongObj(varValuePtr, (i + incrAmount)); -#else if (varValuePtr->typePtr == &tclWideIntType) { - Tcl_WideInt wide = varValuePtr->internalRep.wideValue; + Tcl_WideInt wide; + TclGetWide(wide,varValuePtr); Tcl_SetWideIntObj(varValuePtr, wide + Tcl_LongAsWide(incrAmount)); } else if (varValuePtr->typePtr == &tclIntType) { i = varValuePtr->internalRep.longValue; Tcl_SetIntObj(varValuePtr, i + incrAmount); } else { @@ -1851,11 +1878,10 @@ Tcl_SetLongObj(varValuePtr, Tcl_WideAsLong(wide) + incrAmount); } else { Tcl_SetWideIntObj(varValuePtr, wide + Tcl_LongAsWide(incrAmount)); } } -#endif /* * Store the variable's new value and run any write traces. */ @@ -1931,10 +1957,12 @@ int result; Tcl_Obj *part1Ptr; part1Ptr = Tcl_NewStringObj(part1, -1); Tcl_IncrRefCount(part1Ptr); + /* Filter to pass through only the flags this interface supports. */ + flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); result = TclObjUnsetVar2(interp, part1Ptr, part2, flags); TclDecrRefCount(part1Ptr); return result; } @@ -1969,16 +1997,13 @@ CONST char *part2; /* Name of element within array or NULL. */ int flags; /* OR-ed combination of any of * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, * TCL_LEAVE_ERR_MSG. */ { - Var dummyVar; - Var *varPtr, *dummyVarPtr; + Var *varPtr; Interp *iPtr = (Interp *) interp; Var *arrayPtr; - ActiveVarTrace *activePtr; - Tcl_Obj *objPtr; int result; char *part1; part1 = TclGetString(part1Ptr); varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "unset", @@ -1987,13 +2012,108 @@ return TCL_ERROR; } result = (TclIsVarUndefined(varPtr)? TCL_ERROR : TCL_OK); + /* + * Keep the variable alive until we're done with it. We used to + * increase/decrease the refCount for each operation, making it + * hard to find [Bug 735335] - caused by unsetting the variable + * whose value was the variable's name. + */ + + varPtr->refCount++; + + UnsetVarStruct(varPtr, arrayPtr, iPtr, part1, part2, flags); + + /* + * It's an error to unset an undefined variable. + */ + + if (result != TCL_OK) { + if (flags & TCL_LEAVE_ERR_MSG) { + VarErrMsg(interp, part1, part2, "unset", + ((arrayPtr == NULL) ? noSuchVar : noSuchElement)); + } + } + + /* + * Try to avoid keeping the Var struct allocated due to a tclNsVarNameType + * keeping a reference. This removes some additional exteriorisations of + * [Bug 736729], but may be a good thing independently of the bug. + */ + + if (part1Ptr->typePtr == &tclNsVarNameType) { + part1Ptr->typePtr->freeIntRepProc(part1Ptr); + part1Ptr->typePtr = NULL; + } + + /* + * Finally, if the variable is truly not in use then free up its Var + * structure and remove it from its hash table, if any. The ref count of + * its value object, if any, was decremented above. + */ + + varPtr->refCount--; + CleanupVar(varPtr, arrayPtr); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * UnsetVarStruct -- + * + * Unset and delete a variable. This does the internal work for + * TclObjUnsetVar2 and TclDeleteNamespaceVars, which call here for each + * variable to be unset and deleted. + * + * Results: + * None. + * + * Side effects: + * If the arguments indicate a local or global variable in iPtr, it is + * unset and deleted. + * + *---------------------------------------------------------------------- + */ + +static void +UnsetVarStruct(varPtr, arrayPtr, iPtr, part1, part2, flags) + Var *varPtr; + Var *arrayPtr; + Interp *iPtr; + CONST char *part1; + CONST char *part2; + int flags; +{ + Var dummyVar; + Var *dummyVarPtr; + ActiveVarTrace *activePtr; + if ((arrayPtr != NULL) && (arrayPtr->searchPtr != NULL)) { DeleteSearches(arrayPtr); } + + /* + * For global/upvar variables referenced in procedures, decrement + * the reference count on the variable referred to, and free + * the referenced variable if it's no longer needed. + */ + + if (TclIsVarLink(varPtr)) { + Var *linkPtr = varPtr->value.linkPtr; + linkPtr->refCount--; + if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr) + && (linkPtr->tracePtr == NULL) + && (linkPtr->flags & VAR_IN_HASHTABLE)) { + if (linkPtr->hPtr != NULL) { + Tcl_DeleteHashEntry(linkPtr->hPtr); + } + ckfree((char *) linkPtr); + } + } /* * The code below is tricky, because of the possibility that * a trace procedure might try to access a variable being * deleted. To handle this situation gracefully, do things @@ -2023,11 +2143,10 @@ * call unset traces even if other traces are pending. */ if ((dummyVar.tracePtr != NULL) || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) { - varPtr->refCount++; dummyVar.flags &= ~VAR_TRACE_ACTIVE; CallVarTraces(iPtr, arrayPtr, &dummyVar, part1, part2, (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS, /* leaveErrMsg */ 0); while (dummyVar.tracePtr != NULL) { @@ -2039,11 +2158,10 @@ activePtr = activePtr->nextPtr) { if (activePtr->varPtr == varPtr) { activePtr->nextTracePtr = NULL; } } - varPtr->refCount--; } /* * If the variable is an array, delete all of its elements. This must be * done after calling the traces on the array, above (that's the way @@ -2051,32 +2169,16 @@ * (decrement the ref count of its object, if any). */ dummyVarPtr = &dummyVar; if (TclIsVarArray(dummyVarPtr) && !TclIsVarUndefined(dummyVarPtr)) { - /* - * Deleting the elements of the array may cause traces to be fired - * on those elements. Before deleting them, bump the reference count - * of the array, so that if those trace procs make a global or upvar - * link to the array, the array is not deleted when the call stack - * gets popped (we will delete the array ourselves later in this - * function). - * - * Bumping the count can lead to the odd situation that elements of the - * array are being deleted when the array still exists, but since the - * array is about to be removed anyway, that shouldn't really matter. - */ - varPtr->refCount++; - DeleteArray(iPtr, part1, dummyVarPtr, - (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) - | TCL_TRACE_UNSETS); - /* Decr ref count */ - varPtr->refCount--; + DeleteArray(iPtr, part1, dummyVarPtr, (flags + & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS); } if (TclIsVarScalar(dummyVarPtr) && (dummyVarPtr->value.objPtr != NULL)) { - objPtr = dummyVarPtr->value.objPtr; + Tcl_Obj *objPtr = dummyVarPtr->value.objPtr; TclDecrRefCount(objPtr); dummyVarPtr->value.objPtr = NULL; } /* @@ -2086,29 +2188,10 @@ if (varPtr->flags & VAR_NAMESPACE_VAR) { varPtr->flags &= ~VAR_NAMESPACE_VAR; varPtr->refCount--; } - /* - * It's an error to unset an undefined variable. - */ - - if (result != TCL_OK) { - if (flags & TCL_LEAVE_ERR_MSG) { - VarErrMsg(interp, part1, part2, "unset", - ((arrayPtr == NULL) ? noSuchVar : noSuchElement)); - } - } - - /* - * Finally, if the variable is truly not in use then free up its Var - * structure and remove it from its hash table, if any. The ref count of - * its value object, if any, was decremented above. - */ - - CleanupVar(varPtr, arrayPtr); - return result; } /* *---------------------------------------------------------------------- * @@ -2642,11 +2725,11 @@ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Obj *varValuePtr, *newValuePtr; register List *listRepPtr; register Tcl_Obj **elemPtrs; - int numElems, numRequired, createdNewObj, createVar, i, j; + int numElems, numRequired, createdNewObj, i, j; Var *varPtr, *arrayPtr; char *part1; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "varName ?value value ...?"); @@ -2659,35 +2742,35 @@ * The variable doesn't exist yet. Just create it with an empty * initial value. */ varValuePtr = Tcl_NewObj(); + Tcl_IncrRefCount(varValuePtr); newValuePtr = Tcl_ObjSetVar2(interp, objv[1], NULL, varValuePtr, TCL_LEAVE_ERR_MSG); + Tcl_DecrRefCount(varValuePtr); if (newValuePtr == NULL) { - Tcl_DecrRefCount(varValuePtr); /* free unneeded object */ return TCL_ERROR; } - } + } else { + int result; + + result = Tcl_ListObjLength(interp, newValuePtr, &numElems); + if (result != TCL_OK) { + return result; + } + } } else { /* * We have arguments to append. We used to call Tcl_SetVar2 to * append each argument one at a time to ensure that traces were run * for each append step. We now append the arguments all at once * because it's faster. Note that a read trace and a write trace for * the variable will now each only be called once. Also, if the * variable's old value is unshared we modify it directly, otherwise * we create a new copy to modify: this is "copy on write". - */ - - createdNewObj = 0; - createVar = 1; - - /* - * Use the TCL_TRACE_READS flag to ensure that if we have an - * array with no elements set yet, but with a read trace on it, - * we will create the variable and get read traces triggered. + * * Note that you have to protect the variable pointers around * the TclPtrGetVar call to insure that they remain valid * even if the variable was undefined and unused. */ @@ -2700,24 +2783,24 @@ if (arrayPtr != NULL) { arrayPtr->refCount++; } part1 = TclGetString(objv[1]); varValuePtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1, NULL, - (TCL_TRACE_READS | TCL_LEAVE_ERR_MSG)); + TCL_LEAVE_ERR_MSG); varPtr->refCount--; if (arrayPtr != NULL) { arrayPtr->refCount--; } + createdNewObj = 0; if (varValuePtr == NULL) { /* * We couldn't read the old value: either the var doesn't yet * exist or it's an array element. If it's new, we will try to * create it with Tcl_ObjSetVar2 below. */ - createVar = (TclIsVarUndefined(varPtr)); varValuePtr = Tcl_NewObj(); createdNewObj = 1; } else if (Tcl_IsShared(varValuePtr)) { varValuePtr = Tcl_DuplicateObj(varValuePtr); createdNewObj = 1; @@ -2780,16 +2863,15 @@ * Now store the list object back into the variable. If there is an * error setting the new value, decrement its ref count if it * was new and we didn't create the variable. */ + Tcl_IncrRefCount(varValuePtr); newValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, part1, NULL, varValuePtr, TCL_LEAVE_ERR_MSG); + Tcl_DecrRefCount(varValuePtr); if (newValuePtr == NULL) { - if (createdNewObj && !createVar) { - Tcl_DecrRefCount(varValuePtr); /* free unneeded obj */ - } return TCL_ERROR; } } /* @@ -3389,10 +3471,18 @@ (TclPtrSetVar(interp, elemVarPtr, varPtr, varName, part2, elemPtrs[i+1], TCL_LEAVE_ERR_MSG) == NULL)) { result = TCL_ERROR; break; } + + /* + * The TclPtrSetVar call might have shimmered + * arrayElemObj to another type, so re-fetch + * the pointers for safety. + */ + Tcl_ListObjGetElements(NULL, arrayElemObj, + &elemLen, &elemPtrs); } return result; } } @@ -3456,11 +3546,11 @@ CONST char *otherP2; /* Two-part name of variable in framePtr. */ CONST int otherFlags; /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: * indicates scope of "other" variable. */ CONST char *myName; /* Name of variable which will refer to * otherP1/otherP2. Must be a scalar. */ - CONST int myFlags; /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: + int myFlags; /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: * indicates scope of myName. */ int index; /* If the variable to be linked is an indexed * scalar, this is its index. Otherwise, -1. */ { Interp *iPtr = (Interp *) interp; @@ -3488,11 +3578,11 @@ return TCL_ERROR; } if (index >= 0) { if (!varFramePtr->isProcCallFrame) { - panic("ObjMakeUpVar called with an index outside from a proc.\n"); + panic("ObjMakeUpvar called with an index outside from a proc.\n"); } varPtr = &(varFramePtr->compiledLocals[index]); } else { /* * Check that we are not trying to create a namespace var linked to @@ -3511,15 +3601,20 @@ "refers to procedure variable", (char *) NULL); return TCL_ERROR; } /* - * Lookup and eventually create the new variable. + * Lookup and eventually create the new variable. Set the flag bit + * LOOKUP_FOR_UPVAR to indicate the special resolution rules for + * upvar purposes: + * - Bug #696893 - variable is either proc-local or in the current + * namespace; never follow the second (global) resolution path + * - Bug #631741 - do not use special namespace or interp resolvers */ - varPtr = TclLookupSimpleVar(interp, myName, myFlags, /*create*/ 1, - &errMsg, &index); + varPtr = TclLookupSimpleVar(interp, myName, (myFlags | LOOKUP_FOR_UPVAR), + /* create */ 1, &errMsg, &index); if (varPtr == NULL) { VarErrMsg(interp, myName, NULL, "create", errMsg); return TCL_ERROR; } } @@ -4070,12 +4165,11 @@ CONST char *part1; CONST char *part2; /* Variable's two-part name. */ int flags; /* Flags passed to trace procedures: * indicates what's happening to variable, * plus other stuff like TCL_GLOBAL_ONLY, - * TCL_NAMESPACE_ONLY, and - * TCL_INTERP_DESTROYED. */ + * or TCL_NAMESPACE_ONLY. */ CONST int leaveErrMsg; /* If true, and one of the traces indicates an * error, then leave an error message and stack * trace information in *iPTr. */ { register VarTrace *tracePtr; @@ -4084,10 +4178,12 @@ CONST char *openParen, *p; Tcl_DString nameCopy; int copiedName; int code = TCL_OK; int disposeFlags = 0; + int saveErrFlags = iPtr->flags + & (ERR_IN_PROGRESS | ERR_ALREADY_LOGGED | ERROR_CODE_SET); /* * If there are already similar trace procedures active for the * variable, don't call them again. */ @@ -4150,10 +4246,13 @@ active.nextTracePtr = tracePtr->nextPtr; if (!(tracePtr->flags & flags)) { continue; } Tcl_Preserve((ClientData) tracePtr); + if (Tcl_InterpDeleted((Tcl_Interp *)iPtr)) { + flags |= TCL_INTERP_DESTROYED; + } result = (*tracePtr->traceProc)(tracePtr->clientData, (Tcl_Interp *) iPtr, part1, part2, flags); if (result != NULL) { if (flags & TCL_TRACE_UNSETS) { /* Ignore errors in unset traces */ @@ -4183,10 +4282,13 @@ active.nextTracePtr = tracePtr->nextPtr; if (!(tracePtr->flags & flags)) { continue; } Tcl_Preserve((ClientData) tracePtr); + if (Tcl_InterpDeleted((Tcl_Interp *)iPtr)) { + flags |= TCL_INTERP_DESTROYED; + } result = (*tracePtr->traceProc)(tracePtr->clientData, (Tcl_Interp *) iPtr, part1, part2, flags); if (result != NULL) { if (flags & TCL_TRACE_UNSETS) { /* Ignore errors in unset traces */ @@ -4206,10 +4308,13 @@ * Restore the variable's flags, remove the record of our active * traces, and then return. */ done: + if (code == TCL_OK) { + iPtr->flags |= saveErrFlags; + } if (code == TCL_ERROR) { if (leaveErrMsg) { CONST char *type = ""; switch (flags&(TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_ARRAY)) { case TCL_TRACE_READS: { @@ -4464,10 +4569,78 @@ } /* *---------------------------------------------------------------------- * + * TclDeleteNamespaceVars -- + * + * This procedure is called to recycle all the storage space + * associated with a namespace's table of variables. + * + * Results: + * None. + * + * Side effects: + * Variables are deleted and trace procedures are invoked, if + * any are declared. + * + *---------------------------------------------------------------------- + */ + +void +TclDeleteNamespaceVars(nsPtr) + Namespace *nsPtr; +{ + Tcl_HashTable *tablePtr = &nsPtr->varTable; + Tcl_Interp *interp = nsPtr->interp; + Interp *iPtr = (Interp *)interp; + Tcl_HashSearch search; + Tcl_HashEntry *hPtr; + int flags = 0; + Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); + + /* + * Determine what flags to pass to the trace callback procedures. + */ + + if (nsPtr == iPtr->globalNsPtr) { + flags = TCL_GLOBAL_ONLY; + } else if (nsPtr == currNsPtr) { + flags = TCL_NAMESPACE_ONLY; + } + + for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; + hPtr = Tcl_FirstHashEntry(tablePtr, &search)) { + register Var *varPtr = (Var *) Tcl_GetHashValue(hPtr); + Tcl_Obj *objPtr = Tcl_NewObj(); + varPtr->refCount++; /* Make sure we get to remove from hash */ + Tcl_IncrRefCount(objPtr); + Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, objPtr); + UnsetVarStruct(varPtr, NULL, iPtr, Tcl_GetString(objPtr), NULL, flags); + Tcl_DecrRefCount(objPtr); /* free no longer needed obj */ + varPtr->refCount--; + + /* Remove the variable from the table and force it undefined + * in case an unset trace brought it back from the dead */ + Tcl_DeleteHashEntry(hPtr); + varPtr->hPtr = NULL; + TclSetVarUndefined(varPtr); + TclSetVarScalar(varPtr); + while (varPtr->tracePtr != NULL) { + VarTrace *tracePtr = varPtr->tracePtr; + varPtr->tracePtr = tracePtr->nextPtr; + Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC); + } + CleanupVar(varPtr, NULL); + } + Tcl_DeleteHashTable(tablePtr); +} + + +/* + *---------------------------------------------------------------------- + * * TclDeleteVars -- * * This procedure is called to recycle all the storage space * associated with a table of variables. For this procedure * to work correctly, it must not be possible for any of the @@ -4508,13 +4681,10 @@ if (tablePtr == &iPtr->globalNsPtr->varTable) { flags |= TCL_GLOBAL_ONLY; } else if (tablePtr == &currNsPtr->varTable) { flags |= TCL_NAMESPACE_ONLY; } - if (Tcl_InterpDeleted(interp)) { - flags |= TCL_INTERP_DESTROYED; - } for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { varPtr = (Var *) Tcl_GetHashValue(hPtr); @@ -4745,11 +4915,10 @@ CONST char *arrayName; /* Name of array (used for trace * callbacks). */ Var *varPtr; /* Pointer to variable structure. */ int flags; /* Flags to pass to CallVarTraces: * TCL_TRACE_UNSETS and sometimes - * TCL_INTERP_DESTROYED, * TCL_NAMESPACE_ONLY, or * TCL_GLOBAL_ONLY. */ { Tcl_HashSearch search; register Tcl_HashEntry *hPtr; Index: library/auto.tcl ================================================================== --- library/auto.tcl +++ library/auto.tcl @@ -1,11 +1,11 @@ # auto.tcl -- # # utility procs formerly in init.tcl dealing with auto execution # of commands and can be auto loaded themselves. # -# RCS: @(#) $Id: auto.tcl,v 1.12 2002/10/28 16:34:25 dgp Exp $ +# RCS: @(#) $Id: auto.tcl,v 1.12.2.10 2005/07/23 03:31:41 dgp Exp $ # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1998 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution @@ -31,13 +31,11 @@ tclPkgUnknown tcl::MacOSXPkgUnknown tcl::MacPkgUnknown} $p] < 0)} { rename $p {} } } - catch {unset auto_execs} - catch {unset auto_index} - catch {unset auto_oldpath} + unset -nocomplain auto_execs auto_index auto_oldpath } # tcl_findLibrary -- # # This is a utility for extensions that searches for a library directory @@ -58,58 +56,98 @@ set dirs {} set errors {} # The C application may have hardwired a path, which we honor - - set variableSet [info exists the_library] - if {$variableSet && [string compare $the_library {}]} { + + if {[info exists the_library] && $the_library ne ""} { lappend dirs $the_library } else { # Do the canonical search - # 1. From an environment variable, if it exists + # 1. From an environment variable, if it exists. + # Placing this first gives the end-user ultimate control + # to work-around any bugs, or to customize. if {[info exists env($enVarName)]} { lappend dirs $env($enVarName) } - # 2. Relative to the Tcl library + # 2. In the package script directory registered within + # the configuration of the package itself. + # + # Only do this for Tcl 8.5+, when Tcl_RegsiterConfig() is available. + #if {[catch { + # ::${basename}::pkgconfig get scriptdir,runtime + #} value] == 0} { + # lappend dirs $value + #} - lappend dirs [file join [file dirname [info library]] \ - $basename$version] + # 3. Relative to auto_path directories. This checks relative to the + # Tcl library as well as allowing loading of libraries added to the + # auto_path that is not relative to the core library or binary paths. + foreach d $::auto_path { + lappend dirs [file join $d $basename$version] + if {$::tcl_platform(platform) eq "unix" + && $::tcl_platform(os) eq "Darwin"} { + # 4. On MacOSX, check the Resources/Scripts subdir too + lappend dirs [file join $d $basename$version Resources Scripts] + } + } # 3. Various locations relative to the executable # ../lib/foo1.0 (From bin directory in install hierarchy) # ../../lib/foo1.0 (From bin/arch directory in install hierarchy) # ../library (From unix directory in build hierarchy) - # ../../library (From unix/arch directory in build hierarchy) - # ../../foo1.0.1/library - # (From unix directory in parallel build hierarchy) - # ../../../foo1.0.1/library - # (From unix/arch directory in parallel build hierarchy) - set parentDir [file dirname [file dirname [info nameofexecutable]]] set grandParentDir [file dirname $parentDir] lappend dirs [file join $parentDir lib $basename$version] lappend dirs [file join $grandParentDir lib $basename$version] lappend dirs [file join $parentDir library] - lappend dirs [file join $grandParentDir library] - lappend dirs [file join $grandParentDir $basename$patch library] - lappend dirs [file join [file dirname $grandParentDir] \ - $basename$patch library] - - # 4. On MacOSX, check the directories in the tcl_pkgPath - if {[string equal $::tcl_platform(platform) "unix"] && \ - [string equal $::tcl_platform(os) "Darwin"]} { - foreach d $::tcl_pkgPath { - lappend dirs [file join $d $basename$version] - lappend dirs [file join $d $basename$version Resources Scripts] - } - } - } + + # Remaining locations are out of date (when relevant, they ought + # to be covered by the $::auto_path seach above). + # + # ../../library (From unix/arch directory in build hierarchy) + # ../../foo1.0.1/library + # (From unix directory in parallel build hierarchy) + # ../../../foo1.0.1/library + # (From unix/arch directory in parallel build hierarchy) + # + # For the sake of extra compatibility safety, we keep adding these + # paths during the 8.4.* release series. + if {1} { + lappend dirs [file join $grandParentDir library] + lappend dirs [file join $grandParentDir $basename$patch library] + lappend dirs [file join [file dirname $grandParentDir] \ + $basename$patch library] + } + } + # uniquify $dirs in order + array set seen {} + foreach i $dirs { + # For Tcl 8.4.9, we've disabled the use of [file normalize] here. + # This means that two different path names that are the same path + # in normalized form, will both remain on the search path. There + # should be no harm in that, just a bit more file system access + # than is strictly necessary. + # + # [file normalize] has been disabled because of reports it has + # caused difficulties with the freewrap utility. To keep + # compatibility with freewrap's needs, we'll keep this disabled + # throughout the 8.4.x (x >= 9) releases. See Bug 1072136. + if {1 || [interp issafe]} { + set norm $i + } else { + set norm [file normalize $i] + } + if {[info exists seen($norm)]} { continue } + set seen($norm) "" + lappend uniqdirs $i + } + set dirs $uniqdirs foreach i $dirs { set the_library $i set file [file join $i $initScript] # source everything when in a safe interpreter because @@ -121,13 +159,11 @@ } else { append errors "$file: $msg\n$errorInfo\n" } } } - if {!$variableSet} { - unset the_library - } + unset -nocomplain the_library set msg "Can't find a usable $initScript in the following directories: \n" append msg " $dirs\n\n" append msg "$errors\n\n" append msg "This probably means that $basename wasn't installed properly.\n" error $msg @@ -176,16 +212,16 @@ append index "# and sourced to set up indexing information for one or\n" append index "# more commands. Typically each line is a command that\n" append index "# sets an element in the auto_index array, where the\n" append index "# element name is the name of a command and the value is\n" append index "# a script that loads the command.\n\n" - if {$args == ""} { + if {[llength $args] == 0} { set args *.tcl } auto_mkindex_parser::init - foreach file [eval glob $args] { + foreach file [eval [linsert $args 0 glob --]] { if {[catch {auto_mkindex_parser::mkindex $file} msg] == 0} { append index $msg } else { set code $errorCode set info $errorInfo @@ -214,14 +250,14 @@ append index "# and sourced to set up indexing information for one or\n" append index "# more commands. Typically each line is a command that\n" append index "# sets an element in the auto_index array, where the\n" append index "# element name is the name of a command and the value is\n" append index "# a script that loads the command.\n\n" - if {[string equal $args ""]} { + if {[llength $args] == 0} { set args *.tcl } - foreach file [eval glob $args] { + foreach file [eval [linsert $args 0 glob --]] { set f "" set error [catch { set f [open $file] while {[gets $f line] >= 0} { if {[regexp {^proc[ ]+([^ ]*)} $line match procName]} { @@ -335,11 +371,11 @@ # To avoid this, we replace all $ with \0 (literally, the null char) # later, when getting proc names we will have to reverse this replacement, # in case there were any $ in the proc name. This will cause a problem # if somebody actually tries to have a \0 in their proc name. Too bad # for them. - regsub -all {\$} $contents "\0" contents + set contents [string map "$ \u0000" $contents] set index "" set contextStack "" set imports "" @@ -413,25 +449,23 @@ proc auto_mkindex_parser::commandInit {name arglist body} { variable parser set ns [namespace qualifiers $name] set tail [namespace tail $name] - if {[string equal $ns ""]} { - set fakeName "[namespace current]::_%@fake_$tail" + if {$ns eq ""} { + set fakeName [namespace current]::_%@fake_$tail } else { - set fakeName "_%@fake_$name" - regsub -all {::} $fakeName "_" fakeName - set fakeName "[namespace current]::$fakeName" + set fakeName [namespace current]::[string map {:: _} _%@fake_$name] } proc $fakeName $arglist $body # YUK! Tcl won't let us alias fully qualified command names, # so we can't handle names like "::itcl::class". Instead, # we have to build procs with the fully qualified names, and # have the procs point to the aliases. - if {[regexp {::} $name]} { + if {[string match *::* $name]} { set exportCmd [list _%@namespace export [namespace tail $name]] $parser eval [list _%@namespace eval $ns $exportCmd] # The following proc definition does not work if you # want to tolerate space or something else diabolical @@ -477,20 +511,19 @@ break } } } - if {[string equal [namespace qualifiers $name] ""]} { + if {[namespace qualifiers $name] eq ""} { set name [namespace tail $name] } elseif {![string match ::* $name]} { set name "::$name" } # Earlier, mkindex replaced all $'s with \0. Now, we have to reverse # that replacement. - regsub -all "\0" $name "\$" name - return $name + return [string map "\u0000 $" $name] } # Register all of the procedures for the auto_mkindex parser that # will build the "tclIndex" file. @@ -518,11 +551,11 @@ # to force it to be loaded. This should be a noop if the package has # already been loaded auto_mkindex_parser::hook { if {![catch {package require tbcload}]} { - if {[llength [info commands tbcload::bcproc]] == 0} { + if {[namespace which -command tbcload::bcproc] eq ""} { auto_load tbcload::bcproc } load {} tbcload $auto_mkindex_parser::parser # AUTO MKINDEX: tbcload::bcproc name arglist body @@ -569,15 +602,15 @@ } import { variable parser variable imports foreach pattern $args { - if {[string compare $pattern "-force"]} { + if {$pattern ne "-force"} { lappend imports $pattern } } catch {$parser eval "_%@namespace import $args"} } } } return Index: library/dde/pkgIndex.tcl ================================================================== --- library/dde/pkgIndex.tcl +++ library/dde/pkgIndex.tcl @@ -1,6 +1,7 @@ if {![package vsatisfies [package provide Tcl] 8]} {return} -if {[info exists tcl_platform(debug)]} { - package ifneeded dde 1.2.1 [list load [file join $dir tcldde12g.dll] dde] +if {[string compare $::tcl_platform(platform) windows]} {return} +if {[info exists ::tcl_platform(debug)]} { + package ifneeded dde 1.2.4 [list load [file join $dir tcldde12g.dll] dde] } else { - package ifneeded dde 1.2.1 [list load [file join $dir tcldde12.dll] dde] + package ifneeded dde 1.2.4 [list load [file join $dir tcldde12.dll] dde] } ADDED library/encoding/gb2312-raw.enc Index: library/encoding/gb2312-raw.enc ================================================================== --- /dev/null +++ library/encoding/gb2312-raw.enc @@ -0,0 +1,1380 @@ +# Encoding file: gb2312, double-byte +D +233F 0 81 +21 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000030003001300230FB02C902C700A8300330052015FF5E2225202620182019 +201C201D3014301530083009300A300B300C300D300E300F3016301730103011 +00B100D700F72236222722282211220F222A222922082237221A22A522252220 +23122299222B222E2261224C2248223D221D2260226E226F22642265221E2235 +22342642264000B0203220332103FF0400A4FFE0FFE1203000A7211626062605 +25CB25CF25CE25C725C625A125A025B325B2203B219221902191219330130000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +22 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000024882489248A248B248C248D248E248F2490249124922493249424952496 +249724982499249A249B247424752476247724782479247A247B247C247D247E +247F248024812482248324842485248624872460246124622463246424652466 +2467246824690000000032203221322232233224322532263227322832290000 +00002160216121622163216421652166216721682169216A216B000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +23 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000FF01FF02FF03FFE5FF05FF06FF07FF08FF09FF0AFF0BFF0CFF0DFF0EFF0F +FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19FF1AFF1BFF1CFF1DFF1EFF1F +FF20FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F +FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF3BFF3CFF3DFF3EFF3F +FF40FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F +FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5AFF5BFF5CFF5DFFE30000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +24 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000304130423043304430453046304730483049304A304B304C304D304E304F +3050305130523053305430553056305730583059305A305B305C305D305E305F +3060306130623063306430653066306730683069306A306B306C306D306E306F +3070307130723073307430753076307730783079307A307B307C307D307E307F +3080308130823083308430853086308730883089308A308B308C308D308E308F +3090309130923093000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +25 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF +30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF +30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF +30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF +30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF +30F030F130F230F330F430F530F6000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +26 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000039103920393039403950396039703980399039A039B039C039D039E039F +03A003A103A303A403A503A603A703A803A90000000000000000000000000000 +000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF +03C003C103C303C403C503C603C703C803C90000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +27 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000004100411041204130414041504010416041704180419041A041B041C041D +041E041F0420042104220423042404250426042704280429042A042B042C042D +042E042F00000000000000000000000000000000000000000000000000000000 +000004300431043204330434043504510436043704380439043A043B043C043D +043E043F0440044104420443044404450446044704480449044A044B044C044D +044E044F00000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +28 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000010100E101CE00E0011300E9011B00E8012B00ED01D000EC014D00F301D2 +00F2016B00FA01D400F901D601D801DA01DC00FC00EA00000000000000000000 +0000000000000000000031053106310731083109310A310B310C310D310E310F +3110311131123113311431153116311731183119311A311B311C311D311E311F +3120312131223123312431253126312731283129000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +29 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00000000000000002500250125022503250425052506250725082509250A250B +250C250D250E250F2510251125122513251425152516251725182519251A251B +251C251D251E251F2520252125222523252425252526252725282529252A252B +252C252D252E252F2530253125322533253425352536253725382539253A253B +253C253D253E253F2540254125422543254425452546254725482549254A254B +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +30 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000554A963F57C3632854CE550954C07691764C853C77EE827E788D72319698 +978D6C285B894FFA630966975CB880FA684880AE660276CE51F9655671AC7FF1 +888450B2596561CA6FB382AD634C625253ED54277B06516B75A45DF462D48DCB +9776628A8019575D97387F627238767D67CF767E64464F708D2562DC7A176591 +73ED642C6273822C9881677F7248626E62CC4F3474E3534A529E7ECA90A65E2E +6886699C81807ED168D278C5868C9551508D8C2482DE80DE5305891252650000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +31 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000858496F94FDD582199715B9D62B162A566B48C799C8D7206676F789160B2 +535153178F8880CC8D1D94A1500D72C8590760EB711988AB595482EF672C7B28 +5D297EF7752D6CF58E668FF8903C9F3B6BD491197B145F7C78A784D6853D6BD5 +6BD96BD65E015E8775F995ED655D5F0A5FC58F9F58C181C2907F965B97AD8FB9 +7F168D2C62414FBF53D8535E8FA88FA98FAB904D68075F6A819888689CD6618B +522B762A5F6C658C6FD26EE85BBE6448517551B067C44E1979C9997C70B30000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +32 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000075C55E7673BB83E064AD62E894B56CE2535A52C3640F94C27B944F2F5E1B +82368116818A6E246CCA9A736355535C54FA886557E04E0D5E036B657C3F90E8 +601664E6731C88C16750624D8D22776C8E2991C75F6983DC8521991053C28695 +6B8B60ED60E8707F82CD82314ED36CA785CF64CD7CD969FD66F9834953957B56 +4FA7518C6D4B5C428E6D63D253C9832C833667E578B4643D5BDF5C945DEE8BE7 +62C667F48C7A640063BA8749998B8C177F2094F24EA7961098A4660C73160000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +33 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000573A5C1D5E38957F507F80A05382655E7545553150218D856284949E671D +56326F6E5DE2543570928F66626F64A463A35F7B6F8890F481E38FB05C186668 +5FF16C8996488D81886C649179F057CE6A59621054484E587A0B60E96F848BDA +627F901E9A8B79E4540375F4630153196C608FDF5F1B9A70803B9F7F4F885C3A +8D647FC565A570BD514551B2866B5D075BA062BD916C75748E0C7A2061017B79 +4EC77EF877854E1181ED521D51FA6A7153A88E87950496CF6EC19664695A0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +34 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000784050A877D7641089E6590463E35DDD7A7F693D4F20823955984E3275AE +7A975E625E8A95EF521B5439708A6376952457826625693F918755076DF37EAF +882262337EF075B5832878C196CC8F9E614874F78BCD6B64523A8D506B21806A +847156F153064ECE4E1B51D17C97918B7C074FC38E7F7BE17A9C64675D1450AC +810676017CB96DEC7FE067515B585BF878CB64AE641363AA632B9519642D8FBE +7B5476296253592754466B7950A362345E266B864EE38D37888B5F85902E0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +35 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006020803D62C54E39535590F863B880C665E66C2E4F4660EE6DE18BDE5F39 +86CB5F536321515A83616863520063638E4850125C9B79775BFC52307A3B60BC +905376D75FB75F9776848E6C706F767B7B4977AA51F3909358244F4E6EF48FEA +654C7B1B72C46DA47FDF5AE162B55E95573084827B2C5E1D5F1F90127F1498A0 +63826EC7789870B95178975B57AB75354F4375385E9760E659606DC06BBF7889 +53FC96D551CB52016389540A94938C038DCC7239789F87768FED8C0D53E00000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +36 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004E0176EF53EE948998769F0E952D5B9A8BA24E224E1C51AC846361C252A8 +680B4F97606B51BB6D1E515C6296659796618C46901775D890FD77636BD2728A +72EC8BFB583577798D4C675C9540809A5EA66E2159927AEF77ED953B6BB565AD +7F0E58065151961F5BF958A954288E726566987F56E4949D76FE9041638754C6 +591A593A579B8EB267358DFA8235524160F0581586FE5CE89E454FC4989D8BB9 +5A2560765384627C904F9102997F6069800C513F80335C1499756D314E8C0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +37 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00008D3053D17F5A7B4F4F104E4F96006CD573D085E95E06756A7FFB6A0A77FE +94927E4151E170E653CD8FD483038D2972AF996D6CDB574A82B365B980AA623F +963259A84EFF8BBF7EBA653E83F2975E556198DE80A5532A8BFD542080BA5E9F +6CB88D3982AC915A54296C1B52067EB7575F711A6C7E7C89594B4EFD5FFF6124 +7CAA4E305C0167AB87025CF0950B98CE75AF70FD902251AF7F1D8BBD594951E4 +4F5B5426592B657780A45B75627662C28F905E456C1F7B264F0F4FD8670D0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +38 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006D6E6DAA798F88B15F17752B629A8F854FEF91DC65A7812F81515E9C8150 +8D74526F89868D4B590D50854ED8961C723681798D1F5BCC8BA3964459877F1A +54905676560E8BE565396982949976D66E895E727518674667D17AFF809D8D76 +611F79C665628D635188521A94A27F38809B7EB25C976E2F67607BD9768B9AD8 +818F7F947CD5641E95507A3F544A54E56B4C640162089E3D80F3759952729769 +845B683C86E49601969494EC4E2A54047ED968398DDF801566F45E9A7FB90000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +39 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000057C2803F68975DE5653B529F606D9F9A4F9B8EAC516C5BAB5F135DE96C5E +62F18D21517194A952FE6C9F82DF72D757A267848D2D591F8F9C83C754957B8D +4F306CBD5B6459D19F1353E486CA9AA88C3780A16545987E56FA96C7522E74DC +52505BE1630289024E5662D0602A68FA51735B9851A089C27BA199867F5060EF +704C8D2F51495E7F901B747089C4572D78455F529F9F95FA8F689B3C8BE17678 +684267DC8DEA8D35523D8F8A6EDA68CD950590ED56FD679C88F98FC754C80000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +3A +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009AB85B696D776C264EA55BB39A87916361A890AF97E9542B6DB55BD251FD +558A7F557FF064BC634D65F161BE608D710A6C576C49592F676D822A58D5568E +8C6A6BEB90DD597D801753F76D695475559D837783CF683879BE548C4F555408 +76D28C8996026CB36DB88D6B89109E648D3A563F9ED175D55F8872E0606854FC +4EA86A2A886160528F7054C470D886799E3F6D2A5B8F5F187EA255894FAF7334 +543C539A5019540E547C4E4E5FFD745A58F6846B80E1877472D07CCA6E560000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +3B +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005F27864E552C62A44E926CAA623782B154D7534E733E6ED1753B52125316 +8BDD69D05F8A60006DEE574F6B2273AF68538FD87F13636260A3552475EA8C62 +71156DA35BA65E7B8352614C9EC478FA87577C27768751F060F6714C66435E4C +604D8C0E707063258F895FBD606286D456DE6BC160946167534960E066668D3F +79FD4F1A70E96C478BB38BF27ED88364660F5A5A9B426D516DF78C416D3B4F19 +706B83B7621660D1970D8D27797851FB573E57FA673A75787A3D79EF7B950000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +3C +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000808C99658FF96FC08BA59E2159EC7EE97F095409678168D88F917C4D96C6 +53CA602575BE6C7253735AC97EA7632451E0810A5DF184DF628051805B634F0E +796D524260B86D4E5BC45BC28BA18BB065E25FCC964559937EE77EAA560967B7 +59394F735BB652A0835A988A8D3E753294BE50477A3C4EF767B69A7E5AC16B7C +76D1575A5C167B3A95F4714E517C80A9827059787F04832768C067EC78B17877 +62E363617B804FED526A51CF835069DB92748DF58D3189C1952E7BAD4EF60000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +3D +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000506582305251996F6E106E856DA75EFA50F559DC5C066D466C5F7586848B +686859568BB253209171964D854969127901712680F64EA490CA6D479A845A07 +56BC640594F077EB4FA5811A72E189D2997A7F347EDE527F655991758F7F8F83 +53EB7A9663ED63A5768679F888579636622A52AB8282685467706377776B7AED +6D017ED389E359D0621285C982A5754C501F4ECB75A58BEB5C4A5DFE7B4B65A4 +91D14ECA6D25895F7D2795264EC58C288FDB9773664B79818FD170EC6D780000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +3E +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005C3D52B283465162830E775B66769CB84EAC60CA7CBE7CB37ECF4E958B66 +666F988897595883656C955C5F8475C997567ADF7ADE51C070AF7A9863EA7A76 +7EA0739697ED4E4570784E5D915253A9655165E781FC8205548E5C31759A97A0 +62D872D975BD5C459A7983CA5C40548077E94E3E6CAE805A62D2636E5DE85177 +8DDD8E1E952F4FF153E560E770AC526763509E435A1F5026773753777EE26485 +652B628963985014723589C951B38BC07EDD574783CC94A7519B541B5CFB0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +3F +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004FCA7AE36D5A90E19A8F55805496536154AF5F0063E9697751EF6168520A +582A52D8574E780D770B5EB761777CE0625B62974EA27095800362F770E49760 +577782DB67EF68F578D5989779D158F354B353EF6E34514B523B5BA28BFE80AF +554357A660735751542D7A7A60505B5463A762A053E362635BC767AF54ED7A9F +82E691775E9388E4593857AE630E8DE880EF57577B774FA95FEB5BBD6B3E5321 +7B5072C2684677FF773665F751B54E8F76D45CBF7AA58475594E9B4150800000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +40 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000998861276E8357646606634656F062EC62695ED39614578362C955878721 +814A8FA3556683B167658D5684DD5A6A680F62E67BEE961151706F9C8C3063FD +89C861D27F0670C26EE57405699472FC5ECA90CE67176D6A635E52B372628001 +4F6C59E5916A70D96D9D52D24E5096F7956D857E78CA7D2F5121579264C2808B +7C7B6CEA68F1695E51B7539868A872819ECE7BF172F879BB6F137406674E91CC +9CA4793C83898354540F68174E3D538952B1783E5386522950884F8B4FD00000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +41 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000075E27ACB7C926CA596B6529B748354E94FE9805483B28FDE95705EC9601C +6D9F5E18655B813894FE604B70BC7EC37CAE51C968817CB1826F4E248F8691CF +667E4EAE8C0564A9804A50DA759771CE5BE58FBD6F664E86648295635ED66599 +521788C270C852A3730E7433679778F797164E3490BB9CDE6DCB51DB8D41541D +62CE73B283F196F69F8494C34F367F9A51CC707596755CAD988653E64EE46E9C +740969B4786B998F7559521876246D4167F3516D9F99804B54997B3C7ABF0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +42 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009686578462E29647697C5A0464027BD36F0F964B82A6536298855E907089 +63B35364864F9C819E93788C97328DEF8D429E7F6F5E79845F559646622E9A74 +541594DD4FA365C55C655C617F1586516C2F5F8B73876EE47EFF5CE6631B5B6A +6EE653754E7163A0756562A18F6E4F264ED16CA67EB68BBA841D87BA7F57903B +95237BA99AA188F8843D6D1B9A867EDC59889EBB739B780186829A6C9A82561B +541757CB4E709EA653568FC881097792999286EE6EE1851366FC61626F2B0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +43 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00008C298292832B76F26C135FD983BD732B8305951A6BDB77DB94C6536F8302 +51925E3D8C8C8D384E4873AB679A68859176970971646CA177095A9295416BCF +7F8E66275BD059B95A9A95E895F74EEC840C84996AAC76DF9530731B68A65B5F +772F919A97617CDC8FF78C1C5F257C7379D889C56CCC871C5BC65E4268C97720 +7EF55195514D52C95A297F05976282D763CF778485D079D26E3A5E9959998511 +706D6C1162BF76BF654F60AF95FD660E879F9E2394ED540D547D8C2C64780000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +44 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000647986116A21819C78E864699B5462B9672B83AB58A89ED86CAB6F205BDE +964C8C0B725F67D062C772614EA959C66BCD589366AE5E5552DF6155672876EE +776672677A4662FF54EA545094A090A35A1C7EB36C164E435976801059485357 +753796BE56CA63208111607C95F96DD65462998151855AE980FD59AE9713502A +6CE55C3C62DF4F60533F817B90066EBA852B62C85E7478BE64B5637B5FF55A18 +917F9E1F5C3F634F80425B7D556E954A954D6D8560A867E072DE51DD5B810000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +45 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000062E76CDE725B626D94AE7EBD81136D53519C5F04597452AA601259736696 +8650759F632A61E67CEF8BFA54E66B279E256BB485D5545550766CA4556A8DB4 +722C5E156015743662CD6392724C5F986E436D3E65006F5876D878D076FC7554 +522453DB4E535E9E65C1802A80D6629B5486522870AE888D8DD16CE1547880DA +57F988F48D54966A914D4F696C9B55B776C6783062A870F96F8E5F6D84EC68DA +787C7BF781A8670B9E4F636778B0576F78129739627962AB528874356BD70000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +46 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005564813E75B276AE533975DE50FB5C418B6C7BC7504F72479A9798D86F02 +74E27968648777A562FC98918D2B54C180584E52576A82F9840D5E7351ED74F6 +8BC45C4F57616CFC98875A4678349B448FEB7C955256625194FA4EC683868461 +83E984B257D467345703666E6D668C3166DD7011671F6B3A6816621A59BB4E03 +51C46F0667D26C8F517668CB59476B6775665D0E81109F5065D7794879419A91 +8D775C824E5E4F01542F5951780C56686C148FC45F036C7D6CE38BAB63900000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +47 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000060706D3D72756266948E94C553438FC17B7E4EDF8C264E7E9ED494B194B3 +524D6F5C90636D458C3458115D4C6B206B4967AA545B81547F8C589985375F3A +62A26A47953965726084686577A74E544FA85DE7979864AC7FD85CED4FCF7A8D +520783044E14602F7A8394A64FB54EB279E6743452E482B964D279BD5BDD6C81 +97528F7B6C22503E537F6E0564CE66746C3060C598778BF75E86743C7A7779CB +4E1890B174036C4256DA914B6CC58D8B533A86C666F28EAF5C489A716E200000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +48 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000053D65A369F8B8DA353BB570898A76743919B6CC9516875CA62F372AC5238 +529D7F3A7094763853749E4A69B7786E96C088D97FA4713671C3518967D374E4 +58E4651856B78BA9997662707ED560F970ED58EC4EC14EBA5FCD97E74EFB8BA4 +5203598A7EAB62544ECD65E5620E833884C98363878D71946EB65BB97ED25197 +63C967D480898339881551125B7A59828FB14E736C5D516589258F6F962E854A +745E951095F06DA682E55F3164926D128428816E9CC3585E8D5B4E0953C10000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +49 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004F1E6563685155D34E2764149A9A626B5AC2745F82726DA968EE50E7838E +7802674052396C997EB150BB5565715E7B5B665273CA82EB67495C715220717D +886B95EA965564C58D6181B355846C5562477F2E58924F2455468D4F664C4E0A +5C1A88F368A2634E7A0D70E7828D52FA97F65C1154E890B57ECD59628D4A86C7 +820C820D8D6664445C0461516D89793E8BBE78377533547B4F388EAB6DF15A20 +7EC5795E6C885BA15A76751A80BE614E6E1758F0751F7525727253477EF30000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +4A +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000770176DB526980DC57235E08593172EE65BD6E7F8BD75C388671534177F3 +62FE65F64EC098DF86805B9E8BC653F277E24F7F5C4E9A7659CB5F0F793A58EB +4E1667FF4E8B62ED8A93901D52BF662F55DC566C90024ED54F8D91CA99706C0F +5E0260435BA489C68BD56536624B99965B885BFF6388552E53D77626517D852C +67A268B36B8A62928F9353D482126DD1758F4E668D4E5B70719F85AF669166D9 +7F7287009ECD9F205C5E672F8FF06811675F620D7AD658855EB665706F310000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +4B +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000060555237800D6454887075295E05681362F4971C53CC723D8C016C347761 +7A0E542E77AC987A821C8BF47855671470C165AF64955636601D79C153F84E1D +6B7B80865BFA55E356DB4F3A4F3C99725DF3677E80386002988290015B8B8BBC +8BF5641C825864DE55FD82CF91654FD77D20901F7C9F50F358516EAF5BBF8BC9 +80839178849C7B97867D968B968F7EE59AD3788E5C817A57904296A7795F5B59 +635F7B0B84D168AD55067F2974107D2295016240584C4ED65B83597958540000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +4C +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000736D631E8E4B8E0F80CE82D462AC53F06CF0915E592A60016C70574D644A +8D2A762B6EE9575B6A8075F06F6D8C2D8C0857666BEF889278B363A253F970AD +6C645858642A580268E0819B55107CD650188EBA6DCC8D9F70EB638F6D9B6ED4 +7EE68404684390036DD896768BA85957727985E4817E75BC8A8A68AF52548E22 +951163D098988E44557C4F5366FF568F60D56D9552435C4959296DFB586B7530 +751C606C82148146631167618FE2773A8DF38D3494C15E165385542C70C30000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +4D +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006C405EF7505C4EAD5EAD633A8247901A6850916E77B3540C94DC5F647AE5 +687663457B527EDF75DB507762955934900F51F879C37A8156FE5F9290146D82 +5C60571F541051546E4D56E263A89893817F8715892A9000541E5C6F81C062D6 +625881319E3596409A6E9A7C692D59A562D3553E631654C786D96D3C5A0374E6 +889C6B6A59168C4C5F2F6E7E73A9987D4E3870F75B8C7897633D665A769660CB +5B9B5A494E0781556C6A738B4EA167897F515F8065FA671B5FD859845A010000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +4E +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005DCD5FAE537197E68FDD684556F4552F60DF4E3A6F4D7EF482C7840E59D4 +4F1F4F2A5C3E7EAC672A851A5473754F80C355829B4F4F4D6E2D8C135C096170 +536B761F6E29868A658795FB7EB9543B7A337D0A95EE55E17FC174EE631D8717 +6DA17A9D621165A1536763E16C835DEB545C94A84E4C6C618BEC5C4B65E0829C +68A7543E54346BCB6B664E9463425348821E4F0D4FAE575E620A96FE66647269 +52FF52A1609F8BEF661471996790897F785277FD6670563B54389521727A0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +4F +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00007A00606F5E0C6089819D591560DC718470EF6EAA6C5072806A8488AD5E2D +4E605AB3559C94E36D177CFB9699620F7EC6778E867E5323971E8F9666875CE1 +4FA072ED4E0B53A6590F54136380952851484ED99C9C7EA454B88D2488548237 +95F26D8E5F265ACC663E966973B0732E53BF817A99857FA15BAA967796507EBF +76F853A2957699997BB189446E584E617FD479658BE660F354CD4EAB98795DF7 +6A6150CF54118C618427785D9704524A54EE56A395006D885BB56DC666530000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +50 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005C0F5B5D6821809655787B11654869544E9B6B47874E978B534F631F643A +90AA659C80C18C10519968B0537887F961C86CC46CFB8C225C5185AA82AF950C +6B238F9B65B05FFB5FC34FE18845661F8165732960FA51745211578B5F6290A2 +884C91925E78674F602759D3514451F680F853086C7996C4718A4F114FEE7F9E +673D55C5950879C088967EE3589F620C9700865A5618987B5F908BB884C49157 +53D965ED5E8F755C60647D6E5A7F7EEA7EED8F6955A75BA360AC65CB73840000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +51 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009009766377297EDA9774859B5B667A7496EA884052CB718F5FAA65EC8BE2 +5BFB9A6F5DE16B896C5B8BAD8BAF900A8FC5538B62BC9E269E2D54404E2B82BD +7259869C5D1688596DAF96C554D14E9A8BB6710954BD960970DF6DF976D04E25 +781487125CA95EF68A00989C960E708E6CBF594463A9773C884D6F1482735830 +71D5538C781A96C155015F6671305BB48C1A9A8C6B83592E9E2F79E76768626C +4F6F75A17F8A6D0B96336C274EF075D2517B68376F3E90808170599674760000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +52 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000064475C2790657A918C2359DA54AC8200836F898180006930564E80367237 +91CE51B64E5F987563964E1A53F666F3814B591C6DB24E0058F9533B63D694F1 +4F9D4F0A886398905937905779FB4EEA80F075916C825B9C59E85F5D69058681 +501A5DF24E5977E34EE5827A6291661390915C794EBF5F7981C69038808475AB +4EA688D4610F6BC55FC64E4976CA6EA28BE38BAE8C0A8BD15F027FFC7FCC7ECE +8335836B56E06BB797F3963459FB541F94F66DEB5BC5996E5C395F1596900000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +53 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000537082F16A315A749E705E947F2883B984248425836787478FCE8D6276C8 +5F719896786C662054DF62E54F6381C375C85EB896CD8E0A86F9548F6CF36D8C +6C38607F52C775285E7D4F1860A05FE75C24753190AE94C072B96CB96E389149 +670953CB53F34F5191C98BF153C85E7C8FC26DE44E8E76C26986865E611A8206 +4F594FDE903E9C7C61096E1D6E1496854E885A3196E84E0E5C7F79B95B878BED +7FBD738957DF828B90C15401904755BB5CEA5FA161086B3272F180B28A890000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +54 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006D745BD388D598848C6B9A6D9E336E0A51A4514357A38881539F63F48F95 +56ED54585706733F6E907F188FDC82D1613F6028966266F07EA68D8A8DC394A5 +5CB37CA4670860A6960580184E9190E75300966851418FD08574915D665597F5 +5B55531D78386742683D54C9707E5BB08F7D518D572854B1651266828D5E8D43 +810F846C906D7CDF51FF85FB67A365E96FA186A48E81566A90207682707671E5 +8D2362E952196CFD8D3C600E589E618E66FE8D60624E55B36E23672D8F670000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +55 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000094E195F87728680569A8548B4E4D70B88BC86458658B5B857A84503A5BE8 +77BB6BE18A797C986CBE76CF65A98F975D2D5C5586386808536062187AD96E5B +7EFD6A1F7AE05F706F335F20638C6DA867564E085E108D264ED780C07634969C +62DB662D627E6CBC8D7571677F695146808753EC906E629854F286F08F998005 +951785178FD96D5973CD659F771F7504782781FB8D1E94884FA6679575B98BCA +9707632F9547963584B8632377415F8172F04E896014657462EF6B63653F0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +56 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005E2775C790D18BC1829D679D652F5431871877E580A281026C414E4B7EC7 +804C76F4690D6B966267503C4F84574063076B628DBE53EA65E87EB85FD7631A +63B781F381F47F6E5E1C5CD95236667A79E97A1A8D28709975D46EDE6CBB7A92 +4E2D76C55FE0949F88777EC879CD80BF91CD4EF24F17821F54685DDE6D328BCC +7CA58F7480985E1A549276B15B99663C9AA473E0682A86DB6731732A8BF88BDB +90107AF970DB716E62C477A956314E3B845767F152A986C08D2E94F87B510000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +57 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004F4F6CE8795D9A7B6293722A62FD4E1378168F6C64B08D5A7BC668695E84 +88C55986649E58EE72B6690E95258FFD8D5857607F008C0651C6634962D95353 +684C74228301914C55447740707C6D4A517954A88D4459FF6ECB6DC45B5C7D2B +4ED47C7D6ED35B5081EA6E0D5B579B0368D58E2A5B977EFC603B7EB590B98D70 +594F63CD79DF8DB3535265CF79568BC5963B7EC494BB7E825634918967007F6A +5C0A907566285DE64F5067DE505A4F5C57505EA7000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +58 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004E8D4E0C51404E105EFF53454E154E984E1E9B325B6C56694E2879BA4E3F +53154E47592D723B536E6C1056DF80E499976BD3777E9F174E364E9F9F104E5C +4E694E9382885B5B556C560F4EC4538D539D53A353A553AE97658D5D531A53F5 +5326532E533E8D5C5366536352025208520E522D5233523F5240524C525E5261 +525C84AF527D528252815290529351827F544EBB4EC34EC94EC24EE84EE14EEB +4EDE4F1B4EF34F224F644EF54F254F274F094F2B4F5E4F6765384F5A4F5D0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +59 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004F5F4F574F324F3D4F764F744F914F894F834F8F4F7E4F7B4FAA4F7C4FAC +4F944FE64FE84FEA4FC54FDA4FE34FDC4FD14FDF4FF85029504C4FF3502C500F +502E502D4FFE501C500C50255028507E504350555048504E506C507B50A550A7 +50A950BA50D6510650ED50EC50E650EE5107510B4EDD6C3D4F584F654FCE9FA0 +6C467C74516E5DFD9EC999985181591452F9530D8A07531051EB591951554EA0 +51564EB3886E88A44EB5811488D279805B3488037FB851AB51B151BD51BC0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +5A +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000051C7519651A251A58BA08BA68BA78BAA8BB48BB58BB78BC28BC38BCB8BCF +8BCE8BD28BD38BD48BD68BD88BD98BDC8BDF8BE08BE48BE88BE98BEE8BF08BF3 +8BF68BF98BFC8BFF8C008C028C048C078C0C8C0F8C118C128C148C158C168C19 +8C1B8C188C1D8C1F8C208C218C258C278C2A8C2B8C2E8C2F8C328C338C358C36 +5369537A961D962296219631962A963D963C964296499654965F9667966C9672 +96749688968D969796B09097909B909D909990AC90A190B490B390B690BA0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +5B +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000090B890B090CF90C590BE90D090C490C790D390E690E290DC90D790DB90EB +90EF90FE91049122911E91239131912F913991439146520D594252A252AC52AD +52BE54FF52D052D652F053DF71EE77CD5EF451F551FC9B2F53B65F01755A5DEF +574C57A957A1587E58BC58C558D15729572C572A57335739572E572F575C573B +574257695785576B5786577C577B5768576D5776577357AD57A4578C57B257CF +57A757B4579357A057D557D857DA57D957D257B857F457EF57F857E457DD0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +5C +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000580B580D57FD57ED5800581E5819584458205865586C58815889589A5880 +99A89F1961FF8279827D827F828F828A82A88284828E82918297829982AB82B8 +82BE82B082C882CA82E3829882B782AE82CB82CC82C182A982B482A182AA829F +82C482CE82A482E1830982F782E4830F830782DC82F482D282D8830C82FB82D3 +8311831A83068314831582E082D5831C8351835B835C83088392833C83348331 +839B835E832F834F83478343835F834083178360832D833A8333836683650000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +5D +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00008368831B8369836C836A836D836E83B0837883B383B483A083AA8393839C +8385837C83B683A9837D83B8837B8398839E83A883BA83BC83C1840183E583D8 +58078418840B83DD83FD83D6841C84388411840683D483DF840F840383F883F9 +83EA83C583C0842683F083E1845C8451845A8459847384878488847A84898478 +843C844684698476848C848E8431846D84C184CD84D084E684BD84D384CA84BF +84BA84E084A184B984B4849784E584E3850C750D853884F08539851F853A0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +5E +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00008556853B84FF84FC8559854885688564855E857A77A285438572857B85A4 +85A88587858F857985AE859C858585B985B785B085D385C185DC85FF86278605 +86298616863C5EFE5F08593C594180375955595A5958530F5C225C255C2C5C34 +624C626A629F62BB62CA62DA62D762EE632262F66339634B634363AD63F66371 +637A638E63B4636D63AC638A636963AE63BC63F263F863E063FF63C463DE63CE +645263C663BE64456441640B641B6420640C64266421645E6484646D64960000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +5F +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000647A64B764B8649964BA64C064D064D764E464E265096525652E5F0B5FD2 +75195F11535F53F153FD53E953E853FB541254165406544B5452545354545456 +54435421545754595423543254825494547754715464549A549B548454765466 +549D54D054AD54C254B454D254A754A654D354D4547254A354D554BB54BF54CC +54D954DA54DC54A954AA54A454DD54CF54DE551B54E7552054FD551454F35522 +5523550F55115527552A5567558F55B55549556D55415555553F5550553C0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +60 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005537555655755576557755335530555C558B55D2558355B155B955885581 +559F557E55D65591557B55DF55BD55BE5594559955EA55F755C9561F55D155EB +55EC55D455E655DD55C455EF55E555F255F355CC55CD55E855F555E48F94561E +5608560C56015624562355FE56005627562D565856395657562C564D56625659 +565C564C5654568656645671566B567B567C5685569356AF56D456D756DD56E1 +56F556EB56F956FF5704570A5709571C5E0F5E195E145E115E315E3B5E3C0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +61 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005E375E445E545E5B5E5E5E615C8C5C7A5C8D5C905C965C885C985C995C91 +5C9A5C9C5CB55CA25CBD5CAC5CAB5CB15CA35CC15CB75CC45CD25CE45CCB5CE5 +5D025D035D275D265D2E5D245D1E5D065D1B5D585D3E5D345D3D5D6C5D5B5D6F +5D5D5D6B5D4B5D4A5D695D745D825D995D9D8C735DB75DC55F735F775F825F87 +5F895F8C5F955F995F9C5FA85FAD5FB55FBC88625F6172AD72B072B472B772B8 +72C372C172CE72CD72D272E872EF72E972F272F472F7730172F3730372FA0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +62 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000072FB731773137321730A731E731D7315732273397325732C733873317350 +734D73577360736C736F737E821B592598E7592459029963996799689969996A +996B996C99749977997D998099849987998A998D999099919993999499955E80 +5E915E8B5E965EA55EA05EB95EB55EBE5EB38D535ED25ED15EDB5EE85EEA81BA +5FC45FC95FD65FCF60035FEE60045FE15FE45FFE600560065FEA5FED5FF86019 +60356026601B600F600D6029602B600A603F602160786079607B607A60420000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +63 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000606A607D6096609A60AD609D60836092608C609B60EC60BB60B160DD60D8 +60C660DA60B4612061266115612360F46100610E612B614A617561AC619461A7 +61B761D461F55FDD96B395E995EB95F195F395F595F695FC95FE960396049606 +9608960A960B960C960D960F96129615961696179619961A4E2C723F62156C35 +6C546C5C6C4A6CA36C856C906C946C8C6C686C696C746C766C866CA96CD06CD4 +6CAD6CF76CF86CF16CD76CB26CE06CD66CFA6CEB6CEE6CB16CD36CEF6CFE0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +64 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006D396D276D0C6D436D486D076D046D196D0E6D2B6D4D6D2E6D356D1A6D4F +6D526D546D336D916D6F6D9E6DA06D5E6D936D946D5C6D606D7C6D636E1A6DC7 +6DC56DDE6E0E6DBF6DE06E116DE66DDD6DD96E166DAB6E0C6DAE6E2B6E6E6E4E +6E6B6EB26E5F6E866E536E546E326E256E446EDF6EB16E986EE06F2D6EE26EA5 +6EA76EBD6EBB6EB76ED76EB46ECF6E8F6EC26E9F6F626F466F476F246F156EF9 +6F2F6F366F4B6F746F2A6F096F296F896F8D6F8C6F786F726F7C6F7A6FD10000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +65 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006FC96FA76FB96FB66FC26FE16FEE6FDE6FE06FEF701A7023701B70397035 +704F705E5B805B845B955B935BA55BB8752F9A9E64345BE45BEE89305BF08E47 +8B078FB68FD38FD58FE58FEE8FE48FE98FE68FF38FE890059004900B90269011 +900D9016902190359036902D902F9044905190529050906890589062905B66B9 +9074907D908290889083908B5F505F575F565F585C3B54AB5C505C595B715C63 +5C667FBC5F2A5F295F2D82745F3C9B3B5C6E59815983598D59A959AA59A30000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +66 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000599759CA59AB599E59A459D259B259AF59D759BE5A055A0659DD5A0859E3 +59D859F95A0C5A095A325A345A115A235A135A405A675A4A5A555A3C5A625A75 +80EC5AAA5A9B5A775A7A5ABE5AEB5AB25AD25AD45AB85AE05AE35AF15AD65AE6 +5AD85ADC5B095B175B165B325B375B405C155C1C5B5A5B655B735B515B535B62 +9A759A779A789A7A9A7F9A7D9A809A819A859A889A8A9A909A929A939A969A98 +9A9B9A9C9A9D9A9F9AA09AA29AA39AA59AA77E9F7EA17EA37EA57EA87EA90000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +67 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00007EAD7EB07EBE7EC07EC17EC27EC97ECB7ECC7ED07ED47ED77EDB7EE07EE1 +7EE87EEB7EEE7EEF7EF17EF27F0D7EF67EFA7EFB7EFE7F017F027F037F077F08 +7F0B7F0C7F0F7F117F127F177F197F1C7F1B7F1F7F217F227F237F247F257F26 +7F277F2A7F2B7F2C7F2D7F2F7F307F317F327F337F355E7A757F5DDB753E9095 +738E739173AE73A2739F73CF73C273D173B773B373C073C973C873E573D9987C +740A73E973E773DE73BA73F2740F742A745B7426742574287430742E742C0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +68 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000741B741A7441745C7457745574597477746D747E749C748E748074817487 +748B749E74A874A9749074A774D274BA97EA97EB97EC674C6753675E67486769 +67A56787676A6773679867A7677567A8679E67AD678B6777677C67F0680967D8 +680A67E967B0680C67D967B567DA67B367DD680067C367B867E2680E67C167FD +6832683368606861684E6862684468646883681D68556866684168676840683E +684A6849682968B5688F687468776893686B68C2696E68FC691F692068F90000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +69 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000692468F0690B6901695768E369106971693969606942695D6984696B6980 +69986978693469CC6987698869CE6989696669636979699B69A769BB69AB69AD +69D469B169C169CA69DF699569E0698D69FF6A2F69ED6A176A186A6569F26A44 +6A3E6AA06A506A5B6A356A8E6A796A3D6A286A586A7C6A916A906AA96A976AAB +733773526B816B826B876B846B926B936B8D6B9A6B9B6BA16BAA8F6B8F6D8F71 +8F728F738F758F768F788F778F798F7A8F7C8F7E8F818F828F848F878F8B0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +6A +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00008F8D8F8E8F8F8F988F9A8ECE620B6217621B621F6222622162256224622C +81E774EF74F474FF750F75117513653465EE65EF65F0660A6619677266036615 +6600708566F7661D66346631663666358006665F66546641664F665666616657 +66776684668C66A7669D66BE66DB66DC66E666E98D328D338D368D3B8D3D8D40 +8D458D468D488D498D478D4D8D558D5989C789CA89CB89CC89CE89CF89D089D1 +726E729F725D7266726F727E727F7284728B728D728F72926308633263B00000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +6B +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000643F64D880046BEA6BF36BFD6BF56BF96C056C076C066C0D6C156C186C19 +6C1A6C216C296C246C2A6C3265356555656B724D72527256723086625216809F +809C809380BC670A80BD80B180AB80AD80B480B780E780E880E980EA80DB80C2 +80C480D980CD80D7671080DD80EB80F180F480ED810D810E80F280FC67158112 +8C5A8136811E812C811881328148814C815381748159815A817181608169817C +817D816D8167584D5AB58188818281916ED581A381AA81CC672681CA81BB0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +6C +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000081C181A66B246B376B396B436B466B5998D198D298D398D598D998DA6BB3 +5F406BC289F365909F51659365BC65C665C465C365CC65CE65D265D67080709C +7096709D70BB70C070B770AB70B170E870CA711071137116712F71317173715C +716871457172714A7178717A719871B371B571A871A071E071D471E771F9721D +7228706C7118716671B9623E623D624362486249793B794079467949795B795C +7953795A796279577960796F7967797A7985798A799A79A779B35FD15FD00000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +6D +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000603C605D605A606760416059606360AB6106610D615D61A9619D61CB61D1 +62068080807F6C936CF66DFC77F677F87800780978177818781165AB782D781C +781D7839783A783B781F783C7825782C78237829784E786D7856785778267850 +7847784C786A789B7893789A7887789C78A178A378B278B978A578D478D978C9 +78EC78F2790578F479137924791E79349F9B9EF99EFB9EFC76F17704770D76F9 +77077708771A77227719772D7726773577387750775177477743775A77680000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +6E +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000077627765777F778D777D7780778C7791779F77A077B077B577BD753A7540 +754E754B7548755B7572757975837F587F617F5F8A487F687F747F717F797F81 +7F7E76CD76E58832948594869487948B948A948C948D948F9490949494979495 +949A949B949C94A394A494AB94AA94AD94AC94AF94B094B294B494B694B794B8 +94B994BA94BC94BD94BF94C494C894C994CA94CB94CC94CD94CE94D094D194D2 +94D594D694D794D994D894DB94DE94DF94E094E294E494E594E794E894EA0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +6F +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000094E994EB94EE94EF94F394F494F594F794F994FC94FD94FF950395029506 +95079509950A950D950E950F951295139514951595169518951B951D951E951F +9522952A952B9529952C953195329534953695379538953C953E953F95429535 +9544954595469549954C954E954F9552955395549556955795589559955B955E +955F955D95619562956495659566956795689569956A956B956C956F95719572 +9573953A77E777EC96C979D579ED79E379EB7A065D477A037A027A1E7A140000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +70 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00007A397A377A519ECF99A57A707688768E7693769976A474DE74E0752C9E20 +9E229E289E299E2A9E2B9E2C9E329E319E369E389E379E399E3A9E3E9E419E42 +9E449E469E479E489E499E4B9E4C9E4E9E519E559E579E5A9E5B9E5C9E5E9E63 +9E669E679E689E699E6A9E6B9E6C9E719E6D9E7375927594759675A0759D75AC +75A375B375B475B875C475B175B075C375C275D675CD75E375E875E675E475EB +75E7760375F175FC75FF761076007605760C7617760A76257618761576190000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +71 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000761B763C762276207640762D7630763F76357643763E7633764D765E7654 +765C7656766B766F7FCA7AE67A787A797A807A867A887A957AA67AA07AAC7AA8 +7AAD7AB3886488698872887D887F888288A288C688B788BC88C988E288CE88E3 +88E588F1891A88FC88E888FE88F0892189198913891B890A8934892B89368941 +8966897B758B80E576B276B477DC801280148016801C80208022802580268027 +802980288031800B803580438046804D80528069807189839878988098830000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +72 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009889988C988D988F9894989A989B989E989F98A198A298A598A6864D8654 +866C866E867F867A867C867B86A8868D868B86AC869D86A786A386AA869386A9 +86B686C486B586CE86B086BA86B186AF86C986CF86B486E986F186F286ED86F3 +86D0871386DE86F486DF86D886D18703870786F88708870A870D87098723873B +871E8725872E871A873E87488734873187298737873F87828722877D877E877B +87608770874C876E878B87538763877C876487598765879387AF87A887D20000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +73 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000087C68788878587AD8797878387AB87E587AC87B587B387CB87D387BD87D1 +87C087CA87DB87EA87E087EE8816881387FE880A881B88218839883C7F367F42 +7F447F4582107AFA7AFD7B087B037B047B157B0A7B2B7B0F7B477B387B2A7B19 +7B2E7B317B207B257B247B337B3E7B1E7B587B5A7B457B757B4C7B5D7B607B6E +7B7B7B627B727B717B907BA67BA77BB87BAC7B9D7BA87B857BAA7B9C7BA27BAB +7BB47BD17BC17BCC7BDD7BDA7BE57BE67BEA7C0C7BFE7BFC7C0F7C167C0B0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +74 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00007C1F7C2A7C267C387C417C4081FE82018202820481EC8844822182228223 +822D822F8228822B8238823B82338234823E82448249824B824F825A825F8268 +887E8885888888D888DF895E7F9D7F9F7FA77FAF7FB07FB27C7C65497C917C9D +7C9C7C9E7CA27CB27CBC7CBD7CC17CC77CCC7CCD7CC87CC57CD77CE8826E66A8 +7FBF7FCE7FD57FE57FE17FE67FE97FEE7FF37CF87D777DA67DAE7E477E9B9EB8 +9EB48D738D848D948D918DB18D678D6D8C478C49914A9150914E914F91640000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +75 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009162916191709169916F917D917E917291749179918C91859190918D9191 +91A291A391AA91AD91AE91AF91B591B491BA8C559E7E8DB88DEB8E058E598E69 +8DB58DBF8DBC8DBA8DC48DD68DD78DDA8DDE8DCE8DCF8DDB8DC68DEC8DF78DF8 +8DE38DF98DFB8DE48E098DFD8E148E1D8E1F8E2C8E2E8E238E2F8E3A8E408E39 +8E358E3D8E318E498E418E428E518E528E4A8E708E768E7C8E6F8E748E858E8F +8E948E908E9C8E9E8C788C828C8A8C858C988C94659B89D689DE89DA89DC0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +76 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000089E589EB89EF8A3E8B26975396E996F396EF970697019708970F970E972A +972D9730973E9F809F839F859F869F879F889F899F8A9F8C9EFE9F0B9F0D96B9 +96BC96BD96CE96D277BF96E0928E92AE92C8933E936A93CA938F943E946B9C7F +9C829C859C869C879C887A239C8B9C8E9C909C919C929C949C959C9A9C9B9C9E +9C9F9CA09CA19CA29CA39CA59CA69CA79CA89CA99CAB9CAD9CAE9CB09CB19CB2 +9CB39CB49CB59CB69CB79CBA9CBB9CBC9CBD9CC49CC59CC69CC79CCA9CCB0000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +77 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009CCC9CCD9CCE9CCF9CD09CD39CD49CD59CD79CD89CD99CDC9CDD9CDF9CE2 +977C978597919792979497AF97AB97A397B297B49AB19AB09AB79E589AB69ABA +9ABC9AC19AC09AC59AC29ACB9ACC9AD19B459B439B479B499B489B4D9B5198E8 +990D992E995599549ADF9AE19AE69AEF9AEB9AFB9AED9AF99B089B0F9B139B1F +9B239EBD9EBE7E3B9E829E879E889E8B9E9293D69E9D9E9F9EDB9EDC9EDD9EE0 +9EDF9EE29EE99EE79EE59EEA9EEF9F229F2C9F2F9F399F379F3D9F3E9F440000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 Index: library/encoding/gb2312.enc ================================================================== --- library/encoding/gb2312.enc +++ library/encoding/gb2312.enc @@ -1,100 +1,1386 @@ -# Encoding file: gb2312, double-byte -D -233F 0 81 -21 +# Encoding file: euc-cn, multi-byte +M +003F 0 82 +00 +0000000100020003000400050006000700080009000A000B000C000D000E000F +0010001100120013001400150016001700180019001A001B001C001D001E001F +0020002100220023002400250026002700280029002A002B002C002D002E002F +0030003100320033003400350036003700380039003A003B003C003D003E003F +0040004100420043004400450046004700480049004A004B004C004D004E004F +0050005100520053005400550056005700580059005A005B005C005D005E005F +0060006100620063006400650066006700680069006A006B006C006D006E006F +0070007100720073007400750076007700780079007A007B007C007D007E007F +0080008100820083008400850086008700880089008A008B008C008D008E008F +0090009100920093009400950096009700980099009A009B009C009D009E009F +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +A1 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030003001300230FB02C902C700A8300330052015FF5E2225202620182019 201C201D3014301530083009300A300B300C300D300E300F3016301730103011 00B100D700F72236222722282211220F222A222922082237221A22A522252220 23122299222B222E2261224C2248223D221D2260226E226F22642265221E2235 22342642264000B0203220332103FF0400A4FFE0FFE1203000A7211626062605 25CB25CF25CE25C725C625A125A025B325B2203B219221902191219330130000 +A2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 -22 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000024882489248A248B248C248D248E248F2490249124922493249424952496 249724982499249A249B247424752476247724782479247A247B247C247D247E 247F248024812482248324842485248624872460246124622463246424652466 2467246824690000000032203221322232233224322532263227322832290000 00002160216121622163216421652166216721682169216A216B000000000000 +A3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 -23 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF01FF02FF03FFE5FF05FF06FF07FF08FF09FF0AFF0BFF0CFF0DFF0EFF0F FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19FF1AFF1BFF1CFF1DFF1EFF1F FF20FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF3BFF3CFF3DFF3EFF3F FF40FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5AFF5BFF5CFF5DFFE30000 +A4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 -24 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 +A5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 -25 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 +A6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 -26 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +A7 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000004100411041204130414041504010416041704180419041A041B041C041D +041E041F0420042104220423042404250426042704280429042A042B042C042D +042E042F00000000000000000000000000000000000000000000000000000000 +000004300431043204330434043504510436043704380439043A043B043C043D +043E043F0440044104420443044404450446044704480449044A044B044C044D +044E044F00000000000000000000000000000000000000000000000000000000 +A8 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000010100E101CE00E0011300E9011B00E8012B00ED01D000EC014D00F301D2 +00F2016B00FA01D400F901D601D801DA01DC00FC00EA00000000000000000000 +0000000000000000000031053106310731083109310A310B310C310D310E310F +3110311131123113311431153116311731183119311A311B311C311D311E311F +3120312131223123312431253126312731283129000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +A9 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00000000000000002500250125022503250425052506250725082509250A250B +250C250D250E250F2510251125122513251425152516251725182519251A251B +251C251D251E251F2520252125222523252425252526252725282529252A252B +252C252D252E252F2530253125322533253425352536253725382539253A253B +253C253D253E253F2540254125422543254425452546254725482549254A254B +0000000000000000000000000000000000000000000000000000000000000000 +B0 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000554A963F57C3632854CE550954C07691764C853C77EE827E788D72319698 +978D6C285B894FFA630966975CB880FA684880AE660276CE51F9655671AC7FF1 +888450B2596561CA6FB382AD634C625253ED54277B06516B75A45DF462D48DCB +9776628A8019575D97387F627238767D67CF767E64464F708D2562DC7A176591 +73ED642C6273822C9881677F7248626E62CC4F3474E3534A529E7ECA90A65E2E +6886699C81807ED168D278C5868C9551508D8C2482DE80DE5305891252650000 +B1 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000858496F94FDD582199715B9D62B162A566B48C799C8D7206676F789160B2 +535153178F8880CC8D1D94A1500D72C8590760EB711988AB595482EF672C7B28 +5D297EF7752D6CF58E668FF8903C9F3B6BD491197B145F7C78A784D6853D6BD5 +6BD96BD65E015E8775F995ED655D5F0A5FC58F9F58C181C2907F965B97AD8FB9 +7F168D2C62414FBF53D8535E8FA88FA98FAB904D68075F6A819888689CD6618B +522B762A5F6C658C6FD26EE85BBE6448517551B067C44E1979C9997C70B30000 +B2 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000075C55E7673BB83E064AD62E894B56CE2535A52C3640F94C27B944F2F5E1B +82368116818A6E246CCA9A736355535C54FA886557E04E0D5E036B657C3F90E8 +601664E6731C88C16750624D8D22776C8E2991C75F6983DC8521991053C28695 +6B8B60ED60E8707F82CD82314ED36CA785CF64CD7CD969FD66F9834953957B56 +4FA7518C6D4B5C428E6D63D253C9832C833667E578B4643D5BDF5C945DEE8BE7 +62C667F48C7A640063BA8749998B8C177F2094F24EA7961098A4660C73160000 +B3 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000573A5C1D5E38957F507F80A05382655E7545553150218D856284949E671D +56326F6E5DE2543570928F66626F64A463A35F7B6F8890F481E38FB05C186668 +5FF16C8996488D81886C649179F057CE6A59621054484E587A0B60E96F848BDA +627F901E9A8B79E4540375F4630153196C608FDF5F1B9A70803B9F7F4F885C3A +8D647FC565A570BD514551B2866B5D075BA062BD916C75748E0C7A2061017B79 +4EC77EF877854E1181ED521D51FA6A7153A88E87950496CF6EC19664695A0000 +B4 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000784050A877D7641089E6590463E35DDD7A7F693D4F20823955984E3275AE +7A975E625E8A95EF521B5439708A6376952457826625693F918755076DF37EAF +882262337EF075B5832878C196CC8F9E614874F78BCD6B64523A8D506B21806A +847156F153064ECE4E1B51D17C97918B7C074FC38E7F7BE17A9C64675D1450AC +810676017CB96DEC7FE067515B585BF878CB64AE641363AA632B9519642D8FBE +7B5476296253592754466B7950A362345E266B864EE38D37888B5F85902E0000 +B5 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006020803D62C54E39535590F863B880C665E66C2E4F4660EE6DE18BDE5F39 +86CB5F536321515A83616863520063638E4850125C9B79775BFC52307A3B60BC +905376D75FB75F9776848E6C706F767B7B4977AA51F3909358244F4E6EF48FEA +654C7B1B72C46DA47FDF5AE162B55E95573084827B2C5E1D5F1F90127F1498A0 +63826EC7789870B95178975B57AB75354F4375385E9760E659606DC06BBF7889 +53FC96D551CB52016389540A94938C038DCC7239789F87768FED8C0D53E00000 +B6 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004E0176EF53EE948998769F0E952D5B9A8BA24E224E1C51AC846361C252A8 +680B4F97606B51BB6D1E515C6296659796618C46901775D890FD77636BD2728A +72EC8BFB583577798D4C675C9540809A5EA66E2159927AEF77ED953B6BB565AD +7F0E58065151961F5BF958A954288E726566987F56E4949D76FE9041638754C6 +591A593A579B8EB267358DFA8235524160F0581586FE5CE89E454FC4989D8BB9 +5A2560765384627C904F9102997F6069800C513F80335C1499756D314E8C0000 +B7 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00008D3053D17F5A7B4F4F104E4F96006CD573D085E95E06756A7FFB6A0A77FE +94927E4151E170E653CD8FD483038D2972AF996D6CDB574A82B365B980AA623F +963259A84EFF8BBF7EBA653E83F2975E556198DE80A5532A8BFD542080BA5E9F +6CB88D3982AC915A54296C1B52067EB7575F711A6C7E7C89594B4EFD5FFF6124 +7CAA4E305C0167AB87025CF0950B98CE75AF70FD902251AF7F1D8BBD594951E4 +4F5B5426592B657780A45B75627662C28F905E456C1F7B264F0F4FD8670D0000 +B8 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006D6E6DAA798F88B15F17752B629A8F854FEF91DC65A7812F81515E9C8150 +8D74526F89868D4B590D50854ED8961C723681798D1F5BCC8BA3964459877F1A +54905676560E8BE565396982949976D66E895E727518674667D17AFF809D8D76 +611F79C665628D635188521A94A27F38809B7EB25C976E2F67607BD9768B9AD8 +818F7F947CD5641E95507A3F544A54E56B4C640162089E3D80F3759952729769 +845B683C86E49601969494EC4E2A54047ED968398DDF801566F45E9A7FB90000 +B9 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000057C2803F68975DE5653B529F606D9F9A4F9B8EAC516C5BAB5F135DE96C5E +62F18D21517194A952FE6C9F82DF72D757A267848D2D591F8F9C83C754957B8D +4F306CBD5B6459D19F1353E486CA9AA88C3780A16545987E56FA96C7522E74DC +52505BE1630289024E5662D0602A68FA51735B9851A089C27BA199867F5060EF +704C8D2F51495E7F901B747089C4572D78455F529F9F95FA8F689B3C8BE17678 +684267DC8DEA8D35523D8F8A6EDA68CD950590ED56FD679C88F98FC754C80000 +BA +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009AB85B696D776C264EA55BB39A87916361A890AF97E9542B6DB55BD251FD +558A7F557FF064BC634D65F161BE608D710A6C576C49592F676D822A58D5568E +8C6A6BEB90DD597D801753F76D695475559D837783CF683879BE548C4F555408 +76D28C8996026CB36DB88D6B89109E648D3A563F9ED175D55F8872E0606854FC +4EA86A2A886160528F7054C470D886799E3F6D2A5B8F5F187EA255894FAF7334 +543C539A5019540E547C4E4E5FFD745A58F6846B80E1877472D07CCA6E560000 +BB +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005F27864E552C62A44E926CAA623782B154D7534E733E6ED1753B52125316 +8BDD69D05F8A60006DEE574F6B2273AF68538FD87F13636260A3552475EA8C62 +71156DA35BA65E7B8352614C9EC478FA87577C27768751F060F6714C66435E4C +604D8C0E707063258F895FBD606286D456DE6BC160946167534960E066668D3F +79FD4F1A70E96C478BB38BF27ED88364660F5A5A9B426D516DF78C416D3B4F19 +706B83B7621660D1970D8D27797851FB573E57FA673A75787A3D79EF7B950000 +BC +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000808C99658FF96FC08BA59E2159EC7EE97F095409678168D88F917C4D96C6 +53CA602575BE6C7253735AC97EA7632451E0810A5DF184DF628051805B634F0E +796D524260B86D4E5BC45BC28BA18BB065E25FCC964559937EE77EAA560967B7 +59394F735BB652A0835A988A8D3E753294BE50477A3C4EF767B69A7E5AC16B7C +76D1575A5C167B3A95F4714E517C80A9827059787F04832768C067EC78B17877 +62E363617B804FED526A51CF835069DB92748DF58D3189C1952E7BAD4EF60000 +BD +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000506582305251996F6E106E856DA75EFA50F559DC5C066D466C5F7586848B +686859568BB253209171964D854969127901712680F64EA490CA6D479A845A07 +56BC640594F077EB4FA5811A72E189D2997A7F347EDE527F655991758F7F8F83 +53EB7A9663ED63A5768679F888579636622A52AB8282685467706377776B7AED +6D017ED389E359D0621285C982A5754C501F4ECB75A58BEB5C4A5DFE7B4B65A4 +91D14ECA6D25895F7D2795264EC58C288FDB9773664B79818FD170EC6D780000 +BE +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005C3D52B283465162830E775B66769CB84EAC60CA7CBE7CB37ECF4E958B66 +666F988897595883656C955C5F8475C997567ADF7ADE51C070AF7A9863EA7A76 +7EA0739697ED4E4570784E5D915253A9655165E781FC8205548E5C31759A97A0 +62D872D975BD5C459A7983CA5C40548077E94E3E6CAE805A62D2636E5DE85177 +8DDD8E1E952F4FF153E560E770AC526763509E435A1F5026773753777EE26485 +652B628963985014723589C951B38BC07EDD574783CC94A7519B541B5CFB0000 +BF +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004FCA7AE36D5A90E19A8F55805496536154AF5F0063E9697751EF6168520A +582A52D8574E780D770B5EB761777CE0625B62974EA27095800362F770E49760 +577782DB67EF68F578D5989779D158F354B353EF6E34514B523B5BA28BFE80AF +554357A660735751542D7A7A60505B5463A762A053E362635BC767AF54ED7A9F +82E691775E9388E4593857AE630E8DE880EF57577B774FA95FEB5BBD6B3E5321 +7B5072C2684677FF773665F751B54E8F76D45CBF7AA58475594E9B4150800000 +C0 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000998861276E8357646606634656F062EC62695ED39614578362C955878721 +814A8FA3556683B167658D5684DD5A6A680F62E67BEE961151706F9C8C3063FD +89C861D27F0670C26EE57405699472FC5ECA90CE67176D6A635E52B372628001 +4F6C59E5916A70D96D9D52D24E5096F7956D857E78CA7D2F5121579264C2808B +7C7B6CEA68F1695E51B7539868A872819ECE7BF172F879BB6F137406674E91CC +9CA4793C83898354540F68174E3D538952B1783E5386522950884F8B4FD00000 +C1 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000075E27ACB7C926CA596B6529B748354E94FE9805483B28FDE95705EC9601C +6D9F5E18655B813894FE604B70BC7EC37CAE51C968817CB1826F4E248F8691CF +667E4EAE8C0564A9804A50DA759771CE5BE58FBD6F664E86648295635ED66599 +521788C270C852A3730E7433679778F797164E3490BB9CDE6DCB51DB8D41541D +62CE73B283F196F69F8494C34F367F9A51CC707596755CAD988653E64EE46E9C +740969B4786B998F7559521876246D4167F3516D9F99804B54997B3C7ABF0000 +C2 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009686578462E29647697C5A0464027BD36F0F964B82A6536298855E907089 +63B35364864F9C819E93788C97328DEF8D429E7F6F5E79845F559646622E9A74 +541594DD4FA365C55C655C617F1586516C2F5F8B73876EE47EFF5CE6631B5B6A +6EE653754E7163A0756562A18F6E4F264ED16CA67EB68BBA841D87BA7F57903B +95237BA99AA188F8843D6D1B9A867EDC59889EBB739B780186829A6C9A82561B +541757CB4E709EA653568FC881097792999286EE6EE1851366FC61626F2B0000 +C3 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00008C298292832B76F26C135FD983BD732B8305951A6BDB77DB94C6536F8302 +51925E3D8C8C8D384E4873AB679A68859176970971646CA177095A9295416BCF +7F8E66275BD059B95A9A95E895F74EEC840C84996AAC76DF9530731B68A65B5F +772F919A97617CDC8FF78C1C5F257C7379D889C56CCC871C5BC65E4268C97720 +7EF55195514D52C95A297F05976282D763CF778485D079D26E3A5E9959998511 +706D6C1162BF76BF654F60AF95FD660E879F9E2394ED540D547D8C2C64780000 +C4 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000647986116A21819C78E864699B5462B9672B83AB58A89ED86CAB6F205BDE +964C8C0B725F67D062C772614EA959C66BCD589366AE5E5552DF6155672876EE +776672677A4662FF54EA545094A090A35A1C7EB36C164E435976801059485357 +753796BE56CA63208111607C95F96DD65462998151855AE980FD59AE9713502A +6CE55C3C62DF4F60533F817B90066EBA852B62C85E7478BE64B5637B5FF55A18 +917F9E1F5C3F634F80425B7D556E954A954D6D8560A867E072DE51DD5B810000 +C5 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000062E76CDE725B626D94AE7EBD81136D53519C5F04597452AA601259736696 +8650759F632A61E67CEF8BFA54E66B279E256BB485D5545550766CA4556A8DB4 +722C5E156015743662CD6392724C5F986E436D3E65006F5876D878D076FC7554 +522453DB4E535E9E65C1802A80D6629B5486522870AE888D8DD16CE1547880DA +57F988F48D54966A914D4F696C9B55B776C6783062A870F96F8E5F6D84EC68DA +787C7BF781A8670B9E4F636778B0576F78129739627962AB528874356BD70000 +C6 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005564813E75B276AE533975DE50FB5C418B6C7BC7504F72479A9798D86F02 +74E27968648777A562FC98918D2B54C180584E52576A82F9840D5E7351ED74F6 +8BC45C4F57616CFC98875A4678349B448FEB7C955256625194FA4EC683868461 +83E984B257D467345703666E6D668C3166DD7011671F6B3A6816621A59BB4E03 +51C46F0667D26C8F517668CB59476B6775665D0E81109F5065D7794879419A91 +8D775C824E5E4F01542F5951780C56686C148FC45F036C7D6CE38BAB63900000 +C7 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000060706D3D72756266948E94C553438FC17B7E4EDF8C264E7E9ED494B194B3 +524D6F5C90636D458C3458115D4C6B206B4967AA545B81547F8C589985375F3A +62A26A47953965726084686577A74E544FA85DE7979864AC7FD85CED4FCF7A8D +520783044E14602F7A8394A64FB54EB279E6743452E482B964D279BD5BDD6C81 +97528F7B6C22503E537F6E0564CE66746C3060C598778BF75E86743C7A7779CB +4E1890B174036C4256DA914B6CC58D8B533A86C666F28EAF5C489A716E200000 +C8 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000053D65A369F8B8DA353BB570898A76743919B6CC9516875CA62F372AC5238 +529D7F3A7094763853749E4A69B7786E96C088D97FA4713671C3518967D374E4 +58E4651856B78BA9997662707ED560F970ED58EC4EC14EBA5FCD97E74EFB8BA4 +5203598A7EAB62544ECD65E5620E833884C98363878D71946EB65BB97ED25197 +63C967D480898339881551125B7A59828FB14E736C5D516589258F6F962E854A +745E951095F06DA682E55F3164926D128428816E9CC3585E8D5B4E0953C10000 +C9 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004F1E6563685155D34E2764149A9A626B5AC2745F82726DA968EE50E7838E +7802674052396C997EB150BB5565715E7B5B665273CA82EB67495C715220717D +886B95EA965564C58D6181B355846C5562477F2E58924F2455468D4F664C4E0A +5C1A88F368A2634E7A0D70E7828D52FA97F65C1154E890B57ECD59628D4A86C7 +820C820D8D6664445C0461516D89793E8BBE78377533547B4F388EAB6DF15A20 +7EC5795E6C885BA15A76751A80BE614E6E1758F0751F7525727253477EF30000 +CA +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000770176DB526980DC57235E08593172EE65BD6E7F8BD75C388671534177F3 +62FE65F64EC098DF86805B9E8BC653F277E24F7F5C4E9A7659CB5F0F793A58EB +4E1667FF4E8B62ED8A93901D52BF662F55DC566C90024ED54F8D91CA99706C0F +5E0260435BA489C68BD56536624B99965B885BFF6388552E53D77626517D852C +67A268B36B8A62928F9353D482126DD1758F4E668D4E5B70719F85AF669166D9 +7F7287009ECD9F205C5E672F8FF06811675F620D7AD658855EB665706F310000 +CB +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000060555237800D6454887075295E05681362F4971C53CC723D8C016C347761 +7A0E542E77AC987A821C8BF47855671470C165AF64955636601D79C153F84E1D +6B7B80865BFA55E356DB4F3A4F3C99725DF3677E80386002988290015B8B8BBC +8BF5641C825864DE55FD82CF91654FD77D20901F7C9F50F358516EAF5BBF8BC9 +80839178849C7B97867D968B968F7EE59AD3788E5C817A57904296A7795F5B59 +635F7B0B84D168AD55067F2974107D2295016240584C4ED65B83597958540000 +CC +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000736D631E8E4B8E0F80CE82D462AC53F06CF0915E592A60016C70574D644A +8D2A762B6EE9575B6A8075F06F6D8C2D8C0857666BEF889278B363A253F970AD +6C645858642A580268E0819B55107CD650188EBA6DCC8D9F70EB638F6D9B6ED4 +7EE68404684390036DD896768BA85957727985E4817E75BC8A8A68AF52548E22 +951163D098988E44557C4F5366FF568F60D56D9552435C4959296DFB586B7530 +751C606C82148146631167618FE2773A8DF38D3494C15E165385542C70C30000 +CD +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006C405EF7505C4EAD5EAD633A8247901A6850916E77B3540C94DC5F647AE5 +687663457B527EDF75DB507762955934900F51F879C37A8156FE5F9290146D82 +5C60571F541051546E4D56E263A89893817F8715892A9000541E5C6F81C062D6 +625881319E3596409A6E9A7C692D59A562D3553E631654C786D96D3C5A0374E6 +889C6B6A59168C4C5F2F6E7E73A9987D4E3870F75B8C7897633D665A769660CB +5B9B5A494E0781556C6A738B4EA167897F515F8065FA671B5FD859845A010000 +CE +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005DCD5FAE537197E68FDD684556F4552F60DF4E3A6F4D7EF482C7840E59D4 +4F1F4F2A5C3E7EAC672A851A5473754F80C355829B4F4F4D6E2D8C135C096170 +536B761F6E29868A658795FB7EB9543B7A337D0A95EE55E17FC174EE631D8717 +6DA17A9D621165A1536763E16C835DEB545C94A84E4C6C618BEC5C4B65E0829C +68A7543E54346BCB6B664E9463425348821E4F0D4FAE575E620A96FE66647269 +52FF52A1609F8BEF661471996790897F785277FD6670563B54389521727A0000 +CF +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00007A00606F5E0C6089819D591560DC718470EF6EAA6C5072806A8488AD5E2D +4E605AB3559C94E36D177CFB9699620F7EC6778E867E5323971E8F9666875CE1 +4FA072ED4E0B53A6590F54136380952851484ED99C9C7EA454B88D2488548237 +95F26D8E5F265ACC663E966973B0732E53BF817A99857FA15BAA967796507EBF +76F853A2957699997BB189446E584E617FD479658BE660F354CD4EAB98795DF7 +6A6150CF54118C618427785D9704524A54EE56A395006D885BB56DC666530000 +D0 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005C0F5B5D6821809655787B11654869544E9B6B47874E978B534F631F643A +90AA659C80C18C10519968B0537887F961C86CC46CFB8C225C5185AA82AF950C +6B238F9B65B05FFB5FC34FE18845661F8165732960FA51745211578B5F6290A2 +884C91925E78674F602759D3514451F680F853086C7996C4718A4F114FEE7F9E +673D55C5950879C088967EE3589F620C9700865A5618987B5F908BB884C49157 +53D965ED5E8F755C60647D6E5A7F7EEA7EED8F6955A75BA360AC65CB73840000 +D1 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009009766377297EDA9774859B5B667A7496EA884052CB718F5FAA65EC8BE2 +5BFB9A6F5DE16B896C5B8BAD8BAF900A8FC5538B62BC9E269E2D54404E2B82BD +7259869C5D1688596DAF96C554D14E9A8BB6710954BD960970DF6DF976D04E25 +781487125CA95EF68A00989C960E708E6CBF594463A9773C884D6F1482735830 +71D5538C781A96C155015F6671305BB48C1A9A8C6B83592E9E2F79E76768626C +4F6F75A17F8A6D0B96336C274EF075D2517B68376F3E90808170599674760000 +D2 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000064475C2790657A918C2359DA54AC8200836F898180006930564E80367237 +91CE51B64E5F987563964E1A53F666F3814B591C6DB24E0058F9533B63D694F1 +4F9D4F0A886398905937905779FB4EEA80F075916C825B9C59E85F5D69058681 +501A5DF24E5977E34EE5827A6291661390915C794EBF5F7981C69038808475AB +4EA688D4610F6BC55FC64E4976CA6EA28BE38BAE8C0A8BD15F027FFC7FCC7ECE +8335836B56E06BB797F3963459FB541F94F66DEB5BC5996E5C395F1596900000 +D3 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000537082F16A315A749E705E947F2883B984248425836787478FCE8D6276C8 +5F719896786C662054DF62E54F6381C375C85EB896CD8E0A86F9548F6CF36D8C +6C38607F52C775285E7D4F1860A05FE75C24753190AE94C072B96CB96E389149 +670953CB53F34F5191C98BF153C85E7C8FC26DE44E8E76C26986865E611A8206 +4F594FDE903E9C7C61096E1D6E1496854E885A3196E84E0E5C7F79B95B878BED +7FBD738957DF828B90C15401904755BB5CEA5FA161086B3272F180B28A890000 +D4 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006D745BD388D598848C6B9A6D9E336E0A51A4514357A38881539F63F48F95 +56ED54585706733F6E907F188FDC82D1613F6028966266F07EA68D8A8DC394A5 +5CB37CA4670860A6960580184E9190E75300966851418FD08574915D665597F5 +5B55531D78386742683D54C9707E5BB08F7D518D572854B1651266828D5E8D43 +810F846C906D7CDF51FF85FB67A365E96FA186A48E81566A90207682707671E5 +8D2362E952196CFD8D3C600E589E618E66FE8D60624E55B36E23672D8F670000 +D5 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000094E195F87728680569A8548B4E4D70B88BC86458658B5B857A84503A5BE8 +77BB6BE18A797C986CBE76CF65A98F975D2D5C5586386808536062187AD96E5B +7EFD6A1F7AE05F706F335F20638C6DA867564E085E108D264ED780C07634969C +62DB662D627E6CBC8D7571677F695146808753EC906E629854F286F08F998005 +951785178FD96D5973CD659F771F7504782781FB8D1E94884FA6679575B98BCA +9707632F9547963584B8632377415F8172F04E896014657462EF6B63653F0000 +D6 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005E2775C790D18BC1829D679D652F5431871877E580A281026C414E4B7EC7 +804C76F4690D6B966267503C4F84574063076B628DBE53EA65E87EB85FD7631A +63B781F381F47F6E5E1C5CD95236667A79E97A1A8D28709975D46EDE6CBB7A92 +4E2D76C55FE0949F88777EC879CD80BF91CD4EF24F17821F54685DDE6D328BCC +7CA58F7480985E1A549276B15B99663C9AA473E0682A86DB6731732A8BF88BDB +90107AF970DB716E62C477A956314E3B845767F152A986C08D2E94F87B510000 +D7 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004F4F6CE8795D9A7B6293722A62FD4E1378168F6C64B08D5A7BC668695E84 +88C55986649E58EE72B6690E95258FFD8D5857607F008C0651C6634962D95353 +684C74228301914C55447740707C6D4A517954A88D4459FF6ECB6DC45B5C7D2B +4ED47C7D6ED35B5081EA6E0D5B579B0368D58E2A5B977EFC603B7EB590B98D70 +594F63CD79DF8DB3535265CF79568BC5963B7EC494BB7E825634918967007F6A +5C0A907566285DE64F5067DE505A4F5C57505EA7000000000000000000000000 +D8 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004E8D4E0C51404E105EFF53454E154E984E1E9B325B6C56694E2879BA4E3F +53154E47592D723B536E6C1056DF80E499976BD3777E9F174E364E9F9F104E5C +4E694E9382885B5B556C560F4EC4538D539D53A353A553AE97658D5D531A53F5 +5326532E533E8D5C5366536352025208520E522D5233523F5240524C525E5261 +525C84AF527D528252815290529351827F544EBB4EC34EC94EC24EE84EE14EEB +4EDE4F1B4EF34F224F644EF54F254F274F094F2B4F5E4F6765384F5A4F5D0000 +D9 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00004F5F4F574F324F3D4F764F744F914F894F834F8F4F7E4F7B4FAA4F7C4FAC +4F944FE64FE84FEA4FC54FDA4FE34FDC4FD14FDF4FF85029504C4FF3502C500F +502E502D4FFE501C500C50255028507E504350555048504E506C507B50A550A7 +50A950BA50D6510650ED50EC50E650EE5107510B4EDD6C3D4F584F654FCE9FA0 +6C467C74516E5DFD9EC999985181591452F9530D8A07531051EB591951554EA0 +51564EB3886E88A44EB5811488D279805B3488037FB851AB51B151BD51BC0000 +DA +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000051C7519651A251A58BA08BA68BA78BAA8BB48BB58BB78BC28BC38BCB8BCF +8BCE8BD28BD38BD48BD68BD88BD98BDC8BDF8BE08BE48BE88BE98BEE8BF08BF3 +8BF68BF98BFC8BFF8C008C028C048C078C0C8C0F8C118C128C148C158C168C19 +8C1B8C188C1D8C1F8C208C218C258C278C2A8C2B8C2E8C2F8C328C338C358C36 +5369537A961D962296219631962A963D963C964296499654965F9667966C9672 +96749688968D969796B09097909B909D909990AC90A190B490B390B690BA0000 +DB +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000090B890B090CF90C590BE90D090C490C790D390E690E290DC90D790DB90EB +90EF90FE91049122911E91239131912F913991439146520D594252A252AC52AD +52BE54FF52D052D652F053DF71EE77CD5EF451F551FC9B2F53B65F01755A5DEF +574C57A957A1587E58BC58C558D15729572C572A57335739572E572F575C573B +574257695785576B5786577C577B5768576D5776577357AD57A4578C57B257CF +57A757B4579357A057D557D857DA57D957D257B857F457EF57F857E457DD0000 +DC +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000580B580D57FD57ED5800581E5819584458205865586C58815889589A5880 +99A89F1961FF8279827D827F828F828A82A88284828E82918297829982AB82B8 +82BE82B082C882CA82E3829882B782AE82CB82CC82C182A982B482A182AA829F +82C482CE82A482E1830982F782E4830F830782DC82F482D282D8830C82FB82D3 +8311831A83068314831582E082D5831C8351835B835C83088392833C83348331 +839B835E832F834F83478343835F834083178360832D833A8333836683650000 +DD +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00008368831B8369836C836A836D836E83B0837883B383B483A083AA8393839C +8385837C83B683A9837D83B8837B8398839E83A883BA83BC83C1840183E583D8 +58078418840B83DD83FD83D6841C84388411840683D483DF840F840383F883F9 +83EA83C583C0842683F083E1845C8451845A8459847384878488847A84898478 +843C844684698476848C848E8431846D84C184CD84D084E684BD84D384CA84BF +84BA84E084A184B984B4849784E584E3850C750D853884F08539851F853A0000 +DE +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00008556853B84FF84FC8559854885688564855E857A77A285438572857B85A4 +85A88587858F857985AE859C858585B985B785B085D385C185DC85FF86278605 +86298616863C5EFE5F08593C594180375955595A5958530F5C225C255C2C5C34 +624C626A629F62BB62CA62DA62D762EE632262F66339634B634363AD63F66371 +637A638E63B4636D63AC638A636963AE63BC63F263F863E063FF63C463DE63CE +645263C663BE64456441640B641B6420640C64266421645E6484646D64960000 +DF +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000647A64B764B8649964BA64C064D064D764E464E265096525652E5F0B5FD2 +75195F11535F53F153FD53E953E853FB541254165406544B5452545354545456 +54435421545754595423543254825494547754715464549A549B548454765466 +549D54D054AD54C254B454D254A754A654D354D4547254A354D554BB54BF54CC +54D954DA54DC54A954AA54A454DD54CF54DE551B54E7552054FD551454F35522 +5523550F55115527552A5567558F55B55549556D55415555553F5550553C0000 +E0 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005537555655755576557755335530555C558B55D2558355B155B955885581 +559F557E55D65591557B55DF55BD55BE5594559955EA55F755C9561F55D155EB +55EC55D455E655DD55C455EF55E555F255F355CC55CD55E855F555E48F94561E +5608560C56015624562355FE56005627562D565856395657562C564D56625659 +565C564C5654568656645671566B567B567C5685569356AF56D456D756DD56E1 +56F556EB56F956FF5704570A5709571C5E0F5E195E145E115E315E3B5E3C0000 +E1 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00005E375E445E545E5B5E5E5E615C8C5C7A5C8D5C905C965C885C985C995C91 +5C9A5C9C5CB55CA25CBD5CAC5CAB5CB15CA35CC15CB75CC45CD25CE45CCB5CE5 +5D025D035D275D265D2E5D245D1E5D065D1B5D585D3E5D345D3D5D6C5D5B5D6F +5D5D5D6B5D4B5D4A5D695D745D825D995D9D8C735DB75DC55F735F775F825F87 +5F895F8C5F955F995F9C5FA85FAD5FB55FBC88625F6172AD72B072B472B772B8 +72C372C172CE72CD72D272E872EF72E972F272F472F7730172F3730372FA0000 +E2 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000072FB731773137321730A731E731D7315732273397325732C733873317350 +734D73577360736C736F737E821B592598E7592459029963996799689969996A +996B996C99749977997D998099849987998A998D999099919993999499955E80 +5E915E8B5E965EA55EA05EB95EB55EBE5EB38D535ED25ED15EDB5EE85EEA81BA +5FC45FC95FD65FCF60035FEE60045FE15FE45FFE600560065FEA5FED5FF86019 +60356026601B600F600D6029602B600A603F602160786079607B607A60420000 +E3 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000606A607D6096609A60AD609D60836092608C609B60EC60BB60B160DD60D8 +60C660DA60B4612061266115612360F46100610E612B614A617561AC619461A7 +61B761D461F55FDD96B395E995EB95F195F395F595F695FC95FE960396049606 +9608960A960B960C960D960F96129615961696179619961A4E2C723F62156C35 +6C546C5C6C4A6CA36C856C906C946C8C6C686C696C746C766C866CA96CD06CD4 +6CAD6CF76CF86CF16CD76CB26CE06CD66CFA6CEB6CEE6CB16CD36CEF6CFE0000 +E4 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006D396D276D0C6D436D486D076D046D196D0E6D2B6D4D6D2E6D356D1A6D4F +6D526D546D336D916D6F6D9E6DA06D5E6D936D946D5C6D606D7C6D636E1A6DC7 +6DC56DDE6E0E6DBF6DE06E116DE66DDD6DD96E166DAB6E0C6DAE6E2B6E6E6E4E +6E6B6EB26E5F6E866E536E546E326E256E446EDF6EB16E986EE06F2D6EE26EA5 +6EA76EBD6EBB6EB76ED76EB46ECF6E8F6EC26E9F6F626F466F476F246F156EF9 +6F2F6F366F4B6F746F2A6F096F296F896F8D6F8C6F786F726F7C6F7A6FD10000 +E5 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00006FC96FA76FB96FB66FC26FE16FEE6FDE6FE06FEF701A7023701B70397035 +704F705E5B805B845B955B935BA55BB8752F9A9E64345BE45BEE89305BF08E47 +8B078FB68FD38FD58FE58FEE8FE48FE98FE68FF38FE890059004900B90269011 +900D9016902190359036902D902F9044905190529050906890589062905B66B9 +9074907D908290889083908B5F505F575F565F585C3B54AB5C505C595B715C63 +5C667FBC5F2A5F295F2D82745F3C9B3B5C6E59815983598D59A959AA59A30000 +E6 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000599759CA59AB599E59A459D259B259AF59D759BE5A055A0659DD5A0859E3 +59D859F95A0C5A095A325A345A115A235A135A405A675A4A5A555A3C5A625A75 +80EC5AAA5A9B5A775A7A5ABE5AEB5AB25AD25AD45AB85AE05AE35AF15AD65AE6 +5AD85ADC5B095B175B165B325B375B405C155C1C5B5A5B655B735B515B535B62 +9A759A779A789A7A9A7F9A7D9A809A819A859A889A8A9A909A929A939A969A98 +9A9B9A9C9A9D9A9F9AA09AA29AA39AA59AA77E9F7EA17EA37EA57EA87EA90000 +E7 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00007EAD7EB07EBE7EC07EC17EC27EC97ECB7ECC7ED07ED47ED77EDB7EE07EE1 +7EE87EEB7EEE7EEF7EF17EF27F0D7EF67EFA7EFB7EFE7F017F027F037F077F08 +7F0B7F0C7F0F7F117F127F177F197F1C7F1B7F1F7F217F227F237F247F257F26 +7F277F2A7F2B7F2C7F2D7F2F7F307F317F327F337F355E7A757F5DDB753E9095 +738E739173AE73A2739F73CF73C273D173B773B373C073C973C873E573D9987C +740A73E973E773DE73BA73F2740F742A745B7426742574287430742E742C0000 +E8 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000741B741A7441745C7457745574597477746D747E749C748E748074817487 +748B749E74A874A9749074A774D274BA97EA97EB97EC674C6753675E67486769 +67A56787676A6773679867A7677567A8679E67AD678B6777677C67F0680967D8 +680A67E967B0680C67D967B567DA67B367DD680067C367B867E2680E67C167FD +6832683368606861684E6862684468646883681D68556866684168676840683E +684A6849682968B5688F687468776893686B68C2696E68FC691F692068F90000 +E9 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000692468F0690B6901695768E369106971693969606942695D6984696B6980 +69986978693469CC6987698869CE6989696669636979699B69A769BB69AB69AD +69D469B169C169CA69DF699569E0698D69FF6A2F69ED6A176A186A6569F26A44 +6A3E6AA06A506A5B6A356A8E6A796A3D6A286A586A7C6A916A906AA96A976AAB +733773526B816B826B876B846B926B936B8D6B9A6B9B6BA16BAA8F6B8F6D8F71 +8F728F738F758F768F788F778F798F7A8F7C8F7E8F818F828F848F878F8B0000 +EA +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00008F8D8F8E8F8F8F988F9A8ECE620B6217621B621F6222622162256224622C +81E774EF74F474FF750F75117513653465EE65EF65F0660A6619677266036615 +6600708566F7661D66346631663666358006665F66546641664F665666616657 +66776684668C66A7669D66BE66DB66DC66E666E98D328D338D368D3B8D3D8D40 +8D458D468D488D498D478D4D8D558D5989C789CA89CB89CC89CE89CF89D089D1 +726E729F725D7266726F727E727F7284728B728D728F72926308633263B00000 +EB +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000643F64D880046BEA6BF36BFD6BF56BF96C056C076C066C0D6C156C186C19 +6C1A6C216C296C246C2A6C3265356555656B724D72527256723086625216809F +809C809380BC670A80BD80B180AB80AD80B480B780E780E880E980EA80DB80C2 +80C480D980CD80D7671080DD80EB80F180F480ED810D810E80F280FC67158112 +8C5A8136811E812C811881328148814C815381748159815A817181608169817C +817D816D8167584D5AB58188818281916ED581A381AA81CC672681CA81BB0000 +EC +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000081C181A66B246B376B396B436B466B5998D198D298D398D598D998DA6BB3 +5F406BC289F365909F51659365BC65C665C465C365CC65CE65D265D67080709C +7096709D70BB70C070B770AB70B170E870CA711071137116712F71317173715C +716871457172714A7178717A719871B371B571A871A071E071D471E771F9721D +7228706C7118716671B9623E623D624362486249793B794079467949795B795C +7953795A796279577960796F7967797A7985798A799A79A779B35FD15FD00000 +ED +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000603C605D605A606760416059606360AB6106610D615D61A9619D61CB61D1 +62068080807F6C936CF66DFC77F677F87800780978177818781165AB782D781C +781D7839783A783B781F783C7825782C78237829784E786D7856785778267850 +7847784C786A789B7893789A7887789C78A178A378B278B978A578D478D978C9 +78EC78F2790578F479137924791E79349F9B9EF99EFB9EFC76F17704770D76F9 +77077708771A77227719772D7726773577387750775177477743775A77680000 +EE +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000077627765777F778D777D7780778C7791779F77A077B077B577BD753A7540 +754E754B7548755B7572757975837F587F617F5F8A487F687F747F717F797F81 +7F7E76CD76E58832948594869487948B948A948C948D948F9490949494979495 +949A949B949C94A394A494AB94AA94AD94AC94AF94B094B294B494B694B794B8 +94B994BA94BC94BD94BF94C494C894C994CA94CB94CC94CD94CE94D094D194D2 +94D594D694D794D994D894DB94DE94DF94E094E294E494E594E794E894EA0000 +EF +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000094E994EB94EE94EF94F394F494F594F794F994FC94FD94FF950395029506 +95079509950A950D950E950F951295139514951595169518951B951D951E951F +9522952A952B9529952C953195329534953695379538953C953E953F95429535 +9544954595469549954C954E954F9552955395549556955795589559955B955E +955F955D95619562956495659566956795689569956A956B956C956F95719572 +9573953A77E777EC96C979D579ED79E379EB7A065D477A037A027A1E7A140000 +F0 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00007A397A377A519ECF99A57A707688768E7693769976A474DE74E0752C9E20 +9E229E289E299E2A9E2B9E2C9E329E319E369E389E379E399E3A9E3E9E419E42 +9E449E469E479E489E499E4B9E4C9E4E9E519E559E579E5A9E5B9E5C9E5E9E63 +9E669E679E689E699E6A9E6B9E6C9E719E6D9E7375927594759675A0759D75AC +75A375B375B475B875C475B175B075C375C275D675CD75E375E875E675E475EB +75E7760375F175FC75FF761076007605760C7617760A76257618761576190000 +F1 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000761B763C762276207640762D7630763F76357643763E7633764D765E7654 +765C7656766B766F7FCA7AE67A787A797A807A867A887A957AA67AA07AAC7AA8 +7AAD7AB3886488698872887D887F888288A288C688B788BC88C988E288CE88E3 +88E588F1891A88FC88E888FE88F0892189198913891B890A8934892B89368941 +8966897B758B80E576B276B477DC801280148016801C80208022802580268027 +802980288031800B803580438046804D80528069807189839878988098830000 +F2 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009889988C988D988F9894989A989B989E989F98A198A298A598A6864D8654 +866C866E867F867A867C867B86A8868D868B86AC869D86A786A386AA869386A9 +86B686C486B586CE86B086BA86B186AF86C986CF86B486E986F186F286ED86F3 +86D0871386DE86F486DF86D886D18703870786F88708870A870D87098723873B +871E8725872E871A873E87488734873187298737873F87828722877D877E877B +87608770874C876E878B87538763877C876487598765879387AF87A887D20000 +F3 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000087C68788878587AD8797878387AB87E587AC87B587B387CB87D387BD87D1 +87C087CA87DB87EA87E087EE8816881387FE880A881B88218839883C7F367F42 +7F447F4582107AFA7AFD7B087B037B047B157B0A7B2B7B0F7B477B387B2A7B19 +7B2E7B317B207B257B247B337B3E7B1E7B587B5A7B457B757B4C7B5D7B607B6E +7B7B7B627B727B717B907BA67BA77BB87BAC7B9D7BA87B857BAA7B9C7BA27BAB +7BB47BD17BC17BCC7BDD7BDA7BE57BE67BEA7C0C7BFE7BFC7C0F7C167C0B0000 +F4 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00007C1F7C2A7C267C387C417C4081FE82018202820481EC8844822182228223 +822D822F8228822B8238823B82338234823E82448249824B824F825A825F8268 +887E8885888888D888DF895E7F9D7F9F7FA77FAF7FB07FB27C7C65497C917C9D +7C9C7C9E7CA27CB27CBC7CBD7CC17CC77CCC7CCD7CC87CC57CD77CE8826E66A8 +7FBF7FCE7FD57FE57FE17FE67FE97FEE7FF37CF87D777DA67DAE7E477E9B9EB8 +9EB48D738D848D948D918DB18D678D6D8C478C49914A9150914E914F91640000 +F5 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00009162916191709169916F917D917E917291749179918C91859190918D9191 +91A291A391AA91AD91AE91AF91B591B491BA8C559E7E8DB88DEB8E058E598E69 +8DB58DBF8DBC8DBA8DC48DD68DD78DDA8DDE8DCE8DCF8DDB8DC68DEC8DF78DF8 +8DE38DF98DFB8DE48E098DFD8E148E1D8E1F8E2C8E2E8E238E2F8E3A8E408E39 +8E358E3D8E318E498E418E428E518E528E4A8E708E768E7C8E6F8E748E858E8F +8E948E908E9C8E9E8C788C828C8A8C858C988C94659B89D689DE89DA89DC0000 +F6 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +000089E589EB89EF8A3E8B26975396E996F396EF970697019708970F970E972A +972D9730973E9F809F839F859F869F879F889F899F8A9F8C9EFE9F0B9F0D96B9 +96BC96BD96CE96D277BF96E0928E92AE92C8933E936A93CA938F943E946B9C7F +9C829C859C869C879C887A239C8B9C8E9C909C919C929C949C959C9A9C9B9C9E +9C9F9CA09CA19CA29CA39CA59CA69CA79CA89CA99CAB9CAD9CAE9CB09CB19CB2 +9CB39CB49CB59CB69CB79CBA9CBB9CBC9CBD9CC49CC59CC69CC79CCA9CCB0000 +F7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 @@ -101,1280 +1387,11 @@ 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 -27 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000004100411041204130414041504010416041704180419041A041B041C041D -041E041F0420042104220423042404250426042704280429042A042B042C042D -042E042F00000000000000000000000000000000000000000000000000000000 -000004300431043204330434043504510436043704380439043A043B043C043D -043E043F0440044104420443044404450446044704480449044A044B044C044D -044E044F00000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -28 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000010100E101CE00E0011300E9011B00E8012B00ED01D000EC014D00F301D2 -00F2016B00FA01D400F901D601D801DA01DC00FC00EA00000000000000000000 -0000000000000000000031053106310731083109310A310B310C310D310E310F -3110311131123113311431153116311731183119311A311B311C311D311E311F -3120312131223123312431253126312731283129000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -29 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00000000000000002500250125022503250425052506250725082509250A250B -250C250D250E250F2510251125122513251425152516251725182519251A251B -251C251D251E251F2520252125222523252425252526252725282529252A252B -252C252D252E252F2530253125322533253425352536253725382539253A253B -253C253D253E253F2540254125422543254425452546254725482549254A254B -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -30 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000554A963F57C3632854CE550954C07691764C853C77EE827E788D72319698 -978D6C285B894FFA630966975CB880FA684880AE660276CE51F9655671AC7FF1 -888450B2596561CA6FB382AD634C625253ED54277B06516B75A45DF462D48DCB -9776628A8019575D97387F627238767D67CF767E64464F708D2562DC7A176591 -73ED642C6273822C9881677F7248626E62CC4F3474E3534A529E7ECA90A65E2E -6886699C81807ED168D278C5868C9551508D8C2482DE80DE5305891252650000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -31 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000858496F94FDD582199715B9D62B162A566B48C799C8D7206676F789160B2 -535153178F8880CC8D1D94A1500D72C8590760EB711988AB595482EF672C7B28 -5D297EF7752D6CF58E668FF8903C9F3B6BD491197B145F7C78A784D6853D6BD5 -6BD96BD65E015E8775F995ED655D5F0A5FC58F9F58C181C2907F965B97AD8FB9 -7F168D2C62414FBF53D8535E8FA88FA98FAB904D68075F6A819888689CD6618B -522B762A5F6C658C6FD26EE85BBE6448517551B067C44E1979C9997C70B30000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -32 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000075C55E7673BB83E064AD62E894B56CE2535A52C3640F94C27B944F2F5E1B -82368116818A6E246CCA9A736355535C54FA886557E04E0D5E036B657C3F90E8 -601664E6731C88C16750624D8D22776C8E2991C75F6983DC8521991053C28695 -6B8B60ED60E8707F82CD82314ED36CA785CF64CD7CD969FD66F9834953957B56 -4FA7518C6D4B5C428E6D63D253C9832C833667E578B4643D5BDF5C945DEE8BE7 -62C667F48C7A640063BA8749998B8C177F2094F24EA7961098A4660C73160000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -33 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000573A5C1D5E38957F507F80A05382655E7545553150218D856284949E671D -56326F6E5DE2543570928F66626F64A463A35F7B6F8890F481E38FB05C186668 -5FF16C8996488D81886C649179F057CE6A59621054484E587A0B60E96F848BDA -627F901E9A8B79E4540375F4630153196C608FDF5F1B9A70803B9F7F4F885C3A -8D647FC565A570BD514551B2866B5D075BA062BD916C75748E0C7A2061017B79 -4EC77EF877854E1181ED521D51FA6A7153A88E87950496CF6EC19664695A0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -34 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000784050A877D7641089E6590463E35DDD7A7F693D4F20823955984E3275AE -7A975E625E8A95EF521B5439708A6376952457826625693F918755076DF37EAF -882262337EF075B5832878C196CC8F9E614874F78BCD6B64523A8D506B21806A -847156F153064ECE4E1B51D17C97918B7C074FC38E7F7BE17A9C64675D1450AC -810676017CB96DEC7FE067515B585BF878CB64AE641363AA632B9519642D8FBE -7B5476296253592754466B7950A362345E266B864EE38D37888B5F85902E0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -35 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00006020803D62C54E39535590F863B880C665E66C2E4F4660EE6DE18BDE5F39 -86CB5F536321515A83616863520063638E4850125C9B79775BFC52307A3B60BC -905376D75FB75F9776848E6C706F767B7B4977AA51F3909358244F4E6EF48FEA -654C7B1B72C46DA47FDF5AE162B55E95573084827B2C5E1D5F1F90127F1498A0 -63826EC7789870B95178975B57AB75354F4375385E9760E659606DC06BBF7889 -53FC96D551CB52016389540A94938C038DCC7239789F87768FED8C0D53E00000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -36 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00004E0176EF53EE948998769F0E952D5B9A8BA24E224E1C51AC846361C252A8 -680B4F97606B51BB6D1E515C6296659796618C46901775D890FD77636BD2728A -72EC8BFB583577798D4C675C9540809A5EA66E2159927AEF77ED953B6BB565AD -7F0E58065151961F5BF958A954288E726566987F56E4949D76FE9041638754C6 -591A593A579B8EB267358DFA8235524160F0581586FE5CE89E454FC4989D8BB9 -5A2560765384627C904F9102997F6069800C513F80335C1499756D314E8C0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -37 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00008D3053D17F5A7B4F4F104E4F96006CD573D085E95E06756A7FFB6A0A77FE -94927E4151E170E653CD8FD483038D2972AF996D6CDB574A82B365B980AA623F -963259A84EFF8BBF7EBA653E83F2975E556198DE80A5532A8BFD542080BA5E9F -6CB88D3982AC915A54296C1B52067EB7575F711A6C7E7C89594B4EFD5FFF6124 -7CAA4E305C0167AB87025CF0950B98CE75AF70FD902251AF7F1D8BBD594951E4 -4F5B5426592B657780A45B75627662C28F905E456C1F7B264F0F4FD8670D0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -38 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00006D6E6DAA798F88B15F17752B629A8F854FEF91DC65A7812F81515E9C8150 -8D74526F89868D4B590D50854ED8961C723681798D1F5BCC8BA3964459877F1A -54905676560E8BE565396982949976D66E895E727518674667D17AFF809D8D76 -611F79C665628D635188521A94A27F38809B7EB25C976E2F67607BD9768B9AD8 -818F7F947CD5641E95507A3F544A54E56B4C640162089E3D80F3759952729769 -845B683C86E49601969494EC4E2A54047ED968398DDF801566F45E9A7FB90000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -39 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000057C2803F68975DE5653B529F606D9F9A4F9B8EAC516C5BAB5F135DE96C5E -62F18D21517194A952FE6C9F82DF72D757A267848D2D591F8F9C83C754957B8D -4F306CBD5B6459D19F1353E486CA9AA88C3780A16545987E56FA96C7522E74DC -52505BE1630289024E5662D0602A68FA51735B9851A089C27BA199867F5060EF -704C8D2F51495E7F901B747089C4572D78455F529F9F95FA8F689B3C8BE17678 -684267DC8DEA8D35523D8F8A6EDA68CD950590ED56FD679C88F98FC754C80000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -3A -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00009AB85B696D776C264EA55BB39A87916361A890AF97E9542B6DB55BD251FD -558A7F557FF064BC634D65F161BE608D710A6C576C49592F676D822A58D5568E -8C6A6BEB90DD597D801753F76D695475559D837783CF683879BE548C4F555408 -76D28C8996026CB36DB88D6B89109E648D3A563F9ED175D55F8872E0606854FC -4EA86A2A886160528F7054C470D886799E3F6D2A5B8F5F187EA255894FAF7334 -543C539A5019540E547C4E4E5FFD745A58F6846B80E1877472D07CCA6E560000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -3B -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00005F27864E552C62A44E926CAA623782B154D7534E733E6ED1753B52125316 -8BDD69D05F8A60006DEE574F6B2273AF68538FD87F13636260A3552475EA8C62 -71156DA35BA65E7B8352614C9EC478FA87577C27768751F060F6714C66435E4C -604D8C0E707063258F895FBD606286D456DE6BC160946167534960E066668D3F -79FD4F1A70E96C478BB38BF27ED88364660F5A5A9B426D516DF78C416D3B4F19 -706B83B7621660D1970D8D27797851FB573E57FA673A75787A3D79EF7B950000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -3C -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000808C99658FF96FC08BA59E2159EC7EE97F095409678168D88F917C4D96C6 -53CA602575BE6C7253735AC97EA7632451E0810A5DF184DF628051805B634F0E -796D524260B86D4E5BC45BC28BA18BB065E25FCC964559937EE77EAA560967B7 -59394F735BB652A0835A988A8D3E753294BE50477A3C4EF767B69A7E5AC16B7C -76D1575A5C167B3A95F4714E517C80A9827059787F04832768C067EC78B17877 -62E363617B804FED526A51CF835069DB92748DF58D3189C1952E7BAD4EF60000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -3D -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000506582305251996F6E106E856DA75EFA50F559DC5C066D466C5F7586848B -686859568BB253209171964D854969127901712680F64EA490CA6D479A845A07 -56BC640594F077EB4FA5811A72E189D2997A7F347EDE527F655991758F7F8F83 -53EB7A9663ED63A5768679F888579636622A52AB8282685467706377776B7AED -6D017ED389E359D0621285C982A5754C501F4ECB75A58BEB5C4A5DFE7B4B65A4 -91D14ECA6D25895F7D2795264EC58C288FDB9773664B79818FD170EC6D780000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -3E -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00005C3D52B283465162830E775B66769CB84EAC60CA7CBE7CB37ECF4E958B66 -666F988897595883656C955C5F8475C997567ADF7ADE51C070AF7A9863EA7A76 -7EA0739697ED4E4570784E5D915253A9655165E781FC8205548E5C31759A97A0 -62D872D975BD5C459A7983CA5C40548077E94E3E6CAE805A62D2636E5DE85177 -8DDD8E1E952F4FF153E560E770AC526763509E435A1F5026773753777EE26485 -652B628963985014723589C951B38BC07EDD574783CC94A7519B541B5CFB0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -3F -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00004FCA7AE36D5A90E19A8F55805496536154AF5F0063E9697751EF6168520A -582A52D8574E780D770B5EB761777CE0625B62974EA27095800362F770E49760 -577782DB67EF68F578D5989779D158F354B353EF6E34514B523B5BA28BFE80AF -554357A660735751542D7A7A60505B5463A762A053E362635BC767AF54ED7A9F -82E691775E9388E4593857AE630E8DE880EF57577B774FA95FEB5BBD6B3E5321 -7B5072C2684677FF773665F751B54E8F76D45CBF7AA58475594E9B4150800000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -40 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000998861276E8357646606634656F062EC62695ED39614578362C955878721 -814A8FA3556683B167658D5684DD5A6A680F62E67BEE961151706F9C8C3063FD -89C861D27F0670C26EE57405699472FC5ECA90CE67176D6A635E52B372628001 -4F6C59E5916A70D96D9D52D24E5096F7956D857E78CA7D2F5121579264C2808B -7C7B6CEA68F1695E51B7539868A872819ECE7BF172F879BB6F137406674E91CC -9CA4793C83898354540F68174E3D538952B1783E5386522950884F8B4FD00000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -41 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000075E27ACB7C926CA596B6529B748354E94FE9805483B28FDE95705EC9601C -6D9F5E18655B813894FE604B70BC7EC37CAE51C968817CB1826F4E248F8691CF -667E4EAE8C0564A9804A50DA759771CE5BE58FBD6F664E86648295635ED66599 -521788C270C852A3730E7433679778F797164E3490BB9CDE6DCB51DB8D41541D -62CE73B283F196F69F8494C34F367F9A51CC707596755CAD988653E64EE46E9C -740969B4786B998F7559521876246D4167F3516D9F99804B54997B3C7ABF0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -42 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00009686578462E29647697C5A0464027BD36F0F964B82A6536298855E907089 -63B35364864F9C819E93788C97328DEF8D429E7F6F5E79845F559646622E9A74 -541594DD4FA365C55C655C617F1586516C2F5F8B73876EE47EFF5CE6631B5B6A -6EE653754E7163A0756562A18F6E4F264ED16CA67EB68BBA841D87BA7F57903B -95237BA99AA188F8843D6D1B9A867EDC59889EBB739B780186829A6C9A82561B -541757CB4E709EA653568FC881097792999286EE6EE1851366FC61626F2B0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -43 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00008C298292832B76F26C135FD983BD732B8305951A6BDB77DB94C6536F8302 -51925E3D8C8C8D384E4873AB679A68859176970971646CA177095A9295416BCF -7F8E66275BD059B95A9A95E895F74EEC840C84996AAC76DF9530731B68A65B5F -772F919A97617CDC8FF78C1C5F257C7379D889C56CCC871C5BC65E4268C97720 -7EF55195514D52C95A297F05976282D763CF778485D079D26E3A5E9959998511 -706D6C1162BF76BF654F60AF95FD660E879F9E2394ED540D547D8C2C64780000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -44 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000647986116A21819C78E864699B5462B9672B83AB58A89ED86CAB6F205BDE -964C8C0B725F67D062C772614EA959C66BCD589366AE5E5552DF6155672876EE -776672677A4662FF54EA545094A090A35A1C7EB36C164E435976801059485357 -753796BE56CA63208111607C95F96DD65462998151855AE980FD59AE9713502A -6CE55C3C62DF4F60533F817B90066EBA852B62C85E7478BE64B5637B5FF55A18 -917F9E1F5C3F634F80425B7D556E954A954D6D8560A867E072DE51DD5B810000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -45 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000062E76CDE725B626D94AE7EBD81136D53519C5F04597452AA601259736696 -8650759F632A61E67CEF8BFA54E66B279E256BB485D5545550766CA4556A8DB4 -722C5E156015743662CD6392724C5F986E436D3E65006F5876D878D076FC7554 -522453DB4E535E9E65C1802A80D6629B5486522870AE888D8DD16CE1547880DA -57F988F48D54966A914D4F696C9B55B776C6783062A870F96F8E5F6D84EC68DA -787C7BF781A8670B9E4F636778B0576F78129739627962AB528874356BD70000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -46 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00005564813E75B276AE533975DE50FB5C418B6C7BC7504F72479A9798D86F02 -74E27968648777A562FC98918D2B54C180584E52576A82F9840D5E7351ED74F6 -8BC45C4F57616CFC98875A4678349B448FEB7C955256625194FA4EC683868461 -83E984B257D467345703666E6D668C3166DD7011671F6B3A6816621A59BB4E03 -51C46F0667D26C8F517668CB59476B6775665D0E81109F5065D7794879419A91 -8D775C824E5E4F01542F5951780C56686C148FC45F036C7D6CE38BAB63900000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -47 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000060706D3D72756266948E94C553438FC17B7E4EDF8C264E7E9ED494B194B3 -524D6F5C90636D458C3458115D4C6B206B4967AA545B81547F8C589985375F3A -62A26A47953965726084686577A74E544FA85DE7979864AC7FD85CED4FCF7A8D -520783044E14602F7A8394A64FB54EB279E6743452E482B964D279BD5BDD6C81 -97528F7B6C22503E537F6E0564CE66746C3060C598778BF75E86743C7A7779CB -4E1890B174036C4256DA914B6CC58D8B533A86C666F28EAF5C489A716E200000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -48 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000053D65A369F8B8DA353BB570898A76743919B6CC9516875CA62F372AC5238 -529D7F3A7094763853749E4A69B7786E96C088D97FA4713671C3518967D374E4 -58E4651856B78BA9997662707ED560F970ED58EC4EC14EBA5FCD97E74EFB8BA4 -5203598A7EAB62544ECD65E5620E833884C98363878D71946EB65BB97ED25197 -63C967D480898339881551125B7A59828FB14E736C5D516589258F6F962E854A -745E951095F06DA682E55F3164926D128428816E9CC3585E8D5B4E0953C10000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -49 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00004F1E6563685155D34E2764149A9A626B5AC2745F82726DA968EE50E7838E -7802674052396C997EB150BB5565715E7B5B665273CA82EB67495C715220717D -886B95EA965564C58D6181B355846C5562477F2E58924F2455468D4F664C4E0A -5C1A88F368A2634E7A0D70E7828D52FA97F65C1154E890B57ECD59628D4A86C7 -820C820D8D6664445C0461516D89793E8BBE78377533547B4F388EAB6DF15A20 -7EC5795E6C885BA15A76751A80BE614E6E1758F0751F7525727253477EF30000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -4A -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000770176DB526980DC57235E08593172EE65BD6E7F8BD75C388671534177F3 -62FE65F64EC098DF86805B9E8BC653F277E24F7F5C4E9A7659CB5F0F793A58EB -4E1667FF4E8B62ED8A93901D52BF662F55DC566C90024ED54F8D91CA99706C0F -5E0260435BA489C68BD56536624B99965B885BFF6388552E53D77626517D852C -67A268B36B8A62928F9353D482126DD1758F4E668D4E5B70719F85AF669166D9 -7F7287009ECD9F205C5E672F8FF06811675F620D7AD658855EB665706F310000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -4B -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000060555237800D6454887075295E05681362F4971C53CC723D8C016C347761 -7A0E542E77AC987A821C8BF47855671470C165AF64955636601D79C153F84E1D -6B7B80865BFA55E356DB4F3A4F3C99725DF3677E80386002988290015B8B8BBC -8BF5641C825864DE55FD82CF91654FD77D20901F7C9F50F358516EAF5BBF8BC9 -80839178849C7B97867D968B968F7EE59AD3788E5C817A57904296A7795F5B59 -635F7B0B84D168AD55067F2974107D2295016240584C4ED65B83597958540000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -4C -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000736D631E8E4B8E0F80CE82D462AC53F06CF0915E592A60016C70574D644A -8D2A762B6EE9575B6A8075F06F6D8C2D8C0857666BEF889278B363A253F970AD -6C645858642A580268E0819B55107CD650188EBA6DCC8D9F70EB638F6D9B6ED4 -7EE68404684390036DD896768BA85957727985E4817E75BC8A8A68AF52548E22 -951163D098988E44557C4F5366FF568F60D56D9552435C4959296DFB586B7530 -751C606C82148146631167618FE2773A8DF38D3494C15E165385542C70C30000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -4D -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00006C405EF7505C4EAD5EAD633A8247901A6850916E77B3540C94DC5F647AE5 -687663457B527EDF75DB507762955934900F51F879C37A8156FE5F9290146D82 -5C60571F541051546E4D56E263A89893817F8715892A9000541E5C6F81C062D6 -625881319E3596409A6E9A7C692D59A562D3553E631654C786D96D3C5A0374E6 -889C6B6A59168C4C5F2F6E7E73A9987D4E3870F75B8C7897633D665A769660CB -5B9B5A494E0781556C6A738B4EA167897F515F8065FA671B5FD859845A010000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -4E -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00005DCD5FAE537197E68FDD684556F4552F60DF4E3A6F4D7EF482C7840E59D4 -4F1F4F2A5C3E7EAC672A851A5473754F80C355829B4F4F4D6E2D8C135C096170 -536B761F6E29868A658795FB7EB9543B7A337D0A95EE55E17FC174EE631D8717 -6DA17A9D621165A1536763E16C835DEB545C94A84E4C6C618BEC5C4B65E0829C -68A7543E54346BCB6B664E9463425348821E4F0D4FAE575E620A96FE66647269 -52FF52A1609F8BEF661471996790897F785277FD6670563B54389521727A0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -4F -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00007A00606F5E0C6089819D591560DC718470EF6EAA6C5072806A8488AD5E2D -4E605AB3559C94E36D177CFB9699620F7EC6778E867E5323971E8F9666875CE1 -4FA072ED4E0B53A6590F54136380952851484ED99C9C7EA454B88D2488548237 -95F26D8E5F265ACC663E966973B0732E53BF817A99857FA15BAA967796507EBF -76F853A2957699997BB189446E584E617FD479658BE660F354CD4EAB98795DF7 -6A6150CF54118C618427785D9704524A54EE56A395006D885BB56DC666530000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -50 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00005C0F5B5D6821809655787B11654869544E9B6B47874E978B534F631F643A -90AA659C80C18C10519968B0537887F961C86CC46CFB8C225C5185AA82AF950C -6B238F9B65B05FFB5FC34FE18845661F8165732960FA51745211578B5F6290A2 -884C91925E78674F602759D3514451F680F853086C7996C4718A4F114FEE7F9E -673D55C5950879C088967EE3589F620C9700865A5618987B5F908BB884C49157 -53D965ED5E8F755C60647D6E5A7F7EEA7EED8F6955A75BA360AC65CB73840000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -51 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00009009766377297EDA9774859B5B667A7496EA884052CB718F5FAA65EC8BE2 -5BFB9A6F5DE16B896C5B8BAD8BAF900A8FC5538B62BC9E269E2D54404E2B82BD -7259869C5D1688596DAF96C554D14E9A8BB6710954BD960970DF6DF976D04E25 -781487125CA95EF68A00989C960E708E6CBF594463A9773C884D6F1482735830 -71D5538C781A96C155015F6671305BB48C1A9A8C6B83592E9E2F79E76768626C -4F6F75A17F8A6D0B96336C274EF075D2517B68376F3E90808170599674760000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -52 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000064475C2790657A918C2359DA54AC8200836F898180006930564E80367237 -91CE51B64E5F987563964E1A53F666F3814B591C6DB24E0058F9533B63D694F1 -4F9D4F0A886398905937905779FB4EEA80F075916C825B9C59E85F5D69058681 -501A5DF24E5977E34EE5827A6291661390915C794EBF5F7981C69038808475AB -4EA688D4610F6BC55FC64E4976CA6EA28BE38BAE8C0A8BD15F027FFC7FCC7ECE -8335836B56E06BB797F3963459FB541F94F66DEB5BC5996E5C395F1596900000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -53 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000537082F16A315A749E705E947F2883B984248425836787478FCE8D6276C8 -5F719896786C662054DF62E54F6381C375C85EB896CD8E0A86F9548F6CF36D8C -6C38607F52C775285E7D4F1860A05FE75C24753190AE94C072B96CB96E389149 -670953CB53F34F5191C98BF153C85E7C8FC26DE44E8E76C26986865E611A8206 -4F594FDE903E9C7C61096E1D6E1496854E885A3196E84E0E5C7F79B95B878BED -7FBD738957DF828B90C15401904755BB5CEA5FA161086B3272F180B28A890000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -54 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00006D745BD388D598848C6B9A6D9E336E0A51A4514357A38881539F63F48F95 -56ED54585706733F6E907F188FDC82D1613F6028966266F07EA68D8A8DC394A5 -5CB37CA4670860A6960580184E9190E75300966851418FD08574915D665597F5 -5B55531D78386742683D54C9707E5BB08F7D518D572854B1651266828D5E8D43 -810F846C906D7CDF51FF85FB67A365E96FA186A48E81566A90207682707671E5 -8D2362E952196CFD8D3C600E589E618E66FE8D60624E55B36E23672D8F670000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -55 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000094E195F87728680569A8548B4E4D70B88BC86458658B5B857A84503A5BE8 -77BB6BE18A797C986CBE76CF65A98F975D2D5C5586386808536062187AD96E5B -7EFD6A1F7AE05F706F335F20638C6DA867564E085E108D264ED780C07634969C -62DB662D627E6CBC8D7571677F695146808753EC906E629854F286F08F998005 -951785178FD96D5973CD659F771F7504782781FB8D1E94884FA6679575B98BCA -9707632F9547963584B8632377415F8172F04E896014657462EF6B63653F0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -56 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00005E2775C790D18BC1829D679D652F5431871877E580A281026C414E4B7EC7 -804C76F4690D6B966267503C4F84574063076B628DBE53EA65E87EB85FD7631A -63B781F381F47F6E5E1C5CD95236667A79E97A1A8D28709975D46EDE6CBB7A92 -4E2D76C55FE0949F88777EC879CD80BF91CD4EF24F17821F54685DDE6D328BCC -7CA58F7480985E1A549276B15B99663C9AA473E0682A86DB6731732A8BF88BDB -90107AF970DB716E62C477A956314E3B845767F152A986C08D2E94F87B510000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -57 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00004F4F6CE8795D9A7B6293722A62FD4E1378168F6C64B08D5A7BC668695E84 -88C55986649E58EE72B6690E95258FFD8D5857607F008C0651C6634962D95353 -684C74228301914C55447740707C6D4A517954A88D4459FF6ECB6DC45B5C7D2B -4ED47C7D6ED35B5081EA6E0D5B579B0368D58E2A5B977EFC603B7EB590B98D70 -594F63CD79DF8DB3535265CF79568BC5963B7EC494BB7E825634918967007F6A -5C0A907566285DE64F5067DE505A4F5C57505EA7000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -58 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00004E8D4E0C51404E105EFF53454E154E984E1E9B325B6C56694E2879BA4E3F -53154E47592D723B536E6C1056DF80E499976BD3777E9F174E364E9F9F104E5C -4E694E9382885B5B556C560F4EC4538D539D53A353A553AE97658D5D531A53F5 -5326532E533E8D5C5366536352025208520E522D5233523F5240524C525E5261 -525C84AF527D528252815290529351827F544EBB4EC34EC94EC24EE84EE14EEB -4EDE4F1B4EF34F224F644EF54F254F274F094F2B4F5E4F6765384F5A4F5D0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -59 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00004F5F4F574F324F3D4F764F744F914F894F834F8F4F7E4F7B4FAA4F7C4FAC -4F944FE64FE84FEA4FC54FDA4FE34FDC4FD14FDF4FF85029504C4FF3502C500F -502E502D4FFE501C500C50255028507E504350555048504E506C507B50A550A7 -50A950BA50D6510650ED50EC50E650EE5107510B4EDD6C3D4F584F654FCE9FA0 -6C467C74516E5DFD9EC999985181591452F9530D8A07531051EB591951554EA0 -51564EB3886E88A44EB5811488D279805B3488037FB851AB51B151BD51BC0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -5A -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000051C7519651A251A58BA08BA68BA78BAA8BB48BB58BB78BC28BC38BCB8BCF -8BCE8BD28BD38BD48BD68BD88BD98BDC8BDF8BE08BE48BE88BE98BEE8BF08BF3 -8BF68BF98BFC8BFF8C008C028C048C078C0C8C0F8C118C128C148C158C168C19 -8C1B8C188C1D8C1F8C208C218C258C278C2A8C2B8C2E8C2F8C328C338C358C36 -5369537A961D962296219631962A963D963C964296499654965F9667966C9672 -96749688968D969796B09097909B909D909990AC90A190B490B390B690BA0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -5B -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000090B890B090CF90C590BE90D090C490C790D390E690E290DC90D790DB90EB -90EF90FE91049122911E91239131912F913991439146520D594252A252AC52AD -52BE54FF52D052D652F053DF71EE77CD5EF451F551FC9B2F53B65F01755A5DEF -574C57A957A1587E58BC58C558D15729572C572A57335739572E572F575C573B -574257695785576B5786577C577B5768576D5776577357AD57A4578C57B257CF -57A757B4579357A057D557D857DA57D957D257B857F457EF57F857E457DD0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -5C -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000580B580D57FD57ED5800581E5819584458205865586C58815889589A5880 -99A89F1961FF8279827D827F828F828A82A88284828E82918297829982AB82B8 -82BE82B082C882CA82E3829882B782AE82CB82CC82C182A982B482A182AA829F -82C482CE82A482E1830982F782E4830F830782DC82F482D282D8830C82FB82D3 -8311831A83068314831582E082D5831C8351835B835C83088392833C83348331 -839B835E832F834F83478343835F834083178360832D833A8333836683650000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -5D -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00008368831B8369836C836A836D836E83B0837883B383B483A083AA8393839C -8385837C83B683A9837D83B8837B8398839E83A883BA83BC83C1840183E583D8 -58078418840B83DD83FD83D6841C84388411840683D483DF840F840383F883F9 -83EA83C583C0842683F083E1845C8451845A8459847384878488847A84898478 -843C844684698476848C848E8431846D84C184CD84D084E684BD84D384CA84BF -84BA84E084A184B984B4849784E584E3850C750D853884F08539851F853A0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -5E -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00008556853B84FF84FC8559854885688564855E857A77A285438572857B85A4 -85A88587858F857985AE859C858585B985B785B085D385C185DC85FF86278605 -86298616863C5EFE5F08593C594180375955595A5958530F5C225C255C2C5C34 -624C626A629F62BB62CA62DA62D762EE632262F66339634B634363AD63F66371 -637A638E63B4636D63AC638A636963AE63BC63F263F863E063FF63C463DE63CE -645263C663BE64456441640B641B6420640C64266421645E6484646D64960000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -5F -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000647A64B764B8649964BA64C064D064D764E464E265096525652E5F0B5FD2 -75195F11535F53F153FD53E953E853FB541254165406544B5452545354545456 -54435421545754595423543254825494547754715464549A549B548454765466 -549D54D054AD54C254B454D254A754A654D354D4547254A354D554BB54BF54CC -54D954DA54DC54A954AA54A454DD54CF54DE551B54E7552054FD551454F35522 -5523550F55115527552A5567558F55B55549556D55415555553F5550553C0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -60 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00005537555655755576557755335530555C558B55D2558355B155B955885581 -559F557E55D65591557B55DF55BD55BE5594559955EA55F755C9561F55D155EB -55EC55D455E655DD55C455EF55E555F255F355CC55CD55E855F555E48F94561E -5608560C56015624562355FE56005627562D565856395657562C564D56625659 -565C564C5654568656645671566B567B567C5685569356AF56D456D756DD56E1 -56F556EB56F956FF5704570A5709571C5E0F5E195E145E115E315E3B5E3C0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -61 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00005E375E445E545E5B5E5E5E615C8C5C7A5C8D5C905C965C885C985C995C91 -5C9A5C9C5CB55CA25CBD5CAC5CAB5CB15CA35CC15CB75CC45CD25CE45CCB5CE5 -5D025D035D275D265D2E5D245D1E5D065D1B5D585D3E5D345D3D5D6C5D5B5D6F -5D5D5D6B5D4B5D4A5D695D745D825D995D9D8C735DB75DC55F735F775F825F87 -5F895F8C5F955F995F9C5FA85FAD5FB55FBC88625F6172AD72B072B472B772B8 -72C372C172CE72CD72D272E872EF72E972F272F472F7730172F3730372FA0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -62 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000072FB731773137321730A731E731D7315732273397325732C733873317350 -734D73577360736C736F737E821B592598E7592459029963996799689969996A -996B996C99749977997D998099849987998A998D999099919993999499955E80 -5E915E8B5E965EA55EA05EB95EB55EBE5EB38D535ED25ED15EDB5EE85EEA81BA -5FC45FC95FD65FCF60035FEE60045FE15FE45FFE600560065FEA5FED5FF86019 -60356026601B600F600D6029602B600A603F602160786079607B607A60420000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -63 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000606A607D6096609A60AD609D60836092608C609B60EC60BB60B160DD60D8 -60C660DA60B4612061266115612360F46100610E612B614A617561AC619461A7 -61B761D461F55FDD96B395E995EB95F195F395F595F695FC95FE960396049606 -9608960A960B960C960D960F96129615961696179619961A4E2C723F62156C35 -6C546C5C6C4A6CA36C856C906C946C8C6C686C696C746C766C866CA96CD06CD4 -6CAD6CF76CF86CF16CD76CB26CE06CD66CFA6CEB6CEE6CB16CD36CEF6CFE0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -64 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00006D396D276D0C6D436D486D076D046D196D0E6D2B6D4D6D2E6D356D1A6D4F -6D526D546D336D916D6F6D9E6DA06D5E6D936D946D5C6D606D7C6D636E1A6DC7 -6DC56DDE6E0E6DBF6DE06E116DE66DDD6DD96E166DAB6E0C6DAE6E2B6E6E6E4E -6E6B6EB26E5F6E866E536E546E326E256E446EDF6EB16E986EE06F2D6EE26EA5 -6EA76EBD6EBB6EB76ED76EB46ECF6E8F6EC26E9F6F626F466F476F246F156EF9 -6F2F6F366F4B6F746F2A6F096F296F896F8D6F8C6F786F726F7C6F7A6FD10000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -65 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00006FC96FA76FB96FB66FC26FE16FEE6FDE6FE06FEF701A7023701B70397035 -704F705E5B805B845B955B935BA55BB8752F9A9E64345BE45BEE89305BF08E47 -8B078FB68FD38FD58FE58FEE8FE48FE98FE68FF38FE890059004900B90269011 -900D9016902190359036902D902F9044905190529050906890589062905B66B9 -9074907D908290889083908B5F505F575F565F585C3B54AB5C505C595B715C63 -5C667FBC5F2A5F295F2D82745F3C9B3B5C6E59815983598D59A959AA59A30000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -66 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000599759CA59AB599E59A459D259B259AF59D759BE5A055A0659DD5A0859E3 -59D859F95A0C5A095A325A345A115A235A135A405A675A4A5A555A3C5A625A75 -80EC5AAA5A9B5A775A7A5ABE5AEB5AB25AD25AD45AB85AE05AE35AF15AD65AE6 -5AD85ADC5B095B175B165B325B375B405C155C1C5B5A5B655B735B515B535B62 -9A759A779A789A7A9A7F9A7D9A809A819A859A889A8A9A909A929A939A969A98 -9A9B9A9C9A9D9A9F9AA09AA29AA39AA59AA77E9F7EA17EA37EA57EA87EA90000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -67 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00007EAD7EB07EBE7EC07EC17EC27EC97ECB7ECC7ED07ED47ED77EDB7EE07EE1 -7EE87EEB7EEE7EEF7EF17EF27F0D7EF67EFA7EFB7EFE7F017F027F037F077F08 -7F0B7F0C7F0F7F117F127F177F197F1C7F1B7F1F7F217F227F237F247F257F26 -7F277F2A7F2B7F2C7F2D7F2F7F307F317F327F337F355E7A757F5DDB753E9095 -738E739173AE73A2739F73CF73C273D173B773B373C073C973C873E573D9987C -740A73E973E773DE73BA73F2740F742A745B7426742574287430742E742C0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -68 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000741B741A7441745C7457745574597477746D747E749C748E748074817487 -748B749E74A874A9749074A774D274BA97EA97EB97EC674C6753675E67486769 -67A56787676A6773679867A7677567A8679E67AD678B6777677C67F0680967D8 -680A67E967B0680C67D967B567DA67B367DD680067C367B867E2680E67C167FD -6832683368606861684E6862684468646883681D68556866684168676840683E -684A6849682968B5688F687468776893686B68C2696E68FC691F692068F90000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -69 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000692468F0690B6901695768E369106971693969606942695D6984696B6980 -69986978693469CC6987698869CE6989696669636979699B69A769BB69AB69AD -69D469B169C169CA69DF699569E0698D69FF6A2F69ED6A176A186A6569F26A44 -6A3E6AA06A506A5B6A356A8E6A796A3D6A286A586A7C6A916A906AA96A976AAB -733773526B816B826B876B846B926B936B8D6B9A6B9B6BA16BAA8F6B8F6D8F71 -8F728F738F758F768F788F778F798F7A8F7C8F7E8F818F828F848F878F8B0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -6A -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00008F8D8F8E8F8F8F988F9A8ECE620B6217621B621F6222622162256224622C -81E774EF74F474FF750F75117513653465EE65EF65F0660A6619677266036615 -6600708566F7661D66346631663666358006665F66546641664F665666616657 -66776684668C66A7669D66BE66DB66DC66E666E98D328D338D368D3B8D3D8D40 -8D458D468D488D498D478D4D8D558D5989C789CA89CB89CC89CE89CF89D089D1 -726E729F725D7266726F727E727F7284728B728D728F72926308633263B00000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -6B -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000643F64D880046BEA6BF36BFD6BF56BF96C056C076C066C0D6C156C186C19 -6C1A6C216C296C246C2A6C3265356555656B724D72527256723086625216809F -809C809380BC670A80BD80B180AB80AD80B480B780E780E880E980EA80DB80C2 -80C480D980CD80D7671080DD80EB80F180F480ED810D810E80F280FC67158112 -8C5A8136811E812C811881328148814C815381748159815A817181608169817C -817D816D8167584D5AB58188818281916ED581A381AA81CC672681CA81BB0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -6C -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000081C181A66B246B376B396B436B466B5998D198D298D398D598D998DA6BB3 -5F406BC289F365909F51659365BC65C665C465C365CC65CE65D265D67080709C -7096709D70BB70C070B770AB70B170E870CA711071137116712F71317173715C -716871457172714A7178717A719871B371B571A871A071E071D471E771F9721D -7228706C7118716671B9623E623D624362486249793B794079467949795B795C -7953795A796279577960796F7967797A7985798A799A79A779B35FD15FD00000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -6D -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000603C605D605A606760416059606360AB6106610D615D61A9619D61CB61D1 -62068080807F6C936CF66DFC77F677F87800780978177818781165AB782D781C -781D7839783A783B781F783C7825782C78237829784E786D7856785778267850 -7847784C786A789B7893789A7887789C78A178A378B278B978A578D478D978C9 -78EC78F2790578F479137924791E79349F9B9EF99EFB9EFC76F17704770D76F9 -77077708771A77227719772D7726773577387750775177477743775A77680000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -6E -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000077627765777F778D777D7780778C7791779F77A077B077B577BD753A7540 -754E754B7548755B7572757975837F587F617F5F8A487F687F747F717F797F81 -7F7E76CD76E58832948594869487948B948A948C948D948F9490949494979495 -949A949B949C94A394A494AB94AA94AD94AC94AF94B094B294B494B694B794B8 -94B994BA94BC94BD94BF94C494C894C994CA94CB94CC94CD94CE94D094D194D2 -94D594D694D794D994D894DB94DE94DF94E094E294E494E594E794E894EA0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -6F -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000094E994EB94EE94EF94F394F494F594F794F994FC94FD94FF950395029506 -95079509950A950D950E950F951295139514951595169518951B951D951E951F -9522952A952B9529952C953195329534953695379538953C953E953F95429535 -9544954595469549954C954E954F9552955395549556955795589559955B955E -955F955D95619562956495659566956795689569956A956B956C956F95719572 -9573953A77E777EC96C979D579ED79E379EB7A065D477A037A027A1E7A140000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -70 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00007A397A377A519ECF99A57A707688768E7693769976A474DE74E0752C9E20 -9E229E289E299E2A9E2B9E2C9E329E319E369E389E379E399E3A9E3E9E419E42 -9E449E469E479E489E499E4B9E4C9E4E9E519E559E579E5A9E5B9E5C9E5E9E63 -9E669E679E689E699E6A9E6B9E6C9E719E6D9E7375927594759675A0759D75AC -75A375B375B475B875C475B175B075C375C275D675CD75E375E875E675E475EB -75E7760375F175FC75FF761076007605760C7617760A76257618761576190000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -71 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000761B763C762276207640762D7630763F76357643763E7633764D765E7654 -765C7656766B766F7FCA7AE67A787A797A807A867A887A957AA67AA07AAC7AA8 -7AAD7AB3886488698872887D887F888288A288C688B788BC88C988E288CE88E3 -88E588F1891A88FC88E888FE88F0892189198913891B890A8934892B89368941 -8966897B758B80E576B276B477DC801280148016801C80208022802580268027 -802980288031800B803580438046804D80528069807189839878988098830000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -72 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00009889988C988D988F9894989A989B989E989F98A198A298A598A6864D8654 -866C866E867F867A867C867B86A8868D868B86AC869D86A786A386AA869386A9 -86B686C486B586CE86B086BA86B186AF86C986CF86B486E986F186F286ED86F3 -86D0871386DE86F486DF86D886D18703870786F88708870A870D87098723873B -871E8725872E871A873E87488734873187298737873F87828722877D877E877B -87608770874C876E878B87538763877C876487598765879387AF87A887D20000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -73 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000087C68788878587AD8797878387AB87E587AC87B587B387CB87D387BD87D1 -87C087CA87DB87EA87E087EE8816881387FE880A881B88218839883C7F367F42 -7F447F4582107AFA7AFD7B087B037B047B157B0A7B2B7B0F7B477B387B2A7B19 -7B2E7B317B207B257B247B337B3E7B1E7B587B5A7B457B757B4C7B5D7B607B6E -7B7B7B627B727B717B907BA67BA77BB87BAC7B9D7BA87B857BAA7B9C7BA27BAB -7BB47BD17BC17BCC7BDD7BDA7BE57BE67BEA7C0C7BFE7BFC7C0F7C167C0B0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -74 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00007C1F7C2A7C267C387C417C4081FE82018202820481EC8844822182228223 -822D822F8228822B8238823B82338234823E82448249824B824F825A825F8268 -887E8885888888D888DF895E7F9D7F9F7FA77FAF7FB07FB27C7C65497C917C9D -7C9C7C9E7CA27CB27CBC7CBD7CC17CC77CCC7CCD7CC87CC57CD77CE8826E66A8 -7FBF7FCE7FD57FE57FE17FE67FE97FEE7FF37CF87D777DA67DAE7E477E9B9EB8 -9EB48D738D848D948D918DB18D678D6D8C478C49914A9150914E914F91640000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -75 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -00009162916191709169916F917D917E917291749179918C91859190918D9191 -91A291A391AA91AD91AE91AF91B591B491BA8C559E7E8DB88DEB8E058E598E69 -8DB58DBF8DBC8DBA8DC48DD68DD78DDA8DDE8DCE8DCF8DDB8DC68DEC8DF78DF8 -8DE38DF98DFB8DE48E098DFD8E148E1D8E1F8E2C8E2E8E238E2F8E3A8E408E39 -8E358E3D8E318E498E418E428E518E528E4A8E708E768E7C8E6F8E748E858E8F -8E948E908E9C8E9E8C788C828C8A8C858C988C94659B89D689DE89DA89DC0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -76 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -000089E589EB89EF8A3E8B26975396E996F396EF970697019708970F970E972A -972D9730973E9F809F839F859F869F879F889F899F8A9F8C9EFE9F0B9F0D96B9 -96BC96BD96CE96D277BF96E0928E92AE92C8933E936A93CA938F943E946B9C7F -9C829C859C869C879C887A239C8B9C8E9C909C919C929C949C959C9A9C9B9C9E -9C9F9CA09CA19CA29CA39CA59CA69CA79CA89CA99CAB9CAD9CAE9CB09CB19CB2 -9CB39CB49CB59CB69CB79CBA9CBB9CBC9CBD9CC49CC59CC69CC79CCA9CCB0000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -77 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 00009CCC9CCD9CCE9CCF9CD09CD39CD49CD59CD79CD89CD99CDC9CDD9CDF9CE2 977C978597919792979497AF97AB97A397B297B49AB19AB09AB79E589AB69ABA 9ABC9AC19AC09AC59AC29ACB9ACC9AD19B459B439B479B499B489B4D9B5198E8 990D992E995599549ADF9AE19AE69AEF9AEB9AFB9AED9AF99B089B0F9B139B1F 9B239EBD9EBE7E3B9E829E879E889E8B9E9293D69E9D9E9F9EDB9EDC9EDD9EE0 9EDF9EE29EE99EE79EE59EEA9EEF9F229F2C9F2F9F399F379F3D9F3E9F440000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 -0000000000000000000000000000000000000000000000000000000000000000 Index: library/history.tcl ================================================================== --- library/history.tcl +++ library/history.tcl @@ -1,10 +1,10 @@ # history.tcl -- # # Implementation of the history command. # -# RCS: @(#) $Id: history.tcl,v 1.5 2001/05/17 08:18:56 hobbs Exp $ +# RCS: @(#) $Id: history.tcl,v 1.5.14.1 2005/07/22 21:59:40 dgp Exp $ # # Copyright (c) 1997 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -166,18 +166,18 @@ proc tcl::HistAdd {command {exec {}}} { variable history # Do not add empty commands to the history - if {[string trim $command] == ""} { + if {[string trim $command] eq ""} { return "" } set i [incr history(nextid)] set history($i) $command set j [incr history(oldest)] - if {[info exists history($j)]} {unset history($j)} + unset -nocomplain history($j) if {[string match e* $exec]} { return [uplevel #0 $command] } else { return {} } @@ -196,17 +196,17 @@ # Side Effects: # Updates history(keep) if a limit is specified proc tcl::HistKeep {{limit {}}} { variable history - if {[string length $limit] == 0} { + if {$limit eq ""} { return $history(keep) } else { set oldold $history(oldest) set history(oldest) [expr {$history(nextid) - $limit}] for {} {$oldold <= $history(oldest)} {incr oldold} { - if {[info exists history($oldold)]} {unset history($oldold)} + unset -nocomplain history($oldold) } set history(keep) $limit } } @@ -244,22 +244,21 @@ # Results: # A formatted history list proc tcl::HistInfo {{num {}}} { variable history - if {$num == {}} { + if {$num eq ""} { set num [expr {$history(keep) + 1}] } set result {} set newline "" for {set i [expr {$history(nextid) - $num + 1}]} \ {$i <= $history(nextid)} {incr i} { if {![info exists history($i)]} { continue } - set cmd [string trimright $history($i) \ \n] - regsub -all \n $cmd "\n\t" cmd + set cmd [string map [list \n \n\t] [string trimright $history($i) \ \n]] append result $newline[format "%6d %s" $i $cmd] set newline \n } return $result } @@ -279,11 +278,11 @@ # Side Effects: # Replaces the current history list item with the one being redone. proc tcl::HistRedo {{event -1}} { variable history - if {[string length $event] == 0} { + if {$event eq ""} { set event -1 } set i [HistIndex $event] if {$i == $history(nextid)} { return -code error "cannot redo the current event" Index: library/http/http.tcl ================================================================== --- library/http/http.tcl +++ library/http/http.tcl @@ -1,55 +1,59 @@ # http.tcl -- # -# Client-side HTTP for GET, POST, and HEAD commands. -# These routines can be used in untrusted code that uses -# the Safesock security policy. These procedures use a -# callback interface to avoid using vwait, which is not +# Client-side HTTP for GET, POST, and HEAD commands. These routines can +# be used in untrusted code that uses the Safesock security policy. These +# procedures use a callback interface to avoid using vwait, which is not # defined in the safe base. # -# See the file "license.terms" for information on usage and -# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# See the file "license.terms" for information on usage and redistribution of +# this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: http.tcl,v 1.43 2002/10/03 13:34:32 dkf Exp $ +# RCS: @(#) $Id: http.tcl,v 1.43.2.13 2006/10/06 05:56:48 hobbs Exp $ # Rough version history: -# 1.0 Old http_get interface -# 2.0 http:: namespace and http::geturl -# 2.1 Added callbacks to handle arriving data, and timeouts -# 2.2 Added ability to fetch into a channel -# 2.3 Added SSL support, and ability to post from a channel -# This version also cleans up error cases and eliminates the -# "ioerror" status in favor of raising an error -# 2.4 Added -binary option to http::geturl and charset element -# to the state array. - -package require Tcl 8.2 -# keep this in sync with pkgIndex.tcl -# and with the install directories in Makefiles -package provide http 2.4.2 +# 1.0 Old http_get interface. +# 2.0 http:: namespace and http::geturl. +# 2.1 Added callbacks to handle arriving data, and timeouts. +# 2.2 Added ability to fetch into a channel. +# 2.3 Added SSL support, and ability to post from a channel. This version +# also cleans up error cases and eliminates the "ioerror" status in +# favor of raising an error +# 2.4 Added -binary option to http::geturl and charset element to the state +# array. + +package require Tcl 8.4 +# Keep this in sync with pkgIndex.tcl and with the install directories +# in Makefiles +package provide http 2.5.3 namespace eval http { variable http array set http { -accept */* -proxyhost {} -proxyport {} -proxyfilter http::ProxyRequired + -urlencoding utf-8 } set http(-useragent) "Tcl http client package [package provide http]" proc init {} { - variable formMap - variable alphanumeric a-zA-Z0-9 + # Set up the map for quoting chars. RFC3986 Section 2.3 say percent + # encode all except: "... percent-encoded octets in the ranges of ALPHA + # (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E), + # underscore (%5F), or tilde (%7E) should not be created by URI + # producers ..." for {set i 0} {$i <= 256} {incr i} { set c [format %c $i] - if {![string match \[$alphanumeric\] $c]} { - set formMap($c) %[format %.2x $i] + if {![string match {[-._~a-zA-Z0-9]} $c]} { + set map($c) %[format %.2x $i] } } # These are handled specially - array set formMap { " " + \n %0d%0a } + set map(\n) %0d%0a + variable formMap [array get map] } init variable urlTypes array set urlTypes { @@ -57,10 +61,13 @@ } variable encodings [string tolower [encoding names]] # This can be changed, but iso8859-1 is the RFC standard. variable defaultCharset "iso8859-1" + + # Force RFC 3986 strictness in geturl url verification? Not for 8.4.x + variable strict 0 namespace export geturl config reset wait formatQuery register unregister # Useful, but not exported: data size status code } @@ -117,11 +124,11 @@ foreach name $options { lappend result $name $http($name) } return $result } - regsub -all -- - $options {} options + set options [string map {- ""} $options] set pat ^-([join $options |])$ if {[llength $args] == 1} { set flag [lindex $args 0] if {[regexp -- $pat $flag]} { return $http($flag) @@ -144,13 +151,13 @@ # Clean up the socket and eval close time callbacks # # Arguments: # token Connection token. # errormsg (optional) If set, forces status to error. -# skipCB (optional) If set, don't call the -command callback. This +# skipCB (optional) If set, don't call the -command callback. This # is useful when geturl wants to throw an exception instead -# of calling the callback. That way, the same error isn't +# of calling the callback. That way, the same error isn't # reported to two places. # # Side Effects: # Closes the socket @@ -210,21 +217,21 @@ # Arguments: # url The http URL to goget. # args Option value pairs. Valid options include: # -blocksize, -validate, -headers, -timeout # Results: -# Returns a token for this connection. -# This token is the name of an array that the caller should -# unset to garbage collect the state. +# Returns a token for this connection. This token is the name of an array +# that the caller should unset to garbage collect the state. proc http::geturl { url args } { variable http variable urlTypes variable defaultCharset + variable strict - # Initialize the state variable, an array. We'll return the - # name of this array as the token for the transaction. + # Initialize the state variable, an array. We'll return the name of this + # array as the token for the transaction. if {![info exists http(uid)]} { set http(uid) 0 } set token [namespace current]::[incr http(uid)] @@ -252,26 +259,33 @@ queryoffset 0 type text/html body {} status "" http "" + } + # These flags have their types verified [Bug 811170] + array set type { + -binary boolean + -blocksize integer + -queryblocksize integer + -validate boolean + -timeout integer } set state(charset) $defaultCharset set options {-binary -blocksize -channel -command -handler -headers \ -progress -query -queryblocksize -querychannel -queryprogress\ -validate -timeout -type} set usage [join $options ", "] - regsub -all -- - $options {} options + set options [string map {- ""} $options] set pat ^-([join $options |])$ foreach {flag value} $args { if {[regexp $pat $flag]} { # Validate numbers - if {[info exists state($flag)] && \ - [string is integer -strict $state($flag)] && \ - ![string is integer -strict $value]} { + if {[info exists type($flag)] && \ + ![string is $type($flag) -strict $value]} { unset $token - return -code error "Bad value for $flag ($value), must be integer" + return -code error "Bad value for $flag ($value), must be $type($flag)" } set state($flag) $value } else { unset $token return -code error "Unknown option $flag, can be: $usage" @@ -286,19 +300,122 @@ unset $token return -code error "Can't combine -query and -querychannel options!" } # Validate URL, determine the server host and port, and check proxy case + # Recognize user:pass@host URLs also, although we do not do anything with + # that info yet. + + # URLs have basically four parts. + # First, before the colon, is the protocol scheme (e.g. http) + # Second, for HTTP-like protocols, is the authority + # The authority is preceded by // and lasts up to (but not including) + # the following / and it identifies up to four parts, of which only one, + # the host, is required (if an authority is present at all). All other + # parts of the authority (user name, password, port number) are optional. + # Third is the resource name, which is split into two parts at a ? + # The first part (from the single "/" up to "?") is the path, and the + # second part (from that "?" up to "#") is the query. *HOWEVER*, we do + # not need to separate them; we send the whole lot to the server. + # Fourth is the fragment identifier, which is everything after the first + # "#" in the URL. The fragment identifier MUST NOT be sent to the server + # and indeed, we don't bother to validate it (it could be an error to + # pass it in here, but it's cheap to strip). + # + # An example of a URL that has all the parts: + # http://jschmoe:xyzzy@www.bogus.net:8000/foo/bar.tml?q=foo#changes + # The "http" is the protocol, the user is "jschmoe", the password is + # "xyzzy", the host is "www.bogus.net", the port is "8000", the path is + # "/foo/bar.tml", the query is "q=foo", and the fragment is "changes". + # + # Note that the RE actually combines the user and password parts, as + # recommended in RFC 3986. Indeed, that RFC states that putting passwords + # in URLs is a Really Bad Idea, something with which I would agree utterly. + # Also note that we do not currently support IPv6 addresses. + # + # From a validation perspective, we need to ensure that the parts of the + # URL that are going to the server are correctly encoded. + # This is only done if $::http::strict is true (default 0 for compat). + + set URLmatcher {(?x) # this is _expanded_ syntax + ^ + (?: (\w+) : ) ? # + (?: // + (?: + ( + [^@/\#?]+ # + ) @ + )? + ( [^/:\#?]+ ) # + (?: : (\d+) )? # + )? + ( / [^\#?]* (?: \? [^\#?]* )?)? # (including query) + (?: \# (.*) )? # + $ + } - if {![regexp -nocase {^(([^:]*)://)?([^/:]+)(:([0-9]+))?(/.*)?$} $url \ - x prefix proto host y port srvurl]} { + # Phase one: parse + if {![regexp -- $URLmatcher $url -> proto user host port srvurl]} { unset $token return -code error "Unsupported URL: $url" + } + # Phase two: validate + if {$host eq ""} { + # Caller has to provide a host name; we do not have a "default host" + # that would enable us to handle relative URLs. + unset $token + return -code error "Missing host part: $url" + # Note that we don't check the hostname for validity here; if it's + # invalid, we'll simply fail to resolve it later on. + } + if {$port ne "" && $port>65535} { + unset $token + return -code error "Invalid port number: $port" + } + # The user identification and resource identification parts of the URL can + # have encoded characters in them; take care! + if {$user ne ""} { + # Check for validity according to RFC 3986, Appendix A + set validityRE {(?xi) + ^ + (?: [-\w.~!$&'()*+,;=:] | %[0-9a-f][0-9a-f] )+ + $ + } + if {$strict && ![regexp -- $validityRE $user]} { + unset $token + # Provide a better error message in this error case + if {[regexp {(?i)%(?![0-9a-f][0-9a-f]).?.?} $user bad]} { + return -code error \ + "Illegal encoding character usage \"$bad\" in URL user" + } + return -code error "Illegal characters in URL user" + } + } + if {$srvurl ne ""} { + # Check for validity according to RFC 3986, Appendix A + set validityRE {(?xi) + ^ + # Path part (already must start with / character) + (?: [-\w.~!$&'()*+,;=:@/] | %[0-9a-f][0-9a-f] )* + # Query part (optional, permits ? characters) + (?: \? (?: [-\w.~!$&'()*+,;=:@/?] | %[0-9a-f][0-9a-f] )* )? + $ + } + if {$strict && ![regexp -- $validityRE $srvurl]} { + unset $token + # Provide a better error message in this error case + if {[regexp {(?i)%(?![0-9a-f][0-9a-f])..} $srvurl bad]} { + return -code error \ + "Illegal encoding character usage \"$bad\" in URL path" + } + return -code error "Illegal characters in URL path" + } + } else { + set srvurl / } if {[string length $proto] == 0} { set proto http - set url ${proto}://$url } if {![info exists urlTypes($proto)]} { unset $token return -code error "Unsupported URL type \"$proto\"" } @@ -306,69 +423,76 @@ set defcmd [lindex $urlTypes($proto) 1] if {[string length $port] == 0} { set port $defport } - if {[string length $srvurl] == 0} { - set srvurl / - } - if {[string length $proto] == 0} { - set url http://$url - } - set state(url) $url if {![catch {$http(-proxyfilter) $host} proxy]} { set phost [lindex $proxy 0] set pport [lindex $proxy 1] } - # If a timeout is specified we set up the after event - # and arrange for an asynchronous socket connection. + # OK, now reassemble into a full URL + set url ${proto}:// + if {$user ne ""} { + append url $user + append url @ + } + append url $host + if {$port != $defport} { + append url : $port + } + append url $srvurl + # Don't append the fragment! + set state(url) $url + + # If a timeout is specified we set up the after event and arrange for an + # asynchronous socket connection. if {$state(-timeout) > 0} { set state(after) [after $state(-timeout) \ [list http::reset $token timeout]] set async -async } else { set async "" } - # If we are using the proxy, we must pass in the full URL that - # includes the server name. + # If we are using the proxy, we must pass in the full URL that includes + # the server name. if {[info exists phost] && [string length $phost]} { set srvurl $url set conStat [catch {eval $defcmd $async {$phost $pport}} s] } else { set conStat [catch {eval $defcmd $async {$host $port}} s] } + if {$conStat} { - - # something went wrong while trying to establish the connection - # Clean up after events and such, but DON'T call the command callback - # (if available) because we're going to throw an exception from here + # Something went wrong while trying to establish the connection. Clean + # up after events and such, but DON'T call the command callback (if + # available) because we're going to throw an exception from here # instead. Finish $token "" 1 cleanup $token return -code error $s } set state(sock) $s - # Wait for the connection to complete + # Wait for the connection to complete. if {$state(-timeout) > 0} { fileevent $s writable [list http::Connect $token] http::wait $token - if {[string equal $state(status) "error"]} { - # something went wrong while trying to establish the connection + if {$state(status) eq "error"} { + # Something went wrong while trying to establish the connection. # Clean up after events and such, but DON'T call the command - # callback (if available) because we're going to throw an + # callback (if available) because we're going to throw an # exception from here instead. set err [lindex $state(error) 0] cleanup $token return -code error $err - } elseif {![string equal $state(status) "connect"]} { + } elseif {$state(status) ne "connect"} { # Likely to be connection timeout return $token } set state(status) "" } @@ -375,22 +499,22 @@ # Send data in cr-lf format, but accept any line terminators fconfigure $s -translation {auto crlf} -buffersize $state(-blocksize) - # The following is disallowed in safe interpreters, but the socket - # is already in non-blocking mode in that case. + # The following is disallowed in safe interpreters, but the socket is + # already in non-blocking mode in that case. catch {fconfigure $s -blocking off} set how GET if {$isQuery} { set state(querylength) [string length $state(-query)] if {$state(querylength) > 0} { set how POST set contDone 0 } else { - # there's no query data + # There's no query data. unset state(-query) set isQuery 0 } } elseif {$state(-validate)} { set how HEAD @@ -404,56 +528,55 @@ if {[catch { puts $s "$how $srvurl HTTP/1.0" puts $s "Accept: $http(-accept)" if {$port == $defport} { - # Don't add port in this case, to handle broken servers. - # [Bug #504508] + # Don't add port in this case, to handle broken servers. [Bug + # 504508] puts $s "Host: $host" } else { puts $s "Host: $host:$port" } puts $s "User-Agent: $http(-useragent)" foreach {key value} $state(-headers) { - regsub -all \[\n\r\] $value {} value + set value [string map [list \n "" \r ""] $value] set key [string trim $key] - if {[string equal $key "Content-Length"]} { + if {$key eq "Content-Length"} { set contDone 1 set state(querylength) $value } if {[string length $key]} { puts $s "$key: $value" } } if {$isQueryChannel && $state(querylength) == 0} { - # Try to determine size of data in channel - # If we cannot seek, the surrounding catch will trap us + # Try to determine size of data in channel. If we cannot seek, the + # surrounding catch will trap us set start [tell $state(-querychannel)] seek $state(-querychannel) 0 end set state(querylength) \ [expr {[tell $state(-querychannel)] - $start}] seek $state(-querychannel) $start } - # Flush the request header and set up the fileevent that will - # either push the POST data or read the response. + # Flush the request header and set up the fileevent that will either + # push the POST data or read the response. # # fileevent note: # - # It is possible to have both the read and write fileevents active - # at this point. The only scenario it seems to affect is a server - # that closes the connection without reading the POST data. - # (e.g., early versions TclHttpd in various error cases). - # Depending on the platform, the client may or may not be able to - # get the response from the server because of the error it will - # get trying to write the post data. Having both fileevents active - # changes the timing and the behavior, but no two platforms - # (among Solaris, Linux, and NT) behave the same, and none - # behave all that well in any case. Servers should always read thier - # POST data if they expect the client to read their response. - + # It is possible to have both the read and write fileevents active at + # this point. The only scenario it seems to affect is a server that + # closes the connection without reading the POST data. (e.g., early + # versions TclHttpd in various error cases). Depending on the platform, + # the client may or may not be able to get the response from the server + # because of the error it will get trying to write the post data. + # Having both fileevents active changes the timing and the behavior, + # but no two platforms (among Solaris, Linux, and NT) behave the same, + # and none behave all that well in any case. Servers should always read + # their POST data if they expect the client to read their response. + if {$isQuery || $isQueryChannel} { puts $s "Content-Type: $state(-type)" if {!$contDone} { puts $s "Content-Length: $state(querylength)" } @@ -465,32 +588,31 @@ flush $s fileevent $s readable [list http::Event $token] } if {! [info exists state(-command)]} { - - # geturl does EVERYTHING asynchronously, so if the user - # calls it synchronously, we just do a wait here. + # geturl does EVERYTHING asynchronously, so if the user calls it + # synchronously, we just do a wait here. wait $token - if {[string equal $state(status) "error"]} { + if {$state(status) eq "error"} { # Something went wrong, so throw the exception, and the # enclosing catch will do cleanup. return -code error [lindex $state(error) 0] - } + } } } err]} { - # The socket probably was never connected, - # or the connection dropped later. + # The socket probably was never connected, or the connection dropped + # later. # Clean up after events and such, but DON'T call the command callback # (if available) because we're going to throw an exception from here # instead. - + # if state(status) is error, it means someone's already called Finish # to do the above-described clean up. - if {[string equal $state(status) "error"]} { + if {$state(status) eq "error"} { Finish $token $err 1 } cleanup $token return -code error $err } @@ -598,22 +720,19 @@ proc http::Write {token} { variable $token upvar 0 $token state set s $state(sock) - + # Output a block. Tcl will buffer this if the socket blocks - set done 0 if {[catch { - # Catch I/O errors on dead sockets if {[info exists state(-query)]} { - - # Chop up large query strings so queryprogress callback - # can give smooth feedback + # Chop up large query strings so queryprogress callback can give + # smooth feedback. puts -nonewline $s \ [string range $state(-query) $state(queryoffset) \ [expr {$state(queryoffset) + $state(-queryblocksize) - 1}]] incr state(queryoffset) $state(-queryblocksize) @@ -620,11 +739,10 @@ if {$state(queryoffset) >= $state(querylength)} { set state(queryoffset) $state(querylength) set done 1 } } else { - # Copy blocks from the query channel set outStr [read $state(-querychannel) $state(-queryblocksize)] puts -nonewline $s $outStr incr state(queryoffset) [string length $outStr] @@ -631,12 +749,12 @@ if {[eof $state(-querychannel)]} { set done 1 } } } err]} { - # Do not call Finish here, but instead let the read half of - # the socket process whatever server reply there is to get. + # Do not call Finish here, but instead let the read half of the socket + # process whatever server reply there is to get. set state(posterror) $err set done 1 } if {$done} { @@ -643,11 +761,11 @@ catch {flush $s} fileevent $s writable {} fileevent $s readable [list http::Event $token] } - # Callback to the client after we've completely handled everything + # Callback to the client after we've completely handled everything. if {[string length $state(-queryprogress)]} { eval $state(-queryprogress) [list $token $state(querylength)\ $state(queryoffset)] } @@ -670,28 +788,29 @@ if {[eof $s]} { Eof $token return } - if {[string equal $state(state) "header"]} { + if {$state(state) eq "header"} { if {[catch {gets $s line} n]} { Finish $token $n } elseif {$n == 0} { variable encodings set state(state) body - if {$state(-binary) || ![regexp -nocase ^text $state(type)] || \ - [regexp gzip|compress $state(coding)]} { + if {$state(-binary) || ![string match -nocase text* $state(type)] + || [string match *gzip* $state(coding)] + || [string match *compress* $state(coding)]} { # Turn off conversions for non-text data fconfigure $s -translation binary if {[info exists state(-channel)]} { fconfigure $state(-channel) -translation binary } } else { - # If we are getting text, set the incoming channel's - # encoding correctly. iso8859-1 is the RFC default, but - # this could be any IANA charset. However, we only know - # how to convert what we have encodings for. + # If we are getting text, set the incoming channel's encoding + # correctly. iso8859-1 is the RFC default, but this could be + # any IANA charset. However, we only know how to convert what + # we have encodings for. set idx [lsearch -exact $encodings \ [string tolower $state(charset)]] if {$idx >= 0} { fconfigure $s -encoding [lindex $encodings $idx] } @@ -714,11 +833,11 @@ if {[regexp -nocase {^content-encoding:(.+)$} $line x coding]} { set state(coding) [string trim $coding] } if {[regexp -nocase {^([^:]+):(.+)$} $line x key value]} { lappend state(meta) $key [string trim $value] - } elseif {[regexp ^HTTP $line]} { + } elseif {[string match HTTP* $line]} { set state(http) $line } } } else { if {[catch { @@ -807,11 +926,11 @@ # Clean up the socket proc http::Eof {token} { variable $token upvar 0 $token state - if {[string equal $state(state) "header"]} { + if {$state(state) eq "header"} { # Premature eof set state(status) eof } else { set state(status) ok } @@ -841,27 +960,26 @@ return $state(status) } # http::formatQuery -- # -# See documentaion for details. -# Call http::formatQuery with an even number of arguments, where -# the first is a name, the second is a value, the third is another -# name, and so on. +# See documentaion for details. Call http::formatQuery with an even +# number of arguments, where the first is a name, the second is a value, +# the third is another name, and so on. # # Arguments: # args A list of name-value pairs. # # Results: -# TODO +# TODO proc http::formatQuery {args} { set result "" set sep "" foreach i $args { append result $sep [mapReply $i] - if {[string equal $sep "="]} { + if {$sep eq "="} { set sep & } else { set sep = } } @@ -877,26 +995,33 @@ # # Results: # The encoded string proc http::mapReply {string} { - variable formMap - variable alphanumeric - - # The spec says: "non-alphanumeric characters are replaced by '%HH'" - # 1 leave alphanumerics characters alone - # 2 Convert every other character to an array lookup - # 3 Escape constructs that are "special" to the tcl parser - # 4 "subst" the result, doing all the array substitutions - - regsub -all \[^$alphanumeric\] $string {$formMap(&)} string - regsub -all {[][{})\\]\)} $string {\\&} string - return [subst -nocommand $string] + variable http + variable formMap + + # The spec says: "non-alphanumeric characters are replaced by '%HH'". Use + # a pre-computed map and [string map] to do the conversion (much faster + # than [regsub]/[subst]). [Bug 1020491] + + if {$http(-urlencoding) ne ""} { + set string [encoding convertto $http(-urlencoding) $string] + return [string map $formMap $string] + } + set converted [string map $formMap $string] + if {[string match "*\[\u0100-\uffff\]*" $converted]} { + regexp {[\u0100-\uffff]} $converted badChar + # Return this error message for maximum compatability... :^/ + return -code error \ + "can't read \"formMap($badChar)\": no such element in array" + } + return $converted } # http::ProxyRequired -- -# Default proxy filter. +# Default proxy filter. # # Arguments: # host The destination host # # Results: Index: library/http/pkgIndex.tcl ================================================================== --- library/http/pkgIndex.tcl +++ library/http/pkgIndex.tcl @@ -6,7 +6,7 @@ # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. -if {![package vsatisfies [package provide Tcl] 8.2]} {return} -package ifneeded http 2.4.2 [list tclPkgSetup $dir http 2.4.2 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister}}}] +if {![package vsatisfies [package provide Tcl] 8.4]} {return} +package ifneeded http 2.5.3 [list tclPkgSetup $dir http 2.5.3 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] Index: library/init.tcl ================================================================== --- library/init.tcl +++ library/init.tcl @@ -1,11 +1,11 @@ # init.tcl -- # # Default system startup file for Tcl-based applications. Defines # "unknown" procedure and auto-load facilities. # -# RCS: @(#) $Id: init.tcl,v 1.55 2002/11/23 01:41:35 hobbs Exp $ +# RCS: @(#) $Id: init.tcl,v 1.55.2.6 2005/07/22 21:59:40 dgp Exp $ # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 Scriptics Corporation. # @@ -46,11 +46,11 @@ set auto_path "" } } namespace eval tcl { variable Dir - if {[info library] != ""} { + if {[info library] ne ""} { foreach Dir [list [info library] [file dirname [info library]]] { if {[lsearch -exact $::auto_path $Dir] < 0} { lappend ::auto_path $Dir } } @@ -69,11 +69,11 @@ } } # Windows specific end of initialization -if {(![interp issafe]) && [string equal $tcl_platform(platform) "windows"]} { +if {(![interp issafe]) && $tcl_platform(platform) eq "windows"} { namespace eval tcl { proc EnvTraceProc {lo n1 n2 op} { set x $::env($n2) set ::env($lo) $x set ::env([string toupper $lo]) $x @@ -80,27 +80,27 @@ } proc InitWinEnv {} { global env tcl_platform foreach p [array names env] { set u [string toupper $p] - if {![string equal $u $p]} { + if {$u ne $p} { switch -- $u { COMSPEC - PATH { if {![info exists env($u)]} { set env($u) $env($p) } - trace variable env($p) w \ + trace add variable env($p) write \ [namespace code [list EnvTraceProc $p]] - trace variable env($u) w \ + trace add variable env($u) write \ [namespace code [list EnvTraceProc $p]] } } } } if {![info exists env(COMSPEC)]} { - if {[string equal $tcl_platform(os) "Windows NT"]} { + if {$tcl_platform(os) eq "Windows NT"} { set env(COMSPEC) cmd.exe } else { set env(COMSPEC) command.com } } @@ -113,22 +113,22 @@ package unknown tclPkgUnknown if {![interp issafe]} { # setup platform specific unknown package handlers - if {[string equal $::tcl_platform(platform) "unix"] && \ - [string equal $::tcl_platform(os) "Darwin"]} { + if {$::tcl_platform(platform) eq "unix" + && $::tcl_platform(os) eq "Darwin"} { package unknown [list tcl::MacOSXPkgUnknown [package unknown]] } - if {[string equal $::tcl_platform(platform) "macintosh"]} { + if {$::tcl_platform(platform) eq "macintosh"} { package unknown [list tcl::MacPkgUnknown [package unknown]] } } # Conditionalize for presence of exec. -if {[llength [info commands exec]] == 0} { +if {[namespace which -command exec] eq ""} { # Some machines, such as the Macintosh, do not have exec. Also, on all # platforms, safe interpreters do not have exec. set auto_noexec 1 @@ -137,11 +137,11 @@ set errorInfo "" # Define a log command (which can be overwitten to log errors # differently, specially when stderr is not available) -if {[llength [info commands tclLog]] == 0} { +if {[namespace which -command tclLog] eq ""} { proc tclLog {string} { catch {puts stderr $string} } } @@ -187,13 +187,21 @@ # Save the values of errorCode and errorInfo variables, since they # may get modified if caught errors occur below. The variables will # be restored just before re-executing the missing command. + # Safety check in case something unsets the variables + # ::errorInfo or ::errorCode. [Bug 1063707] + if {![info exists errorCode]} { + set errorCode "" + } + if {![info exists errorInfo]} { + set errorInfo "" + } set savedErrorCode $errorCode set savedErrorInfo $errorInfo - set name [lindex $args 0] + set name $cmd if {![info exists auto_noload]} { # # Make sure we're not trying to load the same proc twice. # if {[info exists unknown_pending($name)]} { @@ -218,14 +226,16 @@ # Compute stack trace contribution from the [uplevel]. # Note the dependence on how Tcl_AddErrorInfo, etc. # construct the stack trace. # set cinfo $args - if {[string length $cinfo] > 150} { - set cinfo "[string range $cinfo 0 149]..." + set ellipsis "" + while {[string bytelength $cinfo] > 150} { + set cinfo [string range $cinfo 0 end-1] + set ellipsis "..." } - append cinfo "\"\n (\"uplevel\" body line 1)" + append cinfo $ellipsis "\"\n (\"uplevel\" body line 1)" append cinfo "\n invoked from within" append cinfo "\n\"uplevel 1 \$args\"" # # Try each possible form of the stack trace # and trim the extra contribution from the matching case @@ -261,58 +271,69 @@ return -code $code $msg } } } - if {([info level] == 1) && [string equal [info script] ""] \ + if {([info level] == 1) && [info script] eq "" \ && [info exists tcl_interactive] && $tcl_interactive} { if {![info exists auto_noexec]} { set new [auto_execok $name] - if {$new != ""} { + if {$new ne ""} { set errorCode $savedErrorCode set errorInfo $savedErrorInfo set redir "" - if {[string equal [info commands console] ""]} { + if {[namespace which -command console] eq ""} { set redir ">&@stdout <@stdin" } return [uplevel 1 exec $redir $new [lrange $args 1 end]] } } set errorCode $savedErrorCode set errorInfo $savedErrorInfo - if {[string equal $name "!!"]} { + if {$name eq "!!"} { set newcmd [history event] - } elseif {[regexp {^!(.+)$} $name dummy event]} { + } elseif {[regexp {^!(.+)$} $name -> event]} { set newcmd [history event $event] - } elseif {[regexp {^\^([^^]*)\^([^^]*)\^?$} $name dummy old new]} { + } elseif {[regexp {^\^([^^]*)\^([^^]*)\^?$} $name -> old new]} { set newcmd [history event -1] catch {regsub -all -- $old $newcmd $new newcmd} } if {[info exists newcmd]} { tclLog $newcmd history change $newcmd 0 return [uplevel 1 $newcmd] } - set ret [catch {set cmds [info commands $name*]} msg] - if {[string equal $name "::"]} { + set ret [catch {set candidates [info commands $name*]} msg] + if {$name eq "::"} { set name "" } if {$ret != 0} { return -code $ret -errorcode $errorCode \ - "error in unknown while checking if \"$name\" is a unique command abbreviation: $msg" + "error in unknown while checking if \"$name\" is\ + a unique command abbreviation:\n$msg" + } + # Handle empty $name separately due to strangeness in [string first] + if {$name eq ""} { + if {[llength $candidates] != 1} { + return -code error "empty command name \"\"" + } + return [uplevel 1 [lreplace $args 0 0 [lindex $candidates 0]]] + } + # Filter out bogus matches when $name contained + # a glob-special char [Bug 946952] + set cmds [list] + foreach x $candidates { + if {[string first $name $x] == 0} { + lappend cmds $x + } } if {[llength $cmds] == 1} { - return [uplevel 1 [lreplace $args 0 0 $cmds]] + return [uplevel 1 [lreplace $args 0 0 [lindex $cmds 0]]] } if {[llength $cmds]} { - if {[string equal $name ""]} { - return -code error "empty command name \"\"" - } else { - return -code error \ - "ambiguous command name \"$name\": [lsort $cmds]" - } + return -code error "ambiguous command name \"$name\": [lsort $cmds]" } } return -code error "invalid command name \"$name\"" } @@ -329,21 +350,30 @@ # for instance. If not given, namespace current is used. proc auto_load {cmd {namespace {}}} { global auto_index auto_oldpath auto_path - if {[string length $namespace] == 0} { + if {$namespace eq ""} { set namespace [uplevel 1 [list ::namespace current]] } set nameList [auto_qualify $cmd $namespace] # workaround non canonical auto_index entries that might be around # from older auto_mkindex versions lappend nameList $cmd foreach name $nameList { if {[info exists auto_index($name)]} { - uplevel #0 $auto_index($name) - return [expr {[info commands $name] != ""}] + namespace eval :: $auto_index($name) + # There's a couple of ways to look for a command of a given + # name. One is to use + # info commands $name + # Unfortunately, if the name has glob-magic chars in it like * + # or [], it may not match. For our purposes here, a better + # route is to use + # namespace which -command $name + if {[namespace which -command $name] ne ""} { + return 1 + } } } if {![info exists auto_path]} { return 0 } @@ -351,19 +381,12 @@ if {![auto_load_index]} { return 0 } foreach name $nameList { if {[info exists auto_index($name)]} { - uplevel #0 $auto_index($name) - # There's a couple of ways to look for a command of a given - # name. One is to use - # info commands $name - # Unfortunately, if the name has glob-magic chars in it like * - # or [], it may not match. For our purposes here, a better - # route is to use - # namespace which -command $name - if { ![string equal [namespace which -command $name] ""] } { + namespace eval :: $auto_index($name) + if {[namespace which -command $name] ne ""} { return 1 } } } return 0 @@ -379,12 +402,11 @@ # None. proc auto_load_index {} { global auto_index auto_oldpath auto_path errorInfo errorCode - if {[info exists auto_oldpath] && \ - [string equal $auto_oldpath $auto_path]} { + if {[info exists auto_oldpath] && $auto_oldpath eq $auto_path} { return 0 } set auto_oldpath $auto_path # Check if we are a safe interpreter. In that case, we support only @@ -399,16 +421,15 @@ } elseif {[catch {set f [open [file join $dir tclIndex]]}]} { continue } else { set error [catch { set id [gets $f] - if {[string equal $id \ - "# Tcl autoload index file, version 2.0"]} { + if {$id eq "# Tcl autoload index file, version 2.0"} { eval [read $f] - } elseif {[string equal $id "# Tcl autoload index file: each line identifies a Tcl"]} { + } elseif {$id eq "# Tcl autoload index file: each line identifies a Tcl"} { while {[gets $f line] >= 0} { - if {[string equal [string index $line 0] "#"] \ + if {[string index $line 0] eq "#" || ([llength $line] != 2)} { continue } set name [lindex $line 0] set auto_index($name) \ @@ -416,11 +437,11 @@ } } else { error "[file join $dir tclIndex] isn't a proper Tcl index file" } } msg] - if {$f != ""} { + if {$f ne ""} { close $f } if {$error} { error $msg $errorInfo $errorCode } @@ -455,32 +476,32 @@ # Before each return case we give an example of which category it is # with the following form : # ( inputCmd, inputNameSpace) -> output - if {[regexp {^::(.*)$} $cmd x tail]} { + if {[string match ::* $cmd]} { if {$n > 1} { # ( ::foo::bar , * ) -> ::foo::bar return [list $cmd] } else { # ( ::global , * ) -> global - return [list $tail] + return [list [string range $cmd 2 end]] } } # Potentially returning 2 elements to try : # (if the current namespace is not the global one) if {$n == 0} { - if {[string equal $namespace ::]} { + if {$namespace eq "::"} { # ( nocolons , :: ) -> nocolons return [list $cmd] } else { # ( nocolons , ::sub ) -> ::sub::nocolons nocolons return [list ${namespace}::$cmd $cmd] } - } elseif {[string equal $namespace ::]} { + } elseif {$namespace eq "::"} { # ( foo::bar , :: ) -> ::foo::bar return [list ::$cmd] } else { # ( foo::bar , ::sub ) -> ::sub::foo::bar ::foo::bar return [list ${namespace}::$cmd ::$cmd] @@ -512,14 +533,13 @@ auto_load_index foreach pattern $patternList { foreach name [array names auto_index $pattern] { - if {[string equal "" [info commands $name]] - && [string equal [namespace qualifiers $pattern] \ - [namespace qualifiers $name]]} { - uplevel #0 $auto_index($name) + if {([namespace which -command $name] eq "") + && ([namespace qualifiers $pattern] eq [namespace qualifiers $name])} { + namespace eval :: $auto_index($name) } } } } @@ -532,11 +552,11 @@ # for speed. # # Arguments: # name - Name of a command. -if {[string equal windows $tcl_platform(platform)]} { +if {$tcl_platform(platform) eq "windows"} { # Windows version. # # Note that info executable doesn't work under Windows, so we have to # look for files with .exe, .com, or .bat extensions. Also, the path # may be in the Path or PATH environment variables, and path @@ -550,11 +570,11 @@ } set auto_execs($name) "" set shellBuiltins [list cls copy date del erase dir echo mkdir \ md rename ren rmdir rd time type ver vol] - if {[string equal $tcl_platform(os) "Windows NT"]} { + if {$tcl_platform(os) eq "Windows NT"} { # NT includes the 'start' built-in lappend shellBuiltins "start" } if {[info exists env(PATHEXT)]} { # Add an initial ; to have the {} extension check first. @@ -587,11 +607,11 @@ set path "[file dirname [info nameof]];.;" if {[info exists env(WINDIR)]} { set windir $env(WINDIR) } if {[info exists windir]} { - if {[string equal $tcl_platform(os) "Windows NT"]} { + if {$tcl_platform(os) eq "Windows NT"} { append path "$windir/system32;" } append path "$windir/system;$windir;" } @@ -601,11 +621,11 @@ } } foreach dir [split $path {;}] { # Skip already checked directories - if {[info exists checked($dir)] || [string equal {} $dir]} { continue } + if {[info exists checked($dir)] || $dir eq {}} { continue } set checked($dir) {} foreach ext $execExtensions { set file [file join $dir ${name}${ext}] if {[file exists $file] && ![file isdirectory $file]} { return [set auto_execs($name) [list $file]] @@ -630,11 +650,11 @@ set auto_execs($name) [list $name] } return $auto_execs($name) } foreach dir [split $env(PATH) :] { - if {[string equal $dir ""]} { + if {$dir eq ""} { set dir . } set file [file join $dir $name] if {[file executable $file] && ![file isdirectory $file]} { set auto_execs($name) [list $file] @@ -661,48 +681,49 @@ # src - source directory # dest - destination directory proc tcl::CopyDirectory {action src dest} { set nsrc [file normalize $src] set ndest [file normalize $dest] - if {[string equal $action "renaming"]} { + if {$action eq "renaming"} { # Can't rename volumes. We could give a more precise # error message here, but that would break the test suite. if {[lsearch -exact [file volumes] $nsrc] != -1} { return -code error "error $action \"$src\" to\ \"$dest\": trying to rename a volume or move a directory\ into itself" } } if {[file exists $dest]} { - if {$nsrc == $ndest} { + if {$nsrc eq $ndest} { return -code error "error $action \"$src\" to\ \"$dest\": trying to rename a volume or move a directory\ into itself" } - if {[string equal $action "copying"]} { + if {$action eq "copying"} { return -code error "error $action \"$src\" to\ \"$dest\": file already exists" } else { # Depending on the platform, and on the current # working directory, the directories '.', '..' # can be returned in various combinations. Anyway, # if any other file is returned, we must signal an error. set existing [glob -nocomplain -directory $dest * .*] - eval [list lappend existing] \ - [glob -nocomplain -directory $dest -type hidden * .*] + eval [linsert \ + [glob -nocomplain -directory $dest -type hidden * .*] 0 \ + lappend existing] foreach s $existing { - if {([file tail $s] != ".") && ([file tail $s] != "..")} { + if {([file tail $s] ne ".") && ([file tail $s] ne "..")} { return -code error "error $action \"$src\" to\ \"$dest\": file already exists" } } } } else { if {[string first $nsrc $ndest] != -1} { set srclen [expr {[llength [file split $nsrc]] -1}] set ndest [lindex [file split $ndest] $srclen] - if {$ndest == [file tail $nsrc]} { + if {$ndest eq [file tail $nsrc]} { return -code error "error $action \"$src\" to\ \"$dest\": trying to rename a volume or move a directory\ into itself" } } @@ -716,11 +737,11 @@ # or filesystems hidden files may have other interpretations. set filelist [concat [glob -nocomplain -directory $src *] \ [glob -nocomplain -directory $src -types hidden *]] foreach s [lsort -unique $filelist] { - if {([file tail $s] != ".") && ([file tail $s] != "..")} { + if {([file tail $s] ne ".") && ([file tail $s] ne "..")} { file copy $s [file join $dest [file tail $s]] } } return } Index: library/msgcat/msgcat.tcl ================================================================== --- library/msgcat/msgcat.tcl +++ library/msgcat/msgcat.tcl @@ -8,16 +8,16 @@ # Copyright (c) 1998 by Mark Harrison. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: msgcat.tcl,v 1.17 2002/08/20 15:33:32 dgp Exp $ +# RCS: @(#) $Id: msgcat.tcl,v 1.17.2.6 2006/09/10 18:23:45 dgp Exp $ package require Tcl 8.2 # When the version number changes, be sure to update the pkgIndex.tcl file, # and the installation directory in the Makefiles. -package provide msgcat 1.3 +package provide msgcat 1.3.4 namespace eval msgcat { namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \ mcunknown @@ -31,135 +31,137 @@ # array key is of the form ",," and the value is # the translated string. array set Msgs {} # Map of language codes used in Windows registry to those of ISO-639 - array set WinRegToISO639 { - 01 ar 0401 ar_SA 0801 ar_IQ 0c01 ar_EG 1001 ar_LY 1401 ar_DZ - 1801 ar_MA 1c01 ar_TN 2001 ar_OM 2401 ar_YE 2801 ar_SY - 2c01 ar_JO 3001 ar_LB 3401 ar_KW 3801 ar_AE 3c01 ar_BH - 4001 ar_QA - 02 bg 0402 bg_BG - 03 ca 0403 ca_ES - 04 zh 0404 zh_TW 0804 zh_CN 0c04 zh_HK 1004 zh_SG 1404 zh_MO - 05 cs 0405 cs_CZ - 06 da 0406 da_DK - 07 de 0407 de_DE 0807 de_CH 0c07 de_AT 1007 de_LU 1407 de_LI - 08 el 0408 el_GR - 09 en 0409 en_US 0809 en_GB 0c09 en_AU 1009 en_CA 1409 en_NZ - 1809 en_IE 1c09 en_ZA 2009 en_JM 2409 en_GD 2809 en_BZ - 2c09 en_TT 3009 en_ZW 3409 en_PH - 0a es 040a es_ES 080a es_MX 0c0a es_ES@modern 100a es_GT 140a es_CR - 180a es_PA 1c0a es_DO 200a es_VE 240a es_CO 280a es_PE - 2c0a es_AR 300a es_EC 340a es_CL 380a es_UY 3c0a es_PY - 400a es_BO 440a es_SV 480a es_HN 4c0a es_NI 500a es_PR - 0b fi 040b fi_FI - 0c fr 040c fr_FR 080c fr_BE 0c0c fr_CA 100c fr_CH 140c fr_LU - 180c fr_MC - 0d he 040d he_IL - 0e hu 040e hu_HU - 0f is 040f is_IS - 10 it 0410 it_IT 0810 it_CH - 11 ja 0411 ja_JP - 12 ko 0412 ko_KR - 13 nl 0413 nl_NL 0813 nl_BE - 14 no 0414 no_NO 0814 nn_NO - 15 pl 0415 pl_PL - 16 pt 0416 pt_BR 0816 pt_PT - 17 rm 0417 rm_CH - 18 ro 0418 ro_RO - 19 ru - 1a hr 041a hr_HR 081a sr_YU 0c1a sr_YU@cyrillic - 1b sk 041b sk_SK - 1c sq 041c sq_AL - 1d sv 041d sv_SE 081d sv_FI - 1e th 041e th_TH - 1f tr 041f tr_TR - 20 ur 0420 ur_PK 0820 ur_IN - 21 id 0421 id_ID - 22 uk 0422 uk_UA - 23 be 0423 be_BY - 24 sl 0424 sl_SI - 25 et 0425 et_EE - 26 lv 0426 lv_LV - 27 lt 0427 lt_LT - 28 tg 0428 tg_TJ - 29 fa 0429 fa_IR - 2a vi 042a vi_VN - 2b hy 042b hy_AM - 2c az 042c az_AZ@latin 082c az_AZ@cyrillic - 2d eu - 2e wen 042e wen_DE - 2f mk 042f mk_MK - 30 bnt 0430 bnt_TZ - 31 ts 0431 ts_ZA - 33 ven 0433 ven_ZA - 34 xh 0434 xh_ZA - 35 zu 0435 zu_ZA - 36 af 0436 af_ZA - 37 ka 0437 ka_GE - 38 fo 0438 fo_FO - 39 hi 0439 hi_IN - 3a mt 043a mt_MT - 3b se 043b se_NO - 043c gd_UK 083c ga_IE - 3d yi 043d yi_IL - 3e ms 043e ms_MY 083e ms_BN - 3f kk 043f kk_KZ - 40 ky 0440 ky_KG - 41 sw 0441 sw_KE - 42 tk 0442 tk_TM - 43 uz 0443 uz_UZ@latin 0843 uz_UZ@cyrillic - 44 tt 0444 tt_RU - 45 bn 0445 bn_IN - 46 pa 0446 pa_IN - 47 gu 0447 gu_IN - 48 or 0448 or_IN - 49 ta - 4a te 044a te_IN - 4b kn 044b kn_IN - 4c ml 044c ml_IN - 4d as 044d as_IN - 4e mr 044e mr_IN - 4f sa 044f sa_IN - 50 mn - 51 bo 0451 bo_CN - 52 cy 0452 cy_GB - 53 km 0453 km_KH - 54 lo 0454 lo_LA - 55 my 0455 my_MM - 56 gl 0456 gl_ES - 57 kok 0457 kok_IN - 58 mni 0458 mni_IN - 59 sd - 5a syr 045a syr_TR - 5b si 045b si_LK - 5c chr 045c chr_US - 5d iu 045d iu_CA - 5e am 045e am_ET - 5f ber 045f ber_MA - 60 ks 0460 ks_PK 0860 ks_IN - 61 ne 0461 ne_NP 0861 ne_IN - 62 fy 0462 fy_NL - 63 ps - 64 tl 0464 tl_PH - 65 div 0465 div_MV - 66 bin 0466 bin_NG - 67 ful 0467 ful_NG - 68 ha 0468 ha_NG - 69 nic 0469 nic_NG - 6a yo 046a yo_NG - 70 ibo 0470 ibo_NG - 71 kau 0471 kau_NG - 72 om 0472 om_ET - 73 ti 0473 ti_ET - 74 gn 0474 gn_PY - 75 cpe 0475 cpe_US - 76 la 0476 la_VA - 77 so 0477 so_SO - 78 sit 0478 sit_CN - 79 pap 0479 pap_AN + if { [string equal $::tcl_platform(platform) windows] } { + array set WinRegToISO639 { + 01 ar 0401 ar_SA 0801 ar_IQ 0c01 ar_EG 1001 ar_LY 1401 ar_DZ + 1801 ar_MA 1c01 ar_TN 2001 ar_OM 2401 ar_YE 2801 ar_SY + 2c01 ar_JO 3001 ar_LB 3401 ar_KW 3801 ar_AE 3c01 ar_BH + 4001 ar_QA + 02 bg 0402 bg_BG + 03 ca 0403 ca_ES + 04 zh 0404 zh_TW 0804 zh_CN 0c04 zh_HK 1004 zh_SG 1404 zh_MO + 05 cs 0405 cs_CZ + 06 da 0406 da_DK + 07 de 0407 de_DE 0807 de_CH 0c07 de_AT 1007 de_LU 1407 de_LI + 08 el 0408 el_GR + 09 en 0409 en_US 0809 en_GB 0c09 en_AU 1009 en_CA 1409 en_NZ + 1809 en_IE 1c09 en_ZA 2009 en_JM 2409 en_GD 2809 en_BZ + 2c09 en_TT 3009 en_ZW 3409 en_PH + 0a es 040a es_ES 080a es_MX 0c0a es_ES@modern 100a es_GT 140a es_CR + 180a es_PA 1c0a es_DO 200a es_VE 240a es_CO 280a es_PE + 2c0a es_AR 300a es_EC 340a es_CL 380a es_UY 3c0a es_PY + 400a es_BO 440a es_SV 480a es_HN 4c0a es_NI 500a es_PR + 0b fi 040b fi_FI + 0c fr 040c fr_FR 080c fr_BE 0c0c fr_CA 100c fr_CH 140c fr_LU + 180c fr_MC + 0d he 040d he_IL + 0e hu 040e hu_HU + 0f is 040f is_IS + 10 it 0410 it_IT 0810 it_CH + 11 ja 0411 ja_JP + 12 ko 0412 ko_KR + 13 nl 0413 nl_NL 0813 nl_BE + 14 no 0414 no_NO 0814 nn_NO + 15 pl 0415 pl_PL + 16 pt 0416 pt_BR 0816 pt_PT + 17 rm 0417 rm_CH + 18 ro 0418 ro_RO + 19 ru + 1a hr 041a hr_HR 081a sr_YU 0c1a sr_YU@cyrillic + 1b sk 041b sk_SK + 1c sq 041c sq_AL + 1d sv 041d sv_SE 081d sv_FI + 1e th 041e th_TH + 1f tr 041f tr_TR + 20 ur 0420 ur_PK 0820 ur_IN + 21 id 0421 id_ID + 22 uk 0422 uk_UA + 23 be 0423 be_BY + 24 sl 0424 sl_SI + 25 et 0425 et_EE + 26 lv 0426 lv_LV + 27 lt 0427 lt_LT + 28 tg 0428 tg_TJ + 29 fa 0429 fa_IR + 2a vi 042a vi_VN + 2b hy 042b hy_AM + 2c az 042c az_AZ@latin 082c az_AZ@cyrillic + 2d eu + 2e wen 042e wen_DE + 2f mk 042f mk_MK + 30 bnt 0430 bnt_TZ + 31 ts 0431 ts_ZA + 33 ven 0433 ven_ZA + 34 xh 0434 xh_ZA + 35 zu 0435 zu_ZA + 36 af 0436 af_ZA + 37 ka 0437 ka_GE + 38 fo 0438 fo_FO + 39 hi 0439 hi_IN + 3a mt 043a mt_MT + 3b se 043b se_NO + 043c gd_UK 083c ga_IE + 3d yi 043d yi_IL + 3e ms 043e ms_MY 083e ms_BN + 3f kk 043f kk_KZ + 40 ky 0440 ky_KG + 41 sw 0441 sw_KE + 42 tk 0442 tk_TM + 43 uz 0443 uz_UZ@latin 0843 uz_UZ@cyrillic + 44 tt 0444 tt_RU + 45 bn 0445 bn_IN + 46 pa 0446 pa_IN + 47 gu 0447 gu_IN + 48 or 0448 or_IN + 49 ta + 4a te 044a te_IN + 4b kn 044b kn_IN + 4c ml 044c ml_IN + 4d as 044d as_IN + 4e mr 044e mr_IN + 4f sa 044f sa_IN + 50 mn + 51 bo 0451 bo_CN + 52 cy 0452 cy_GB + 53 km 0453 km_KH + 54 lo 0454 lo_LA + 55 my 0455 my_MM + 56 gl 0456 gl_ES + 57 kok 0457 kok_IN + 58 mni 0458 mni_IN + 59 sd + 5a syr 045a syr_TR + 5b si 045b si_LK + 5c chr 045c chr_US + 5d iu 045d iu_CA + 5e am 045e am_ET + 5f ber 045f ber_MA + 60 ks 0460 ks_PK 0860 ks_IN + 61 ne 0461 ne_NP 0861 ne_IN + 62 fy 0462 fy_NL + 63 ps + 64 tl 0464 tl_PH + 65 div 0465 div_MV + 66 bin 0466 bin_NG + 67 ful 0467 ful_NG + 68 ha 0468 ha_NG + 69 nic 0469 nic_NG + 6a yo 046a yo_NG + 70 ibo 0470 ibo_NG + 71 kau 0471 kau_NG + 72 om 0472 om_ET + 73 ti 0473 ti_ET + 74 gn 0474 gn_PY + 75 cpe 0475 cpe_US + 76 la 0476 la_VA + 77 so 0477 so_SO + 78 sit 0478 sit_CN + 79 pap 0479 pap_AN + } } } # msgcat::mc -- # @@ -225,11 +227,16 @@ if {$len > 1} { error {wrong # args: should be "mclocale ?newLocale?"} } if {$len == 1} { - set Locale [string tolower [lindex $args 0]] + set newLocale [lindex $args 0] + if {$newLocale ne [file tail $newLocale]} { + return -code error "invalid newLocale value \"$newLocale\":\ + could be path to unsafe code." + } + set Locale [string tolower $newLocale] set Loclist {} set word "" foreach part [split $Locale _] { set word [string trimleft "${word}_${part}" _] set Loclist [linsert $Loclist 0 $word] @@ -293,12 +300,12 @@ # Results: # Returns the new locale. proc msgcat::mcset {locale src {dest ""}} { variable Msgs - if {[string equal $dest ""]} { - set dest $src + if {[llength [info level 0]] == 3} { ;# dest not specified + set dest $src } set ns [uplevel 1 [list ::namespace current]] set Msgs([string tolower $locale],$ns,$src) $dest @@ -395,12 +402,14 @@ # (_([^.@]*))? # Match (optional) "territory"; starts with _ # ([.]([^@]*))? # Match (optional) "codeset"; starts with . # (@(.*))? # Match (optional) "modifier"; starts with @ # $ # Match all the way to the end # } $value -> language _ territory _ codeset _ modifier - regexp {^([^_.@]*)(_([^.@]*))?([.]([^@]*))?(@(.*))?$} $value \ - -> language _ territory _ codeset _ modifier + if {![regexp {^([^_.@]+)(_([^.@]*))?([.]([^@]*))?(@(.*))?$} $value \ + -> language _ territory _ codeset _ modifier]} { + return -code error "invalid locale '$value': empty language part" + } set ret $language if {[string length $territory]} { append ret _$territory } if {[string length $modifier]} { @@ -415,18 +424,37 @@ # set default locale, try to get from environment # foreach varName {LC_ALL LC_MESSAGES LANG} { if {[info exists ::env($varName)] && ![string equal "" $::env($varName)]} { - mclocale [ConvertLocale $::env($varName)] + if {![catch {mclocale [ConvertLocale $::env($varName)]}]} { + return + } + } + } + # + # On Darwin, fallback to current CFLocale identifier if available. + # + if {[string equal $::tcl_platform(os) Darwin] + && [string equal $::tcl_platform(platform) unix] + && [info exists ::tcl::mac::locale] + && ![string equal $::tcl::mac::locale ""]} { + if {![catch {mclocale [ConvertLocale $::tcl::mac::locale]}]} { return } } + # + # The rest of this routine is special processing for Windows; + # all other platforms, get out now. + # + if { ![string equal $::tcl_platform(platform) windows] } { + mclocale C + return + } # # On Windows, try to set locale depending on registry settings, - # or fall back on locale of "C". Other platforms will return - # when they fail to load the registry package. + # or fall back on locale of "C". # set key {HKEY_CURRENT_USER\Control Panel\International} if {[catch {package require registry}] \ || [catch {registry get $key "locale"} locale]} { mclocale C Index: library/msgcat/pkgIndex.tcl ================================================================== --- library/msgcat/pkgIndex.tcl +++ library/msgcat/pkgIndex.tcl @@ -1,2 +1,2 @@ if {![package vsatisfies [package provide Tcl] 8.2]} {return} -package ifneeded msgcat 1.3 [list source [file join $dir msgcat.tcl]] +package ifneeded msgcat 1.3.4 [list source [file join $dir msgcat.tcl]] Index: library/opt/optparse.tcl ================================================================== --- library/opt/optparse.tcl +++ library/opt/optparse.tcl @@ -6,16 +6,16 @@ # WARNING: This code will go away in a future release # of Tcl. It is NOT supported and you should not rely # on it. If your code does rely on this package you # may directly incorporate this code into your application. # -# RCS: @(#) $Id: optparse.tcl,v 1.8 2002/11/23 01:41:35 hobbs Exp $ +# RCS: @(#) $Id: optparse.tcl,v 1.8.2.1 2003/09/10 20:29:59 dgp Exp $ -package require Tcl 8 +package require Tcl 8.2 # When this version number changes, update the pkgIndex.tcl file # and the install directory in the Makefiles. -package provide opt 0.4.4 +package provide opt 0.4.4.1 namespace eval ::tcl { # Exported APIs namespace export OptKeyRegister OptKeyDelete OptKeyError OptKeyParse \ Index: library/opt/pkgIndex.tcl ================================================================== --- library/opt/pkgIndex.tcl +++ library/opt/pkgIndex.tcl @@ -6,7 +6,7 @@ # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. -if {![package vsatisfies [package provide Tcl] 8]} {return} -package ifneeded opt 0.4.4 [list source [file join $dir optparse.tcl]] +if {![package vsatisfies [package provide Tcl] 8.2]} {return} +package ifneeded opt 0.4.4.1 [list source [file join $dir optparse.tcl]] Index: library/package.tcl ================================================================== --- library/package.tcl +++ library/package.tcl @@ -1,11 +1,11 @@ # package.tcl -- # # utility procs formerly in init.tcl which can be loaded on demand # for package management. # -# RCS: @(#) $Id: package.tcl,v 1.23 2003/02/25 23:58:09 dgp Exp $ +# RCS: @(#) $Id: package.tcl,v 1.23.2.4 2006/09/22 01:26:24 andreas_kupries Exp $ # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1998 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution @@ -31,20 +31,20 @@ # Results: # Returns 1 if the extension matches, 0 otherwise proc pkg_compareExtension { fileName {ext {}} } { global tcl_platform - if {![string length $ext]} {set ext [info sharedlibextension]} - if {[string equal $tcl_platform(platform) "windows"]} { + if {$ext eq ""} {set ext [info sharedlibextension]} + if {$tcl_platform(platform) eq "windows"} { return [string equal -nocase [file extension $fileName] $ext] } else { # Some unices add trailing numbers after the .so, so # we could have something like '.so.1.2'. set root $fileName while {1} { set currExt [file extension $root] - if {[string equal $currExt $ext]} { + if {$currExt eq $ext} { return 1 } # The current extension does not match; if it is not a numeric # value, quit, as we are only looking to ignore version number @@ -138,11 +138,11 @@ } set oldDir [pwd] cd $dir - if {[catch {eval glob $patternList} fileList]} { + if {[catch {eval [linsert $patternList 0 glob --]} fileList]} { global errorCode errorInfo cd $oldDir return -code error -errorcode $errorCode -errorinfo $errorInfo $fileList } foreach file $fileList { @@ -149,11 +149,11 @@ # For each file, figure out what commands and packages it provides. # To do this, create a child interpreter, load the file into the # interpreter, and get a list of the new commands and packages # that are defined. - if {[string equal $file "pkgIndex.tcl"]} { + if {$file eq "pkgIndex.tcl"} { continue } # Changed back to the original directory before initializing the # slave in case TCL_LIBRARY is a relative path (e.g. in the test @@ -163,11 +163,11 @@ set c [interp create] # Load into the child any packages currently loaded in the parent # interpreter that match the -load pattern. - if {[string length $loadPat]} { + if {$loadPat ne ""} { if {$doVerbose} { tclLog "currently loaded packages: '[info loaded]'" tclLog "trying to load all packages matching $loadPat" } if {![llength [info loaded]]} { @@ -189,11 +189,11 @@ tclLog "warning: load [lindex $pkg 0] [lindex $pkg 1]\nfailed with: $err" } } elseif {$doVerbose} { tclLog "loaded [lindex $pkg 0] [lindex $pkg 1]" } - if {[string equal [lindex $pkg 1] "Tk"]} { + if {[lindex $pkg 1] eq "Tk"} { # Withdraw . if Tk was loaded, to avoid showing a window. $c eval [list wm withdraw .] } } cd $dir @@ -204,11 +204,11 @@ rename package __package_orig proc package {what args} { switch -- $what { require { return ; # ignore transitive requires } - default { eval __package_orig {$what} $args } + default { uplevel 1 [linsert $args 0 __package_orig $what] } } } proc tclPkgUnknown args {} package unknown tclPkgUnknown @@ -259,11 +259,12 @@ # the "partial pkgIndex.tcl" step above. proc ::tcl::GetAllNamespaces {{root ::}} { set list $root foreach ns [namespace children $root] { - eval lappend list [::tcl::GetAllNamespaces $ns] + eval [linsert [::tcl::GetAllNamespaces $ns] 0 \ + lappend list] } return $list } # init the list of existing namespaces, packages, commands @@ -270,11 +271,13 @@ foreach ::tcl::x [::tcl::GetAllNamespaces] { set ::tcl::namespaces($::tcl::x) 1 } foreach ::tcl::x [package names] { - set ::tcl::packages($::tcl::x) 1 + if {[package provide $::tcl::x] ne ""} { + set ::tcl::packages($::tcl::x) 1 + } } set ::tcl::origCmds [info commands] # Try to load the file if it has the shared library # extension, otherwise source it. It's important not to @@ -316,11 +319,11 @@ foreach ::tcl::x [info commands] { set ::tcl::newCmds($::tcl::x) 1 } foreach ::tcl::x $::tcl::origCmds { - catch {unset ::tcl::newCmds($::tcl::x)} + unset -nocomplain ::tcl::newCmds($::tcl::x) } foreach ::tcl::x [array names ::tcl::newCmds] { # determine which namespace a command comes from set ::tcl::abs [namespace origin $::tcl::x] @@ -329,11 +332,11 @@ # ::, this is required by the unknown command set ::tcl::abs \ [lindex [auto_qualify $::tcl::abs ::] 0] - if {[string compare $::tcl::x $::tcl::abs]} { + if {$::tcl::x ne $::tcl::abs} { # Name changed during qualification set ::tcl::newCmds($::tcl::abs) 1 unset ::tcl::newCmds($::tcl::x) } @@ -343,11 +346,11 @@ # Look through the packages that appeared, and if there is # a version provided, then record it foreach ::tcl::x [package names] { - if {[string compare [package provide $::tcl::x] ""] \ + if {[package provide $::tcl::x] ne "" && ![info exists ::tcl::packages($::tcl::x)]} { lappend ::tcl::newPkgs \ [list $::tcl::x [package provide $::tcl::x]] } } @@ -364,11 +367,13 @@ } set type [$c eval set ::tcl::type] set cmds [lsort [$c eval array names ::tcl::newCmds]] set pkgs [$c eval set ::tcl::newPkgs] if {$doVerbose} { - tclLog "commands provided were $cmds" + if { !$direct } { + tclLog "commands provided were $cmds" + } tclLog "packages provided were $pkgs" } if {[llength $pkgs] > 1} { tclLog "warning: \"$file\" provides more than one package ($pkgs)" } @@ -441,11 +446,11 @@ package provide $pkg $version foreach fileInfo $files { set f [lindex $fileInfo 0] set type [lindex $fileInfo 1] foreach cmd [lindex $fileInfo 2] { - if {[string equal $type "load"]} { + if {$type eq "load"} { set auto_index($cmd) [list load [file join $dir $f] $pkg] } else { set auto_index($cmd) [list source [file join $dir $f]] } } @@ -464,11 +469,16 @@ # Arguments: # name - Name of desired package. Not used. # version - Version of desired package. Not used. # exact - Either "-exact" or omitted. Not used. -proc tclPkgUnknown {name version {exact {}}} { + +proc tclPkgUnknown [expr { + [info exists tcl_platform(tip,268)] + ? "name args" + : "name version {exact {}}" + }] { global auto_path env if {![info exists auto_path]} { return } @@ -557,47 +567,90 @@ # for [interp issafe] as in tclPkgUnknown. # # Arguments: # original - original [package unknown] procedure # name - Name of desired package. Not used. +#ifndef TCL_TIP268 # version - Version of desired package. Not used. # exact - Either "-exact" or omitted. Not used. - -proc tcl::MacOSXPkgUnknown {original name version {exact {}}} { - - # First do the cross-platform default search - uplevel 1 $original [list $name $version $exact] - - # Now do MacOSX specific searching - global auto_path - - if {![info exists auto_path]} { - return - } - # Cache the auto_path, because it may change while we run through - # the first set of pkgIndex.tcl files - set old_path [set use_path $auto_path] - while {[llength $use_path]} { - set dir [lindex $use_path end] - # get the pkgIndex files out of the subdirectories - foreach file [glob -directory $dir -join -nocomplain \ - * Resources Scripts pkgIndex.tcl] { - set dir [file dirname $file] - if {[file readable $file] && ![info exists procdDirs($dir)]} { - if {[catch {source $file} msg]} { - tclLog "error reading package index file $file: $msg" - } else { - set procdDirs($dir) 1 - } - } - } - set use_path [lrange $use_path 0 end-1] - if {[string compare $old_path $auto_path]} { - foreach dir $auto_path { - lappend use_path $dir - } - set old_path $auto_path +#else +# args - List of requirements. Not used. +#endif + +if {[info exists tcl_platform(tip,268)]} { + proc tcl::MacOSXPkgUnknown {original name args} { + # First do the cross-platform default search + uplevel 1 $original [linsert $args 0 $name] + + # Now do MacOSX specific searching + global auto_path + + if {![info exists auto_path]} { + return + } + # Cache the auto_path, because it may change while we run through + # the first set of pkgIndex.tcl files + set old_path [set use_path $auto_path] + while {[llength $use_path]} { + set dir [lindex $use_path end] + # get the pkgIndex files out of the subdirectories + foreach file [glob -directory $dir -join -nocomplain \ + * Resources Scripts pkgIndex.tcl] { + set dir [file dirname $file] + if {[file readable $file] && ![info exists procdDirs($dir)]} { + if {[catch {source $file} msg]} { + tclLog "error reading package index file $file: $msg" + } else { + set procdDirs($dir) 1 + } + } + } + set use_path [lrange $use_path 0 end-1] + if {$old_path ne $auto_path} { + foreach dir $auto_path { + lappend use_path $dir + } + set old_path $auto_path + } + } + } +} else { + proc tcl::MacOSXPkgUnknown {original name version {exact {}}} { + + # First do the cross-platform default search + uplevel 1 $original [list $name $version $exact] + + # Now do MacOSX specific searching + global auto_path + + if {![info exists auto_path]} { + return + } + # Cache the auto_path, because it may change while we run through + # the first set of pkgIndex.tcl files + set old_path [set use_path $auto_path] + while {[llength $use_path]} { + set dir [lindex $use_path end] + # get the pkgIndex files out of the subdirectories + foreach file [glob -directory $dir -join -nocomplain \ + * Resources Scripts pkgIndex.tcl] { + set dir [file dirname $file] + if {[file readable $file] && ![info exists procdDirs($dir)]} { + if {[catch {source $file} msg]} { + tclLog "error reading package index file $file: $msg" + } else { + set procdDirs($dir) 1 + } + } + } + set use_path [lrange $use_path 0 end-1] + if {$old_path ne $auto_path} { + foreach dir $auto_path { + lappend use_path $dir + } + set old_path $auto_path + } } } } # tcl::MacPkgUnknown -- @@ -634,20 +687,20 @@ set dir $x foreach x [glob -directory $dir -nocomplain *.shlb] { if {[file isfile $x]} { set res [resource open $x] foreach y [resource list TEXT $res] { - if {[string equal $y "pkgIndex"]} {source -rsrc pkgIndex} + if {$y eq "pkgIndex"} {source -rsrc pkgIndex} } catch {resource close $res} } } set procdDirs($dir) 1 } } set use_path [lrange $use_path 0 end-1] - if {[string compare $old_path $auto_path]} { + if {$old_path ne $auto_path} { foreach dir $auto_path { lappend use_path $dir } set old_path $auto_path } Index: library/reg/pkgIndex.tcl ================================================================== --- library/reg/pkgIndex.tcl +++ library/reg/pkgIndex.tcl @@ -1,8 +1,9 @@ if {![package vsatisfies [package provide Tcl] 8]} {return} -if {[info exists tcl_platform(debug)]} { - package ifneeded registry 1.1.1 \ +if {[string compare $::tcl_platform(platform) windows]} {return} +if {[info exists ::tcl_platform(debug)]} { + package ifneeded registry 1.1.5 \ [list load [file join $dir tclreg11g.dll] registry] } else { - package ifneeded registry 1.1.1 \ + package ifneeded registry 1.1.5 \ [list load [file join $dir tclreg11.dll] registry] } Index: library/safe.tcl ================================================================== --- library/safe.tcl +++ library/safe.tcl @@ -10,11 +10,11 @@ # Copyright (c) 1996-1997 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: safe.tcl,v 1.9 2003/02/08 22:03:20 hobbs Exp $ +# RCS: @(#) $Id: safe.tcl,v 1.9.2.3 2005/07/22 21:59:41 dgp Exp $ # # The implementation is based on namespaces. These naming conventions # are followed: # Private procs starts with uppercase. @@ -34,10 +34,14 @@ #### # # Setup the arguments parsing # #### + + # Make sure that our temporary variable is local to this + # namespace. [Bug 981733] + variable temp # Share the descriptions set temp [::tcl::OptKeyRegister { {-accessPath -list {} "access path for the slave"} {-noStatics "prevent loading of statically linked pkgs"} @@ -71,11 +75,11 @@ proc InterpStatics {} { foreach v {Args statics noStatics} { upvar $v $v } set flag [::tcl::OptProcArgGiven -noStatics]; - if {$flag && ($noStatics == $statics) + if {$flag && (!$noStatics == !$statics) && ([::tcl::OptProcArgGiven -statics])} { return -code error\ "conflicting values given for -statics and -noStatics" } if {$flag} { @@ -92,11 +96,11 @@ upvar $v $v } set flag [::tcl::OptProcArgGiven -nestedLoadOk]; # note that the test here is the opposite of the "InterpStatics" # one (it is not -noNested... because of the wanted default value) - if {$flag && ($nestedLoadOk != $nested) + if {$flag && (!$nestedLoadOk != !$nested) && ([::tcl::OptProcArgGiven -nested])} { return -code error\ "conflicting values given for -nested and -nestedLoadOk" } if {$flag} { @@ -318,12 +322,12 @@ proc ::safe::InterpSetConfig {slave access_path staticsok\ nestedok deletehook} { # determine and store the access path if empty - if {[string equal "" $access_path]} { - set access_path [uplevel #0 set auto_path] + if {$access_path eq ""} { + set access_path [uplevel \#0 set auto_path] # Make sure that tcl_library is in auto_path # and at the first position (needed by setAccessPath) set where [lsearch -exact $access_path [info library]] if {$where == -1} { # not found, add it. @@ -634,19 +638,19 @@ proc Toplevel {args} { namespace eval [namespace current] $args } # set/get values proc Set {args} { - eval [list Toplevel set] $args + eval [linsert $args 0 Toplevel set] } # lappend on toplevel vars proc Lappend {args} { - eval [list Toplevel lappend] $args + eval [linsert $args 0 Toplevel lappend] } # unset a var/token (currently just an global level eval) proc Unset {args} { - eval [list Toplevel unset] $args + eval [linsert $args 0 Toplevel unset] } # test existance proc Exists {varname} { Toplevel info exists $varname } @@ -772,11 +776,11 @@ set package [lindex $args 0] # Determine where to load. load use a relative interp path # and {} means self, so we can directly and safely use passed arg. set target [lindex $args 1] - if {[string length $target]} { + if {$target ne ""} { # we will try to load into a sub sub interp # check that we want to authorize that. if {![NestedOk $slave]} { Log $slave "loading to a sub interp (nestedok)\ disabled (trying to load $package to $target)" @@ -784,13 +788,13 @@ } } # Determine what kind of load is requested - if {[string length $file] == 0} { + if {$file eq ""} { # static package loading - if {[string length $package] == 0} { + if {$package eq ""} { set msg "load error: empty filename and no package name" Log $slave $msg return -code error $msg } if {![StaticsOk $slave]} { @@ -835,11 +839,19 @@ if {[file isdirectory $file]} { error "\"$file\": is a directory" } set parent [file dirname $file] - if {[lsearch -exact $access_path $parent] == -1} { + + # Normalize paths for comparison since lsearch knows nothing of + # potential pathname anomalies. + set norm_parent [file normalize $parent] + foreach path $access_path { + lappend norm_access_path [file normalize $path] + } + + if {[lsearch -exact $norm_access_path $norm_parent] == -1} { error "\"$file\": not in access_path" } } # This procedure enables access from a safe interpreter to only a subset of @@ -846,11 +858,11 @@ # the subcommands of a command: proc Subset {slave command okpat args} { set subcommand [lindex $args 0] if {[regexp $okpat $subcommand]} { - return [eval [list $command $subcommand] [lrange $args 1 end]] + return [eval [linsert $args 0 $command]] } set msg "not allowed to invoke subcommand $subcommand of $command" Log $slave $msg error $msg } @@ -881,15 +893,15 @@ set okpat "^(name.*|convert.*)\$" set subcommand [lindex $args 0] if {[regexp $okpat $subcommand]} { - return [eval ::interp invokehidden $slave encoding $subcommand \ - [lrange $args 1 end]] + return [eval [linsert $args 0 \ + ::interp invokehidden $slave encoding]] } - if {[string match $subcommand system]} { + if {[string first $subcommand system] == 0} { if {$argc == 1} { # passed all the tests , lets source it: if {[catch {::interp invokehidden \ $slave encoding system} msg]} { Log $slave $msg Index: library/tcltest/pkgIndex.tcl ================================================================== --- library/tcltest/pkgIndex.tcl +++ library/tcltest/pkgIndex.tcl @@ -7,6 +7,6 @@ # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. if {![package vsatisfies [package provide Tcl] 8.3]} {return} -package ifneeded tcltest 2.2.2 [list source [file join $dir tcltest.tcl]] +package ifneeded tcltest 2.2.8 [list source [file join $dir tcltest.tcl]] Index: library/tcltest/tcltest.tcl ================================================================== --- library/tcltest/tcltest.tcl +++ library/tcltest/tcltest.tcl @@ -14,19 +14,19 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2000 by Ajuba Solutions # Contributions from Don Porter, NIST, 2002. (not subject to US copyright) # All rights reserved. # -# RCS: @(#) $Id: tcltest.tcl,v 1.78 2003/02/17 19:12:06 dgp Exp $ +# RCS: @(#) $Id: tcltest.tcl,v 1.78.2.13 2005/02/24 18:03:36 dgp Exp $ package require Tcl 8.3 ;# uses [glob -directory] namespace eval tcltest { # When the version number changes, be sure to update the pkgIndex.tcl file, # and the install directory in the Makefiles. When the minor version # changes (new feature) be sure to update the man page as well. - variable Version 2.2.2 + variable Version 2.2.8 # Compatibility support for dumb variables defined in tcltest 1 # Do not use these. Call [package provide Tcl] and [info patchlevel] # yourself. You don't need tcltest to wrap it for you. variable version [package provide Tcl] @@ -628,11 +628,11 @@ variable Option return [expr {[lsearch -exact $Option(-verbose) $level] != -1}] } # Default verbosity is to show bodies of failed tests - Option -verbose body { + Option -verbose {body error} { Takes any combination of the values 'p', 's', 'b', 't' and 'e'. Test suite will display all passed tests if 'p' is specified, all skipped tests if 's' is specified, the bodies of failed tests if 'b' is specified, and when tests start if 't' is specified. ErrorInfo is displayed if 'e' is specified. @@ -1417,11 +1417,11 @@ if {[llength $flagArray] == 0} { RemoveAutoConfigureTraces } else { set args $flagArray - while {[llength $args] && [catch {eval configure $args} msg]} { + while {[llength $args]>1 && [catch {eval configure $args} msg]} { # Something went wrong parsing $args for tcltest options # Check whether the problem is "unknown option" if {[regexp {^unknown option (\S+):} $msg -> option]} { # Could be this is an option the Hook knows about @@ -1429,11 +1429,11 @@ if {[lsearch -exact $moreOptions $option] == -1} { # Nope. Report the error, including additional options, # but keep going if {[llength $moreOptions]} { append msg ", " - append msg [join [lrange $moreOptions 0 end -1] ", "] + append msg [join [lrange $moreOptions 0 end-1] ", "] append msg "or [lindex $moreOptions end]" } Warn $msg } } else { @@ -1448,15 +1448,22 @@ while {![string equal [lindex $args 0] $option]} { set args [lrange $args 2 end] } set args [lrange $args 2 end] } + if {[llength $args] == 1} { + puts [errorChannel] \ + "missing value for option [lindex $args 0]" + exit 1 + } } # Call the hook - array set flag $flagArray - processCmdLineArgsHook [array get flag] + catch { + array set flag $flagArray + processCmdLineArgsHook [array get flag] + } return } # tcltest::ProcessCmdLineArgs -- # @@ -1492,12 +1499,12 @@ DebugPuts 2 "Flags passed into tcltest:" if {[info exists ::env(TCLTEST_OPTIONS)]} { DebugPuts 2 \ " ::env(TCLTEST_OPTIONS): $::env(TCLTEST_OPTIONS)" } - if {[info exists argv]} { - DebugPuts 2 " argv: $argv" + if {[info exists ::argv]} { + DebugPuts 2 " argv: $::argv" } DebugPuts 2 "tcltest::debug = [debug]" DebugPuts 2 "tcltest::testsDirectory = [testsDirectory]" DebugPuts 2 "tcltest::workingDirectory = [workingDirectory]" DebugPuts 2 "tcltest::temporaryDirectory = [temporaryDirectory]" @@ -1603,30 +1610,20 @@ variable errData DebugPuts 3 "[lindex [info level 0] 0] called" if {!$ignoreOutput} { set outData {} set errData {} - set callerHasPuts [llength [uplevel 1 { - ::info commands [::namespace current]::puts - }]] - if {$callerHasPuts} { - uplevel 1 [list ::rename puts [namespace current]::Replace::Puts] - } else { - interp alias {} [namespace current]::Replace::Puts {} ::puts - } - uplevel 1 [list ::namespace import [namespace origin Replace::puts]] + rename ::puts [namespace current]::Replace::Puts + namespace eval :: \ + [list namespace import [namespace origin Replace::puts]] namespace import Replace::puts } set result [uplevel 1 $script] if {!$ignoreOutput} { namespace forget puts - uplevel 1 ::namespace forget puts - if {$callerHasPuts} { - uplevel 1 [list ::rename [namespace current]::Replace::Puts puts] - } else { - interp alias {} [namespace current]::Replace::Puts {} - } + namespace eval :: namespace forget puts + rename [namespace current]::Replace::Puts ::puts } return $result } # tcltest::CompareStrings -- @@ -1840,10 +1837,17 @@ proc tcltest::test {name description args} { global tcl_platform variable testLevel variable coreModTime DebugPuts 3 "test $name $args" + DebugDo 1 { + variable TestNames + catch { + puts "test name '$name' re-used; prior use in $TestNames($name)" + } + set TestNames($name) [info script] + } FillFilesExisted incr testLevel # Pre-define everything to null except output and errorOutput. We @@ -1910,15 +1914,13 @@ return -code error "bad -match value \"$match\":\ must be $values" } # Replace symbolic valies supplied for -returnCodes - regsub -nocase normal $returnCodes 0 returnCodes - regsub -nocase error $returnCodes 1 returnCodes - regsub -nocase return $returnCodes 2 returnCodes - regsub -nocase break $returnCodes 3 returnCodes - regsub -nocase continue $returnCodes 4 returnCodes + foreach {strcode numcode} {ok 0 normal 0 error 1 return 2 break 3 continue 4} { + set returnCodes [string map -nocase [list $strcode $numcode] $returnCodes] + } } else { # This is parsing for the old test command format; it is here # for backward compatibility. set result [lindex $args end] if {[llength $args] == 2} { @@ -1945,10 +1947,14 @@ } } # First, run the setup script set code [catch {uplevel 1 $setup} setupMsg] + if {$code == 1} { + set errorInfo(setup) $::errorInfo + set errorCode(setup) $::errorCode + } set setupFailure [expr {$code != 0}] # Only run the test body if the setup was successful if {!$setupFailure} { @@ -1963,14 +1969,22 @@ set testResult [uplevel 1 [list [namespace origin Eval] $command 0]] } else { set testResult [uplevel 1 [list [namespace origin Eval] $command 1]] } foreach {actualAnswer returnCode} $testResult break + if {$returnCode == 1} { + set errorInfo(body) $::errorInfo + set errorCode(body) $::errorCode + } } # Always run the cleanup script set code [catch {uplevel 1 $cleanup} cleanupMsg] + if {$code == 1} { + set errorInfo(cleanup) $::errorInfo + set errorCode(cleanup) $::errorCode + } set cleanupFailure [expr {$code != 0}] set coreFailure 0 set coreMsg "" # check for a core file first - if one was created by the test, @@ -2001,16 +2015,22 @@ Problem renaming core file: $msg" } } } } + + # check if the return code matched the expected return code + set codeFailure 0 + if {!$setupFailure && [lsearch -exact $returnCodes $returnCode] == -1} { + set codeFailure 1 + } # If expected output/error strings exist, we have to compare # them. If the comparison fails, then so did the test. set outputFailure 0 variable outData - if {[info exists output]} { + if {[info exists output] && !$codeFailure} { if {[set outputCompare [catch { CompareStrings $outData $output $match } outputMatch]] == 0} { set outputFailure [expr {!$outputMatch}] } else { @@ -2018,29 +2038,23 @@ } } set errorFailure 0 variable errData - if {[info exists errorOutput]} { + if {[info exists errorOutput] && !$codeFailure} { if {[set errorCompare [catch { CompareStrings $errData $errorOutput $match } errorMatch]] == 0} { set errorFailure [expr {!$errorMatch}] } else { set errorFailure 1 } } - # check if the return code matched the expected return code - set codeFailure 0 - if {!$setupFailure && [lsearch -exact $returnCodes $returnCode] == -1} { - set codeFailure 1 - } - # check if the answer matched the expected answer # Only check if we ran the body of the test (no setup failure) - if {$setupFailure} { + if {$setupFailure || $codeFailure} { set scriptFailure 0 } elseif {[set scriptCompare [catch { CompareStrings $actualAnswer $result $match } scriptMatch]] == 0} { set scriptFailure [expr {!$scriptMatch}] @@ -2080,10 +2094,14 @@ puts [outputChannel] $body } if {$setupFailure} { puts [outputChannel] "---- Test setup\ failed:\n$setupMsg" + if {[info exists errorInfo(setup)]} { + puts [outputChannel] "---- errorInfo(setup): $errorInfo(setup)" + puts [outputChannel] "---- errorCode(setup): $errorCode(setup)" + } } if {$scriptFailure} { if {$scriptCompare} { puts [outputChannel] "---- Error testing result: $scriptMatch" } else { @@ -2103,13 +2121,13 @@ } puts [outputChannel] "---- $msg; Return code was: $returnCode" puts [outputChannel] "---- Return code should have been\ one of: $returnCodes" if {[IsVerbose error]} { - if {[info exists ::errorInfo]} { - puts [outputChannel] "---- errorInfo: $::errorInfo" - puts [outputChannel] "---- errorCode: $::errorCode" + if {[info exists errorInfo(body)] && ([lsearch $returnCodes 1]<0)} { + puts [outputChannel] "---- errorInfo: $errorInfo(body)" + puts [outputChannel] "---- errorCode: $errorCode(body)" } } } if {$outputFailure} { if {$outputCompare} { @@ -2129,10 +2147,14 @@ been ($match matching):\n$errorOutput" } } if {$cleanupFailure} { puts [outputChannel] "---- Test cleanup failed:\n$cleanupMsg" + if {[info exists errorInfo(cleanup)]} { + puts [outputChannel] "---- errorInfo(cleanup): $errorInfo(cleanup)" + puts [outputChannel] "---- errorCode(cleanup): $errorCode(cleanup)" + } } if {$coreFailure} { puts [outputChannel] "---- Core file produced while running\ test! $coreMsg" } @@ -2416,11 +2438,10 @@ # if we're deferring stat-reporting until all files are sourced, # then add current file to failFile list if any tests in this # file failed - incr numTestFiles if {$currentFailure \ && ([lsearch -exact $failFiles $testFileName] == -1)} { lappend failFiles $testFileName } set currentFailure false @@ -2477,14 +2498,14 @@ if {[file exists [file join [workingDirectory] core]]} { if {[preserveCore] > 1} { puts "rename core file (> 1)" puts [outputChannel] "produced core file! \ Moving file to: \ - [file join [temporaryDirectory] core-$name]" + [file join [temporaryDirectory] core-$testFileName]" catch {file rename -force \ [file join [workingDirectory] core] \ - [file join [temporaryDirectory] core-$name] + [file join [temporaryDirectory] core-$testFileName] } msg if {[string length $msg] > 0} { PrintError "Problem renaming file: $msg" } } else { @@ -2546,18 +2567,20 @@ # List files in $directory that match patterns to run. set matchFileList [list] foreach match [matchFiles] { set matchFileList [concat $matchFileList \ - [glob -directory $directory -nocomplain -- $match]] + [glob -directory $directory -types {b c f p s} \ + -nocomplain -- $match]] } # List files in $directory that match patterns to skip. set skipFileList [list] foreach skip [skipFiles] { set skipFileList [concat $skipFileList \ - [glob -directory $directory -nocomplain -- $skip]] + [glob -directory $directory -types {b c f p s} \ + -nocomplain -- $skip]] } # Add to result list all files in match list and not in skip list foreach file $matchFileList { if {[lsearch -exact $skipFileList $file] == -1} { @@ -2595,29 +2618,24 @@ # Determine the skip list first, to avoid [glob]-ing over subdirectories # we're going to throw away anyway. Be sure we skip the $rootdir if it # comes up to avoid infinite loops. set skipDirs [list $rootdir] foreach pattern [skipDirectories] { - foreach path [glob -directory $rootdir -nocomplain -- $pattern] { - if {[file isdirectory $path]} { - lappend skipDirs $path - } - } + set skipDirs [concat $skipDirs [glob -directory $rootdir -types d \ + -nocomplain -- $pattern]] } # Now step through the matching directories, prune out the skipped ones # as you go. set matchDirs [list] foreach pattern [matchDirectories] { - foreach path [glob -directory $rootdir -nocomplain -- $pattern] { - if {[file isdirectory $path]} { - if {[lsearch -exact $skipDirs $path] == -1} { - set matchDirs [concat $matchDirs \ - [GetMatchingDirectories $path]] - if {[file exists [file join $path all.tcl]]} { - lappend matchDirs $path - } + foreach path [glob -directory $rootdir -types d -nocomplain -- \ + $pattern] { + if {[lsearch -exact $skipDirs $path] == -1} { + set matchDirs [concat $matchDirs [GetMatchingDirectories $path]] + if {[file exists [file join $path all.tcl]]} { + lappend matchDirs $path } } } } @@ -2880,13 +2898,12 @@ # Side effects: # None. proc tcltest::normalizeMsg {msg} { regsub "\n$" [string tolower $msg] "" msg - regsub -all "\n\n" $msg "\n" msg - regsub -all "\n\}" $msg "\}" msg - return $msg + set msg [string map [list "\n\n" "\n"] $msg] + return [string map [list "\n\}" "\}"] $msg] } # tcltest::makeFile -- # # Create a new file with the name , and write to it. @@ -3286,11 +3303,11 @@ if {[catch {llength $options} msg]} { Warn "invalid TCLTEST_OPTIONS \"$options\":\n invalid\ Tcl list: $msg" return } - if {[llength $::env(TCLTEST_OPTIONS)] < 2} { + if {[llength $::env(TCLTEST_OPTIONS)] % 2} { Warn "invalid TCLTEST_OPTIONS: \"$options\":\n should be\ -option value ?-option value ...?" return } if {[catch {eval Configure $::env(TCLTEST_OPTIONS)} msg]} { Index: library/word.tcl ================================================================== --- library/word.tcl +++ library/word.tcl @@ -8,16 +8,16 @@ # Copyright (c) 1998 by Scritpics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: word.tcl,v 1.7 2002/11/01 00:28:51 andreas_kupries Exp $ +# RCS: @(#) $Id: word.tcl,v 1.7.2.1 2005/07/22 21:59:41 dgp Exp $ # The following variables are used to determine which characters are # interpreted as white space. -if {[string equal $::tcl_platform(platform) "windows"]} { +if {$::tcl_platform(platform) eq "windows"} { # Windows style - any but a unicode space char set tcl_wordchars "\\S" set tcl_nonwordchars "\\s" } else { # Motif style - any unicode word char (number, letter, or underscore) @@ -56,11 +56,11 @@ # str - String to search. # start - Index into string specifying starting point. proc tcl_wordBreakBefore {str start} { global tcl_nonwordchars tcl_wordchars - if {[string equal $start end]} { + if {$start eq "end"} { set start [string length $str] } if {[regexp -indices "^.*($tcl_wordchars$tcl_nonwordchars|$tcl_nonwordchars$tcl_wordchars)" [string range $str 0 $start] result]} { return [lindex $result 1] } @@ -118,15 +118,15 @@ # str - String to search. # start - Index into string specifying starting point. proc tcl_startOfPreviousWord {str start} { global tcl_nonwordchars tcl_wordchars - if {[string equal $start end]} { + if {$start eq "end"} { set start [string length $str] } if {[regexp -indices \ "$tcl_nonwordchars*($tcl_wordchars+)$tcl_nonwordchars*\$" \ [string range $str 0 [expr {$start - 1}]] result word]} { return [lindex $word 0] } return -1 } Index: mac/README ================================================================== --- mac/README +++ mac/README @@ -1,8 +1,20 @@ Tcl 8.4 for Macintosh -RCS: @(#) $Id: README,v 1.17 2002/03/04 23:26:03 hobbs Exp $ +RCS: @(#) $Id: README,v 1.17.2.1 2005/12/04 00:50:03 das Exp $ + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +Note that Tcl on Mac OS Classic is no longer supported and likely no longer +compiles, the last release known to work is 8.4.2. The 'mac' source +directory and all other Mac Classic code have been removed from Tk 8.5. + +The Mac OS X port of Tcl can be found in the 'macosx' source directory. + +The information and URLs below are known to be outdated and incorrect. + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1. Introduction --------------- This is the README file for the Macintosh version of the Tcl Index: mac/tclMacChan.c ================================================================== --- mac/tclMacChan.c +++ mac/tclMacChan.c @@ -7,11 +7,11 @@ * Copyright (c) 1996-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMacChan.c,v 1.21 2003/03/03 20:22:42 das Exp $ + * RCS: @(#) $Id: tclMacChan.c,v 1.21.2.1 2005/01/27 22:53:34 andreas_kupries Exp $ */ #include "tclInt.h" #include "tclPort.h" #include "tclMacInt.h" @@ -100,10 +100,12 @@ CONST char *buf, int toWrite, int *errorCode)); static int FileSeek _ANSI_ARGS_((ClientData instanceData, long offset, int mode, int *errorCode)); static void FileSetupProc _ANSI_ARGS_((ClientData clientData, int flags)); +static void FileThreadActionProc _ANSI_ARGS_ (( + ClientData instanceData, int action)); static Tcl_Channel OpenFileChannel _ANSI_ARGS_((CONST char *fileName, int mode, int permissions, int *errorCodePtr)); static int StdIOBlockMode _ANSI_ARGS_((ClientData instanceData, int mode)); static int StdIOClose _ANSI_ARGS_((ClientData instanceData, @@ -121,37 +123,48 @@ * This structure describes the channel type structure for file based IO: */ static Tcl_ChannelType consoleChannelType = { "file", /* Type name. */ - (Tcl_ChannelTypeVersion)StdIOBlockMode, /* Set blocking/nonblocking mode.*/ + TCL_CHANNEL_VERSION_4, /* v4 channel */ StdIOClose, /* Close proc. */ StdIOInput, /* Input proc. */ StdIOOutput, /* Output proc. */ StdIOSeek, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ CommonWatch, /* Initialize notifier. */ CommonGetHandle /* Get OS handles out of channel. */ + NULL, /* close2proc. */ + StdIOBlockMode, /* Set blocking/nonblocking mode.*/ + NULL, /* flush proc. */ + NULL, /* handler proc. */ + NULL, /* wide seek proc. */ + NULL, /* thread actions */ }; /* * This variable describes the channel type structure for file based IO. */ static Tcl_ChannelType fileChannelType = { "file", /* Type name. */ - (Tcl_ChannelTypeVersion)FileBlockMode, /* Set blocking or - * non-blocking mode.*/ + TCL_CHANNEL_VERSION_4, /* v4 channel */ FileClose, /* Close proc. */ FileInput, /* Input proc. */ FileOutput, /* Output proc. */ FileSeek, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ CommonWatch, /* Initialize notifier. */ CommonGetHandle /* Get OS handles out of channel. */ + NULL, /* close2proc. */ + FileBlockMode, /* Set blocking/nonblocking mode.*/ + NULL, /* flush proc. */ + NULL, /* handler proc. */ + NULL, /* wide seek proc. */ + FileThreadActionProc, /* thread actions */ }; /* * Hack to allow Mac Tk to override the TclGetStdChannels function. @@ -1210,14 +1223,13 @@ } /* *---------------------------------------------------------------------- * - * TclpCutFileChannel -- + * FileThreadActionProc -- * - * Remove any thread local refs to this channel. See - * Tcl_CutChannel for more info. + * Insert or remove any thread local refs to this channel. * * Results: * None. * * Side effects: @@ -1224,77 +1236,40 @@ * Changes thread local list of valid channels. * *---------------------------------------------------------------------- */ -void -TclpCutFileChannel(chan) - Tcl_Channel chan; /* The channel being removed. Must - * not be referenced in any - * interpreter. */ -{ - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - Channel *chanPtr = (Channel *) chan; - FileState *infoPtr; - FileState **nextPtrPtr; - int removed = 0; - - if (chanPtr->typePtr != &fileChannelType) - return; - - infoPtr = (FileState *) chanPtr->instanceData; - - for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL; - nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { - if ((*nextPtrPtr) == infoPtr) { - (*nextPtrPtr) = infoPtr->nextPtr; - removed = 1; - break; - } - } - - /* - * This could happen if the channel was created in one thread - * and then moved to another without updating the thread - * local data in each thread. - */ - - if (!removed) - panic("file info ptr not on thread channel list"); - -} - -/* - *---------------------------------------------------------------------- - * - * TclpSpliceFileChannel -- - * - * Insert thread local ref for this channel. - * Tcl_SpliceChannel for more info. - * - * Results: - * None. - * - * Side effects: - * Changes thread local list of valid channels. - * - *---------------------------------------------------------------------- - */ - -void -TclpSpliceFileChannel(chan) - Tcl_Channel chan; /* The channel being removed. Must - * not be referenced in any - * interpreter. */ -{ - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - Channel *chanPtr = (Channel *) chan; - FileState *infoPtr; - - if (chanPtr->typePtr != &fileChannelType) - return; - - infoPtr = (FileState *) chanPtr->instanceData; - - infoPtr->nextPtr = tsdPtr->firstFilePtr; - tsdPtr->firstFilePtr = infoPtr; +static void +FileThreadActionProc (instanceData, action) + ClientData instanceData; + int action; +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + FileState *infoPtr = (FileState *) instanceData; + + if (action == TCL_CHANNEL_THREAD_INSERT) { + infoPtr->nextPtr = tsdPtr->firstFilePtr; + tsdPtr->firstFilePtr = infoPtr; + } else { + FileState **nextPtrPtr; + int removed = 0; + + for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL; + nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { + if ((*nextPtrPtr) == infoPtr) { + (*nextPtrPtr) = infoPtr->nextPtr; + removed = 1; + break; + } + } + + /* + * This could happen if the channel was created in one thread + * and then moved to another without updating the thread + * local data in each thread. + */ + + if (!removed) { + panic("file info ptr not on thread channel list"); + } + } } Index: mac/tclMacFile.c ================================================================== --- mac/tclMacFile.c +++ mac/tclMacFile.c @@ -8,11 +8,11 @@ * Copyright (c) 1995-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMacFile.c,v 1.27 2003/03/03 20:22:43 das Exp $ + * RCS: @(#) $Id: tclMacFile.c,v 1.27.2.1 2003/10/03 17:45:37 vincentdarley Exp $ */ /* * Note: This code eventually needs to support async I/O. In doing this * we will need to keep track of all current async I/O. If exit to shell @@ -176,10 +176,11 @@ CInfoPBRec paramBlock; FSSpec fileSpec; if (TclpObjLstat(fileNamePtr, &buf) != 0) { /* File doesn't exist */ + Tcl_DecrRefCount(fileNamePtr); return TCL_OK; } if (FspLLocationFromFsPath(fileNamePtr, &fileSpec) == noErr) { paramBlock.hFileInfo.ioCompletion = NULL; @@ -200,10 +201,11 @@ Tcl_NewStringObj(fname+1, fnameLen-1)); } else { Tcl_ListObjAppendElement(interp, resultPtr, pathPtr); } } + Tcl_DecrRefCount(fileNamePtr); return TCL_OK; } else { char *fname; int fnameLen, result = TCL_OK; int baseLength; @@ -256,10 +258,11 @@ err = FSpGetDirectoryID(&dirSpec, &dirID, &isDirectory); } if ((err != noErr) || !isDirectory) { Tcl_DStringFree(&dsOrig); + Tcl_DecrRefCount(fileNamePtr); return TCL_OK; } } /* Make sure we have a trailing directory delimiter */ @@ -324,10 +327,11 @@ Tcl_DStringFree(&fileString); itemIndex++; } Tcl_DStringFree(&dsOrig); + Tcl_DecrRefCount(fileNamePtr); return result; } } static int @@ -1209,10 +1213,11 @@ if (TclpReadlink(Tcl_GetString(transPtr), &ds) != NULL) { link = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1); Tcl_IncrRefCount(link); Tcl_DStringFree(&ds); } + Tcl_DecrRefCount(transPtr); } return link; } #endif Index: mac/tclMacInit.c ================================================================== --- mac/tclMacInit.c +++ mac/tclMacInit.c @@ -6,11 +6,11 @@ * Copyright (c) 1995-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMacInit.c,v 1.9 2002/02/08 02:52:54 dgp Exp $ + * RCS: @(#) $Id: tclMacInit.c,v 1.9.2.2 2005/10/23 22:01:31 msofer Exp $ */ #include #include #include @@ -337,19 +337,20 @@ * what the native encoding actually is. * * Called at process initialization time. * * Results: - * None. + * Return 1, indicating that the UTF may be dirty and require "cleanup" + * after encodings are initialized. * * Side effects: * None. * *--------------------------------------------------------------------------- */ -void +int TclpInitLibraryPath(argv0) CONST char *argv0; /* Name of executable from argv[0] to main(). * Not used because we can determine the name * by querying the module handle. */ { @@ -409,10 +410,12 @@ Tcl_DStringFree(&ds); Tcl_DStringFree(&libPath); Tcl_DStringFree(&path); } TclSetLibraryPath(pathPtr); + + return 1; /* 1 indicates that pathPtr may be dirty utf (needs cleaning) */ } /* *--------------------------------------------------------------------------- * @@ -707,11 +710,13 @@ pathPtr = TclGetLibraryPath(); if (pathPtr == NULL) { pathPtr = Tcl_NewObj(); } + Tcl_IncrRefCount(pathPtr); Tcl_SetVar2Ex(interp, "auto_path", NULL, pathPtr, TCL_GLOBAL_ONLY); + Tcl_DecrRefCount(pathPtr); return Tcl_Eval(interp, initCmd); } /* *---------------------------------------------------------------------- Index: mac/tclMacNotify.c ================================================================== --- mac/tclMacNotify.c +++ mac/tclMacNotify.c @@ -12,11 +12,11 @@ * Copyright (c) 1995-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMacNotify.c,v 1.8 2001/11/23 01:27:53 das Exp $ + * RCS: @(#) $Id: tclMacNotify.c,v 1.8.4.1 2003/03/21 03:24:08 dgp Exp $ */ #include "tclInt.h" #include "tclPort.h" #include "tclMac.h" @@ -46,10 +46,11 @@ * Need this for replacing Tcl_SetTimer and Tcl_WaitForEvent defined * in THIS file with ones defined in the stub table. */ extern TclStubs tclStubs; +extern Tcl_NotifierProcs tclOriginalNotifier; /* * The follwing static indicates whether this module has been initialized. */ @@ -337,11 +338,11 @@ /* * Allow the notifier to be hooked. This may not make sense * on the Mac, but mirrors the UNIX hook. */ - if (tclStubs.tcl_SetTimer != Tcl_SetTimer) { + if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) { tclStubs.tcl_SetTimer(timePtr); return; } if (!timePtr) { @@ -418,11 +419,11 @@ /* * Allow the notifier to be hooked. This may not make * sense on the Mac, but mirrors the UNIX hook. */ - if (tclStubs.tcl_WaitForEvent != Tcl_WaitForEvent) { + if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) { return tclStubs.tcl_WaitForEvent(timePtr); } /* * Compute the next timeout value. Index: mac/tclMacResource.c ================================================================== --- mac/tclMacResource.c +++ mac/tclMacResource.c @@ -9,11 +9,11 @@ * Copyright (c) 1996-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMacResource.c,v 1.14 2002/06/05 11:59:49 das Exp $ + * RCS: @(#) $Id: tclMacResource.c,v 1.14.2.1 2003/10/01 14:34:16 das Exp $ */ #include #include #include @@ -1484,11 +1484,11 @@ rezName); } Tcl_DStringFree(&ds); } - if (*resource == NULL) { + if (resource != NULL && *resource == NULL) { *releaseIt = 1; LoadResource(resource); } else { *releaseIt = 0; } Index: mac/tclMacSock.c ================================================================== --- mac/tclMacSock.c +++ mac/tclMacSock.c @@ -6,11 +6,11 @@ * Copyright (c) 1996-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMacSock.c,v 1.14 2002/04/08 09:03:17 das Exp $ + * RCS: @(#) $Id: tclMacSock.c,v 1.14.2.1 2006/03/10 14:27:41 vasiljevic Exp $ */ #include "tclInt.h" #include "tclPort.h" #include "tclMacInt.h" @@ -157,11 +157,10 @@ Tcl_DString *dsPtr)); static void SocketCheckProc _ANSI_ARGS_((ClientData clientData, int flags)); static int SocketEventProc _ANSI_ARGS_((Tcl_Event *evPtr, int flags)); -static void SocketExitHandler _ANSI_ARGS_((ClientData clientData)); static void SocketFreeProc _ANSI_ARGS_((ClientData clientData)); static int SocketReady _ANSI_ARGS_((TcpState *statePtr)); static void SocketSetupProc _ANSI_ARGS_((ClientData clientData, int flags)); static void TcpAccept _ANSI_ARGS_((TcpState *statePtr)); @@ -365,41 +364,40 @@ * Do per-thread initialization. */ tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { + tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->socketList = NULL; Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL); - Tcl_CreateThreadExitHandler(SocketExitHandler, (ClientData) NULL); } } /* *---------------------------------------------------------------------- * - * SocketExitHandler -- + * TclpFinalizeSockets -- * - * Callback invoked during exit clean up to deinitialize the - * socket module. + * Invoked during exit clean up to deinitialize the socket module. * * Results: * None. * * Side effects: - * None. + * Removed event source. * *---------------------------------------------------------------------- */ -static void -SocketExitHandler( - ClientData clientData) /* Not used. */ -{ - if (hasSockets) { - Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL); - /* CleanUpExitProc(); - TclMacDeleteExitToShellPatch(CleanUpExitProc); */ +void +TclpFinalizeSockets() +{ + ThreadSpecificData *tsdPtr; + + tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); + if (tsdPtr != NULL) { + Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL); } } /* *---------------------------------------------------------------------- Index: mac/tclMacThrd.c ================================================================== --- mac/tclMacThrd.c +++ mac/tclMacThrd.c @@ -166,21 +166,21 @@ * *---------------------------------------------------------------------- */ int -Tcl_JoinThread(id, result) - Tcl_ThreadId id; /* Id of the thread to wait upon */ - int* result; /* Reference to the storage the result - * of the thread we wait upon will be - * written into. */ +Tcl_JoinThread(threadId, result) + Tcl_ThreadId threadId; /* Id of the thread to wait upon */ + int* result; /* Reference to the storage the result + * of the thread we wait upon will be + * written into. */ { if (!TclMacHaveThreads()) { return TCL_ERROR; } - return TclJoinThread (id, result); + return TclJoinThread (threadId, result); } /* *---------------------------------------------------------------------- * Index: macosx/Makefile ================================================================== --- macosx/Makefile +++ macosx/Makefile @@ -1,87 +1,207 @@ -################################################################################ -# -# Simple makefile for building on Mac OS X with the -# Project Builder command line tool 'pbxbuild' -# -# RCS: @(#) $Id: Makefile,v 1.5 2003/02/19 16:43:29 das Exp $ -# -################################################################################ - -INSTALL_ROOT ?= - -BUILD_DIR ?= ${CURDIR}/../../build - -TARGET = Tcl - -DEVBUILDSTYLE = Development -DEPBUILDSTYLE = Deployment - -PBXBUILD = /usr/bin/pbxbuild - -BUILD = ${PBXBUILD} SYMROOT="${BUILD_DIR}" -target "${TARGET}" - -DEVBUILD = ${BUILD} -buildstyle "${DEVBUILDSTYLE}" -DEPBUILD = ${BUILD} -buildstyle "${DEPBUILDSTYLE}" - -INSTALLOPTS = INSTALL_ROOT="${INSTALL_ROOT}" - -EMBEDDEDOPTS = EMBEDDED_BUILD=1 - -################################################################################ - -all: develop deploy - -install: install-develop install-deploy - -embedded: embedded-deploy - -install-embedded: install-embedded-deploy - -clean: clean-develop clean-deploy - -################################################################################ - -develop: - ${DEVBUILD} - -deploy: - ${DEPBUILD} - -install-develop: - ${DEVBUILD} install ${INSTALLOPTS} - -install-deploy: - ${DEPBUILD} install ${INSTALLOPTS} - -embedded-develop: - ${DEVBUILD} ${EMBEDDEDOPTS} - -embedded-deploy: - ${DEPBUILD} ${EMBEDDEDOPTS} - -install-embedded-develop: - ${DEVBUILD} install ${INSTALLOPTS} ${EMBEDDEDOPTS} - -install-embedded-deploy: - ${DEPBUILD} install ${INSTALLOPTS} ${EMBEDDEDOPTS} - -clean-develop: - ${DEVBUILD} clean - -clean-deploy: - ${DEPBUILD} clean - -################################################################################ - -forceRelink: - @-cd ${BUILD_DIR}; \ - rm -rf Tcl.framework tclsh8.4 \ - Development.build/Tcl.build/Tcl Deployment.build/Tcl.build/Tcl - -################################################################################ - -.PHONY: all install embedded clean develop deploy install-develop install-deploy \ -embedded-develop embedded-deploy install-embedded-develop install-embedded-deploy \ -clean-develop clean-deploy forceRelink \ - -################################################################################ +######################################################################################################## +# +# Makefile wrapper to build tcl on Mac OS X in a way compatible with the tk/macosx Xcode buildsystem +# uses the standard unix build system in tcl/unix (which can be used directly instead of this +# if you are not using the tk/macosx projects). +# +# Copyright (c) 2002-2007 Daniel A. Steffen +# +# See the file "license.terms" for information on usage and redistribution of +# this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: Makefile,v 1.5.2.17 2007/04/29 02:21:33 das Exp $ +# +######################################################################################################## + +#------------------------------------------------------------------------------------------------------- +# customizable settings + +DESTDIR ?= +INSTALL_ROOT ?= ${DESTDIR} + +BUILD_DIR ?= ${CURDIR}/../../build +SYMROOT ?= ${BUILD_DIR}/${PROJECT} +OBJROOT ?= ${SYMROOT} + +EXTRA_CONFIGURE_ARGS ?= +EXTRA_MAKE_ARGS ?= + +INSTALL_PATH ?= /Library/Frameworks +PREFIX ?= /usr/local +BINDIR ?= ${PREFIX}/bin +LIBDIR ?= ${INSTALL_PATH} +MANDIR ?= ${PREFIX}/man + +# set to non-empty value to install manpages in addition to html help: +INSTALL_MANPAGES ?= + +#------------------------------------------------------------------------------------------------------- +# meta targets + +meta := all install embedded install-embedded clean distclean test + +styles := develop deploy + +all := ${styles} +all : ${all} + +install := ${styles:%=install-%} +install : ${install} +install-%: action := install- + +embedded := ${styles:%=embedded-%} +embedded : embedded-deploy +install-embedded := ${embedded:%=install-%} +install-embedded : install-embedded-deploy + +clean := ${styles:%=clean-%} +clean : ${clean} +clean-%: action := clean- +distclean := ${styles:%=distclean-%} +distclean : ${distclean} +distclean-%: action := distclean- + +test := ${styles:%=test-%} +test : ${test} +test-%: action := test- + +targets := $(foreach v,${meta},${$v}) + +#------------------------------------------------------------------------------------------------------- +# build styles + +BUILD_STYLE = +CONFIGURE_ARGS = +OBJ_DIR = ${OBJROOT}/${BUILD_STYLE} + +develop_make_args := BUILD_STYLE=Development CONFIGURE_ARGS=--enable-symbols +deploy_make_args := BUILD_STYLE=Deployment INSTALL_TARGET=install-strip \ + GENERIC_FLAGS=-DNDEBUG +embedded_make_args := EMBEDDED_BUILD=1 +install_make_args := INSTALL_BUILD=1 + +${targets}: + ${MAKE} ${action}${PROJECT} \ + $(foreach s,${styles} embedded install,$(if $(findstring $s,$@),${${s}_make_args})) + +#------------------------------------------------------------------------------------------------------- +# project specific settings + +PROJECT := tcl +PRODUCT_NAME := Tcl + +UNIX_DIR := ${CURDIR}/../unix +VERSION := $(shell awk -F= '/^TCL_VERSION/ {print $$2; nextfile}' ${UNIX_DIR}/configure.in) +TCLSH := tclsh${VERSION} + +BUILD_TARGET := all tcltest +INSTALL_TARGET := install + +export CPPROG := cp -p + +INSTALL_TARGETS = install-binaries install-libraries +ifeq (${EMBEDDED_BUILD},) +INSTALL_TARGETS += install-private-headers +endif +ifeq (${INSTALL_BUILD}_${EMBEDDED_BUILD}_${BUILD_STYLE},1__Deployment) +INSTALL_TARGETS += html-tcl +ifneq (${INSTALL_MANPAGES},) +INSTALL_TARGETS += install-doc +endif +endif + +MAKE_VARS := INSTALL_ROOT INSTALL_TARGETS VERSION GENERIC_FLAGS +MAKE_ARGS_V = $(foreach v,${MAKE_VARS},$v='${$v}') + +build-${PROJECT}: target = ${BUILD_TARGET} +install-${PROJECT}: target = ${INSTALL_TARGET} +clean-${PROJECT} distclean-${PROJECT} test-${PROJECT}: \ + target = $* + +DO_MAKE = +${MAKE} -C ${OBJ_DIR} ${target} ${MAKE_ARGS_V} ${MAKE_ARGS} ${EXTRA_MAKE_ARGS} + +#------------------------------------------------------------------------------------------------------- +# build rules + +${PROJECT}: + ${MAKE} install-${PROJECT} INSTALL_ROOT=${OBJ_DIR}/ + +${OBJ_DIR}/Makefile: ${UNIX_DIR}/Makefile.in ${UNIX_DIR}/configure \ + ${UNIX_DIR}/tclConfig.sh.in Tcl-Info.plist.in + mkdir -p ${OBJ_DIR} && cd ${OBJ_DIR} && \ + if [ ${UNIX_DIR}/configure -nt config.status ]; then ${UNIX_DIR}/configure \ + --prefix=${PREFIX} --bindir=${BINDIR} --libdir=${LIBDIR} \ + --mandir=${MANDIR} --enable-threads --enable-framework \ + ${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS}; else ./config.status; fi + +build-${PROJECT}: ${OBJ_DIR}/Makefile + ${DO_MAKE} +ifeq (${INSTALL_BUILD},) +# symolic link hackery to trick +# 'make install INSTALL_ROOT=${OBJ_DIR}' +# into building Tcl.framework and tclsh in ${SYMROOT} + @cd ${OBJ_DIR} && mkdir -p $(dir ./${LIBDIR}) $(dir ./${BINDIR}) ${SYMROOT} && \ + rm -f ./${LIBDIR} ./${BINDIR} && ln -fs ${SYMROOT} ./${LIBDIR} && \ + ln -fs ${SYMROOT} ./${BINDIR} && ln -fs ${OBJ_DIR}/tcltest ${SYMROOT} +endif + +install-${PROJECT}: build-${PROJECT} +ifeq (${EMBEDDED_BUILD}_${INSTALL_ROOT},1_) + @echo "Cannot install-embedded with empty INSTALL_ROOT !" && false +endif +ifeq (${EMBEDDED_BUILD},1) + @rm -rf "${INSTALL_ROOT}/${LIBDIR}/Tcl.framework" +endif + ${DO_MAKE} +ifeq (${INSTALL_BUILD},1) +ifeq (${EMBEDDED_BUILD},1) +# if we are embedding frameworks, don't install tclsh + @rm -f "${INSTALL_ROOT}${BINDIR}/${TCLSH}" && \ + rmdir -p "${INSTALL_ROOT}${BINDIR}" 2>&- || true +else +# redo prebinding (when not building for Mac OS X 10.4 or later only) + @if [ "`echo "$${MACOSX_DEPLOYMENT_TARGET}" | \ + awk -F '10\\.' '{print int($$2)}'`" -lt 4 -a "`echo "$${CFLAGS}" | \ + awk -F '-mmacosx-version-min=10\\.' '{print int($$2)}'`" -lt 4 ]; \ + then cd ${INSTALL_ROOT}/; \ + if [ ! -d usr/lib ]; then mkdir -p usr && ln -fs /usr/lib usr/ && RM_USRLIB=1; fi; \ + if [ ! -d System ]; then ln -fs /System . && RM_SYSTEM=1; fi; \ + redo_prebinding -r . "./${LIBDIR}/${PRODUCT_NAME}.framework/Versions/${VERSION}/${PRODUCT_NAME}"; \ + redo_prebinding -r . "./${BINDIR}/${TCLSH}"; \ + if [ -n "$${RM_USRLIB:-}" ]; then rm -f usr/lib; rmdir -p usr 2>&-; fi; \ + if [ -n "$${RM_SYSTEM:-}" ]; then rm -f System; fi; fi +# install tclsh symbolic link + @ln -fs ${TCLSH} ${INSTALL_ROOT}${BINDIR}/tclsh +endif +endif +ifeq (${BUILD_STYLE}_${EMBEDDED_BUILD},Development_) +# keep copy of debug library around, so that +# Deployment build can be installed on top +# of Development build without overwriting +# the debug library + @cd ${INSTALL_ROOT}${LIBDIR}/${PRODUCT_NAME}.framework/Versions/${VERSION} && \ + ln -f "${PRODUCT_NAME}" "${PRODUCT_NAME}_debug" +endif + +clean-${PROJECT}: %-${PROJECT}: + ${DO_MAKE} + rm -rf ${SYMROOT}/{${PRODUCT_NAME}.framework,${TCLSH},tcltest} + rm -f ${OBJ_DIR}{${LIBDIR},${BINDIR}} && \ + rmdir -p ${OBJ_DIR}$(dir ${LIBDIR}) 2>&- || true && \ + rmdir -p ${OBJ_DIR}$(dir ${BINDIR}) 2>&- || true + +distclean-${PROJECT}: %-${PROJECT}: clean-${PROJECT} + ${DO_MAKE} + rm -rf ${OBJ_DIR} + +test-${PROJECT}: %-${PROJECT}: build-${PROJECT} + ${DO_MAKE} + +#------------------------------------------------------------------------------------------------------- + +.PHONY: ${meta} ${targets} ${PROJECT} build-${PROJECT} install-${PROJECT} \ + clean-${PROJECT} distclean-${PROJECT} + +.NOTPARALLEL: + +#------------------------------------------------------------------------------------------------------- ADDED macosx/README Index: macosx/README ================================================================== --- /dev/null +++ macosx/README @@ -0,0 +1,150 @@ +Tcl Mac OS X README +------------------- + +RCS: @(#) $Id: README,v 1.1.2.9 2007/04/29 02:21:33 das Exp $ + +This is the README file for the Mac OS X/Darwin version of Tcl. + + +1. Where to go for support +-------------------------- + +- The tcl-mac mailing list on sourceforge is the best place to ask questions +specific to Tcl & Tk on Mac OS X: + http://lists.sourceforge.net/lists/listinfo/tcl-mac +(this page also has a link to searchable archives of the list, please check them +before asking on the list, many questions have already been answered). + +- For general Tcl/Tk questions, the newsgroup comp.lang.tcl is your best bet: + http://groups.google.com/group/comp.lang.tcl/ + +- The Tcl'ers Wiki also has many pages dealing with Tcl & Tk on Mac OS X, see + http://wiki.tcl.tk/references/3753! + http://wiki.tcl.tk/references/8361! + +- Please report bugs with Tcl or Tk on Mac OS X to the sourceforge bug trackers: + Tcl: http://sf.net/tracker/?func=add&group_id=10894&atid=110894 + Tk: http://sf.net/tracker/?func=add&group_id=12997&atid=112997 +please make sure that your report Tk specific bugs to the tktoolkit project bug +tracker rather than the tcl project bug tracker. +Mac OS X specific bugs should usually be assigned to 'das' or 'wolfsuit'. + + +2. Using Tcl on Mac OS X +------------------------ + +- At a minimum, Mac OS X 10.1 is required to run Tcl, but OS X 10.3 or higher is +recommended (certain [file] operations behave incorrectly on earlier releases). + +- Unless weak-linking is used, Tcl built on Mac OS X 10.x will not run on 10.y +with y < x; on the other hand Tcl built on 10.y will always run on 10.x with +y <= x (but without any of the fixes and optimizations that would be available +in a binary built on 10.x). +Weak-linking is available on OS X 10.2 or later, it additionally allows Tcl +built on 10.x to run on any 10.y with x > y >= z (for a chosen z >= 2). + +- Tcl extensions can be installed in any of: + $HOME/Library/Tcl /Library/Tcl /Network/Library/Tcl /System/Library/Tcl + $HOME/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks + /System/Library/Frameworks (searched in that order). +Given a potential package directory $pkg, Tcl on OSX checks for the file +$pkg/Resources/Scripts/pkgIndex.tcl as well as the usual $pkg/pkgIndex.tcl. +This allows building extensions as frameworks with all script files contained in +the Resources/Scripts directory of the framework. + +- [load]able binary extensions can linked as either ordinary shared libraries +(.dylib) or as MachO bundles (since 8.4.10/8.5a3); only bundles can be unloaded, +and bundles are also loaded more efficiently from VFS (no temporary copy to the +native filesystem required). + +- The 'deploy' target of macosx/Makefile installs the html manpages into the +standard documentation location in the Tcl framework: + Tcl.framework/Resources/Documentation/Reference/Tcl +No nroff manpages are installed by default by the Makefile. + +- The Tcl framework can be installed in any of the system's standard +framework directories: + $HOME/Library/Frameworks /Library/Frameworks + /Network/Library/Frameworks /System/Library/Frameworks + + +3. Building Tcl on Mac OS X +--------------------------- + +- At least Mac OS X 10.1 is required to build Tcl, and Apple's Developer Tools +need to be installed (only the most recent version matching your OS release is +supported). The Developer Tools installer is available on Mac OS X retail disks +or is present in /Applications/Installers on Macs that came with OS X +preinstalled. The most recent version can be downloaded from the ADC website +http://connect.apple.com (after you register for free ADC membership). + +- Tcl is most easily built as a Mac OS X framework via Makefile in tcl/macosx +(see below for details), but can also be built with the standard unix configure +and make buildsystem in tcl/unix as on any other unix platform (indeed, the +Makefile is just a wrapper around the unix buildsystem). +The Mac OS X specific configure flags are --enable-framework and +--disable-corefoundation (which disables CF and notably reverts to the standard +select based notifier). + +- It is also possible to build with Apple's IDE via the tcl/macosx/Tcl.pbproj +project, this simply calls through to the tcl/macosx/Makefile. + +- To build universal binaries, set CFLAGS as follows: + export CFLAGS="-arch ppc -arch ppc64 -arch i386 -arch x86_64 \ + -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4" +This requires Mac OS X 10.4 and Xcode 2.4 (or Xcode 2.2 if -arch x86_64 is +omitted, but _not_ Xcode 2.1) and will work on any of the architectures (the +-isysroot flag is only required on PowerPC Tiger). +Note that configure requires CFLAGS to contain a least one architecture that can +be run on the build machine (i.e. ppc on G3/G4, ppc or ppc64 on G5, ppc or i386 +on Core and ppc, i386 or x86_64 on Core2/Xeon). +Universal builds of Tcl TEA extensions are also possible with CFLAGS set as +above, they will be [load]able by universal as well as thin binaries of Tcl. + +- To enable weak-linking, set the MACOSX_DEPLOYMENT_TARGET environment variable +to the minimal OS version (>= 10.2) the binaries should be able to run on, e.g: + export MACOSX_DEPLOYMENT_TARGET=10.2 +This requires Mac OS X 10.2 and gcc 3.1; if you have gcc 4 or later you can set +CFLAGS instead: + export CFLAGS="-mmacosx-version-min=10.2" +Support for weak-linking was added to the code for 8.4.14/8.5a5. + +Detailed Instructions for building with macosx/Makefile +------------------------------------------------------- + +- Unpack the tcl source release archive. + +- The following instructions assume the tcl source tree is named "tcl${ver}", +where ${ver} is a shell variable containing the tcl version number (for example +'8.4.12'). +Setup the shell variable as follows: + set ver="8.4.12" ;: if your shell is csh + ver="8.4.12" ;: if your shell is sh +The source tree will be named this way only if you are building from a release +archive, if you are building from CVS, the version numbers will be missing; so +set ${ver} to the empty string instead: + set ver="" ;: if your shell is csh + ver="" ;: if your shell is sh + +- The following steps will build Tcl from the Terminal, assuming you are located +in the directory containing the tcl source tree: + make -C tcl${ver}/macosx +and the following will then install Tcl onto the root volume (admin password +required): + sudo make -C tcl${ver}/macosx install +if you don't have the admin password, you can install into your home directory, +instead by passing an INSTALL_ROOT argument to make: + make -C tcl${ver}/macosx install INSTALL_ROOT="${HOME}/" + +- The default Makefile targets will build _both_ debug and optimized versions of +the Tcl framework with the standard convention of naming the debug library +Tcl.framework/Tcl_debug. +This allows switching to the debug libraries at runtime by setting + export DYLD_IMAGE_SUFFIX=_debug +(c.f. man dyld for more details) + +If you only want to build and install the debug or optimized build, use the +'develop' or 'deploy' target variants of the Makefiles, respectively. +For example, to build and install only the optimized versions: + make -C tcl${ver}/macosx deploy + sudo make -C tcl${ver}/macosx install-deploy ADDED macosx/Tcl-Info.plist.in Index: macosx/Tcl-Info.plist.in ================================================================== --- /dev/null +++ macosx/Tcl-Info.plist.in @@ -0,0 +1,38 @@ + + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + @TCL_LIB_FILE@ + CFBundleGetInfoString + Tcl @TCL_VERSION@@TCL_PATCH_LEVEL@, +Copyright © @TCL_YEAR@ Tcl Core Team, +Copyright © 2001-@TCL_YEAR@ Daniel A. Steffen, +Initial MacOS X Port by Jim Ingham & Ian Reid, +Copyright © 2001-2002, Apple Computer, Inc. + CFBundleIdentifier + com.tcltk.tcllibrary + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Tcl @TCL_VERSION@ + CFBundlePackageType + FMWK + CFBundleShortVersionString + @TCL_VERSION@@TCL_PATCH_LEVEL@ + CFBundleSignature + Tcl + CFBundleVersion + @TCL_VERSION@@TCL_PATCH_LEVEL@ + + ADDED macosx/Tcl.pbproj/default.pbxuser Index: macosx/Tcl.pbproj/default.pbxuser ================================================================== --- /dev/null +++ macosx/Tcl.pbproj/default.pbxuser @@ -0,0 +1,173 @@ +// !$*UTF8*$! +{ + 00E2F845016E82EB0ACA28DC = { + activeBuildStyle = 00E2F847016E82EB0ACA28DC; + activeExecutable = F594E5F1030774B1016F146B; + activeTarget = 00E2F84C016E8B780ACA28DC; + addToTargets = ( + ); + codeSenseManager = F9D167E40610239A0027C147; + executables = ( + F53ACC52031D9AFE016F146B, + F594E5F1030774B1016F146B, + ); + sourceControlManager = F9D167E30610239A0027C147; + userBuildSettings = { + SYMROOT = "${SRCROOT}/../../build/tcl"; + }; + }; + 00E2F84C016E8B780ACA28DC = { + activeExec = 0; + }; + F53ACC52031D9AFE016F146B = { + activeArgIndex = 2147483647; + activeArgIndices = ( + NO, + NO, + ); + argumentStrings = ( + "${SRCROOT}/../../tcl/tests/all.tcl", + "-verbose \"\"", + ); + configStateDict = { + "PBXLSLaunchAction-0" = { + PBXLSLaunchAction = 0; + PBXLSLaunchStartAction = 1; + PBXLSLaunchStdioStyle = 2; + PBXLSLaunchStyle = 0; + class = PBXLSRunLaunchConfig; + displayName = "Executable Runner"; + identifier = com.apple.Xcode.launch.runConfig; + remoteHostInfo = ""; + startActionInfo = ""; + }; + "PBXLSLaunchAction-1" = { + PBXLSLaunchAction = 1; + PBXLSLaunchStartAction = 1; + PBXLSLaunchStdioStyle = 2; + PBXLSLaunchStyle = 0; + class = PBXGDB_LaunchConfig; + displayName = GDB; + identifier = com.apple.Xcode.launch.GDBMI_Config; + remoteHostInfo = ""; + startActionInfo = ""; + }; + }; + cppStopOnCatchEnabled = 0; + cppStopOnThrowEnabled = 0; + customDataFormattersEnabled = 1; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = _debug; + enableDebugStr = 0; + environmentEntries = ( + { + active = YES; + name = TCL_LIBRARY; + value = "${SRCROOT}/../../tcl/library"; + }, + { + active = NO; + name = DYLD_PRINT_LIBRARIES; + }, + ); + isa = PBXExecutable; + launchableReference = F5C37CF303D5BEDF016F146B; + libgmallocEnabled = 0; + name = tcltest; + shlibInfoDictList = ( + ); + sourceDirectories = ( + ); + startupPath = "<>"; + }; + F594E5F1030774B1016F146B = { + activeArgIndex = 2147483647; + activeArgIndices = ( + ); + argumentStrings = ( + ); + configStateDict = { + "PBXLSLaunchAction-0" = { + PBXLSLaunchAction = 0; + PBXLSLaunchStartAction = 1; + PBXLSLaunchStdioStyle = 2; + PBXLSLaunchStyle = 0; + class = PBXLSRunLaunchConfig; + displayName = "Executable Runner"; + identifier = com.apple.Xcode.launch.runConfig; + remoteHostInfo = ""; + startActionInfo = ""; + }; + "PBXLSLaunchAction-1" = { + PBXLSLaunchAction = 1; + PBXLSLaunchStartAction = 1; + PBXLSLaunchStdioStyle = 2; + PBXLSLaunchStyle = 0; + class = PBXGDB_LaunchConfig; + displayName = GDB; + identifier = com.apple.Xcode.launch.GDBMI_Config; + remoteHostInfo = ""; + startActionInfo = ""; + }; + }; + cppStopOnCatchEnabled = 0; + cppStopOnThrowEnabled = 0; + customDataFormattersEnabled = 1; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = _debug; + enableDebugStr = 0; + environmentEntries = ( + { + active = NO; + name = DYLD_PRINT_LIBRARIES; + }, + ); + isa = PBXExecutable; + launchableReference = F98F02E608E7EF9A00D0320A; + libgmallocEnabled = 0; + name = tclsh; + shlibInfoDictList = ( + ); + sourceDirectories = ( + ); + startupPath = "<>"; + }; + F5C37CF303D5BEDF016F146B = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.executable"; + path = tcltest; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; + F98F02E608E7EF9A00D0320A = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.executable"; + path = tclsh8.4; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; + F9D167E30610239A0027C147 = { + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + isa = PBXSourceControlManager; + scmConfiguration = { + }; + scmType = scm.cvs; + }; + F9D167E40610239A0027C147 = { + indexTemplatePath = ""; + isa = PBXCodeSenseManager; + usesDefaults = 1; + wantsCodeCompletion = 1; + wantsCodeCompletionAutoSuggestions = 1; + wantsCodeCompletionCaseSensitivity = 1; + wantsCodeCompletionListAlways = 1; + wantsCodeCompletionOnlyMatchingItems = 1; + wantsCodeCompletionParametersIncluded = 1; + wantsCodeCompletionPlaceholdersInserted = 1; + wantsCodeCompletionTabCompletes = 1; + wantsIndex = 1; + }; +} Index: macosx/Tcl.pbproj/jingham.pbxuser ================================================================== --- macosx/Tcl.pbproj/jingham.pbxuser +++ macosx/Tcl.pbproj/jingham.pbxuser @@ -1,405 +1,173 @@ // !$*UTF8*$! { - 005751AA02FB00930AC916F0 = { - fRef = 005751AB02FB00930AC916F0; - isa = PBXTextBookmark; - name = "DefaultsDoc.rtf: 30"; - rLen = 32; - rLoc = 2777; - rType = 0; - vrLen = 1334; - vrLoc = 2136; - }; - 005751AB02FB00930AC916F0 = { - isa = PBXFileReference; - name = DefaultsDoc.rtf; - path = "/Developer/Applications/Project Builder.app/Contents/Resources/DefaultsDoc.rtf"; - refType = 0; - }; 00E2F845016E82EB0ACA28DC = { activeBuildStyle = 00E2F847016E82EB0ACA28DC; - activeTarget = F50DC359017027D801DC9062; + activeExecutable = F594E5F1030774B1016F146B; + activeTarget = 00E2F84C016E8B780ACA28DC; addToTargets = ( - 00E2F84C016E8B780ACA28DC, - ); - breakpoints = ( - ); - perUserDictionary = { - PBXPerProjectTemplateStateSaveDate = 49920633; - "PBXTemplateGeometry-F5314676015831810DCA290F" = { - ContentSize = "{789, 551}"; - LeftSlideOut = { - Collapsed = NO; - Frame = "{{0, 23}, {789, 528}}"; - Split0 = { - ActiveTab = 2; - Collapsed = NO; - Frame = "{{0, 0}, {789, 528}}"; - Split0 = { - Frame = "{{0, 204}, {789, 324}}"; - }; - SplitCount = 1; - Tab0 = { - Debugger = { - Collapsed = NO; - Frame = "{{0, 0}, {952, 321}}"; - Split0 = { - Frame = "{{0, 24}, {952, 297}}"; - Split0 = { - Frame = "{{0, 0}, {468, 297}}"; - }; - Split1 = { - DebugVariablesTableConfiguration = ( - Name, - 123, - Value, - 85, - Summary, - 241.123, - ); - Frame = "{{477, 0}, {475, 297}}"; - }; - SplitCount = 2; - }; - SplitCount = 1; - Tab0 = { - Frame = "{{0, 0}, {100, 50}}"; - }; - Tab1 = { - Frame = "{{0, 0}, {100, 50}}"; - }; - TabCount = 2; - TabsVisible = YES; - }; - Frame = "{{0, 0}, {952, 321}}"; - LauncherConfigVersion = 7; - }; - Tab1 = { - Frame = "{{0, 0}, {781, 452}}"; - LauncherConfigVersion = 3; - Runner = { - Frame = "{{0, 0}, {781, 452}}"; - }; - }; - Tab2 = { - BuildMessageFrame = "{{0, 0}, {791, 191}}"; - BuildTranscriptFrame = "{{0, 200}, {791, 0}}"; - Frame = "{{0, 0}, {789, 198}}"; - }; - Tab3 = { - Frame = "{{0, 0}, {612, 295}}"; - }; - TabCount = 4; - TabsVisible = NO; - }; - SplitCount = 1; - Tab0 = { - Frame = "{{0, 0}, {300, 533}}"; - GroupTreeTableConfiguration = ( - TargetStatusColumn, - 18, - MainColumn, - 267, - ); - }; - Tab1 = { - ClassesFrame = "{{0, 0}, {280, 398}}"; - ClassesTreeTableConfiguration = ( - PBXBookColumnIdentifier, - 20, - PBXClassColumnIdentifier, - 237, - ); - Frame = "{{0, 0}, {278, 659}}"; - MembersFrame = "{{0, 407}, {280, 252}}"; - MembersTreeTableConfiguration = ( - PBXBookColumnIdentifier, - 20, - PBXMethodColumnIdentifier, - 236, - ); - }; - Tab2 = { - Frame = "{{0, 0}, {200, 100}}"; - }; - Tab3 = { - Frame = "{{0, 0}, {200, 100}}"; - TargetTableConfiguration = ( - ActiveObject, - 16, - ObjectNames, - 202.296, - ); - }; - Tab4 = { - BreakpointsTreeTableConfiguration = ( - breakpointColumn, - 197, - enabledColumn, - 31, - ); - Frame = "{{0, 0}, {250, 100}}"; - }; - TabCount = 5; - TabsVisible = NO; - }; - StatusViewVisible = YES; - Template = F5314676015831810DCA290F; - ToolbarVisible = YES; - WindowLocation = "{7, 385}"; - }; - PBXWorkspaceContents = ( - { - LeftSlideOut = { - Split0 = { - Split0 = { - NavContent0 = { - bookmark = 005751AA02FB00930AC916F0; - history = ( - F5BFE56402F8B7A901DC9062, - F5BFE56702F8B7A901DC9062, - 00F4D9CE02F9BA490AC916F0, - ); - prevStack = ( - F5BFE56A02F8B7A901DC9062, - ); - }; - NavCount = 1; - NavGeometry0 = { - Frame = "{{0, 0}, {571, 548}}"; - NavBarVisible = YES; - }; - }; - SplitCount = 1; - Tab0 = { - Debugger = { - Split0 = { - SplitCount = 2; - }; - SplitCount = 1; - TabCount = 2; - }; - LauncherConfigVersion = 7; - }; - Tab1 = { - LauncherConfigVersion = 3; - Runner = { - }; - }; - TabCount = 4; - }; - SplitCount = 1; - Tab1 = { - OptionsSetName = "Default Options"; - }; - TabCount = 5; - }; - }, - ); - PBXWorkspaceGeometries = ( - { - ContentSize = "{855, 571}"; - LeftSlideOut = { - ActiveTab = 0; - Collapsed = NO; - Frame = "{{0, 23}, {855, 548}}"; - Split0 = { - Collapsed = NO; - Frame = "{{284, 0}, {571, 548}}"; - Split0 = { - Frame = "{{0, 0}, {571, 548}}"; - }; - SplitCount = 1; - Tab0 = { - Debugger = { - Collapsed = NO; - Frame = "{{0, 0}, {681, 289}}"; - Split0 = { - Frame = "{{0, 24}, {681, 265}}"; - Split0 = { - Frame = "{{0, 0}, {333, 265}}"; - }; - Split1 = { - DebugVariablesTableConfiguration = ( - Name, - 82.80298, - Value, - 104.074, - Summary, - 126.123, - ); - Frame = "{{342, 0}, {339, 265}}"; - }; - SplitCount = 2; - }; - SplitCount = 1; - Tab0 = { - Frame = "{{0, 0}, {100, 50}}"; - }; - Tab1 = { - Frame = "{{0, 0}, {100, 50}}"; - }; - TabCount = 2; - TabsVisible = YES; - }; - Frame = "{{0, 0}, {681, 289}}"; - LauncherConfigVersion = 7; - }; - Tab1 = { - Frame = "{{0, 0}, {681, 120}}"; - LauncherConfigVersion = 3; - Runner = { - Frame = "{{0, 0}, {681, 120}}"; - }; - }; - Tab2 = { - BuildMessageFrame = "{{0, 0}, {683, 127}}"; - BuildTranscriptFrame = "{{0, 136}, {683, 100}}"; - Frame = "{{0, 0}, {681, 234}}"; - }; - Tab3 = { - Frame = "{{0, 0}, {681, 238}}"; - }; - TabCount = 4; - TabsVisible = NO; - }; - SplitCount = 1; - Tab0 = { - Frame = "{{0, 0}, {260, 548}}"; - GroupTreeTableConfiguration = ( - SCMStatusColumn, - 22, - TargetStatusColumn, - 18, - MainColumn, - 205, - ); - }; - Tab1 = { - ClassesFrame = "{{0, 0}, {250, 333}}"; - ClassesTreeTableConfiguration = ( - PBXBookColumnIdentifier, - 20, - PBXClassColumnIdentifier, - 207, - ); - Frame = "{{0, 0}, {248, 554}}"; - MembersFrame = "{{0, 342}, {250, 212}}"; - MembersTreeTableConfiguration = ( - PBXBookColumnIdentifier, - 20, - PBXMethodColumnIdentifier, - 206, - ); - }; - Tab2 = { - Frame = "{{0, 0}, {217, 554}}"; - }; - Tab3 = { - Frame = "{{0, 0}, {239, 548}}"; - TargetTableConfiguration = ( - ActiveObject, - 16, - ObjectNames, - 206, - ); - }; - Tab4 = { - BreakpointsTreeTableConfiguration = ( - breakpointColumn, - 197, - enabledColumn, - 31, - ); - Frame = "{{0, 0}, {250, 554}}"; - }; - TabCount = 5; - TabsVisible = YES; - }; - StatusViewVisible = YES; - Template = 64ABBB4501FA494900185B06; - ToolbarVisible = YES; - WindowLocation = "{77, 330}"; - }, - ); - PBXWorkspaceStateSaveDate = 49920633; - }; - perUserProjectItems = { - 005751AA02FB00930AC916F0 = 005751AA02FB00930AC916F0; - 00F4D9CE02F9BA490AC916F0 = 00F4D9CE02F9BA490AC916F0; - F5BFE56402F8B7A901DC9062 = F5BFE56402F8B7A901DC9062; - F5BFE56702F8B7A901DC9062 = F5BFE56702F8B7A901DC9062; - F5BFE56A02F8B7A901DC9062 = F5BFE56A02F8B7A901DC9062; - }; - projectwideBuildSettings = { - OBJROOT = "/Volumes/TheCloset/jingham/tcl-tk/source/tcl-merge/Objects"; - SYMROOT = "/Volumes/TheCloset/jingham/tcl-tk/source/tcl-merge/Products"; - }; - wantsIndex = 1; - wantsSCM = 1; - }; - 00E2F84B016E8A830ACA28DC = { - activeExec = 0; + ); + codeSenseManager = F9D167E40610239A0027C147; + executables = ( + F53ACC52031D9AFE016F146B, + F594E5F1030774B1016F146B, + ); + sourceControlManager = F9D167E30610239A0027C147; + userBuildSettings = { + SYMROOT = "${SRCROOT}/../../build/tcl"; + }; }; 00E2F84C016E8B780ACA28DC = { activeExec = 0; }; - 00E2F84E016E92110ACA28DC = { - activeExec = 0; - }; - 00F4D9CE02F9BA490AC916F0 = { - fRef = 00F4D9CF02F9BA4A0AC916F0; - isa = PBXTextBookmark; - name = "DefaultsDoc.rtf: 30"; - rLen = 32; - rLoc = 2777; - rType = 0; - vrLen = 1334; - vrLoc = 2136; - }; - 00F4D9CF02F9BA4A0AC916F0 = { - isa = PBXFileReference; - name = DefaultsDoc.rtf; - path = "/Developer/Applications/Project Builder.app/Contents/Resources/DefaultsDoc.rtf"; - refType = 0; - }; - F50DC359017027D801DC9062 = { - activeExec = 0; - }; - F5BFE56402F8B7A901DC9062 = { - fRef = F5BFE56E02F8B7AA01DC9062; - isa = PBXTextBookmark; - name = "stat.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 1666; - vrLoc = 3618; - }; - F5BFE56702F8B7A901DC9062 = { - fRef = F5F24F6E016ECAA401DC9062; - isa = PBXTextBookmark; - name = "tcl.h: 397"; - rLen = 6; - rLoc = 11199; - rType = 0; - vrLen = 1293; - vrLoc = 10644; - }; - F5BFE56A02F8B7A901DC9062 = { - fRef = F5F24F6E016ECAA401DC9062; - isa = PBXTextBookmark; - name = "tcl.h: 397"; - rLen = 6; - rLoc = 11199; - rType = 0; - vrLen = 1293; - vrLoc = 10644; - }; - F5BFE56E02F8B7AA01DC9062 = { - isa = PBXFileReference; - name = stat.h; - path = /usr/include/sys/stat.h; - refType = 0; + F53ACC52031D9AFE016F146B = { + activeArgIndex = 2147483647; + activeArgIndices = ( + NO, + NO, + ); + argumentStrings = ( + "${SRCROOT}/../../tcl/tests/all.tcl", + "-verbose \"\"", + ); + configStateDict = { + "PBXLSLaunchAction-0" = { + PBXLSLaunchAction = 0; + PBXLSLaunchStartAction = 1; + PBXLSLaunchStdioStyle = 2; + PBXLSLaunchStyle = 0; + class = PBXLSRunLaunchConfig; + displayName = "Executable Runner"; + identifier = com.apple.Xcode.launch.runConfig; + remoteHostInfo = ""; + startActionInfo = ""; + }; + "PBXLSLaunchAction-1" = { + PBXLSLaunchAction = 1; + PBXLSLaunchStartAction = 1; + PBXLSLaunchStdioStyle = 2; + PBXLSLaunchStyle = 0; + class = PBXGDB_LaunchConfig; + displayName = GDB; + identifier = com.apple.Xcode.launch.GDBMI_Config; + remoteHostInfo = ""; + startActionInfo = ""; + }; + }; + cppStopOnCatchEnabled = 0; + cppStopOnThrowEnabled = 0; + customDataFormattersEnabled = 1; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = _debug; + enableDebugStr = 0; + environmentEntries = ( + { + active = YES; + name = TCL_LIBRARY; + value = "${SRCROOT}/../../tcl/library"; + }, + { + active = NO; + name = DYLD_PRINT_LIBRARIES; + }, + ); + isa = PBXExecutable; + launchableReference = F5C37CF303D5BEDF016F146B; + libgmallocEnabled = 0; + name = tcltest; + shlibInfoDictList = ( + ); + sourceDirectories = ( + ); + startupPath = "<>"; + }; + F594E5F1030774B1016F146B = { + activeArgIndex = 2147483647; + activeArgIndices = ( + ); + argumentStrings = ( + ); + configStateDict = { + "PBXLSLaunchAction-0" = { + PBXLSLaunchAction = 0; + PBXLSLaunchStartAction = 1; + PBXLSLaunchStdioStyle = 2; + PBXLSLaunchStyle = 0; + class = PBXLSRunLaunchConfig; + displayName = "Executable Runner"; + identifier = com.apple.Xcode.launch.runConfig; + remoteHostInfo = ""; + startActionInfo = ""; + }; + "PBXLSLaunchAction-1" = { + PBXLSLaunchAction = 1; + PBXLSLaunchStartAction = 1; + PBXLSLaunchStdioStyle = 2; + PBXLSLaunchStyle = 0; + class = PBXGDB_LaunchConfig; + displayName = GDB; + identifier = com.apple.Xcode.launch.GDBMI_Config; + remoteHostInfo = ""; + startActionInfo = ""; + }; + }; + cppStopOnCatchEnabled = 0; + cppStopOnThrowEnabled = 0; + customDataFormattersEnabled = 1; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = _debug; + enableDebugStr = 0; + environmentEntries = ( + { + active = NO; + name = DYLD_PRINT_LIBRARIES; + }, + ); + isa = PBXExecutable; + launchableReference = F98F02E608E7EF9A00D0320A; + libgmallocEnabled = 0; + name = tclsh; + shlibInfoDictList = ( + ); + sourceDirectories = ( + ); + startupPath = "<>"; + }; + F5C37CF303D5BEDF016F146B = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.executable"; + path = tcltest; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; + F98F02E608E7EF9A00D0320A = { + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.executable"; + path = tclsh8.4; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; + F9D167E30610239A0027C147 = { + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + isa = PBXSourceControlManager; + scmConfiguration = { + }; + scmType = scm.cvs; + }; + F9D167E40610239A0027C147 = { + indexTemplatePath = ""; + isa = PBXCodeSenseManager; + usesDefaults = 1; + wantsCodeCompletion = 1; + wantsCodeCompletionAutoSuggestions = 1; + wantsCodeCompletionCaseSensitivity = 1; + wantsCodeCompletionListAlways = 1; + wantsCodeCompletionOnlyMatchingItems = 1; + wantsCodeCompletionParametersIncluded = 1; + wantsCodeCompletionPlaceholdersInserted = 1; + wantsCodeCompletionTabCompletes = 1; + wantsIndex = 1; }; } Index: macosx/Tcl.pbproj/project.pbxproj ================================================================== --- macosx/Tcl.pbproj/project.pbxproj +++ macosx/Tcl.pbproj/project.pbxproj @@ -1,39 +1,15 @@ // !$*UTF8*$! { archiveVersion = 1; classes = { }; - objectVersion = 38; + objectVersion = 39; objects = { - 00530A0D0173C8270ACA28DC = { - buildActionMask = 12; - files = ( - ); - generatedFileNames = ( - ); - isa = PBXShellScriptBuildPhase; - neededFileNames = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# install to ${INSTALL_ROOT} with optional stripping\ncd ${TEMP_DIR}/..\nif test \"${INSTALL_STRIP}\" = \"YES\"; then\nexport INSTALL_PROGRAM='${INSTALL} ${INSTALL_STRIP_PROGRAM}'\nexport INSTALL_LIBRARY='${INSTALL} ${INSTALL_STRIP_LIBRARY}'\nelse\nexport INSTALL_PROGRAM='${INSTALL}'\nexport INSTALL_LIBRARY='${INSTALL}'\nfi\nexport CPPROG='cp -p'\ngnumake install-binaries install-libraries TCL_LIBRARY=\"@TCL_IN_FRAMEWORK@\" INSTALL_ROOT=\"${INSTALL_ROOT}\" SCRIPT_INSTALL_DIR=\"${INSTALL_ROOT}${LIBDIR}/Resources/Scripts\" INSTALL_PROGRAM=\"${INSTALL_PROGRAM}\" INSTALL_LIBRARY=\"${INSTALL_LIBRARY}\""; - }; - 00530A0E0173CC960ACA28DC = { - buildActionMask = 12; - files = ( - ); - generatedFileNames = ( - ); - isa = PBXShellScriptBuildPhase; - neededFileNames = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# fixup Framework structure\ncd \"${INSTALL_ROOT}${LIBDIR}\"\nln -fs Versions/Current/Headers ../..\nmv -f tclConfig.sh Resources\nln -fs \"Resources/tclConfig.sh\" ../..\nln -fs `ls libtclstub* | sed -e 's|.*|Versions/Current/&|'` ../..\nif [ \"${BUILD_STYLE}\" = \"Development\" ]; then\n\t# keep copy of debug library around, so that\n\t# Deployment build can be installed on top\n\t# of Development build without overwriting\n\t# the debug library\n\tcp -fp \"${PRODUCT_NAME}\" \"${PRODUCT_NAME}_debug\"\n\tln -fs \"Versions/Current/${PRODUCT_NAME}_debug\" ../..\nfi"; - }; 00E2F845016E82EB0ACA28DC = { + buildSettings = { + }; buildStyles = ( 00E2F847016E82EB0ACA28DC, 00E2F848016E82EB0ACA28DC, ); hasScannedForEncodings = 1; @@ -40,12 +16,10 @@ isa = PBXProject; mainGroup = 00E2F846016E82EB0ACA28DC; productRefGroup = 00E2F84A016E8A830ACA28DC; projectDirPath = ""; targets = ( - 00E2F84E016E92110ACA28DC, - 00E2F84B016E8A830ACA28DC, 00E2F84C016E8B780ACA28DC, ); }; 00E2F846016E82EB0ACA28DC = { children = ( @@ -58,169 +32,58 @@ 00E2F85A016E92B00ACA28DC, 00E2F84A016E8A830ACA28DC, ); isa = PBXGroup; refType = 4; + sourceTree = ""; }; 00E2F847016E82EB0ACA28DC = { - buildRules = ( - ); buildSettings = { - EXTRA_CONFIGURE_FLAGS = "--enable-symbols"; - INSTALL_STRIP = NO; - TEMP_DIR = "${OBJROOT}/Development.build/$(PROJECT_NAME).build/$(TARGET_NAME).build"; + MAKE_TARGET = develop; }; isa = PBXBuildStyle; name = Development; }; 00E2F848016E82EB0ACA28DC = { - buildRules = ( - ); buildSettings = { - INSTALL_STRIP = YES; - TEMP_DIR = "${OBJROOT}/Deployment.build/$(PROJECT_NAME).build/$(TARGET_NAME).build"; + MAKE_TARGET = deploy; }; isa = PBXBuildStyle; name = Deployment; }; 00E2F84A016E8A830ACA28DC = { children = ( - 00E2F84D016E92110ACA28DC, + F53ACC73031DA405016F146B, F53ACC5C031D9D11016F146B, - F53ACC73031DA405016F146B, + F9A61C9D04C2B4E3006F5A0B, ); isa = PBXGroup; name = Products; refType = 4; - }; - 00E2F84B016E8A830ACA28DC = { - buildArgumentsString = "-c \"if [ \\\"${ACTION}\\\" != \\\"clean\\\" ]; then if [ -z \\\"`find . ! \\\\( -path './*/*' -prune \\\\) -name Makefile -newer \\\"${SRCROOT}/../unix/configure\\\"`\\\" ]; then \\\"${SRCROOT}/../unix/configure\\\" --prefix=/usr --mandir=/usr/share/man --libdir=\\\"${LIBDIR}\\\" --includedir=\\\"${LIBDIR}/Headers\\\" --enable-threads --enable-framework ${EXTRA_CONFIGURE_FLAGS}; mkdir -p Tcl.framework; ln -fs ../Tcl Tcl.framework/Tcl; fi; fi\""; - buildPhases = ( - ); - buildSettings = { - EXTRA_CONFIGURE_FLAGS = ""; - FRAMEWORK_VERSION = 8.4; - INSTALL_PATH = /Library/Frameworks; - LIBDIR = "${INSTALL_PATH}/${PRODUCT_NAME}.framework/Versions/${FRAMEWORK_VERSION}"; - PRODUCT_NAME = Tcl; - }; - buildToolPath = /bin/sh; - buildWorkingDirectory = "${TEMP_DIR}/.."; - dependencies = ( - ); - isa = PBXLegacyTarget; - name = Configure; - passBuildSettingsInEnvironment = 1; - productName = Configure; - settingsToExpand = 6; - settingsToPassInEnvironment = 287; - settingsToPassOnCommandLine = 280; - }; - 00E2F84C016E8B780ACA28DC = { - buildArgumentsString = "-c \"if [ \\\"${ACTION}\\\" != \\\"clean\\\" ]; then gnumake tclsh tcltest TCL_LIBRARY=\\\"@TCL_IN_FRAMEWORK@\\\" TCL_PACKAGE_PATH=\\\"~/Library/Tcl /Library/Tcl /Network/Library/Tcl /System/Library/Tcl ~/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks /System/Library/Frameworks\\\" DYLIB_INSTALL_DIR=\\\"${DYLIB_INSTALL_DIR}\\\" ${EXTRA_MAKE_FLAGS}; else gnumake distclean; fi\""; - buildPhases = ( - ); - buildSettings = { - DYLIB_INSTALL_DIR = "${DYLIB_INSTALL_PATH}/${PRODUCT_NAME}.framework/Versions/${FRAMEWORK_VERSION}"; - DYLIB_INSTALL_PATH = "${INSTALL_PATH}"; - EXTRA_MAKE_FLAGS = ""; - FRAMEWORK_VERSION = 8.4; - INSTALL_PATH = /Library/Frameworks; - PRODUCT_NAME = Tcl; - }; - buildToolPath = /bin/sh; - buildWorkingDirectory = "${TEMP_DIR}/.."; - dependencies = ( - F5877EB5031F7997016F146B, - ); - isa = PBXLegacyTarget; - name = Make; - passBuildSettingsInEnvironment = 1; - productName = Make; - settingsToExpand = 6; - settingsToPassInEnvironment = 287; - settingsToPassOnCommandLine = 280; - }; - 00E2F84D016E92110ACA28DC = { - isa = PBXFrameworkReference; - path = Tcl.framework; - refType = 3; - }; - 00E2F84E016E92110ACA28DC = { - buildPhases = ( - F5877FB6031F97AF016F146B, - F50DC36A01703B7301DC9062, - F50DC367017033D701DC9062, - F50DC3680170344801DC9062, - 00E2F84F016E92110ACA28DC, - F5BE9BBF02FB5974016F146B, - 00530A0D0173C8270ACA28DC, - 00530A0E0173CC960ACA28DC, - F5877FBB031FA90A016F146B, - F59AE5E3017AC67A01DC9062, - ); - buildSettings = { - DSTROOT = "${TEMP_DIR}"; - EXTRA_MAKE_INSTALL_FLAGS = ""; - FRAMEWORK_VERSION = 8.4; - INSTALL_PATH = /Library/Frameworks; - LIBDIR = "${INSTALL_PATH}/${PRODUCT_NAME}.${WRAPPER_EXTENSION}/Versions/${FRAMEWORK_VERSION}"; - PRODUCT_NAME = Tcl; - WRAPPER_EXTENSION = framework; - }; - dependencies = ( - F5877EB6031F79A4016F146B, - ); - isa = PBXFrameworkTarget; - name = Tcl; - productInstallPath = /Library/Frameworks; - productName = TclLibrary; - productReference = 00E2F84D016E92110ACA28DC; - productSettingsXML = " - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - Tcl - CFBundleGetInfoString - Tcl Library 8.4, Copyright © 2002 Tcl Core Team. -MacOS X Port by Jim Ingham <jingham@apple.com> & Ian Reid, Copyright © 2001-2002, Apple Computer, Inc. - CFBundleIconFile - - CFBundleIdentifier - com.tcltk.tcllibrary - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Tcl Library 8.4 - CFBundlePackageType - FMWK - CFBundleShortVersionString - 8.4.2 - CFBundleSignature - Tcl - CFBundleVersion - 8.4.2 - - -"; - }; - 00E2F84F016E92110ACA28DC = { - buildActionMask = 2147483647; - files = ( - F59D846A0338FAA4016F146B, - F59D846B0338FAA4016F146B, - F59D846E0338FAA4016F146B, - F59D84620338F9CA016F146B, - F59D846C0338FAA4016F146B, - F59D846D0338FAA4016F146B, - F5C093BB0342F7D6016F146B, - ); - isa = PBXHeadersBuildPhase; - runOnlyForDeploymentPostprocessing = 0; + sourceTree = ""; + }; + 00E2F84C016E8B780ACA28DC = { + buildArgumentsString = "-c \"cd \\\"${TCL_SRCROOT}/macosx\\\" && ACTION=${ACTION} && gnumake \\${ACTION:+\\${ACTION/clean/distclean}-}${MAKE_TARGET} INSTALL_ROOT=\\\"${DSTROOT}\\\" INSTALL_PATH=\\\"${INSTALL_PATH}\\\" PREFIX=\\\"${PREFIX}\\\" BINDIR=\\\"${BINDIR}\\\" MANDIR=\\\"${MANDIR}\\\" \\${EXTRA_MAKE_FLAGS} ${ALL_SETTINGS}\""; + buildPhases = ( + ); + buildSettings = { + BINDIR = "${PREFIX}/bin"; + INSTALL_PATH = /Library/Frameworks; + MANDIR = "${PREFIX}/man"; + PREFIX = /usr/local; + PRODUCT_NAME = Tcl; + TCL_SRCROOT = "${SRCROOT}/../../tcl"; + TEMP_DIR = "${PROJECT_TEMP_DIR}"; + }; + buildToolPath = /bin/bash; + buildWorkingDirectory = "${SRCROOT}"; + dependencies = ( + ); + isa = PBXLegacyTarget; + name = Tcl; + passBuildSettingsInEnvironment = 0; + productName = Tcl; }; 00E2F854016E922C0ACA28DC = { children = ( F5F24F87016ECAFC01DC9062, F5F24F88016ECAFC01DC9062, @@ -300,19 +163,21 @@ ); isa = PBXGroup; name = Sources; path = ""; refType = 4; + sourceTree = ""; }; 00E2F855016E922C0ACA28DC = { children = ( 00E2F856016E92B00ACA28DC, 00E2F854016E922C0ACA28DC, ); isa = PBXGroup; name = generic; refType = 4; + sourceTree = ""; }; 00E2F856016E92B00ACA28DC = { children = ( F5F24F6B016ECAA401DC9062, F5F24F6C016ECAA401DC9062, @@ -332,52 +197,58 @@ F5F24FD2016ECB1E01DC9062, ); isa = PBXGroup; name = Headers; refType = 4; + sourceTree = ""; }; 00E2F857016E92B00ACA28DC = { children = ( 00E2F858016E92B00ACA28DC, 00E2F859016E92B00ACA28DC, ); isa = PBXGroup; name = macosx; refType = 4; + sourceTree = ""; }; 00E2F858016E92B00ACA28DC = { children = ( ); isa = PBXGroup; name = Headers; refType = 4; + sourceTree = ""; }; 00E2F859016E92B00ACA28DC = { children = ( F5A1836F018242A501DC9062, ); isa = PBXGroup; name = Sources; refType = 4; + sourceTree = ""; }; 00E2F85A016E92B00ACA28DC = { children = ( 00E2F85B016E92B00ACA28DC, 00E2F85C016E92B00ACA28DC, ); isa = PBXGroup; name = unix; refType = 4; + sourceTree = ""; }; 00E2F85B016E92B00ACA28DC = { children = ( F5F24FD6016ECC0F01DC9062, F5F24FD7016ECC0F01DC9062, ); isa = PBXGroup; name = Headers; refType = 4; + sourceTree = ""; }; 00E2F85C016E92B00ACA28DC = { children = ( F5F24FD8016ECC0F01DC9062, F5F24FD9016ECC0F01DC9062, @@ -396,10 +267,11 @@ F5F24FE7016ECC0F01DC9062, ); isa = PBXGroup; name = Sources; refType = 4; + sourceTree = ""; }; //000 //001 //002 //003 @@ -407,241 +279,77 @@ //F50 //F51 //F52 //F53 //F54 - F50DC367017033D701DC9062 = { - buildActionMask = 2147483647; - files = ( - ); - isa = PBXFrameworksBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - F50DC3680170344801DC9062 = { - buildActionMask = 2147483647; - files = ( - ); - isa = PBXResourcesBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - F50DC36A01703B7301DC9062 = { - buildActionMask = 2147483647; - files = ( - F59D84630338F9EC016F146B, - F59D84640338F9ED016F146B, - F59D84670338FA8B016F146B, - F59D84680338FA8D016F146B, - F59D84690338FA90016F146B, - F5C093BA0342F7B4016F146B, - ); - isa = PBXSourcesBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; F5306C9F03CAC979016F146B = { children = ( F5306CA303CAC9DE016F146B, F5306CA103CAC9DE016F146B, F5306CA203CAC9DE016F146B, ); isa = PBXGroup; name = "Build System"; refType = 4; + sourceTree = ""; }; F5306CA003CAC9AE016F146B = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = text; name = ChangeLog; path = ../ChangeLog; refType = 2; + sourceTree = SOURCE_ROOT; }; F5306CA103CAC9DE016F146B = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = text.script.sh; name = configure.in; path = ../unix/configure.in; refType = 2; + sourceTree = SOURCE_ROOT; }; F5306CA203CAC9DE016F146B = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = text; name = Makefile.in; path = ../unix/Makefile.in; refType = 2; + sourceTree = SOURCE_ROOT; }; F5306CA303CAC9DE016F146B = { isa = PBXFileReference; + lastKnownFileType = text; name = tcl.m4; path = ../unix/tcl.m4; refType = 2; + sourceTree = SOURCE_ROOT; }; F53ACC5C031D9D11016F146B = { - isa = PBXExecutableFileReference; - name = tclsh8.4; - path = ../../build/tclsh8.4; - refType = 2; + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.executable"; + path = tclsh8.4; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; }; F53ACC73031DA405016F146B = { - isa = PBXExecutableFileReference; - name = tcltest; - path = ../../build/tcltest; - refType = 2; - }; - F5877EB5031F7997016F146B = { - isa = PBXTargetDependency; - target = 00E2F84B016E8A830ACA28DC; - }; - F5877EB6031F79A4016F146B = { - isa = PBXTargetDependency; - target = 00E2F84C016E8B780ACA28DC; - }; - F5877FB6031F97AF016F146B = { - buildActionMask = 8; - files = ( - ); - generatedFileNames = ( - ); - isa = PBXShellScriptBuildPhase; - neededFileNames = ( - ); - runOnlyForDeploymentPostprocessing = 1; - shellPath = /bin/sh; - shellScript = "# ensure we can overwrite a previous install\nif [ -d \"${INSTALL_ROOT}${INSTALL_PATH}/${PRODUCT_NAME}.${WRAPPER_EXTENSION}\" ]; then\n chmod -RH u+w \"${INSTALL_ROOT}${INSTALL_PATH}/${PRODUCT_NAME}.${WRAPPER_EXTENSION}\"\nfi"; - }; - F5877FBB031FA90A016F146B = { - buildActionMask = 8; - files = ( - ); - generatedFileNames = ( - ); - isa = PBXShellScriptBuildPhase; - neededFileNames = ( - ); - runOnlyForDeploymentPostprocessing = 1; - shellPath = /bin/sh; - shellScript = "if [ -n \"${EMBEDDED_BUILD:-}\" ]; then\n# if we are embedding frameworks, don't install tclsh\nrm -f \"${INSTALL_ROOT}/usr/bin/tclsh${FRAMEWORK_VERSION}\"\nrmdir -p \"${INSTALL_ROOT}/usr/bin\" 2>&-\ntrue\nelse\n# redo prebinding\ncd \"${INSTALL_ROOT}\"\nif [ ! -d usr/lib ]; then mkdir -p usr; ln -fs /usr/lib usr/; RM_USRLIB=1; fi\nif [ ! -d System ]; then ln -fs /System .; RM_SYSTEM=1; fi\nredo_prebinding -r . \"./usr/bin/tclsh${FRAMEWORK_VERSION}\"\nif [ -n \"${RM_USRLIB:-}\" ]; then rm -f usr/lib; rmdir -p usr 2>&-; fi\nif [ -n \"${RM_SYSTEM:-}\" ]; then rm -f System; fi\n# install tclsh symbolic link\nmkdir -p \"${INSTALL_ROOT}/usr/bin\"\nln -fs \"tclsh${FRAMEWORK_VERSION}\" \"${INSTALL_ROOT}/usr/bin/tclsh\"\nfi"; - }; - F59AE5E3017AC67A01DC9062 = { - buildActionMask = 8; - files = ( - ); - generatedFileNames = ( - ); - isa = PBXShellScriptBuildPhase; - neededFileNames = ( - ); - runOnlyForDeploymentPostprocessing = 1; - shellPath = /bin/sh; - shellScript = "if [ -z \"${EMBEDDED_BUILD:-}\" ]; then\n# build html documentation\nif [ \"${BUILD_STYLE}\" = \"Deployment\" ]; then\n cd \"${TEMP_DIR}/..\"\n export DYLD_FRAMEWORK_PATH=${SYMROOT}\n gnumake html DISTDIR=\"${INSTALL_ROOT}${LIBDIR}/Resources/English.lproj/Documentation/Reference\"\n cd \"${INSTALL_ROOT}${LIBDIR}/Resources/English.lproj/Documentation/Reference\"\n ln -fs contents.htm html/TclTOC.html\n rm -fr \"${PRODUCT_NAME}\"; mv -f html \"${PRODUCT_NAME}\"\nfi\nfi"; - }; - F59D84620338F9CA016F146B = { - fileRef = F5F24F72016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - ATTRIBUTES = ( - Private, - ); - }; - }; - F59D84630338F9EC016F146B = { - fileRef = F5F24F73016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - }; - }; - F59D84640338F9ED016F146B = { - fileRef = F5F24F74016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - }; - }; - F59D84670338FA8B016F146B = { - fileRef = F5F24F6E016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - }; - }; - F59D84680338FA8D016F146B = { - fileRef = F5F24F70016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - }; - }; - F59D84690338FA90016F146B = { - fileRef = F5F24F77016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - }; - }; - F59D846A0338FAA4016F146B = { - fileRef = F5F24F6E016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - }; - }; - F59D846B0338FAA4016F146B = { - fileRef = F5F24F70016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - }; - }; - F59D846C0338FAA4016F146B = { - fileRef = F5F24F73016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - ATTRIBUTES = ( - Private, - ); - }; - }; - F59D846D0338FAA4016F146B = { - fileRef = F5F24F74016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - ATTRIBUTES = ( - Private, - ); - }; - }; - F59D846E0338FAA4016F146B = { - fileRef = F5F24F77016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - }; + isa = PBXFileReference; + lastKnownFileType = "compiled.mach-o.executable"; + path = tcltest; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; }; F5A1836F018242A501DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; path = tclMacOSXBundle.c; refType = 2; - }; - F5BE9BBF02FB5974016F146B = { - buildActionMask = 2147483647; - files = ( - ); - generatedFileNames = ( - ); - isa = PBXShellScriptBuildPhase; - neededFileNames = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# symolic link hackery to trick\n# 'make install INSTALL_ROOT=${TEMP_DIR}'\n# into building Tcl.framework and tclsh in ${SYMROOT}\ncd \"${TEMP_DIR}\"\nmkdir -p Library\nmkdir -p usr\nrm -f Library/Frameworks; ln -fs \"${SYMROOT}\" Library/Frameworks\nrm -f usr/bin; ln -fs \"${SYMROOT}\" usr/bin\nln -fs \"${TEMP_DIR}/../tcltest\" \"${SYMROOT}\""; - }; - F5C093BA0342F7B4016F146B = { - fileRef = F5F24F76016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - }; - }; - F5C093BB0342F7D6016F146B = { - fileRef = F5F24F76016ECAA401DC9062; - isa = PBXBuildFile; - settings = { - ATTRIBUTES = ( - Private, - ); - }; + sourceTree = SOURCE_ROOT; }; F5C88655017D604601DC9062 = { children = ( F5C88656017D604601DC9062, F5C88657017D60C901DC9062, @@ -648,784 +356,1007 @@ F5C88658017D60C901DC9062, ); isa = PBXGroup; name = "Header Tools"; refType = 4; + sourceTree = ""; }; F5C88656017D604601DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = genStubs.tcl; path = ../tools/genStubs.tcl; refType = 2; + sourceTree = SOURCE_ROOT; }; F5C88657017D60C901DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = tcl.decls; path = ../generic/tcl.decls; refType = 2; + sourceTree = SOURCE_ROOT; }; F5C88658017D60C901DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = tclInt.decls; path = ../generic/tclInt.decls; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F6B016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = regcustom.h; path = ../generic/regcustom.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F6C016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = regerrs.h; path = ../generic/regerrs.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F6D016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = regguts.h; path = ../generic/regguts.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F6E016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tcl.h; path = ../generic/tcl.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F6F016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclCompile.h; path = ../generic/tclCompile.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F70016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclDecls.h; path = ../generic/tclDecls.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F71016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclInitScript.h; path = ../generic/tclInitScript.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F72016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclInt.h; path = ../generic/tclInt.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F73016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclIntDecls.h; path = ../generic/tclIntDecls.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F74016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclIntPlatDecls.h; path = ../generic/tclIntPlatDecls.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F75016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclIO.h; path = ../generic/tclIO.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F76016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclMath.h; path = ../generic/tclMath.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F77016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclPlatDecls.h; path = ../generic/tclPlatDecls.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F78016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclRegexp.h; path = ../generic/tclRegexp.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F87016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = regc_color.c; path = ../generic/regc_color.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F88016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = regc_cvec.c; path = ../generic/regc_cvec.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F89016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = regc_lex.c; path = ../generic/regc_lex.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F8A016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = regc_locale.c; path = ../generic/regc_locale.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F8B016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = regc_nfa.c; path = ../generic/regc_nfa.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F8C016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = regcomp.c; path = ../generic/regcomp.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F8D016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = rege_dfa.c; path = ../generic/rege_dfa.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F8E016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = regerror.c; path = ../generic/regerror.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F8F016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = regexec.c; path = ../generic/regexec.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F90016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = regfree.c; path = ../generic/regfree.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F91016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = regfronts.c; path = ../generic/regfronts.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F92016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclAlloc.c; path = ../generic/tclAlloc.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F93016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclAsync.c; path = ../generic/tclAsync.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F94016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclBasic.c; path = ../generic/tclBasic.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F95016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclBinary.c; path = ../generic/tclBinary.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F96016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclCkalloc.c; path = ../generic/tclCkalloc.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F97016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclClock.c; path = ../generic/tclClock.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F98016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclCmdAH.c; path = ../generic/tclCmdAH.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F99016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclCmdIL.c; path = ../generic/tclCmdIL.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F9A016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclCmdMZ.c; path = ../generic/tclCmdMZ.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F9B016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclCompCmds.c; path = ../generic/tclCompCmds.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F9C016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclCompExpr.c; path = ../generic/tclCompExpr.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F9D016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclCompile.c; path = ../generic/tclCompile.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F9E016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclDate.c; path = ../generic/tclDate.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24F9F016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclEncoding.c; path = ../generic/tclEncoding.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FA0016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclEnv.c; path = ../generic/tclEnv.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FA1016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclEvent.c; path = ../generic/tclEvent.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FA2016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclExecute.c; path = ../generic/tclExecute.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FA3016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclFCmd.c; path = ../generic/tclFCmd.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FA4016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclFileName.c; path = ../generic/tclFileName.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FA5016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclGet.c; path = ../generic/tclGet.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FA6016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclHash.c; path = ../generic/tclHash.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FA7016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclHistory.c; path = ../generic/tclHistory.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FA8016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclIndexObj.c; path = ../generic/tclIndexObj.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FA9016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclInterp.c; path = ../generic/tclInterp.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FAA016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclIO.c; path = ../generic/tclIO.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FAB016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclIOCmd.c; path = ../generic/tclIOCmd.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FAC016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclIOGT.c; path = ../generic/tclIOGT.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FAD016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclIOSock.c; path = ../generic/tclIOSock.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FAE016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclIOUtil.c; path = ../generic/tclIOUtil.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FAF016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclLink.c; path = ../generic/tclLink.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FB0016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclListObj.c; path = ../generic/tclListObj.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FB1016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclLiteral.c; path = ../generic/tclLiteral.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FB2016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclLoad.c; path = ../generic/tclLoad.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FB3016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclLoadNone.c; path = ../generic/tclLoadNone.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FB4016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclMain.c; path = ../generic/tclMain.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FB5016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclNamesp.c; path = ../generic/tclNamesp.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FB6016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclNotify.c; path = ../generic/tclNotify.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FB7016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclObj.c; path = ../generic/tclObj.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FB8016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclPanic.c; path = ../generic/tclPanic.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FB9016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclParse.c; path = ../generic/tclParse.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FBA016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclParseExpr.c; path = ../generic/tclParseExpr.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FBB016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclPipe.c; path = ../generic/tclPipe.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FBC016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclPosixStr.c; path = ../generic/tclPosixStr.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FBD016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclPreserve.c; path = ../generic/tclPreserve.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FBE016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclProc.c; path = ../generic/tclProc.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FBF016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclRegexp.c; path = ../generic/tclRegexp.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FC0016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclResolve.c; path = ../generic/tclResolve.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FC1016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclResult.c; path = ../generic/tclResult.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FC2016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclScan.c; path = ../generic/tclScan.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FC3016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclStringObj.c; path = ../generic/tclStringObj.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FC4016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclStubInit.c; path = ../generic/tclStubInit.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FC5016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclStubLib.c; path = ../generic/tclStubLib.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FC6016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclTest.c; path = ../generic/tclTest.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FC7016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclTestObj.c; path = ../generic/tclTestObj.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FC8016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclTestProcBodyObj.c; path = ../generic/tclTestProcBodyObj.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FC9016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclThread.c; path = ../generic/tclThread.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FCA016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclThreadJoin.c; path = ../generic/tclThreadJoin.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FCB016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclThreadTest.c; path = ../generic/tclThreadTest.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FCC016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclTimer.c; path = ../generic/tclTimer.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FCD016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUniData.c; path = ../generic/tclUniData.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FCE016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUtf.c; path = ../generic/tclUtf.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FCF016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUtil.c; path = ../generic/tclUtil.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FD0016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclVar.c; path = ../generic/tclVar.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FD1016ECB1E01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = regex.h; path = ../generic/regex.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FD2016ECB1E01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclPort.h; path = ../generic/tclPort.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FD3016ECB4901DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclPkg.c; path = ../generic/tclPkg.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FD6016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclUnixPort.h; path = ../unix/tclUnixPort.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FD7016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; name = tclUnixThrd.h; path = ../unix/tclUnixThrd.h; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FD8016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclAppInit.c; path = ../unix/tclAppInit.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FD9016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclLoadDyld.c; path = ../unix/tclLoadDyld.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FDB016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixChan.c; path = ../unix/tclUnixChan.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FDC016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixEvent.c; path = ../unix/tclUnixEvent.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FDD016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixFCmd.c; path = ../unix/tclUnixFCmd.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FDE016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixFile.c; path = ../unix/tclUnixFile.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FDF016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixInit.c; path = ../unix/tclUnixInit.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FE0016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixNotfy.c; path = ../unix/tclUnixNotfy.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FE1016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixPipe.c; path = ../unix/tclUnixPipe.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FE2016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixSock.c; path = ../unix/tclUnixSock.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FE3016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixTest.c; path = ../unix/tclUnixTest.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FE4016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixThrd.c; path = ../unix/tclUnixThrd.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FE5016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclUnixTime.c; path = ../unix/tclUnixTime.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FE6016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclXtNotify.c; path = ../unix/tclXtNotify.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FE7016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; name = tclXtTest.c; path = ../unix/tclXtTest.c; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FEE016ED0DF01DC9062 = { children = ( F5F24FEF016ED0DF01DC9062, F5F24FF0016ED0DF01DC9062, @@ -1446,120 +1377,172 @@ F5F2500A016ED0DF01DC9062, ); isa = PBXGroup; name = Scripts; refType = 4; + sourceTree = ""; }; F5F24FEF016ED0DF01DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = auto.tcl; path = ../library/auto.tcl; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FF0016ED0DF01DC9062 = { includeInIndex = 0; - isa = PBXFolderReference; + isa = PBXFileReference; + lastKnownFileType = folder; name = dde; path = ../library/dde; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FF3016ED0DF01DC9062 = { includeInIndex = 0; - isa = PBXFolderReference; + isa = PBXFileReference; + lastKnownFileType = folder; name = encoding; path = ../library/encoding; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FF4016ED0DF01DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = history.tcl; path = ../library/history.tcl; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FF5016ED0DF01DC9062 = { includeInIndex = 0; - isa = PBXFolderReference; + isa = PBXFileReference; + lastKnownFileType = folder; name = http; path = ../library/http; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FF6016ED0DF01DC9062 = { includeInIndex = 0; - isa = PBXFolderReference; + isa = PBXFileReference; + lastKnownFileType = folder; name = http1.0; path = ../library/http1.0; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FFA016ED0DF01DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = init.tcl; path = ../library/init.tcl; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FFB016ED0DF01DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = ldAout.tcl; path = ../library/ldAout.tcl; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FFC016ED0DF01DC9062 = { includeInIndex = 0; - isa = PBXFolderReference; + isa = PBXFileReference; + lastKnownFileType = folder; name = msgcat; path = ../library/msgcat; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F24FFE016ED0DF01DC9062 = { includeInIndex = 0; - isa = PBXFolderReference; + isa = PBXFileReference; + lastKnownFileType = folder; name = opt; path = ../library/opt; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F25001016ED0DF01DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = package.tcl; path = ../library/package.tcl; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F25002016ED0DF01DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = parray.tcl; path = ../library/parray.tcl; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F25003016ED0DF01DC9062 = { includeInIndex = 0; - isa = PBXFolderReference; + isa = PBXFileReference; + lastKnownFileType = folder; name = reg; path = ../library/reg; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F25005016ED0DF01DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = safe.tcl; path = ../library/safe.tcl; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F25007016ED0DF01DC9062 = { fileEncoding = 5; isa = PBXFileReference; + lastKnownFileType = text; name = tclIndex; path = ../library/tclIndex; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F25008016ED0DF01DC9062 = { includeInIndex = 0; - isa = PBXFolderReference; + isa = PBXFileReference; + lastKnownFileType = folder; name = tcltest; path = ../library/tcltest; refType = 2; + sourceTree = SOURCE_ROOT; }; F5F2500A016ED0DF01DC9062 = { isa = PBXFileReference; + lastKnownFileType = text; name = word.tcl; path = ../library/word.tcl; refType = 2; + sourceTree = SOURCE_ROOT; + }; +//F50 +//F51 +//F52 +//F53 +//F54 +//F90 +//F91 +//F92 +//F93 +//F94 + F9A61C9D04C2B4E3006F5A0B = { + explicitFileType = wrapper.framework; + isa = PBXFileReference; + path = Tcl.framework; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; }; }; rootObject = 00E2F845016E82EB0ACA28DC; } ADDED macosx/Tclsh-Info.plist.in Index: macosx/Tclsh-Info.plist.in ================================================================== --- /dev/null +++ macosx/Tclsh-Info.plist.in @@ -0,0 +1,38 @@ + + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + tclsh@TCL_VERSION@ + CFBundleGetInfoString + Tcl Shell @TCL_VERSION@@TCL_PATCH_LEVEL@, +Copyright © @TCL_YEAR@ Tcl Core Team, +Copyright © 2001-@TCL_YEAR@ Daniel A. Steffen, +Initial MacOS X Port by Jim Ingham & Ian Reid, +Copyright © 2001-2002, Apple Computer, Inc. + CFBundleIdentifier + com.tcltk.tclsh + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + tclsh + CFBundlePackageType + APPL + CFBundleShortVersionString + @TCL_VERSION@@TCL_PATCH_LEVEL@ + CFBundleSignature + TclS + CFBundleVersion + @TCL_VERSION@@TCL_PATCH_LEVEL@ + + Index: macosx/tclMacOSXBundle.c ================================================================== --- macosx/tclMacOSXBundle.c +++ macosx/tclMacOSXBundle.c @@ -1,75 +1,78 @@ /* * tclMacOSXBundle.c -- * - * This file implements functions that inspect CFBundle structures - * on MacOS X. - * - * Copyright 2001, Apple Computer, Inc. - * - * The following terms apply to all files originating from Apple - * Computer, Inc. ("Apple") and associated with the software - * unless explicitly disclaimed in individual files. - * - * - * Apple hereby grants permission to use, copy, modify, - * distribute, and license this software and its documentation - * for any purpose, provided that existing copyright notices are - * retained in all copies and that this notice is included - * verbatim in any distributions. No written agreement, license, - * or royalty fee is required for any of the authorized - * uses. Modifications to this software may be copyrighted by - * their authors and need not follow the licensing terms - * described here, provided that the new terms are clearly - * indicated on the first page of each file where they apply. - * - * - * IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE - * SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, - * INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF - * THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, - * EVEN IF APPLE OR THE AUTHORS HAVE BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. APPLE, THE AUTHORS AND - * DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS - * SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND APPLE,THE - * AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE - * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * GOVERNMENT USE: If you are acquiring this software on behalf - * of the U.S. government, the Government shall have only - * "Restricted Rights" in the software and related documentation - * as defined in the Federal Acquisition Regulations (FARs) in - * Clause 52.227.19 (c) (2). If you are acquiring the software - * on behalf of the Department of Defense, the software shall be - * classified as "Commercial Computer Software" and the - * Government shall have only "Restricted Rights" as defined in - * Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the - * foregoing, the authors grant the U.S. Government and others - * acting in its behalf permission to use and distribute the - * software in accordance with the terms specified in this - * license. + * This file implements functions that inspect CFBundle structures on + * MacOS X. + * + * Copyright 2001, Apple Computer, Inc. + * Copyright (c) 2003-2007 Daniel A. Steffen + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * The following terms apply to all files originating from Apple + * Computer, Inc. ("Apple") and associated with the software unless + * explicitly disclaimed in individual files. + * + * Apple hereby grants permission to use, copy, modify, distribute, and + * license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that + * this notice is included verbatim in any distributions. No written + * agreement, license, or royalty fee is required for any of the + * authorized uses. Modifications to this software may be copyrighted by + * their authors and need not follow the licensing terms described here, + * provided that the new terms are clearly indicated on the first page of + * each file where they apply. + * + * IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE SOFTWARE + * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS + * DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF APPLE OR THE + * AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. APPLE, + * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND + * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND + * APPLE,THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE + * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * GOVERNMENT USE: If you are acquiring this software on behalf of the + * U.S. government, the Government shall have only "Restricted Rights" in + * the software and related documentation as defined in the Federal + * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are + * acquiring the software on behalf of the Department of Defense, the + * software shall be classified as "Commercial Computer Software" and the + * Government shall have only "Restricted Rights" as defined in Clause + * 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the + * authors grant the U.S. Government and others acting in its behalf + * permission to use and distribute the software in accordance with the + * terms specified in this license. + * + * RCS: @(#) $Id: tclMacOSXBundle.c,v 1.3.2.6 2007/04/29 02:21:33 das Exp $ */ +#include "tclPort.h" + +#ifdef HAVE_COREFOUNDATION #include -#include "tcl.h" +#include +#endif /* HAVE_COREFOUNDATION */ /* *---------------------------------------------------------------------- * * Tcl_MacOSXOpenBundleResources -- * * Given the bundle name for a shared library, this routine sets * libraryPath to the Resources/Scripts directory in the framework - * package. If hasResourceFile is true, it will also open the main + * package. If hasResourceFile is true, it will also open the main * resource file for the bundle. - * * * Results: * TCL_OK if the bundle could be opened, and the Scripts folder found. - * TCL_ERROR otherwise. + * TCL_ERROR otherwise. * * Side effects: * libraryVariableName may be set, and the resource file opened. * *---------------------------------------------------------------------- @@ -77,50 +80,153 @@ int Tcl_MacOSXOpenBundleResources( Tcl_Interp *interp, CONST char *bundleName, - int hasResourceFile, - int maxPathLen, - char *libraryPath) + int hasResourceFile, + int maxPathLen, + char *libraryPath) +{ + return Tcl_MacOSXOpenVersionedBundleResources(interp, bundleName, + NULL, hasResourceFile, maxPathLen, libraryPath); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_MacOSXOpenVersionedBundleResources -- + * + * Given the bundle and version name for a shared library (version name + * can be NULL to indicate latest version), this routine sets libraryPath + * to the Resources/Scripts directory in the framework package. If + * hasResourceFile is true, it will also open the main resource file for + * the bundle. + * + * Results: + * TCL_OK if the bundle could be opened, and the Scripts folder found. + * TCL_ERROR otherwise. + * + * Side effects: + * libraryVariableName may be set, and the resource file opened. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_MacOSXOpenVersionedBundleResources( + Tcl_Interp *interp, + CONST char *bundleName, + CONST char *bundleVersion, + int hasResourceFile, + int maxPathLen, + char *libraryPath) { +#ifdef HAVE_COREFOUNDATION CFBundleRef bundleRef; CFStringRef bundleNameRef; + CFURLRef libURL; libraryPath[0] = '\0'; - bundleNameRef = CFStringCreateWithCString(NULL, - bundleName, kCFStringEncodingUTF8); + bundleNameRef = CFStringCreateWithCString(NULL, bundleName, + kCFStringEncodingUTF8); bundleRef = CFBundleGetBundleWithIdentifier(bundleNameRef); CFRelease(bundleNameRef); - if (bundleRef == 0) { - return TCL_ERROR; - } else { - CFURLRef libURL; - - if (hasResourceFile) { - short refNum; - refNum = CFBundleOpenBundleResourceMap(bundleRef); - } - - libURL = CFBundleCopyResourceURL(bundleRef, - CFSTR("Scripts"), NULL, NULL); - - if (libURL != NULL) { - /* - * FIXME: This is a quick fix, it is probably not right - * for internationalization. - */ - - if (CFURLGetFileSystemRepresentation(libURL, true, - libraryPath, maxPathLen)) { - } - CFRelease(libURL); - } else { - return TCL_ERROR; - } - } - - return TCL_OK; + if (bundleVersion && bundleRef) { + /* + * Create bundle from bundleVersion subdirectory of 'Versions'. + */ + + CFBundleRef versionedBundleRef = NULL; + CFURLRef versionedBundleURL = NULL; + CFStringRef bundleVersionRef = CFStringCreateWithCString(NULL, + bundleVersion, kCFStringEncodingUTF8); + CFURLRef bundleURL = CFBundleCopyBundleURL(bundleRef); + + if (bundleURL) { + CFStringRef bundleTailRef = CFURLCopyLastPathComponent(bundleURL); + + if (bundleTailRef) { + if (CFStringCompare(bundleTailRef, bundleVersionRef, 0) == + kCFCompareEqualTo) { + versionedBundleRef = bundleRef; + } + CFRelease(bundleTailRef); + } + } + + if (bundleURL && !versionedBundleRef) { + CFURLRef versURL = CFURLCreateCopyAppendingPathComponent(NULL, + bundleURL, CFSTR("Versions"), TRUE); + + if (versURL) { + versionedBundleURL = CFURLCreateCopyAppendingPathComponent( + NULL, versURL, bundleVersionRef, TRUE); + CFRelease(versURL); + } + CFRelease(bundleURL); + } + CFRelease(bundleVersionRef); + if (versionedBundleURL) { + versionedBundleRef = CFBundleCreate(NULL, versionedBundleURL); + CFRelease(versionedBundleURL); + } + bundleRef = versionedBundleRef; + } + + if (bundleRef) { + if (hasResourceFile) { + /* + * Dynamically acquire address for CFBundleOpenBundleResourceMap + * symbol, since it is only present in full CoreFoundation on Mac + * OS X and not in CFLite on pure Darwin. + */ + + static int initialized = FALSE; + static short (*openresourcemap)(CFBundleRef) = NULL; + + if (!initialized) { + NSSymbol nsSymbol = NULL; + if (NSIsSymbolNameDefinedWithHint( + "_CFBundleOpenBundleResourceMap", "CoreFoundation")) { + nsSymbol = NSLookupAndBindSymbolWithHint( + "_CFBundleOpenBundleResourceMap","CoreFoundation"); + if (nsSymbol) { + openresourcemap = NSAddressOfSymbol(nsSymbol); + } + } + initialized = TRUE; + } + + if (openresourcemap) { + short refNum; + + refNum = openresourcemap(bundleRef); + } + } + + libURL = CFBundleCopyResourceURL(bundleRef, CFSTR("Scripts"), + NULL, NULL); + + if (libURL) { + /* + * FIXME: This is a quick fix, it is probably not right for + * internationalization. + */ + + CFURLGetFileSystemRepresentation(libURL, TRUE, + (unsigned char*) libraryPath, maxPathLen); + CFRelease(libURL); + } + } + + if (libraryPath[0]) { + return TCL_OK; + } else { + return TCL_ERROR; + } +#else /* HAVE_COREFOUNDATION */ + return TCL_ERROR; +#endif /* HAVE_COREFOUNDATION */ } ADDED macosx/tclMacOSXNotify.c Index: macosx/tclMacOSXNotify.c ================================================================== --- /dev/null +++ macosx/tclMacOSXNotify.c @@ -0,0 +1,1281 @@ +/* + * tclMacOSXNotify.c -- + * + * This file contains the implementation of a merged CFRunLoop/select() + * based notifier, which is the lowest-level part of the Tcl event loop. + * This file works together with generic/tclNotify.c. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * Copyright 2001, Apple Computer, Inc. + * Copyright (c) 2005-2007 Daniel A. Steffen + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tclMacOSXNotify.c,v 1.1.2.12 2007/04/29 02:21:33 das Exp $ + */ + +#include "tclInt.h" +#include "tclPort.h" +#ifdef HAVE_COREFOUNDATION /* Traditional unix select-based notifier is + * in tclUnixNotfy.c */ +#include +#include + +extern TclStubs tclStubs; +extern Tcl_NotifierProcs tclOriginalNotifier; + +/* + * This structure is used to keep track of the notifier info for a registered + * file. + */ + +typedef struct FileHandler { + int fd; + int mask; /* Mask of desired events: TCL_READABLE, + * etc. */ + int readyMask; /* Mask of events that have been seen since + * the last time file handlers were invoked + * for this file. */ + Tcl_FileProc *proc; /* Function to call, in the style of + * Tcl_CreateFileHandler. */ + ClientData clientData; /* Argument to pass to proc. */ + struct FileHandler *nextPtr;/* Next in list of all files we care about. */ +} FileHandler; + +/* + * The following structure is what is added to the Tcl event queue when file + * handlers are ready to fire. + */ + +typedef struct FileHandlerEvent { + Tcl_Event header; /* Information that is standard for all + * events. */ + int fd; /* File descriptor that is ready. Used to find + * the FileHandler structure for the file + * (can't point directly to the FileHandler + * structure because it could go away while + * the event is queued). */ +} FileHandlerEvent; + +/* + * The following structure contains a set of select() masks to track readable, + * writable, and exceptional conditions. + */ + +typedef struct SelectMasks { + fd_set readable; + fd_set writable; + fd_set exceptional; +} SelectMasks; + +/* + * The following static structure contains the state information for the + * select based implementation of the Tcl notifier. One of these structures is + * created for each thread that is using the notifier. + */ + +typedef struct ThreadSpecificData { + FileHandler *firstFileHandlerPtr; + /* Pointer to head of file handler list. */ + SelectMasks checkMasks; /* This structure is used to build up the + * masks to be used in the next call to + * select. Bits are set in response to calls + * to Tcl_CreateFileHandler. */ + SelectMasks readyMasks; /* This array reflects the readable/writable + * conditions that were found to exist by the + * last call to select. */ + int numFdBits; /* Number of valid bits in checkMasks (one + * more than highest fd for which + * Tcl_WatchFile has been called). */ + int onList; /* True if it is in this list */ + unsigned int pollState; /* pollState is used to implement a polling + * handshake between each thread and the + * notifier thread. Bits defined below. */ + struct ThreadSpecificData *nextPtr, *prevPtr; + /* All threads that are currently waiting on + * an event have their ThreadSpecificData + * structure on a doubly-linked listed formed + * from these pointers. You must hold the + * notifierLock before accessing these + * fields. */ + CFRunLoopSourceRef runLoopSource; + /* Any other thread alerts a notifier that an + * event is ready to be processed by signaling + * this CFRunLoopSource. */ + CFRunLoopRef runLoop; /* This thread's CFRunLoop, needs to be woken + * up whenever the runLoopSource is + * signaled. */ + int eventReady; /* True if an event is ready to be + * processed. */ +} ThreadSpecificData; + +static Tcl_ThreadDataKey dataKey; + +/* + * The following static indicates the number of threads that have initialized + * notifiers. + * + * You must hold the notifierInitLock before accessing this variable. + */ + +static int notifierCount = 0; + +/* + * The following variable points to the head of a doubly-linked list of + * ThreadSpecificData structures for all threads that are currently waiting on + * an event. + * + * You must hold the notifierLock before accessing this list. + */ + +static ThreadSpecificData *waitingListPtr = NULL; + +/* + * The notifier thread spends all its time in select() waiting for a file + * descriptor associated with one of the threads on the waitingListPtr list to + * do something interesting. But if the contents of the waitingListPtr list + * ever changes, we need to wake up and restart the select() system call. You + * can wake up the notifier thread by writing a single byte to the file + * descriptor defined below. This file descriptor is the input-end of a pipe + * and the notifier thread is listening for data on the output-end of the same + * pipe. Hence writing to this file descriptor will cause the select() system + * call to return and wake up the notifier thread. + * + * You must hold the notifierLock lock before writing to the pipe. + */ + +static int triggerPipe = -1; +static int receivePipe = -1; /* Output end of triggerPipe */ + +/* + * We use the Darwin-native spinlock API rather than pthread mutexes for + * notifier locking: this radically simplifies the implementation and lowers + * overhead. Note that these are not pure spinlocks, they employ various + * strategies to back off and relinquish the processor, making them immune to + * most priority-inversion livelocks (c.f. 'man 3 OSSpinLockLock' and Darwin + * sources: xnu/osfmk/{ppc,i386}/commpage/spinlocks.s). + */ + +#if defined(HAVE_LIBKERN_OSATOMIC_H) && defined(HAVE_OSSPINLOCKLOCK) +/* + * Use OSSpinLock API where available (Tiger or later). + */ + +#include + +#if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 +/* + * Support for weakly importing spinlock API. + */ +#define WEAK_IMPORT_SPINLOCKLOCK +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 +#define VOLATILE volatile +#else +#define VOLATILE +#endif +#ifndef bool +#define bool int +#endif +extern void OSSpinLockLock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +extern void OSSpinLockUnlock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +extern bool OSSpinLockTry(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +extern void _spin_lock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +extern void _spin_unlock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +extern bool _spin_lock_try(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; +static void (* lockLock)(VOLATILE OSSpinLock *lock) = NULL; +static void (* lockUnlock)(VOLATILE OSSpinLock *lock) = NULL; +static bool (* lockTry)(VOLATILE OSSpinLock *lock) = NULL; +#undef VOLATILE +static pthread_once_t spinLockLockInitControl = PTHREAD_ONCE_INIT; +static void SpinLockLockInit(void) { + lockLock = OSSpinLockLock != NULL ? OSSpinLockLock : _spin_lock; + lockUnlock = OSSpinLockUnlock != NULL ? OSSpinLockUnlock : _spin_unlock; + lockTry = OSSpinLockTry != NULL ? OSSpinLockTry : _spin_lock_try; + if (lockLock == NULL || lockUnlock == NULL) { + Tcl_Panic("SpinLockLockInit: no spinlock API available"); + } +} +#define SpinLockLock(p) lockLock(p) +#define SpinLockUnlock(p) lockUnlock(p) +#define SpinLockTry(p) lockTry(p) +#else +#define SpinLockLock(p) OSSpinLockLock(p) +#define SpinLockUnlock(p) OSSpinLockUnlock(p) +#define SpinLockTry(p) OSSpinLockTry(p) +#endif /* HAVE_WEAK_IMPORT */ +#define SPINLOCK_INIT OS_SPINLOCK_INIT + +#else +/* + * Otherwise, use commpage spinlock SPI directly. + */ + +typedef uint32_t OSSpinLock; +extern void _spin_lock(OSSpinLock *lock); +extern void _spin_unlock(OSSpinLock *lock); +extern int _spin_lock_try(OSSpinLock *lock); +#define SpinLockLock(p) _spin_lock(p) +#define SpinLockUnlock(p) _spin_unlock(p) +#define SpinLockTry(p) _spin_lock_try(p) +#define SPINLOCK_INIT 0 + +#endif /* HAVE_LIBKERN_OSATOMIC_H && HAVE_OSSPINLOCKLOCK */ + +/* + * These spinlocks lock access to the global notifier state. + */ + +static OSSpinLock notifierInitLock = SPINLOCK_INIT; +static OSSpinLock notifierLock = SPINLOCK_INIT; + +/* + * Macros abstracting notifier locking/unlocking + */ + +#define LOCK_NOTIFIER_INIT SpinLockLock(¬ifierInitLock) +#define UNLOCK_NOTIFIER_INIT SpinLockUnlock(¬ifierInitLock) +#define LOCK_NOTIFIER SpinLockLock(¬ifierLock) +#define UNLOCK_NOTIFIER SpinLockUnlock(¬ifierLock) + +/* + * The pollState bits + * POLL_WANT is set by each thread before it waits on its condition + * variable. It is checked by the notifier before it does select. + * POLL_DONE is set by the notifier if it goes into select after seeing + * POLL_WANT. The idea is to ensure it tries a select with the + * same bits the initial thread had set. + */ + +#define POLL_WANT 0x1 +#define POLL_DONE 0x2 + +/* + * This is the thread ID of the notifier thread that does select. + */ + +static pthread_t notifierThread; + +/* + * Custom run loop mode containing only the run loop source for the + * notifier thread. + */ + +#ifndef TCL_EVENTS_ONLY_RUN_LOOP_MODE +#define TCL_EVENTS_ONLY_RUN_LOOP_MODE "com.tcltk.tclEventsOnlyRunLoopMode" +#endif +#ifdef __CONSTANT_CFSTRINGS__ +#define tclEventsOnlyRunLoopMode CFSTR(TCL_EVENTS_ONLY_RUN_LOOP_MODE) +#else +static CFStringRef tclEventsOnlyRunLoopMode = NULL; +#endif + +/* + * Static routines defined in this file. + */ + +static void NotifierThreadProc(ClientData clientData) + __attribute__ ((__noreturn__)); +static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); + +#ifdef HAVE_PTHREAD_ATFORK +static int atForkInit = 0; +static void AtForkPrepare(void); +static void AtForkParent(void); +static void AtForkChild(void); +#if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 +/* Support for weakly importing pthread_atfork. */ +#define WEAK_IMPORT_PTHREAD_ATFORK +extern int pthread_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)) WEAK_IMPORT_ATTRIBUTE; +#endif /* HAVE_WEAK_IMPORT */ +#endif /* HAVE_PTHREAD_ATFORK */ + +/* + *---------------------------------------------------------------------- + * + * 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) +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + tsdPtr->eventReady = 0; + +#ifdef WEAK_IMPORT_SPINLOCKLOCK + /* + * Initialize support for weakly imported spinlock API. + */ + if (pthread_once(&spinLockLockInitControl, SpinLockLockInit)) { + Tcl_Panic("Tcl_InitNotifier: pthread_once failed"); + } +#endif + +#ifndef __CONSTANT_CFSTRINGS__ + if (!tclEventsOnlyRunLoopMode) { + tclEventsOnlyRunLoopMode = CFSTR(TCL_EVENTS_ONLY_RUN_LOOP_MODE); + } +#endif + + /* + * Initialize CFRunLoopSource and add it to CFRunLoop of this thread. + */ + + if (!tsdPtr->runLoop) { + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + CFRunLoopSourceRef runLoopSource; + CFRunLoopSourceContext runLoopSourceContext; + + bzero(&runLoopSourceContext, sizeof(CFRunLoopSourceContext)); + runLoopSourceContext.info = tsdPtr; + runLoopSource = CFRunLoopSourceCreate(NULL, 0, &runLoopSourceContext); + if (!runLoopSource) { + Tcl_Panic("Tcl_InitNotifier: could not create CFRunLoopSource"); + } + CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopCommonModes); + CFRunLoopAddSource(runLoop, runLoopSource, tclEventsOnlyRunLoopMode); + tsdPtr->runLoopSource = runLoopSource; + tsdPtr->runLoop = runLoop; + } + + LOCK_NOTIFIER_INIT; +#ifdef HAVE_PTHREAD_ATFORK + /* + * Install pthread_atfork handlers to reinitialize the notifier in the + * child of a fork. + */ + + if ( +#ifdef WEAK_IMPORT_PTHREAD_ATFORK + pthread_atfork != NULL && +#endif + !atForkInit) { + int result = pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild); + if (result) { + Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed"); + } + atForkInit = 1; + } +#endif + if (notifierCount == 0) { + int fds[2], status; + + /* + * Initialize trigger pipe. + */ + + if (pipe(fds) != 0) { + Tcl_Panic("Tcl_InitNotifier: could not create trigger pipe"); + } + + status = fcntl(fds[0], F_GETFL); + status |= O_NONBLOCK; + if (fcntl(fds[0], F_SETFL, status) < 0) { + Tcl_Panic("Tcl_InitNotifier: could not make receive pipe non blocking"); + } + status = fcntl(fds[1], F_GETFL); + status |= O_NONBLOCK; + if (fcntl(fds[1], F_SETFL, status) < 0) { + Tcl_Panic("Tcl_InitNotifier: could not make trigger pipe non blocking"); + } + + receivePipe = fds[0]; + triggerPipe = fds[1]; + + /* + * Create notifier thread lazily in Tcl_WaitForEvent() to avoid + * interfering with fork() followed immediately by execve() + * (cannot execve() when more than one thread is present). + */ + + notifierThread = 0; + } + notifierCount++; + UNLOCK_NOTIFIER_INIT; + + return (ClientData) tsdPtr; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_FinalizeNotifier -- + * + * This function is called to cleanup the notifier state before a thread + * is terminated. + * + * Results: + * None. + * + * Side effects: + * May terminate the background notifier thread if this is the last + * notifier instance. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_FinalizeNotifier( + ClientData clientData) /* Not used. */ +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + LOCK_NOTIFIER_INIT; + notifierCount--; + + /* + * If this is the last thread to use the notifier, close the notifier pipe + * and wait for the background thread to terminate. + */ + + if (notifierCount == 0) { + int result; + + if (triggerPipe < 0) { + Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized"); + } + + /* + * Send "q" message to the notifier thread so that it will terminate. + * The notifier will return from its call to select() and notice that + * a "q" message has arrived, it will then close its side of the pipe + * and terminate its thread. Note the we can not just close the pipe + * and check for EOF in the notifier thread because if a background + * child process was created with exec, select() would not register + * the EOF on the pipe until the child processes had terminated. [Bug: + * 4139] [Bug: 1222872] + */ + + write(triggerPipe, "q", 1); + close(triggerPipe); + + if (notifierThread) { + result = pthread_join(notifierThread, NULL); + if (result) { + Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread"); + } + notifierThread = 0; + } + + close(receivePipe); + triggerPipe = -1; + } + UNLOCK_NOTIFIER_INIT; + + LOCK_NOTIFIER; /* for concurrency with Tcl_AlertNotifier */ + if (tsdPtr->runLoop) { + tsdPtr->runLoop = NULL; + + /* + * Remove runLoopSource from all CFRunLoops and release it. + */ + + CFRunLoopSourceInvalidate(tsdPtr->runLoopSource); + CFRelease(tsdPtr->runLoopSource); + tsdPtr->runLoopSource = NULL; + } + UNLOCK_NOTIFIER; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_AlertNotifier -- + * + * Wake up the specified notifier from any thread. This routine is called + * by the platform independent notifier code whenever the Tcl_ThreadAlert + * routine is called. This routine is guaranteed not to be called on a + * given notifier after Tcl_FinalizeNotifier is called for that notifier. + * + * Results: + * None. + * + * Side effects: + * Signals the notifier condition variable for the specified notifier. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_AlertNotifier( + ClientData clientData) +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; + + LOCK_NOTIFIER; + if (tsdPtr->runLoop) { + tsdPtr->eventReady = 1; + CFRunLoopSourceSignal(tsdPtr->runLoopSource); + CFRunLoopWakeUp(tsdPtr->runLoop); + } + UNLOCK_NOTIFIER; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SetTimer -- + * + * This function sets the current notifier timer value. This interface is + * not implemented in this notifier because we are always running inside + * of Tcl_DoOneEvent. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_SetTimer( + Tcl_Time *timePtr) /* Timeout value, may be NULL. */ +{ + /* + * The interval timer doesn't do anything in this implementation, because + * the only event loop is via Tcl_DoOneEvent, which passes timeout values + * to Tcl_WaitForEvent. + */ + + if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) { + tclStubs.tcl_SetTimer(timePtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_ServiceModeHook -- + * + * This function is invoked whenever the service mode changes. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_ServiceModeHook( + int mode) /* Either TCL_SERVICE_ALL, or + * TCL_SERVICE_NONE. */ +{ +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_CreateFileHandler -- + * + * This function registers a file handler with the select notifier. + * + * Results: + * None. + * + * Side effects: + * Creates a new file handler structure. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_CreateFileHandler( + int fd, /* Handle of stream to watch. */ + int mask, /* OR'ed combination of TCL_READABLE, + * TCL_WRITABLE, and TCL_EXCEPTION: indicates + * conditions under which proc should be + * called. */ + Tcl_FileProc *proc, /* Function to call for each selected + * event. */ + ClientData clientData) /* Arbitrary data to pass to proc. */ +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + FileHandler *filePtr; + + if (tclStubs.tcl_CreateFileHandler != + tclOriginalNotifier.createFileHandlerProc) { + tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData); + return; + } + + for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + if (filePtr->fd == fd) { + break; + } + } + if (filePtr == NULL) { + filePtr = (FileHandler*) ckalloc(sizeof(FileHandler)); + filePtr->fd = fd; + filePtr->readyMask = 0; + filePtr->nextPtr = tsdPtr->firstFileHandlerPtr; + tsdPtr->firstFileHandlerPtr = filePtr; + } + filePtr->proc = proc; + filePtr->clientData = clientData; + filePtr->mask = mask; + + /* + * Update the check masks for this file. + */ + + if (mask & TCL_READABLE) { + FD_SET(fd, &(tsdPtr->checkMasks.readable)); + } else { + FD_CLR(fd, &(tsdPtr->checkMasks.readable)); + } + if (mask & TCL_WRITABLE) { + FD_SET(fd, &(tsdPtr->checkMasks.writable)); + } else { + FD_CLR(fd, &(tsdPtr->checkMasks.writable)); + } + if (mask & TCL_EXCEPTION) { + FD_SET(fd, &(tsdPtr->checkMasks.exceptional)); + } else { + FD_CLR(fd, &(tsdPtr->checkMasks.exceptional)); + } + if (tsdPtr->numFdBits <= fd) { + tsdPtr->numFdBits = fd+1; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DeleteFileHandler -- + * + * Cancel a previously-arranged callback arrangement for a file. + * + * Results: + * None. + * + * Side effects: + * If a callback was previously registered on file, remove it. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DeleteFileHandler( + int fd) /* Stream id for which to remove callback + * function. */ +{ + FileHandler *filePtr, *prevPtr; + int i; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + if (tclStubs.tcl_DeleteFileHandler != + tclOriginalNotifier.deleteFileHandlerProc) { + tclStubs.tcl_DeleteFileHandler(fd); + return; + } + + /* + * Find the entry for the given file (and return if there isn't one). + */ + + for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ; + prevPtr = filePtr, filePtr = filePtr->nextPtr) { + if (filePtr == NULL) { + return; + } + if (filePtr->fd == fd) { + break; + } + } + + /* + * Update the check masks for this file. + */ + + if (filePtr->mask & TCL_READABLE) { + FD_CLR(fd, &(tsdPtr->checkMasks.readable)); + } + if (filePtr->mask & TCL_WRITABLE) { + FD_CLR(fd, &(tsdPtr->checkMasks.writable)); + } + if (filePtr->mask & TCL_EXCEPTION) { + FD_CLR(fd, &(tsdPtr->checkMasks.exceptional)); + } + + /* + * Find current max fd. + */ + + if (fd+1 == tsdPtr->numFdBits) { + tsdPtr->numFdBits = 0; + for (i = fd-1; i >= 0; i--) { + if (FD_ISSET(i, &(tsdPtr->checkMasks.readable)) + || FD_ISSET(i, &(tsdPtr->checkMasks.writable)) + || FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) { + tsdPtr->numFdBits = i+1; + break; + } + } + } + + /* + * Clean up information in the callback record. + */ + + if (prevPtr == NULL) { + tsdPtr->firstFileHandlerPtr = filePtr->nextPtr; + } else { + prevPtr->nextPtr = filePtr->nextPtr; + } + ckfree((char *) filePtr); +} + +/* + *---------------------------------------------------------------------- + * + * FileHandlerEventProc -- + * + * This function is called by Tcl_ServiceEvent when a file event reaches + * the front of the event queue. This function is responsible for + * actually handling the event by invoking the callback for the file + * handler. + * + * Results: + * Returns 1 if the event was handled, meaning it should be removed from + * the queue. Returns 0 if the event was not handled, meaning it should + * stay on the queue. The only time the event isn't handled is if the + * TCL_FILE_EVENTS flag bit isn't set. + * + * Side effects: + * Whatever the file handler's callback function does. + * + *---------------------------------------------------------------------- + */ + +static int +FileHandlerEventProc( + Tcl_Event *evPtr, /* Event to service. */ + int flags) /* Flags that indicate what events to handle, + * such as TCL_FILE_EVENTS. */ +{ + int mask; + FileHandler *filePtr; + FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr; + ThreadSpecificData *tsdPtr; + + if (!(flags & TCL_FILE_EVENTS)) { + return 0; + } + + /* + * Search through the file handlers to find the one whose handle matches + * the event. We do this rather than keeping a pointer to the file handler + * directly in the event, so that the handler can be deleted while the + * event is queued without leaving a dangling pointer. + */ + + tsdPtr = TCL_TSD_INIT(&dataKey); + for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + if (filePtr->fd != fileEvPtr->fd) { + continue; + } + + /* + * The code is tricky for two reasons: + * 1. The file handler's desired events could have changed since the + * time when the event was queued, so AND the ready mask with the + * desired mask. + * 2. The file could have been closed and re-opened since the time + * when the event was queued. This is why the ready mask is stored + * in the file handler rather than the queued event: it will be + * zeroed when a new file handler is created for the newly opened + * file. + */ + + mask = filePtr->readyMask & filePtr->mask; + filePtr->readyMask = 0; + if (mask != 0) { + (*filePtr->proc)(filePtr->clientData, mask); + } + break; + } + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_WaitForEvent -- + * + * This function is called by Tcl_DoOneEvent to wait for new events on + * the message queue. If the block time is 0, then Tcl_WaitForEvent just + * polls without blocking. + * + * Results: + * Returns -1 if the select would block forever, otherwise returns 0. + * + * Side effects: + * Queues file events that are detected by the select. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_WaitForEvent( + Tcl_Time *timePtr) /* Maximum block time, or NULL. */ +{ + FileHandler *filePtr; + FileHandlerEvent *fileEvPtr; + int mask; + int waitForFiles; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) { + return tclStubs.tcl_WaitForEvent(timePtr); + } + + /* + * Start notifier thread if necessary. + */ + + LOCK_NOTIFIER_INIT; + if (!notifierCount) { + Tcl_Panic("Tcl_WaitForEvent: notifier not initialized"); + } + if (!notifierThread) { + int result; + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + pthread_attr_setstacksize(&attr, 60 * 1024); + result = pthread_create(¬ifierThread, &attr, + (void * (*)(void *))NotifierThreadProc, NULL); + pthread_attr_destroy(&attr); + if (result || !notifierThread) { + Tcl_Panic("Tcl_WaitForEvent: unable to start notifier thread"); + } + } + UNLOCK_NOTIFIER_INIT; + + /* + * Place this thread on the list of interested threads, signal the + * notifier thread, and wait for a response or a timeout. + */ + + LOCK_NOTIFIER; + if (!tsdPtr->runLoop) { + Tcl_Panic("Tcl_WaitForEvent: CFRunLoop not initialized"); + } + waitForFiles = (tsdPtr->numFdBits > 0); + if (timePtr != NULL && timePtr->sec == 0 && timePtr->usec == 0) { + /* + * Cannot emulate a polling select with a polling condition variable. + * Instead, pretend to wait for files and tell the notifier thread + * what we are doing. The notifier thread makes sure it goes through + * select with its select mask in the same state as ours currently is. + * We block until that happens. + */ + + waitForFiles = 1; + tsdPtr->pollState = POLL_WANT; + timePtr = NULL; + } else { + tsdPtr->pollState = 0; + } + + if (waitForFiles) { + /* + * Add the ThreadSpecificData structure of this thread to the list of + * ThreadSpecificData structures of all threads that are waiting on + * file events. + */ + + tsdPtr->nextPtr = waitingListPtr; + if (waitingListPtr) { + waitingListPtr->prevPtr = tsdPtr; + } + tsdPtr->prevPtr = 0; + waitingListPtr = tsdPtr; + tsdPtr->onList = 1; + + write(triggerPipe, "", 1); + } + + FD_ZERO(&(tsdPtr->readyMasks.readable)); + FD_ZERO(&(tsdPtr->readyMasks.writable)); + FD_ZERO(&(tsdPtr->readyMasks.exceptional)); + + if (!tsdPtr->eventReady) { + CFTimeInterval waitTime; + CFStringRef runLoopMode; + + if (timePtr == NULL) { + waitTime = 1.0e10; /* Wait forever, as per CFRunLoop.c */ + } else { + waitTime = timePtr->sec + 1.0e-6 * timePtr->usec; + } + /* + * If the run loop is already running (e.g. if Tcl_WaitForEvent was + * called recursively), re-run it in a custom run loop mode containing + * only the source for the notifier thread, otherwise wakeups from other + * sources added to the common run loop modes might get lost. + */ + if ((runLoopMode = CFRunLoopCopyCurrentMode(tsdPtr->runLoop))) { + CFRelease(runLoopMode); + runLoopMode = tclEventsOnlyRunLoopMode; + } else { + runLoopMode = kCFRunLoopDefaultMode; + } + UNLOCK_NOTIFIER; + CFRunLoopRunInMode(runLoopMode, waitTime, TRUE); + LOCK_NOTIFIER; + } + tsdPtr->eventReady = 0; + + if (waitForFiles && tsdPtr->onList) { + /* + * Remove the ThreadSpecificData structure of this thread from the + * waiting list. Alert the notifier thread to recompute its select + * masks - skipping this caused a hang when trying to close a pipe + * which the notifier thread was still doing a select on. + */ + + if (tsdPtr->prevPtr) { + tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; + } else { + waitingListPtr = tsdPtr->nextPtr; + } + if (tsdPtr->nextPtr) { + tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; + } + tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; + tsdPtr->onList = 0; + write(triggerPipe, "", 1); + } + + /* + * Queue all detected file events before returning. + */ + + for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL); + filePtr = filePtr->nextPtr) { + + mask = 0; + if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) { + mask |= TCL_READABLE; + } + if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) { + mask |= TCL_WRITABLE; + } + if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) { + mask |= TCL_EXCEPTION; + } + + if (!mask) { + continue; + } + + /* + * Don't bother to queue an event if the mask was previously non-zero + * since an event must still be on the queue. + */ + + if (filePtr->readyMask == 0) { + fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent)); + fileEvPtr->header.proc = FileHandlerEventProc; + fileEvPtr->fd = filePtr->fd; + Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); + } + filePtr->readyMask = mask; + } + UNLOCK_NOTIFIER; + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * NotifierThreadProc -- + * + * This routine is the initial (and only) function executed by the + * special notifier thread. Its job is to wait for file descriptors to + * become readable or writable or to have an exception condition and then + * to notify other threads who are interested in this information by + * signalling a condition variable. Other threads can signal this + * notifier thread of a change in their interests by writing a single + * byte to a special pipe that the notifier thread is monitoring. + * + * Result: + * None. Once started, this routine never exits. It dies with the overall + * process. + * + * Side effects: + * The trigger pipe used to signal the notifier thread is created when + * the notifier thread first starts. + * + *---------------------------------------------------------------------- + */ + +static void +NotifierThreadProc( + ClientData clientData) /* Not used. */ +{ + ThreadSpecificData *tsdPtr; + fd_set readableMask; + fd_set writableMask; + fd_set exceptionalMask; + int i, numFdBits = 0; + long found; + struct timeval poll = {0., 0.}, *timePtr; + char buf[2]; + + /* + * Look for file events and report them to interested threads. + */ + + while (1) { + FD_ZERO(&readableMask); + FD_ZERO(&writableMask); + FD_ZERO(&exceptionalMask); + + /* + * Compute the logical OR of the select masks from all the waiting + * notifiers. + */ + + LOCK_NOTIFIER; + timePtr = NULL; + for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { + for (i = tsdPtr->numFdBits-1; i >= 0; --i) { + if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))) { + FD_SET(i, &readableMask); + } + if (FD_ISSET(i, &(tsdPtr->checkMasks.writable))) { + FD_SET(i, &writableMask); + } + if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) { + FD_SET(i, &exceptionalMask); + } + } + if (tsdPtr->numFdBits > numFdBits) { + numFdBits = tsdPtr->numFdBits; + } + if (tsdPtr->pollState & POLL_WANT) { + /* + * Here we make sure we go through select() with the same mask + * bits that were present when the thread tried to poll. + */ + + tsdPtr->pollState |= POLL_DONE; + timePtr = &poll; + } + } + UNLOCK_NOTIFIER; + + /* + * Set up the select mask to include the receive pipe. + */ + + if (receivePipe >= numFdBits) { + numFdBits = receivePipe + 1; + } + FD_SET(receivePipe, &readableMask); + + if (select(numFdBits, &readableMask, &writableMask, &exceptionalMask, + timePtr) == -1) { + /* + * Try again immediately on an error. + */ + + continue; + } + + /* + * Alert any threads that are waiting on a ready file descriptor. + */ + + LOCK_NOTIFIER; + for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { + found = 0; + + for (i = tsdPtr->numFdBits-1; i >= 0; --i) { + if (FD_ISSET(i, &(tsdPtr->checkMasks.readable)) + && FD_ISSET(i, &readableMask)) { + FD_SET(i, &(tsdPtr->readyMasks.readable)); + found = 1; + } + if (FD_ISSET(i, &(tsdPtr->checkMasks.writable)) + && FD_ISSET(i, &writableMask)) { + FD_SET(i, &(tsdPtr->readyMasks.writable)); + found = 1; + } + if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional)) + && FD_ISSET(i, &exceptionalMask)) { + FD_SET(i, &(tsdPtr->readyMasks.exceptional)); + found = 1; + } + } + + if (found || (tsdPtr->pollState & POLL_DONE)) { + tsdPtr->eventReady = 1; + if (tsdPtr->onList) { + /* + * Remove the ThreadSpecificData structure of this thread + * from the waiting list. This prevents us from + * continuously spining on select until the other threads + * runs and services the file event. + */ + + if (tsdPtr->prevPtr) { + tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; + } else { + waitingListPtr = tsdPtr->nextPtr; + } + if (tsdPtr->nextPtr) { + tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; + } + tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; + tsdPtr->onList = 0; + tsdPtr->pollState = 0; + } + if (tsdPtr->runLoop) { + CFRunLoopSourceSignal(tsdPtr->runLoopSource); + CFRunLoopWakeUp(tsdPtr->runLoop); + } + } + } + UNLOCK_NOTIFIER; + + /* + * Consume the next byte from the notifier pipe if the pipe was + * readable. Note that there may be multiple bytes pending, but to + * avoid a race condition we only read one at a time. + */ + + if (FD_ISSET(receivePipe, &readableMask)) { + i = read(receivePipe, buf, 1); + + if ((i == 0) || ((i == 1) && (buf[0] == 'q'))) { + /* + * Someone closed the write end of the pipe or sent us a Quit + * message [Bug: 4139] and then closed the write end of the + * pipe so we need to shut down the notifier thread. + */ + + break; + } + } + } + pthread_exit(0); +} + +#ifdef HAVE_PTHREAD_ATFORK +/* + *---------------------------------------------------------------------- + * + * AtForkPrepare -- + * + * Lock the notifier in preparation for a fork. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +AtForkPrepare(void) +{ + LOCK_NOTIFIER_INIT; + LOCK_NOTIFIER; +} + +/* + *---------------------------------------------------------------------- + * + * AtForkParent -- + * + * Unlock the notifier in the parent after a fork. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +AtForkParent(void) +{ + UNLOCK_NOTIFIER; + UNLOCK_NOTIFIER_INIT; +} + +/* + *---------------------------------------------------------------------- + * + * AtForkChild -- + * + * Unlock and reinstall the notifier in the child after a fork. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +AtForkChild(void) +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + + UNLOCK_NOTIFIER; + UNLOCK_NOTIFIER_INIT; + if (tsdPtr->runLoop) { + tsdPtr->runLoop = NULL; + CFRunLoopSourceInvalidate(tsdPtr->runLoopSource); + CFRelease(tsdPtr->runLoopSource); + tsdPtr->runLoopSource = NULL; + } + if (notifierCount > 0) { + notifierCount = 0; + + /* + * Assume that the return value of Tcl_InitNotifier in the child will + * be identical to the one stored as clientData in tclNotify.c's + * ThreadSpecificData by the parent's TclInitNotifier, so discard the + * return value here. This assumption may require the fork() to be + * executed in the main thread of the parent, otherwise + * Tcl_AlertNotifier may break in the child. + */ + + Tcl_InitNotifier(); + } +} +#endif /* HAVE_PTHREAD_ATFORK */ + +#endif /* HAVE_COREFOUNDATION */ Index: tests/README ================================================================== --- tests/README +++ tests/README @@ -1,14 +1,16 @@ README -- Tcl test suite design document. -RCS: @(#) $Id: README,v 1.11 2002/08/08 14:50:51 dgp Exp $ +RCS: @(#) $Id: README,v 1.11.2.1 2003/04/01 21:13:07 dgp Exp $ Contents: --------- 1. Introduction - 2. Incompatibilities with prior Tcl versions + 2. Running tests + 3. Adding tests + 4. Incompatibilities with prior Tcl versions 1. Introduction: ---------------- This directory contains a set of validation tests for the Tcl commands @@ -16,28 +18,40 @@ in ".test" is intended to fully exercise the functions in the C source file that corresponds to the file prefix. The C functions and/or Tcl commands tested by a given file are listed in the first line of the file. -You can run the tests in three ways: - - (a) type "make test" in ../unix; this will create the tcltest - executable and run all of the tests. At least "make tcltest" - must be run to create the tcltest executable for the other - options. - - (b) type "tcltest ?