From aa4274da58363cc82765a9eba3e5f3a957573041 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 8 Nov 2012 15:25:30 +0000 Subject: Create Tcl 8.6.0 release branch --- README | 2 +- generic/tcl.h | 6 +++--- library/init.tcl | 2 +- unix/configure | 2 +- unix/configure.in | 2 +- unix/tcl.spec | 2 +- win/configure | 2 +- win/configure.in | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README b/README index 56f7e38..f8965b4 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ README: Tcl - This is the Tcl 8.6b3 source distribution. + This is the Tcl 8.6.0 source distribution. http://tcl.sourceforge.net/ You can get any source release of Tcl from the file distributions link at the above URL. diff --git a/generic/tcl.h b/generic/tcl.h index 5f6146e..d765967 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -55,11 +55,11 @@ extern "C" { #define TCL_MAJOR_VERSION 8 #define TCL_MINOR_VERSION 6 -#define TCL_RELEASE_LEVEL TCL_BETA_RELEASE -#define TCL_RELEASE_SERIAL 3 +#define TCL_RELEASE_LEVEL TCL_FINAL_RELEASE +#define TCL_RELEASE_SERIAL 0 #define TCL_VERSION "8.6" -#define TCL_PATCH_LEVEL "8.6b3" +#define TCL_PATCH_LEVEL "8.6.0" /* *---------------------------------------------------------------------------- diff --git a/library/init.tcl b/library/init.tcl index 3ec78af..e836df9 100644 --- a/library/init.tcl +++ b/library/init.tcl @@ -15,7 +15,7 @@ if {[info commands package] == ""} { error "version mismatch: library\nscripts expect Tcl version 7.5b1 or later but the loaded version is\nonly [info patchlevel]" } -package require -exact Tcl 8.6b3 +package require -exact Tcl 8.6.0 # Compute the auto path to use in this interpreter. # The values on the path come from several locations: diff --git a/unix/configure b/unix/configure index cbb10b4..f778a7b 100755 --- a/unix/configure +++ b/unix/configure @@ -1335,7 +1335,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu TCL_VERSION=8.6 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=6 -TCL_PATCH_LEVEL="b3" +TCL_PATCH_LEVEL=".0" VERSION=${TCL_VERSION} #------------------------------------------------------------------------ diff --git a/unix/configure.in b/unix/configure.in index f4b695d..087bb05 100644 --- a/unix/configure.in +++ b/unix/configure.in @@ -25,7 +25,7 @@ m4_ifdef([SC_USE_CONFIG_HEADERS], [ TCL_VERSION=8.6 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=6 -TCL_PATCH_LEVEL="b3" +TCL_PATCH_LEVEL=".0" VERSION=${TCL_VERSION} #------------------------------------------------------------------------ diff --git a/unix/tcl.spec b/unix/tcl.spec index 0c42aa4..27f7189 100644 --- a/unix/tcl.spec +++ b/unix/tcl.spec @@ -4,7 +4,7 @@ Name: tcl Summary: Tcl scripting language development environment -Version: 8.6b3 +Version: 8.6.0 Release: 2 License: BSD Group: Development/Languages diff --git a/win/configure b/win/configure index 0258898..03a20b4 100755 --- a/win/configure +++ b/win/configure @@ -1311,7 +1311,7 @@ SHELL=/bin/sh TCL_VERSION=8.6 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=6 -TCL_PATCH_LEVEL="b3" +TCL_PATCH_LEVEL=".0" VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION TCL_DDE_VERSION=1.4 diff --git a/win/configure.in b/win/configure.in index 0426bb1..b0c007a 100644 --- a/win/configure.in +++ b/win/configure.in @@ -14,7 +14,7 @@ SHELL=/bin/sh TCL_VERSION=8.6 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=6 -TCL_PATCH_LEVEL="b3" +TCL_PATCH_LEVEL=".0" VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION TCL_DDE_VERSION=1.4 -- cgit v0.12 From ad8ed66c0296f8baa6364cb9704835ca44b83138 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 8 Nov 2012 15:43:45 +0000 Subject: Declare TclOO portion of the Tcl API to be stable -> TclOO 1.0 --- generic/tclOO.h | 2 +- tests/oo.test | 2 +- tests/ooNext2.test | 2 +- unix/tclooConfig.sh | 2 +- win/tclooConfig.sh | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/generic/tclOO.h b/generic/tclOO.h index 280481c..cf253b1 100644 --- a/generic/tclOO.h +++ b/generic/tclOO.h @@ -39,7 +39,7 @@ extern const char *TclOOInitializeStubs( * win/tclooConfig.sh */ -#define TCLOO_VERSION "0.7" +#define TCLOO_VERSION "1.0" #define TCLOO_PATCHLEVEL TCLOO_VERSION /* diff --git a/tests/oo.test b/tests/oo.test index 540cdf3..5d34077 100644 --- a/tests/oo.test +++ b/tests/oo.test @@ -7,7 +7,7 @@ # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. -package require -exact TclOO 0.7 ;# Must match value in generic/tclOO.h +package require TclOO 1.0 package require tcltest 2 if {"::tcltest" in [namespace children]} { namespace import -force ::tcltest::* diff --git a/tests/ooNext2.test b/tests/ooNext2.test index e78e0d0..d77e8d1 100644 --- a/tests/ooNext2.test +++ b/tests/ooNext2.test @@ -7,7 +7,7 @@ # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. -package require -exact TclOO 0.7 ;# Must match value in configure.in +package require TclOO 1.0 package require tcltest 2 if {"::tcltest" in [namespace children]} { namespace import -force ::tcltest::* diff --git a/unix/tclooConfig.sh b/unix/tclooConfig.sh index dce540a..d2be8dd 100644 --- a/unix/tclooConfig.sh +++ b/unix/tclooConfig.sh @@ -16,4 +16,4 @@ TCLOO_STUB_LIB_SPEC="" TCLOO_INCLUDE_SPEC="" TCLOO_PRIVATE_INCLUDE_SPEC="" TCLOO_CFLAGS=-DUSE_TCLOO_STUBS -TCLOO_VERSION=0.7 +TCLOO_VERSION=1.0 diff --git a/win/tclooConfig.sh b/win/tclooConfig.sh index dce540a..d2be8dd 100644 --- a/win/tclooConfig.sh +++ b/win/tclooConfig.sh @@ -16,4 +16,4 @@ TCLOO_STUB_LIB_SPEC="" TCLOO_INCLUDE_SPEC="" TCLOO_PRIVATE_INCLUDE_SPEC="" TCLOO_CFLAGS=-DUSE_TCLOO_STUBS -TCLOO_VERSION=0.7 +TCLOO_VERSION=1.0 -- cgit v0.12 From 06d38df148ae4415dd9b1ed7afff6d74a5482345 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 2 Dec 2012 14:35:03 +0000 Subject: Allow http, msgcat and tcltest to be loaded by Tcl 9 as well. I think that this should be included in tcl8.6.0: Those 3 packages are so widely used, we don't want to introduce Tcl-level incompatibilities in Tcl9 such that those packages wouldn't work any more. Moved to branch novem-support. For now, novem is a playground. The trunk is not. By all means lets track what we need for migration, but hold back committing to them until we commit more meaningfully to where we're going. --- library/http/http.tcl | 2 +- library/http/pkgIndex.tcl | 2 +- library/msgcat/msgcat.tcl | 2 +- library/msgcat/pkgIndex.tcl | 2 +- library/tcltest/pkgIndex.tcl | 2 +- library/tcltest/tcltest.tcl | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index d57e3ce..c3290c9 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -8,7 +8,7 @@ # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. -package require Tcl 8.6 +package require Tcl 8.6- # Keep this in sync with pkgIndex.tcl and with the install directories in # Makefiles package provide http 2.8.5 diff --git a/library/http/pkgIndex.tcl b/library/http/pkgIndex.tcl index 303d3bd..828c860 100644 --- a/library/http/pkgIndex.tcl +++ b/library/http/pkgIndex.tcl @@ -1,2 +1,2 @@ -if {![package vsatisfies [package provide Tcl] 8.6]} {return} +if {![package vsatisfies [package provide Tcl] 8.6-]} {return} package ifneeded http 2.8.5 [list tclPkgSetup $dir http 2.8.5 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] diff --git a/library/msgcat/msgcat.tcl b/library/msgcat/msgcat.tcl index 112507a..5f8e1e9 100644 --- a/library/msgcat/msgcat.tcl +++ b/library/msgcat/msgcat.tcl @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. -package require Tcl 8.5 +package require Tcl 8.5- # When the version number changes, be sure to update the pkgIndex.tcl file, # and the installation directory in the Makefiles. package provide msgcat 1.5.0 diff --git a/library/msgcat/pkgIndex.tcl b/library/msgcat/pkgIndex.tcl index 832bf81..a5b6499 100644 --- a/library/msgcat/pkgIndex.tcl +++ b/library/msgcat/pkgIndex.tcl @@ -1,2 +1,2 @@ -if {![package vsatisfies [package provide Tcl] 8.5]} {return} +if {![package vsatisfies [package provide Tcl] 8.5-]} {return} package ifneeded msgcat 1.5.0 [list source [file join $dir msgcat.tcl]] diff --git a/library/tcltest/pkgIndex.tcl b/library/tcltest/pkgIndex.tcl index 0e4568d..3769155 100644 --- a/library/tcltest/pkgIndex.tcl +++ b/library/tcltest/pkgIndex.tcl @@ -8,5 +8,5 @@ # script is sourced, the variable $dir must contain the # full path name of this file's directory. -if {![package vsatisfies [package provide Tcl] 8.5]} {return} +if {![package vsatisfies [package provide Tcl] 8.5-]} {return} package ifneeded tcltest 2.3.4 [list source [file join $dir tcltest.tcl]] diff --git a/library/tcltest/tcltest.tcl b/library/tcltest/tcltest.tcl index 02da62f..12692bb 100644 --- a/library/tcltest/tcltest.tcl +++ b/library/tcltest/tcltest.tcl @@ -16,7 +16,7 @@ # Contributions from Don Porter, NIST, 2002. (not subject to US copyright) # All rights reserved. -package require Tcl 8.5 ;# -verbose line uses [info frame] +package require Tcl 8.5- ;# -verbose line uses [info frame] namespace eval tcltest { # When the version number changes, be sure to update the pkgIndex.tcl file, -- cgit v0.12 From b1e66e34704ff978d2dbacea83cc81ae8650a6d0 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 5 Dec 2012 13:31:22 +0000 Subject: Fix gcc warning in cygwin build: implicitely declared function TclUnixOpenTemporaryFile. Move the function to slot 30, and define it (as 0) for win32 as well. --- generic/tclInt.decls | 19 +++++++++---------- generic/tclIntPlatDecls.h | 41 +++++++++++++++++++++++++++-------------- generic/tclStubInit.c | 8 ++++++-- 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/generic/tclInt.decls b/generic/tclInt.decls index 8f8b992..f215d32 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -1148,9 +1148,6 @@ declare 27 win { declare 28 win { void TclWinResetInterfaces(void) } -declare 29 win { - int TclWinCPUID(unsigned int index, unsigned int *regs) -} ################################ # Unix specific functions @@ -1219,12 +1216,6 @@ declare 14 unix { const Tcl_StatBuf *statBufPtr, int dontCopyAtts) } -# Added in 8.6; core of TclpOpenTemporaryFile -declare 20 unix { - int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, Tcl_Obj *basenameObj, - Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj) -} - ################################ # Mac OS X specific functions @@ -1248,9 +1239,17 @@ declare 18 macosx { declare 19 macosx { void TclMacOSXNotifierAddRunLoopMode(const void *runLoopMode) } -declare 29 unix { + +declare 29 {win unix} { int TclWinCPUID(unsigned int index, unsigned int *regs) } +# Added in 8.6; core of TclpOpenTemporaryFile +declare 30 {win unix} { + int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, Tcl_Obj *basenameObj, + Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj) +} + + # Local Variables: # mode: tcl diff --git a/generic/tclIntPlatDecls.h b/generic/tclIntPlatDecls.h index f265e7e..dcf1753 100644 --- a/generic/tclIntPlatDecls.h +++ b/generic/tclIntPlatDecls.h @@ -84,10 +84,7 @@ EXTERN int TclUnixCopyFile(const char *src, const char *dst, /* Slot 17 is reserved */ /* Slot 18 is reserved */ /* Slot 19 is reserved */ -/* 20 */ -EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, - Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, - Tcl_Obj *resultingNameObj); +/* Slot 20 is reserved */ /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ @@ -98,6 +95,10 @@ EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, /* Slot 28 is reserved */ /* 29 */ EXTERN int TclWinCPUID(unsigned int index, unsigned int *regs); +/* 30 */ +EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, + Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, + Tcl_Obj *resultingNameObj); #endif /* UNIX */ #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ /* 0 */ @@ -169,6 +170,10 @@ EXTERN void TclWinFlushDirtyChannels(void); EXTERN void TclWinResetInterfaces(void); /* 29 */ EXTERN int TclWinCPUID(unsigned int index, unsigned int *regs); +/* 30 */ +EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, + Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, + Tcl_Obj *resultingNameObj); #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 0 */ @@ -228,10 +233,7 @@ EXTERN int TclMacOSXMatchType(Tcl_Interp *interp, /* 19 */ EXTERN void TclMacOSXNotifierAddRunLoopMode( const void *runLoopMode); -/* 20 */ -EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, - Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, - Tcl_Obj *resultingNameObj); +/* Slot 20 is reserved */ /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ @@ -242,6 +244,10 @@ EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, /* Slot 28 is reserved */ /* 29 */ EXTERN int TclWinCPUID(unsigned int index, unsigned int *regs); +/* 30 */ +EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, + Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, + Tcl_Obj *resultingNameObj); #endif /* MACOSX */ typedef struct TclIntPlatStubs { @@ -269,7 +275,7 @@ typedef struct TclIntPlatStubs { void (*reserved17)(void); void (*reserved18)(void); void (*reserved19)(void); - int (*tclUnixOpenTemporaryFile) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj); /* 20 */ + void (*reserved20)(void); void (*reserved21)(void); void (*reserved22)(void); void (*reserved23)(void); @@ -279,6 +285,7 @@ typedef struct TclIntPlatStubs { void (*reserved27)(void); void (*reserved28)(void); int (*tclWinCPUID) (unsigned int index, unsigned int *regs); /* 29 */ + int (*tclUnixOpenTemporaryFile) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj); /* 30 */ #endif /* UNIX */ #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ void (*tclWinConvertError) (DWORD errCode); /* 0 */ @@ -311,6 +318,7 @@ typedef struct TclIntPlatStubs { void (*tclWinFlushDirtyChannels) (void); /* 27 */ void (*tclWinResetInterfaces) (void); /* 28 */ int (*tclWinCPUID) (unsigned int index, unsigned int *regs); /* 29 */ + int (*tclUnixOpenTemporaryFile) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj); /* 30 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ void (*tclGetAndDetachPids) (Tcl_Interp *interp, Tcl_Channel chan); /* 0 */ @@ -333,7 +341,7 @@ typedef struct TclIntPlatStubs { int (*tclMacOSXCopyFileAttributes) (const char *src, const char *dst, const Tcl_StatBuf *statBufPtr); /* 17 */ int (*tclMacOSXMatchType) (Tcl_Interp *interp, const char *pathName, const char *fileName, Tcl_StatBuf *statBufPtr, Tcl_GlobTypeData *types); /* 18 */ void (*tclMacOSXNotifierAddRunLoopMode) (const void *runLoopMode); /* 19 */ - int (*tclUnixOpenTemporaryFile) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj); /* 20 */ + void (*reserved20)(void); void (*reserved21)(void); void (*reserved22)(void); void (*reserved23)(void); @@ -343,6 +351,7 @@ typedef struct TclIntPlatStubs { void (*reserved27)(void); void (*reserved28)(void); int (*tclWinCPUID) (unsigned int index, unsigned int *regs); /* 29 */ + int (*tclUnixOpenTemporaryFile) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj); /* 30 */ #endif /* MACOSX */ } TclIntPlatStubs; @@ -395,8 +404,7 @@ extern const TclIntPlatStubs *tclIntPlatStubsPtr; /* Slot 17 is reserved */ /* Slot 18 is reserved */ /* Slot 19 is reserved */ -#define TclUnixOpenTemporaryFile \ - (tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 20 */ +/* Slot 20 is reserved */ /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ @@ -407,6 +415,8 @@ extern const TclIntPlatStubs *tclIntPlatStubsPtr; /* Slot 28 is reserved */ #define TclWinCPUID \ (tclIntPlatStubsPtr->tclWinCPUID) /* 29 */ +#define TclUnixOpenTemporaryFile \ + (tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 30 */ #endif /* UNIX */ #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ #define TclWinConvertError \ @@ -467,6 +477,8 @@ extern const TclIntPlatStubs *tclIntPlatStubsPtr; (tclIntPlatStubsPtr->tclWinResetInterfaces) /* 28 */ #define TclWinCPUID \ (tclIntPlatStubsPtr->tclWinCPUID) /* 29 */ +#define TclUnixOpenTemporaryFile \ + (tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 30 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ #define TclGetAndDetachPids \ @@ -508,8 +520,7 @@ extern const TclIntPlatStubs *tclIntPlatStubsPtr; (tclIntPlatStubsPtr->tclMacOSXMatchType) /* 18 */ #define TclMacOSXNotifierAddRunLoopMode \ (tclIntPlatStubsPtr->tclMacOSXNotifierAddRunLoopMode) /* 19 */ -#define TclUnixOpenTemporaryFile \ - (tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 20 */ +/* Slot 20 is reserved */ /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ @@ -520,6 +531,8 @@ extern const TclIntPlatStubs *tclIntPlatStubsPtr; /* Slot 28 is reserved */ #define TclWinCPUID \ (tclIntPlatStubsPtr->tclWinCPUID) /* 29 */ +#define TclUnixOpenTemporaryFile \ + (tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 30 */ #endif /* MACOSX */ #endif /* defined(USE_TCL_STUBS) */ diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 0bede56..88ada19 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -65,6 +65,7 @@ static unsigned short TclWinNToHS(unsigned short ns) { #ifdef __WIN32__ # define TclUnixWaitForFile 0 # define TclUnixCopyFile 0 +# define TclUnixOpenTemporaryFile 0 # define TclpReaddir 0 # define TclpIsAtty 0 #elif defined(__CYGWIN__) @@ -465,7 +466,7 @@ static const TclIntPlatStubs tclIntPlatStubs = { 0, /* 17 */ 0, /* 18 */ 0, /* 19 */ - TclUnixOpenTemporaryFile, /* 20 */ + 0, /* 20 */ 0, /* 21 */ 0, /* 22 */ 0, /* 23 */ @@ -475,6 +476,7 @@ static const TclIntPlatStubs tclIntPlatStubs = { 0, /* 27 */ 0, /* 28 */ TclWinCPUID, /* 29 */ + TclUnixOpenTemporaryFile, /* 30 */ #endif /* UNIX */ #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ TclWinConvertError, /* 0 */ @@ -507,6 +509,7 @@ static const TclIntPlatStubs tclIntPlatStubs = { TclWinFlushDirtyChannels, /* 27 */ TclWinResetInterfaces, /* 28 */ TclWinCPUID, /* 29 */ + TclUnixOpenTemporaryFile, /* 30 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ TclGetAndDetachPids, /* 0 */ @@ -529,7 +532,7 @@ static const TclIntPlatStubs tclIntPlatStubs = { TclMacOSXCopyFileAttributes, /* 17 */ TclMacOSXMatchType, /* 18 */ TclMacOSXNotifierAddRunLoopMode, /* 19 */ - TclUnixOpenTemporaryFile, /* 20 */ + 0, /* 20 */ 0, /* 21 */ 0, /* 22 */ 0, /* 23 */ @@ -539,6 +542,7 @@ static const TclIntPlatStubs tclIntPlatStubs = { 0, /* 27 */ 0, /* 28 */ TclWinCPUID, /* 29 */ + TclUnixOpenTemporaryFile, /* 30 */ #endif /* MACOSX */ }; -- cgit v0.12 From 80f5d8964ac592076e2adbb83d4402382d01914d Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 5 Dec 2012 14:42:48 +0000 Subject: use Tcl_PkgProvideEx everywhere (again, for testing purposes) --- generic/tclTest.c | 2 +- generic/tclTestProcBodyObj.c | 2 +- generic/tclZlib.c | 2 +- unix/dltest/pkga.c | 2 +- unix/dltest/pkgb.c | 4 ++-- unix/dltest/pkgc.c | 4 ++-- unix/dltest/pkgd.c | 4 ++-- unix/dltest/pkgua.c | 2 +- win/tclWinDde.c | 2 +- win/tclWinReg.c | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/generic/tclTest.c b/generic/tclTest.c index a8b27fb..b112e2d 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -544,7 +544,7 @@ Tcltest_Init( } /* TIP #268: Full patchlevel instead of just major.minor */ - if (Tcl_PkgProvide(interp, "Tcltest", TCL_PATCH_LEVEL) == TCL_ERROR) { + if (Tcl_PkgProvideEx(interp, "Tcltest", TCL_PATCH_LEVEL, NULL) == TCL_ERROR) { return TCL_ERROR; } diff --git a/generic/tclTestProcBodyObj.c b/generic/tclTestProcBodyObj.c index a3f89f6..7b33895 100644 --- a/generic/tclTestProcBodyObj.c +++ b/generic/tclTestProcBodyObj.c @@ -185,7 +185,7 @@ ProcBodyTestInitInternal( } } - return Tcl_PkgProvide(interp, packageName, packageVersion); + return Tcl_PkgProvideEx(interp, packageName, packageVersion, NULL); } /* diff --git a/generic/tclZlib.c b/generic/tclZlib.c index 8fbe049..c85123b 100644 --- a/generic/tclZlib.c +++ b/generic/tclZlib.c @@ -3884,7 +3884,7 @@ TclZlibInit( * Formally provide the package as a Tcl built-in. */ - return Tcl_PkgProvide(interp, "zlib", TCL_ZLIB_VERSION); + return Tcl_PkgProvideEx(interp, "zlib", TCL_ZLIB_VERSION, NULL); } /* diff --git a/unix/dltest/pkga.c b/unix/dltest/pkga.c index 901f4c9..8d40758 100644 --- a/unix/dltest/pkga.c +++ b/unix/dltest/pkga.c @@ -134,7 +134,7 @@ Pkga_Init( if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) { return TCL_ERROR; } - code = Tcl_PkgProvide(interp, "Pkga", "1.0"); + code = Tcl_PkgProvideEx(interp, "Pkga", "1.0", NULL); if (code != TCL_OK) { return code; } diff --git a/unix/dltest/pkgb.c b/unix/dltest/pkgb.c index b00d4e5..f6f7bbb 100644 --- a/unix/dltest/pkgb.c +++ b/unix/dltest/pkgb.c @@ -124,7 +124,7 @@ Pkgb_Init( if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) { return TCL_ERROR; } - code = Tcl_PkgProvide(interp, "Pkgb", "2.3"); + code = Tcl_PkgProvideEx(interp, "Pkgb", "2.3", NULL); if (code != TCL_OK) { return code; } @@ -161,7 +161,7 @@ Pkgb_SafeInit( if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) { return TCL_ERROR; } - code = Tcl_PkgProvide(interp, "Pkgb", "2.3"); + code = Tcl_PkgProvideEx(interp, "Pkgb", "2.3", NULL); if (code != TCL_OK) { return code; } diff --git a/unix/dltest/pkgc.c b/unix/dltest/pkgc.c index e5678dc..a70f929 100644 --- a/unix/dltest/pkgc.c +++ b/unix/dltest/pkgc.c @@ -124,7 +124,7 @@ Pkgc_Init( if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) { return TCL_ERROR; } - code = Tcl_PkgProvide(interp, "Pkgc", "1.7.2"); + code = Tcl_PkgProvideEx(interp, "Pkgc", "1.7.2", NULL); if (code != TCL_OK) { return code; } @@ -161,7 +161,7 @@ Pkgc_SafeInit( if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) { return TCL_ERROR; } - code = Tcl_PkgProvide(interp, "Pkgc", "1.7.2"); + code = Tcl_PkgProvideEx(interp, "Pkgc", "1.7.2", NULL); if (code != TCL_OK) { return code; } diff --git a/unix/dltest/pkgd.c b/unix/dltest/pkgd.c index 877489c..e6538cd 100644 --- a/unix/dltest/pkgd.c +++ b/unix/dltest/pkgd.c @@ -124,7 +124,7 @@ Pkgd_Init( if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) { return TCL_ERROR; } - code = Tcl_PkgProvide(interp, "Pkgd", "7.3"); + code = Tcl_PkgProvideEx(interp, "Pkgd", "7.3", NULL); if (code != TCL_OK) { return code; } @@ -161,7 +161,7 @@ Pkgd_SafeInit( if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) { return TCL_ERROR; } - code = Tcl_PkgProvide(interp, "Pkgd", "7.3"); + code = Tcl_PkgProvideEx(interp, "Pkgd", "7.3", NULL); if (code != TCL_OK) { return code; } diff --git a/unix/dltest/pkgua.c b/unix/dltest/pkgua.c index 18a1cac..87df4a0 100644 --- a/unix/dltest/pkgua.c +++ b/unix/dltest/pkgua.c @@ -219,7 +219,7 @@ Pkgua_Init( PkguaInitTokensHashTable(); - code = Tcl_PkgProvide(interp, "Pkgua", "1.0"); + code = Tcl_PkgProvideEx(interp, "Pkgua", "1.0", NULL); if (code != TCL_OK) { return code; } diff --git a/win/tclWinDde.c b/win/tclWinDde.c index 13e1f18..4df308b 100644 --- a/win/tclWinDde.c +++ b/win/tclWinDde.c @@ -170,7 +170,7 @@ Dde_Init( #endif Tcl_CreateObjCommand(interp, "dde", DdeObjCmd, NULL, NULL); Tcl_CreateExitHandler(DdeExitProc, NULL); - return Tcl_PkgProvide(interp, TCL_DDE_PACKAGE_NAME, TCL_DDE_VERSION); + return Tcl_PkgProvideEx(interp, TCL_DDE_PACKAGE_NAME, TCL_DDE_VERSION, NULL); } /* diff --git a/win/tclWinReg.c b/win/tclWinReg.c index 8bb14d0..8b13afb 100644 --- a/win/tclWinReg.c +++ b/win/tclWinReg.c @@ -172,7 +172,7 @@ Registry_Init( cmd = Tcl_CreateObjCommand(interp, "registry", RegistryObjCmd, interp, DeleteCmd); Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, cmd); - return Tcl_PkgProvide(interp, "registry", "1.3.0"); + return Tcl_PkgProvideEx(interp, "registry", "1.3.0", NULL); } /* -- cgit v0.12 From 6a27e83c7193e742481d954eddb39a02586b54bf Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 5 Dec 2012 22:38:20 +0000 Subject: do some Tcl_EvalEx, for test-purposes, demonstrating a crash --- unix/dltest/pkgb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/unix/dltest/pkgb.c b/unix/dltest/pkgb.c index f6f7bbb..772b239 100644 --- a/unix/dltest/pkgb.c +++ b/unix/dltest/pkgb.c @@ -93,8 +93,7 @@ Pkgb_UnsafeObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - Tcl_SetObjResult(interp, Tcl_NewStringObj("unsafe command invoked", -1)); - return TCL_OK; + return Tcl_EvalEx(interp, "list unsafe command invoked", -1, TCL_EVAL_GLOBAL); } /* -- cgit v0.12 From 92b20ad57f4d24e7d2d915c6059e0decb570276d Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 6 Dec 2012 21:03:22 +0000 Subject: Tcl_InitStubs("8.5",1) would succeed in an "8.50" interp. Fixed. --- generic/tclStubLib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclStubLib.c b/generic/tclStubLib.c index 871d7ea..9774731 100644 --- a/generic/tclStubLib.c +++ b/generic/tclStubLib.c @@ -118,7 +118,7 @@ Tcl_InitStubs( while (*p && (*p == *q)) { p++; q++; } - if (*p) { + if (*p || isDigit(*q)) { /* Construct error message */ Tcl_PkgRequireEx(interp, "Tcl", version, 1, NULL); return NULL; -- cgit v0.12 From 99bda89c0b6500e673ecacd280527492c780b562 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 7 Dec 2012 14:53:40 +0000 Subject: Extended test of [load]ing Tcl 8 compiled extension into Tcl 9 interp. --- unix/dltest/pkgb.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/unix/dltest/pkgb.c b/unix/dltest/pkgb.c index 02bd233..9c199ca 100644 --- a/unix/dltest/pkgb.c +++ b/unix/dltest/pkgb.c @@ -30,6 +30,8 @@ static int Pkgb_SubObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int Pkgb_UnsafeObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); +static int Pkgb_DemoObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* *---------------------------------------------------------------------- @@ -95,6 +97,17 @@ Pkgb_UnsafeObjCmd( { return Tcl_EvalEx(interp, "list unsafe command invoked", -1, TCL_EVAL_GLOBAL); } + +static int +Pkgb_DemoObjCmd( + ClientData dummy, /* Not used. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[]) /* Argument objects. */ +{ + const char *foo = Tcl_GetDefaultEncodingDir(); + return TCL_OK; +} /* *---------------------------------------------------------------------- @@ -128,8 +141,8 @@ Pkgb_Init( return code; } Tcl_CreateObjCommand(interp, "pkgb_sub", Pkgb_SubObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "pkgb_unsafe", Pkgb_UnsafeObjCmd, NULL, - NULL); + Tcl_CreateObjCommand(interp, "pkgb_unsafe", Pkgb_UnsafeObjCmd, NULL, NULL); + Tcl_CreateObjCommand(interp, "pkgb_demo", Pkgb_DemoObjCmd, NULL, NULL); return TCL_OK; } -- cgit v0.12 From fa2a03a1bf7c810f5d6fb14da98de6d4526339af Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 7 Dec 2012 15:51:25 +0000 Subject: add proper runtime-detection to pkgb.so --- unix/dltest/pkgb.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/unix/dltest/pkgb.c b/unix/dltest/pkgb.c index 9c199ca..1a362ef 100644 --- a/unix/dltest/pkgb.c +++ b/unix/dltest/pkgb.c @@ -98,6 +98,11 @@ Pkgb_UnsafeObjCmd( return Tcl_EvalEx(interp, "list unsafe command invoked", -1, TCL_EVAL_GLOBAL); } +#if (TCL_MAJOR_VERSION > 8) +# define Tcl_GetDefaultEncodingDir ((const char *(*)(void)) \ + ((&(tclStubsPtr->tcl_PkgProvideEx))[341])) +#endif + static int Pkgb_DemoObjCmd( ClientData dummy, /* Not used. */ @@ -105,7 +110,11 @@ Pkgb_DemoObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - const char *foo = Tcl_GetDefaultEncodingDir(); + if(!Tcl_GetDefaultEncodingDir) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("not supported", -1)); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetDefaultEncodingDir(), -1)); return TCL_OK; } -- cgit v0.12 From ef331c2b06dede42238295f9b0fbaedb83f668b2 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 7 Dec 2012 15:53:29 +0000 Subject: fix failing test --- tests/load.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/load.test b/tests/load.test index eef677f..cded85d 100644 --- a/tests/load.test +++ b/tests/load.test @@ -188,7 +188,7 @@ test load-8.3 {TclGetLoadedPackages procedure} [list teststaticpkg $dll $loaded] test load-8.4 {TclGetLoadedPackages procedure} [list $dll $loaded teststaticpkg] { load [file join $testDir pkgb$ext] pkgb list [info loaded {}] [lsort [info commands pkgb_*]] -} [list [concat [list [list [file join $testDir pkgb$ext] Pkgb] {{} Double} {{} More} {{} Another} {{} Test} [list [file join $testDir pkga$ext] Pkga]] $alreadyLoaded] {pkgb_sub pkgb_unsafe}] +} [list [concat [list [list [file join $testDir pkgb$ext] Pkgb] {{} Double} {{} More} {{} Another} {{} Test} [list [file join $testDir pkga$ext] Pkga]] $alreadyLoaded] {pkgb_demo pkgb_sub pkgb_unsafe}] interp delete child test load-9.1 {Tcl_StaticPackage, load already-loaded package into another interp} \ -- cgit v0.12 From a4a99b73219c5f30bd18f6349427c834691b2c46 Mon Sep 17 00:00:00 2001 From: mig Date: Fri, 7 Dec 2012 15:56:13 +0000 Subject: small correction in doc/NRE.3 --- doc/NRE.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/NRE.3 b/doc/NRE.3 index be2c58b..4ad78b3 100644 --- a/doc/NRE.3 +++ b/doc/NRE.3 @@ -295,7 +295,7 @@ int int result) { /* \fIdata[0] .. data[3]\fR are the four words of data - * passed to \fBTcl_NREvalObj\fR */ + * passed to \fBTcl_NRAddCallback\fR */ \fI... postprocessing ...\fR -- cgit v0.12 From cee1ce03b712770dc55c7c3b4b65c5026546d53f Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 7 Dec 2012 17:03:39 +0000 Subject: Source compat, rather than stubs compat demo. --- unix/dltest/pkgb.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/unix/dltest/pkgb.c b/unix/dltest/pkgb.c index 1a362ef..9884a64 100644 --- a/unix/dltest/pkgb.c +++ b/unix/dltest/pkgb.c @@ -99,8 +99,19 @@ Pkgb_UnsafeObjCmd( } #if (TCL_MAJOR_VERSION > 8) -# define Tcl_GetDefaultEncodingDir ((const char *(*)(void)) \ - ((&(tclStubsPtr->tcl_PkgProvideEx))[341])) +const char *Tcl_GetDefaultEncodingDir(void) +{ + int numDirs; + Tcl_Obj *first, *searchPath = Tcl_GetEncodingSearchPath(); + + Tcl_ListObjLength(NULL, searchPath, &numDirs); + if (numDirs == 0) { + return NULL; + } + Tcl_ListObjIndex(NULL, searchPath, 0, &first); + + return Tcl_GetString(first); +} #endif static int @@ -110,10 +121,6 @@ Pkgb_DemoObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - if(!Tcl_GetDefaultEncodingDir) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("not supported", -1)); - return TCL_ERROR; - } Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetDefaultEncodingDir(), -1)); return TCL_OK; } -- cgit v0.12 From 6d6c732492789c16c16f822a7b3ae1421261b86d Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 7 Dec 2012 18:07:18 +0000 Subject: 3593703 Don't crash on bad input to Tcl_PkgRequire*(). --- generic/tclPkg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/generic/tclPkg.c b/generic/tclPkg.c index aed80c0..b3396e6 100644 --- a/generic/tclPkg.c +++ b/generic/tclPkg.c @@ -353,6 +353,10 @@ PkgRequireCore( char *script, *pkgVersionI; Tcl_DString command; + if (TCL_OK != CheckAllRequirements(interp, reqc, reqv)) { + return NULL; + } + /* * 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 -- cgit v0.12 From e76d16d3eba7f034fc003f1061736c298b03c74f Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 7 Dec 2012 21:28:49 +0000 Subject: only set tclStubsPtr if all version checks pass. Backported from tcl 8.5. --- generic/tclStubLib.c | 105 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/generic/tclStubLib.c b/generic/tclStubLib.c index 7bf04a0..39e94c8 100644 --- a/generic/tclStubLib.c +++ b/generic/tclStubLib.c @@ -1,45 +1,26 @@ -/* +/* * tclStubLib.c -- * - * Stub object that will be statically linked into extensions that wish + * Stub object that will be statically linked into extensions that want * to access Tcl. * * Copyright (c) 1998-1999 by Scriptics Corporation. * 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. - */ - -/* - * 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 - * to build an extension that references Tcl_InitStubs but doesn't end up - * including the rest of the stub functions. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -#ifndef USE_TCL_STUBS -#define USE_TCL_STUBS -#endif -#undef USE_TCL_STUB_PROCS - #include "tclInt.h" #include "tclPort.h" -/* - * Ensure that Tcl_InitStubs is built as an exported symbol. The other stub - * functions should be built as non-exported symbols. - */ - TclStubs *tclStubsPtr = NULL; TclPlatStubs *tclPlatStubsPtr = NULL; TclIntStubs *tclIntStubsPtr = NULL; TclIntPlatStubs *tclIntPlatStubsPtr = NULL; -static TclStubs * HasStubSupport _ANSI_ARGS_((Tcl_Interp *interp)); - static TclStubs * -HasStubSupport (interp) +HasStubSupport(interp) Tcl_Interp *interp; { Interp *iPtr = (Interp *) interp; @@ -49,57 +30,87 @@ HasStubSupport (interp) } interp->result = "interpreter uses an incompatible stubs mechanism"; interp->freeProc = TCL_STATIC; - return NULL; } /* + * Use our own isdigit to avoid linking to libc on windows + */ + +static int isDigit(const int c) +{ + return (c >= '0' && c <= '9'); +} + +/* *---------------------------------------------------------------------- * * Tcl_InitStubs -- * - * Tries to initialise the stub table pointers and ensures that - * the correct version of Tcl is loaded. + * Tries to initialise the stub table pointers and ensures that the + * correct version of Tcl is loaded. * * Results: - * The actual version of Tcl that satisfies the request, or - * NULL to indicate that an error occurred. + * The actual version of Tcl that satisfies the request, or NULL to + * indicate that an error occurred. * * Side effects: * Sets the stub table pointers. * *---------------------------------------------------------------------- */ - -#ifdef Tcl_InitStubs #undef Tcl_InitStubs -#endif - CONST char * -Tcl_InitStubs (interp, version, exact) +Tcl_InitStubs(interp, version, exact) Tcl_Interp *interp; CONST char *version; int exact; { CONST char *actualVersion = NULL; - ClientData pkgData = NULL; + TclStubs *stubsPtr; /* - * 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] + * 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] */ - tclStubsPtr = HasStubSupport(interp); - if (!tclStubsPtr) { + stubsPtr = HasStubSupport(interp); + if (!stubsPtr) { return NULL; } - actualVersion = Tcl_PkgRequireEx(interp, "Tcl", version, exact, &pkgData); + actualVersion = stubsPtr->tcl_PkgRequireEx(interp, "Tcl", version, 0, NULL); if (actualVersion == NULL) { return NULL; } - tclStubsPtr = (TclStubs*)pkgData; + if (exact) { + CONST char *p = version; + int count = 0; + + while (*p) { + count += !isDigit(*p++); + } + if (count == 1) { + CONST char *q = actualVersion; + + p = version; + while (*p && (*p == *q)) { + p++; q++; + } + if (*p || isDigit(*q)) { + /* Construct error message */ + stubsPtr->tcl_PkgRequireEx(interp, "Tcl", version, 1, NULL); + return NULL; + } + } else { + actualVersion = stubsPtr->tcl_PkgRequireEx(interp, "Tcl", version, 1, NULL); + if (actualVersion == NULL) { + return NULL; + } + } + } + tclStubsPtr = stubsPtr; if (tclStubsPtr->hooks) { tclPlatStubsPtr = tclStubsPtr->hooks->tclPlatStubs; @@ -110,6 +121,14 @@ Tcl_InitStubs (interp, version, exact) tclIntStubsPtr = NULL; tclIntPlatStubsPtr = NULL; } - + return actualVersion; } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ -- cgit v0.12 From 8ea32cad84602b02b1eab7b2ca01bf583bd1c9db Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 7 Dec 2012 22:14:26 +0000 Subject: just lost one MODULE_SCOPE in the merge --- generic/tclStubLib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclStubLib.c b/generic/tclStubLib.c index 5a122dd..b8979df 100644 --- a/generic/tclStubLib.c +++ b/generic/tclStubLib.c @@ -64,7 +64,7 @@ static int isDigit(const int c) *---------------------------------------------------------------------- */ #undef Tcl_InitStubs -const char * +MODULE_SCOPE const char * Tcl_InitStubs( Tcl_Interp *interp, const char *version, -- cgit v0.12 From 5ab4d052c526754eca52cbec0aea41c6a61d7fb6 Mon Sep 17 00:00:00 2001 From: ferrieux Date: Sat, 8 Dec 2012 17:13:03 +0000 Subject: Fix busyloop at exit under TCL_FINALIZE_ON_EXIT when there are unflushed nonblocking channels. Thanks Miguel for spotting. --- ChangeLog | 5 +++++ generic/tclIO.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 37c3e2e..c1a3ff7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-12-08 Alexandre Ferrieux + * generic/tclIO.c: Fix busyloop at exit under TCL_FINALIZE_ON_EXIT + when there are unflushed nonblocking channels. Thanks Miguel for + spotting. + 2012-12-07 Jan Nijtmans * unix/dltest/pkgb.c: Turn pkgb.so into a Tcl9 interoperability test diff --git a/generic/tclIO.c b/generic/tclIO.c index 0cb9fa9..715c1ef 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -2472,7 +2472,7 @@ FlushChannel( * it's a tty channel (dup'ed underneath) */ - if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { + if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED) && !TclInExit()) { SetFlag(statePtr, BG_FLUSH_SCHEDULED); UpdateInterest(chanPtr); } -- cgit v0.12 From ff12195b2b7d3b9d0f8f4441bd3ec0c991ba742b Mon Sep 17 00:00:00 2001 From: ferrieux Date: Sun, 9 Dec 2012 11:52:04 +0000 Subject: Clean up unwanted eofchar side-effect of chan-4.6 leading to a spurious "'" at end of chan.test under certain conditions (see [Bug 3389289] and [Bug 3389251]). --- ChangeLog | 5 +++++ tests/chan.test | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index c1a3ff7..aeb6a62 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-12-09 Alexandre Ferrieux + * tests/chan.test: Clean up unwanted eofchar side-effect of + chan-4.6 leading to a spurious "'" at end of chan.test under + certain conditions (see [Bug 3389289] and [Bug 3389251]). + 2012-12-08 Alexandre Ferrieux * generic/tclIO.c: Fix busyloop at exit under TCL_FINALIZE_ON_EXIT when there are unflushed nonblocking channels. Thanks Miguel for diff --git a/tests/chan.test b/tests/chan.test index da44ffd..d8390e2 100644 --- a/tests/chan.test +++ b/tests/chan.test @@ -61,7 +61,7 @@ test chan-4.5 {chan command: check valid inValue, invalid outValue} -body { } -returnCodes error -match glob -result {bad value for -eofchar:*} test chan-4.6 {chan command: check no inValue, valid outValue} -body { chan configure stdout -eofchar [list {} \x27] -} -returnCodes ok -result {} +} -returnCodes ok -result {} -cleanup {chan configure stdout -eofchar [list {} {}]} test chan-5.1 {chan command: copy subcommand} -body { chan copy foo -- cgit v0.12 From a68a31f4bff004ca60d9cf17cb74a9fc8b94d2ed Mon Sep 17 00:00:00 2001 From: ferrieux Date: Sun, 9 Dec 2012 19:44:57 +0000 Subject: [Bug 3594188] Clarifications about commas. --- ChangeLog | 1 + doc/expr.n | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index aeb6a62..9c42929 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ * tests/chan.test: Clean up unwanted eofchar side-effect of chan-4.6 leading to a spurious "'" at end of chan.test under certain conditions (see [Bug 3389289] and [Bug 3389251]). + * doc/expr.n: [Bug 3594188] Clarifications about commas. 2012-12-08 Alexandre Ferrieux * generic/tclIO.c: Fix busyloop at exit under TCL_FINALIZE_ON_EXIT diff --git a/doc/expr.n b/doc/expr.n index 6d965fb..8698f5c 100644 --- a/doc/expr.n +++ b/doc/expr.n @@ -39,9 +39,9 @@ additional operators not found in C. .SS OPERANDS .PP A Tcl expression consists of a combination of operands, operators, -and parentheses. +parentheses and commas. White space may be used between the operands and operators and -parentheses; it is ignored by the expression's instructions. +parentheses (or commas); it is ignored by the expression's instructions. Where possible, operands are interpreted as integer values. Integer values may be specified in decimal (the normal case), in binary (if the first two characters of the operand are \fB0b\fR), in octal @@ -283,6 +283,18 @@ rules for resolving functions in namespaces. Either current]::tcl::mathfunc::sin\fR will satisfy the request, and others may as well (depending on the current \fBnamespace path\fR setting). .PP +Some mathematical functions have several arguments, separated by commas like in C. Thus: +.PP +.CS +\fBexpr\fR {hypot($x,$y)} +.CE +.PP +ends up as +.PP +.CS +tcl::mathfunc::hypot $x $y +.CE +.PP See the \fBmathfunc\fR(n) manual page for the math functions that are available by default. .SS "TYPES, OVERFLOW, AND PRECISION" -- cgit v0.12 From e595fefe85b468cabc5e2cbebb030a525b46228f Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 10 Dec 2012 14:08:59 +0000 Subject: Restore the initialization of tclStubsPtr from the "Tcl" package clientData so that we don't close off a potential avenue of future innovations. --- generic/tclStubLib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/generic/tclStubLib.c b/generic/tclStubLib.c index 39e94c8..ceee8f3 100644 --- a/generic/tclStubLib.c +++ b/generic/tclStubLib.c @@ -67,6 +67,7 @@ Tcl_InitStubs(interp, version, exact) int exact; { CONST char *actualVersion = NULL; + ClientData pkgData = NULL; TclStubs *stubsPtr; /* @@ -80,7 +81,7 @@ Tcl_InitStubs(interp, version, exact) return NULL; } - actualVersion = stubsPtr->tcl_PkgRequireEx(interp, "Tcl", version, 0, NULL); + actualVersion = stubsPtr->tcl_PkgRequireEx(interp, "Tcl", version, 0, &pkgData); if (actualVersion == NULL) { return NULL; } @@ -110,7 +111,7 @@ Tcl_InitStubs(interp, version, exact) } } } - tclStubsPtr = stubsPtr; + tclStubsPtr = (TclStubs *)pkgData; if (tclStubsPtr->hooks) { tclPlatStubsPtr = tclStubsPtr->hooks->tclPlatStubs; -- cgit v0.12 From 005010e14da826074d8b45810962d7eee6fe8c36 Mon Sep 17 00:00:00 2001 From: dkf Date: Mon, 10 Dec 2012 23:23:50 +0000 Subject: Improve the generation of HTML documentation in 8.6, allowing for contributed packages whose non-version name parts are prefixes of others. Also ensure that documentation builds are complete after distribution, and that we generate a better error message when using the wrong tclsh version to do the build. --- ChangeLog | 29 ++++++++++++++++++++--------- tools/tcltk-man2html.tcl | 22 +++++++++++++++------- unix/Makefile.in | 3 ++- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9c42929..9beccc7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,12 +1,23 @@ +2012-12-10 Donal K. Fellows + + * tools/tcltk-man2html.tcl (plus-pkgs): Increased robustness of + version number detection code to deal with packages whose names are + prefixes of other packages. + * unix/Makefile.in (dist): Added pkgs/package.list.txt to distribution + builds to ensure that 'make html' will work better. + 2012-12-09 Alexandre Ferrieux - * tests/chan.test: Clean up unwanted eofchar side-effect of - chan-4.6 leading to a spurious "'" at end of chan.test under - certain conditions (see [Bug 3389289] and [Bug 3389251]). - * doc/expr.n: [Bug 3594188] Clarifications about commas. + + * tests/chan.test: Clean up unwanted eofchar side-effect of chan-4.6 + leading to a spurious "'" at end of chan.test under certain conditions + (see [Bug 3389289] and [Bug 3389251]). + + * doc/expr.n: [Bug 3594188]: Clarifications about commas. 2012-12-08 Alexandre Ferrieux + * generic/tclIO.c: Fix busyloop at exit under TCL_FINALIZE_ON_EXIT - when there are unflushed nonblocking channels. Thanks Miguel for + when there are unflushed nonblocking channels. Thanks Miguel for spotting. 2012-12-07 Jan Nijtmans @@ -24,10 +35,10 @@ 2012-11-26 Reinhard Max * unix/tclUnixSock.c: Factor out creation of the -sockname and - -peername lists from TcpGetOptionProc() to TcpHostPortList(). - Make it robust against implementations of getnameinfo() that error - out if reverse mapping fails instead of falling back to the - numeric representation. + -peername lists from TcpGetOptionProc() to TcpHostPortList(). Make it + robust against implementations of getnameinfo() that error out if + reverse mapping fails instead of falling back to the numeric + representation. 2012-11-20 Donal K. Fellows diff --git a/tools/tcltk-man2html.tcl b/tools/tcltk-man2html.tcl index 665a1d4..270a774 100755 --- a/tools/tcltk-man2html.tcl +++ b/tools/tcltk-man2html.tcl @@ -1,6 +1,12 @@ #!/usr/bin/env tclsh -package require Tcl 8.6 +if {[catch {package require Tcl 8.6} msg]} { + puts stderr "ERROR: $msg" + puts stderr "If running this script from 'make html', set the\ + NATIVE_TCLSH environment\nvariable to point to an installed\ + tclsh8.6 (or the equivalent tclsh86.exe\non Windows)." + exit 1 +} # Convert Ousterhout format man pages into highly crosslinked hypertext. # @@ -16,7 +22,7 @@ package require Tcl 8.6 # Copyright (c) 1995-1997 Roger E. Critchlow Jr # Copyright (c) 2004-2010 Donal K. Fellows -regexp {\d+\.\d+} {$Revision: 1.49 $} ::Version +set ::Version "50/8.6" set ::CSSFILE "docs.css" ## @@ -454,16 +460,18 @@ proc plus-pkgs {type args} { } if {!$build_tcl} return set result {} + set pkgsdir $tcltkdir/$tcldir/pkgs foreach {dir name} $args { - set globpat $tcltkdir/$tcldir/pkgs/$dir*/doc/*.$type - if {![llength [glob -nocomplain $globpat]]} { + set globpat $pkgsdir/{$dir,$dir\[0-9\]*}/doc/*.$type + if {![llength [glob -type f -nocomplain $globpat]]} { # Fallback for manpages generated using doctools - set globpat $tcltkdir/$tcldir/pkgs/$dir*/doc/man/*.$type - if {![llength [glob -nocomplain $globpat]]} { + set globpat $pkgsdir/{$dir,$dir\[0-9\]*}/doc/man/*.$type + if {![llength [glob -type f -nocomplain $globpat]]} { continue } } - regexp "pkgs/${dir}(.*)/doc$" [glob $tcltkdir/$tcldir/pkgs/$dir*/doc] \ + regexp "pkgs/${dir}(.*)/doc$" \ + [lindex [glob -type d $pkgsdir/{$dir,$dir\[0-9\]*}/doc] 0] \ -> version switch $type { n { diff --git a/unix/Makefile.in b/unix/Makefile.in index df05759..680d4ce 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -2019,7 +2019,8 @@ dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tclConfig.h.in $(UNIX_DIR)/tcl.pc.in $(M cp -p $(TOMMATH_SRCS) $(TOMMATH_DIR)/*.h \ $(DISTDIR)/libtommath mkdir $(DISTDIR)/pkgs - cp $(TOP_DIR)/pkgs/README $(DISTDIR)/pkgs + cp $(TOP_DIR)/pkgs/README $(TOP_DIR)/pkgs/package.list.txt \ + $(DISTDIR)/pkgs for i in `ls $(DISTROOT)/pkgs/*.tar.gz 2> /dev/null`; do \ tar -C $(DISTDIR)/pkgs -xzf "$$i"; \ done -- cgit v0.12 From 1f1d7f55107bdc5a370bd404c4e35e171a0f2eea Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 11 Dec 2012 21:19:11 +0000 Subject: update changes --- changes | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/changes b/changes index 0ced7a1..b517cec 100644 --- a/changes +++ b/changes @@ -8117,11 +8117,45 @@ Dropped support for OS X versions less than 10.4 (Tiger) (fellows) --- Released 8.6b3, September 18, 2012 --- See ChangeLog for details --- +2012-09-20 (enhancement) full Unicode support (nijtmans) +=> dde 1.4.0 + +2012-09-20 (enhancement) update bundled zlib to 1.2.7 (nijtmans) + 2012-10-03 (bug fix) exit panic on stacked std channel (griffin,porter) 2012-10-14 (bug fix) [tcl::Bgerror] crash on non-dict options (nijtmans) +2012-10-16 (TIP 400) New [zlib] options to set compression dict (fellows) + +2012-10-16 (TIP 405) New commands [lmap] and [dict map] (fellows) + +2012-10-24 (enhancement) [dict unset] now bytecompiled (fellows) + +2012-11-05 (TIP 413) Revisions to default [string trim*] trimset (nijtmans) + *** POTENTIAL INCOMPATIBILITY *** + +2012-11-05 (enhancement) Now bytecompiled: [array exists], [array set], +[array unset], [dict create], [dict exists], [dict merge], [format], +[info commands], [info coroutine], [info level], [info object], +[namespace current], [namespace code], [namespace qualifiers], [namespace tail], +[namespace which], [regsub], [self], [string first], [string last], +[string map], [string range], [tailcall], [yield]. (fellows) + 2012-11-06 (bug fix)[3581754] avoid multiple callback on keep-alive (fellows) => http 2.8.5 ---- Released 8.6.0, ??? ??, 2012 --- See ChangeLog for details --- +2012-11-07 tzdata updated to Olson's tzdata2012i (kenny) + +2012-11-13 (bug fix)[3567063] thread fp settings from master (mistachkin) + +2012-11-14 (bug fix)[2933003] tempfile creation in $TMPDIR (fellows) + +2012-11-15 (TIP 416) New [load] options -global and -lazy (nijtmans) + +2012-11-20 (bug fix)[3033307] base64 trail whitespace (kovalenko,goth) + +2012-12-03 (bug fix) [configure] query broke init from argv (porter) +=> tcltest 2.3.5 + +--- Released 8.6.0, December 20, 2012 --- See ChangeLog for details --- -- cgit v0.12 From 55ceb591d7bd0c530c73961be1c05996e8cc5920 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 12 Dec 2012 20:16:13 +0000 Subject: Prefer to extract package data from the *contents* not the directory name. --- pkgs/package.list.txt | 2 +- tools/tcltk-man2html.tcl | 57 +++++++++++++++++++++++++++++++++++++++++------- unix/Makefile.in | 3 +-- 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/pkgs/package.list.txt b/pkgs/package.list.txt index f12111d..a13b0fb 100644 --- a/pkgs/package.list.txt +++ b/pkgs/package.list.txt @@ -23,4 +23,4 @@ TDBC TDBC tdbcmysql tdbc::mysql tdbcodbc tdbc::odbc tdbcpostgres tdbc::postgres -tdbcsqlite3- tdbc::sqlite3 +tdbcsqlite3 tdbc::sqlite3 diff --git a/tools/tcltk-man2html.tcl b/tools/tcltk-man2html.tcl index 270a774..f392bce 100755 --- a/tools/tcltk-man2html.tcl +++ b/tools/tcltk-man2html.tcl @@ -461,18 +461,15 @@ proc plus-pkgs {type args} { if {!$build_tcl} return set result {} set pkgsdir $tcltkdir/$tcldir/pkgs - foreach {dir name} $args { - set globpat $pkgsdir/{$dir,$dir\[0-9\]*}/doc/*.$type + foreach {dir name version} $args { + set globpat $pkgsdir/$dir/doc/*.$type if {![llength [glob -type f -nocomplain $globpat]]} { # Fallback for manpages generated using doctools - set globpat $pkgsdir/{$dir,$dir\[0-9\]*}/doc/man/*.$type + set globpat $pkgsdir/$dir/doc/man/*.$type if {![llength [glob -type f -nocomplain $globpat]]} { continue } } - regexp "pkgs/${dir}(.*)/doc$" \ - [lindex [glob -type d $pkgsdir/{$dir,$dir\[0-9\]*}/doc] 0] \ - -> version switch $type { n { set title "$name Package Commands" @@ -650,6 +647,42 @@ try { append appdir "$tkdir" } + + # When building docs for Tcl, try to build docs for bundled packages too + set packageBuildList {} + if {$build_tcl} { + set pkgsDir [file join $tcltkdir $tcldir pkgs] + set subdirs [glob -nocomplain -types d -tails -directory $pkgsDir *] + + foreach dir [lsort $subdirs] { + # Parse the subdir name into (name, version) as fallback... + set description [split $dir -] + if {2 != [llength $description]} { + regexp {([^0-9]*)(.*)} $dir -> n v + set description [list $n $v] + } + + # ... but try to extract (name, version) from subdir contents + try { + set f [open [file join $pkgsDir $dir configure.in]] + foreach line [split [read $f] \n] { + if {2 == [scan $line \ + { AC_INIT ( [%[^]]] , [%[^]]] ) } n v]} { + set description [list $n $v] + break + } + } + } finally { + catch {close $f; unset f} + } + + if {[file exists [file join $pkgsDir $dir configure]]} { + # Looks like a package, record our best extraction attempt + lappend packageBuildList $dir {*}$description + } + } + } + # Get the list of packages to try, and what their human-readable names # are. Note that the package directory list should be version-less. try { @@ -674,6 +707,14 @@ try { } } + # Convert to human readable names, if applicable + for {set idx 0} {$idx < [llength $packageBuildList]} {incr idx 3} { + lassign [lrange $packageBuildList $idx $idx+2] d n v + if {[dict exists $packageDirNameMap $n]} { + lset packageBuildList $idx+1 [dict get $packageDirNameMap $n] + } + } + # # Invoke the scraper/converter engine. # @@ -684,12 +725,12 @@ try { "The commands which the tclsh interpreter implements."] \ [plus-base $build_tk $tkdir doc/*.n {Tk Commands} TkCmd \ "The additional commands which the wish interpreter implements."] \ - {*}[plus-pkgs n {*}$packageDirNameMap] \ + {*}[plus-pkgs n {*}$packageBuildList] \ [plus-base $build_tcl $tcldir doc/*.3 {Tcl C API} TclLib \ "The C functions which a Tcl extended C program may use."] \ [plus-base $build_tk $tkdir doc/*.3 {Tk C API} TkLib \ "The additional C functions which a Tk extended C program may use."] \ - {*}[plus-pkgs 3 {*}$packageDirNameMap] + {*}[plus-pkgs 3 {*}$packageBuildList] } on error {msg opts} { # On failure make sure we show what went wrong. We're not supposed # to get here though; it represents a bug in the script. diff --git a/unix/Makefile.in b/unix/Makefile.in index 680d4ce..df05759 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -2019,8 +2019,7 @@ dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tclConfig.h.in $(UNIX_DIR)/tcl.pc.in $(M cp -p $(TOMMATH_SRCS) $(TOMMATH_DIR)/*.h \ $(DISTDIR)/libtommath mkdir $(DISTDIR)/pkgs - cp $(TOP_DIR)/pkgs/README $(TOP_DIR)/pkgs/package.list.txt \ - $(DISTDIR)/pkgs + cp $(TOP_DIR)/pkgs/README $(DISTDIR)/pkgs for i in `ls $(DISTROOT)/pkgs/*.tar.gz 2> /dev/null`; do \ tar -C $(DISTDIR)/pkgs -xzf "$$i"; \ done -- cgit v0.12 From b8f7032b2378ad5140908f50da466efe081d0afb Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 13 Dec 2012 10:48:04 +0000 Subject: Fix Tcl_DecrRefCount macro, not to refer to its objPtr parameter twice. --- generic/tcl.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/generic/tcl.h b/generic/tcl.h index 36077e6..48fe062 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -810,9 +810,7 @@ typedef struct Tcl_Obj { * Note: clients should use Tcl_DecrRefCount() when they are finished using * an object, and should never call TclFreeObj() directly. TclFreeObj() is * only defined and made public in tcl.h to support Tcl_DecrRefCount's macro - * definition. Note also that Tcl_DecrRefCount() refers to the parameter - * "obj" twice. This means that you should avoid calling it with an - * expression that is expensive to compute or has side effects. + * definition. */ void Tcl_IncrRefCount _ANSI_ARGS_((Tcl_Obj *objPtr)); void Tcl_DecrRefCount _ANSI_ARGS_((Tcl_Obj *objPtr)); @@ -833,7 +831,12 @@ int Tcl_IsShared _ANSI_ARGS_((Tcl_Obj *objPtr)); * http://c2.com/cgi/wiki?TrivialDoWhileLoop */ # define Tcl_DecrRefCount(objPtr) \ - do { if (--(objPtr)->refCount <= 0) TclFreeObj(objPtr); } while(0) + do { \ + Tcl_Obj *obj = (objPtr); \ + if ((obj)->refCount-- < 2) { \ + TclFreeObj(obj); \ + } \ + } while(0) # define Tcl_IsShared(objPtr) \ ((objPtr)->refCount > 1) #endif -- cgit v0.12 From e30259f5920c3e4e6a6ff76d6c7d80bdbfd5ac32 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 13 Dec 2012 12:03:51 +0000 Subject: Changelog entry, and change macro variable to not conflict with possible outside variable names --- ChangeLog | 5 +++++ generic/tcl.h | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index ef04907..092d5f9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-12-13 Jan Nijtmans + + * generic/tcl.h: Fix Tcl_DecrRefCount macro such that it + doesn't access its objPtr parameter twice any more. + 2012-11-14 Donal K. Fellows * unix/tclUnixPipe.c (DefaultTempDir): [Bug 2933003]: Allow overriding diff --git a/generic/tcl.h b/generic/tcl.h index 48fe062..bf9b446 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -832,9 +832,9 @@ int Tcl_IsShared _ANSI_ARGS_((Tcl_Obj *objPtr)); */ # define Tcl_DecrRefCount(objPtr) \ do { \ - Tcl_Obj *obj = (objPtr); \ - if ((obj)->refCount-- < 2) { \ - TclFreeObj(obj); \ + Tcl_Obj *_objPtr = (objPtr); \ + if (_objPtr->refCount-- < 2) { \ + TclFreeObj(_objPtr); \ } \ } while(0) # define Tcl_IsShared(objPtr) \ -- cgit v0.12 From 86ced50657a467a7e29470be90d1d13061b84a2d Mon Sep 17 00:00:00 2001 From: mig Date: Thu, 13 Dec 2012 13:37:19 +0000 Subject: Fix for [Bug 3595576], found by andrewsh --- ChangeLog | 7 +++++++ generic/tclCmdAH.c | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 87f0260..13fcaf8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2012-11-13 Miguel Sofer + + * generic/tclCmdAH.c (CatchObjCmdCallback): do not decrRefCount + the newValuePtr sent to Tcl_ObjSetVar2: TOSV2 is 'fire and + forget', it decrs on its own. Fix for [Bug 3595576], found by + andrewsh. + 2012-12-13 Jan Nijtmans * generic/tcl.h: Fix Tcl_DecrRefCount macro such that it diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index 14951e4..133a61b 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -361,7 +361,8 @@ CatchObjCmdCallback( if (NULL == Tcl_ObjSetVar2(interp, optionVarNamePtr, NULL, options, TCL_LEAVE_ERR_MSG)) { - Tcl_DecrRefCount(options); + /* Do not decrRefCount 'options', it was already done by + * Tcl_ObjSetVar2 */ return TCL_ERROR; } } -- cgit v0.12 From 7cf0ac1eafc58e6473a6f2d2e2c0480628ac626c Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 13 Dec 2012 15:59:51 +0000 Subject: 3595576 Tests/fix for mem corruption: [catch] fails to store options in a var. --- generic/tclCmdAH.c | 1 - tests/cmdAH.test | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index 8e32389..44f08a3 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -273,7 +273,6 @@ Tcl_CatchObjCmd( Tcl_Obj *options = Tcl_GetReturnOptions(interp, result); if (NULL == Tcl_ObjSetVar2(interp, optionVarNamePtr, NULL, options, 0)) { - Tcl_DecrRefCount(options); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "couldn't save return options in variable", NULL); diff --git a/tests/cmdAH.test b/tests/cmdAH.test index 2e94d7d..fb0fefc 100644 --- a/tests/cmdAH.test +++ b/tests/cmdAH.test @@ -46,6 +46,12 @@ test cmdAH-1.2 {Tcl_CatchObjCmd, errors} { test cmdAH-1.3 {Tcl_CatchObjCmd, errors} { list [catch {catch foo bar baz spaz} msg] $msg } {1 {wrong # args: should be "catch script ?resultVarName? ?optionVarName?"}} +test cmdAH-1.4 {Bug 3595576} { + catch {catch {} -> noSuchNs::var} +} 1 +test cmdAH-1.5 {Bug 3595576} { + catch {catch error -> noSuchNs::var} +} 1 test cmdAH-2.1 {Tcl_CdObjCmd} { list [catch {cd foo bar} msg] $msg -- cgit v0.12 From 990ca78bafc3a3a4363dbdaca20c2c3f78b8ee83 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 13 Dec 2012 16:11:07 +0000 Subject: Restore clarity to macro test. --- generic/tcl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tcl.h b/generic/tcl.h index bf9b446..9dd6ff0 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -833,7 +833,7 @@ int Tcl_IsShared _ANSI_ARGS_((Tcl_Obj *objPtr)); # define Tcl_DecrRefCount(objPtr) \ do { \ Tcl_Obj *_objPtr = (objPtr); \ - if (_objPtr->refCount-- < 2) { \ + if (--(_objPtr)->refCount <= 0) { \ TclFreeObj(_objPtr); \ } \ } while(0) -- cgit v0.12 From 73eeb5f121c51edba58ed7deaa273a7381110e26 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 13 Dec 2012 19:43:43 +0000 Subject: Simplify the [info object] and [info class] additions. --- generic/tclOOInfo.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/generic/tclOOInfo.c b/generic/tclOOInfo.c index e09ee4e..3f37a6d 100644 --- a/generic/tclOOInfo.c +++ b/generic/tclOOInfo.c @@ -114,21 +114,15 @@ TclOOInitInfo( infoCmd = Tcl_FindCommand(interp, "info", NULL, TCL_GLOBAL_ONLY); if (infoCmd != NULL && Tcl_IsEnsemble(infoCmd)) { - Tcl_Obj *mapDict, *objectObj, *classObj; + Tcl_Obj *mapDict; Tcl_GetEnsembleMappingDict(NULL, infoCmd, &mapDict); if (mapDict != NULL) { - objectObj = Tcl_NewStringObj("object", -1); - classObj = Tcl_NewStringObj("class", -1); - Tcl_IncrRefCount(objectObj); - Tcl_IncrRefCount(classObj); - Tcl_DictObjPut(NULL, mapDict, objectObj, + Tcl_DictObjPut(NULL, mapDict, Tcl_NewStringObj("object", -1), Tcl_NewStringObj("::oo::InfoObject", -1)); - Tcl_DictObjPut(NULL, mapDict, classObj, + Tcl_DictObjPut(NULL, mapDict, Tcl_NewStringObj("class", -1), Tcl_NewStringObj("::oo::InfoClass", -1)); - Tcl_DecrRefCount(objectObj); - Tcl_DecrRefCount(classObj); Tcl_SetEnsembleMappingDict(interp, infoCmd, mapDict); } } -- cgit v0.12 From 4eaff43e124f523dca05591bc760fa9f32eb7672 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 13 Dec 2012 20:20:46 +0000 Subject: TIP 400 suffered from the same segfaulting flaw as 3595576. Segfaulting test and fix committed. --- generic/tclZlib.c | 19 +++---------------- tests/zlib.test | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/generic/tclZlib.c b/generic/tclZlib.c index 8fbe049..9c1176e 100644 --- a/generic/tclZlib.c +++ b/generic/tclZlib.c @@ -507,7 +507,7 @@ GenerateHeader( * ExtractHeader -- * * Take the values out of a gzip header and store them in a dictionary. - * SetValue is a helper function. + * SetValue is a helper macro. * * Results: * None. @@ -518,18 +518,8 @@ GenerateHeader( *---------------------------------------------------------------------- */ -static inline void -SetValue( - Tcl_Obj *dictObj, - const char *key, - Tcl_Obj *value) -{ - Tcl_Obj *keyObj = Tcl_NewStringObj(key, -1); - - Tcl_IncrRefCount(keyObj); - Tcl_DictObjPut(NULL, dictObj, keyObj, value); - TclDecrRefCount(keyObj); -} +#define SetValue(dictObj, key, value) \ + Tcl_DictObjPut(NULL, (dictObj), Tcl_NewStringObj((key), -1), (value)) static void ExtractHeader( @@ -2119,9 +2109,6 @@ ZlibCmd( } if (headerVarObj != NULL && Tcl_ObjSetVar2(interp, headerVarObj, NULL, headerDictObj, TCL_LEAVE_ERR_MSG) == NULL) { - if (headerDictObj) { - TclDecrRefCount(headerDictObj); - } return TCL_ERROR; } return TCL_OK; diff --git a/tests/zlib.test b/tests/zlib.test index 5f1e5fc..891dba0 100644 --- a/tests/zlib.test +++ b/tests/zlib.test @@ -826,6 +826,20 @@ test zlib-11.2 "Bug #3390073: mis-appled gzip filtering" -setup { } -cleanup { removeFile $file } -result {1000 /foo/bar 0} +test zlib-11.3 {Bug 3595576 variant} -setup { + set file [makeFile {} test.input] +} -constraints zlib -body { + set f [open $file wb] + puts -nonewline [zlib push gzip $f -header {filename /foo/bar}] \ + [string repeat "hello" 1000] + close $f + set f [open $file rb] + set d [read $f] + close $f + zlib gunzip $d -header noSuchNs::foo +} -cleanup { + removeFile $file +} -returnCodes error -result {can't set "noSuchNs::foo": parent namespace doesn't exist} ::tcltest::cleanupTests return -- cgit v0.12 From 2226bec6cf911febed6c3ab9e80527ca71ba4be4 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 14 Dec 2012 17:47:55 +0000 Subject: Various bits of cleanup, efficiencies, and comment documentation in tclVar.c --- generic/tclVar.c | 111 +++++++++++++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 57 deletions(-) diff --git a/generic/tclVar.c b/generic/tclVar.c index aaf1cb9..7622675 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -47,6 +47,13 @@ static inline void CleanupVar(Var *varPtr, Var *arrayPtr); #define VarHashGetValue(hPtr) \ ((Var *) ((char *)hPtr - TclOffset(VarInHash, entry))) +/* + * NOTE: VarHashCreateVar increments the recount of its key argument. + * All callers that will call Tcl_DecrRefCount on that argument must + * call Tcl_IncrRefCount on it before passing it in. This requirement + * can bubble up to callers of callers .... etc. + */ + static inline Var * VarHashCreateVar( TclVarHashTable *tablePtr, @@ -381,11 +388,12 @@ TclLookupVar( * address of array variable. Otherwise this * is set to NULL. */ { - Tcl_Obj *part1Ptr; Var *varPtr; + Tcl_Obj *part1Ptr = Tcl_NewStringObj(part1, -1); - part1Ptr = Tcl_NewStringObj(part1, -1); - Tcl_IncrRefCount(part1Ptr); + if (createPart1) { + Tcl_IncrRefCount(part1Ptr); + } varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, msg, createPart1, createPart2, arrayPtrPtr); @@ -430,6 +438,8 @@ TclLookupVar( * are 1. The object part1Ptr is converted to one of localVarNameType, * tclNsVarNameType or tclParsedVarNameType and caches as much of the * lookup as it can. + * When createPart1 is 1, callers must IncrRefCount part1Ptr if they + * plan to DecrRefCount it. * *---------------------------------------------------------------------- */ @@ -458,14 +468,11 @@ TclObjLookupVar( * address of array variable. Otherwise this * is set to NULL. */ { - Tcl_Obj *part2Ptr; + Tcl_Obj *part2Ptr = NULL; Var *resPtr; if (part2) { part2Ptr = Tcl_NewStringObj(part2, -1); - Tcl_IncrRefCount(part2Ptr); - } else { - part2Ptr = NULL; } resPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, @@ -840,6 +847,7 @@ TclObjLookupVarEx( * * Side effects: * A new hashtable entry may be created if create is 1. + * Callers must Incr varNamePtr if they plan to Decr it if create is 1. * *---------------------------------------------------------------------- */ @@ -1277,15 +1285,10 @@ Tcl_GetVar2Ex( int flags) /* OR-ed combination of TCL_GLOBAL_ONLY, and * TCL_LEAVE_ERR_MSG bits. */ { - Tcl_Obj *part1Ptr, *part2Ptr, *resPtr; + Tcl_Obj *resPtr, *part2Ptr = NULL, *part1Ptr = Tcl_NewStringObj(part1, -1); - part1Ptr = Tcl_NewStringObj(part1, -1); - Tcl_IncrRefCount(part1Ptr); if (part2) { part2Ptr = Tcl_NewStringObj(part2, -1); - Tcl_IncrRefCount(part2Ptr); - } else { - part2Ptr = NULL; } resPtr = Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags); @@ -1566,18 +1569,8 @@ Tcl_SetVar2( * TCL_APPEND_VALUE, TCL_LIST_ELEMENT, or * TCL_LEAVE_ERR_MSG. */ { - register Tcl_Obj *valuePtr; - Tcl_Obj *varValuePtr; - - /* - * Create an object holding the variable's new value and use Tcl_SetVar2Ex - * to actually set the variable. - */ - - valuePtr = Tcl_NewStringObj(newValue, -1); - Tcl_IncrRefCount(valuePtr); - varValuePtr = Tcl_SetVar2Ex(interp, part1, part2, valuePtr, flags); - Tcl_DecrRefCount(valuePtr); + Tcl_Obj *varValuePtr = Tcl_SetVar2Ex(interp, part1, part2, + Tcl_NewStringObj(newValue, -1), flags); if (varValuePtr == NULL) { return NULL; @@ -1637,15 +1630,12 @@ Tcl_SetVar2Ex( * TCL_APPEND_VALUE, TCL_LIST_ELEMENT or * TCL_LEAVE_ERR_MSG. */ { - Tcl_Obj *part1Ptr, *part2Ptr, *resPtr; + Tcl_Obj *resPtr, *part2Ptr = NULL, *part1Ptr = Tcl_NewStringObj(part1, -1); - part1Ptr = Tcl_NewStringObj(part1, -1); Tcl_IncrRefCount(part1Ptr); if (part2) { part2Ptr = Tcl_NewStringObj(part2, -1); Tcl_IncrRefCount(part2Ptr); - } else { - part2Ptr = NULL; } resPtr = Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, newValuePtr, flags); @@ -1678,6 +1668,7 @@ Tcl_SetVar2Ex( * Side effects: * The value of the given variable is set. If either the array or the * entry didn't exist then a new variable is created. + * Callers must Incr part1Ptr if they plan to Decr it. * *---------------------------------------------------------------------- */ @@ -1965,6 +1956,7 @@ TclPtrSetVar( * variable is created. The ref count for the returned object is _not_ * incremented to reflect the returned reference; if you want to keep a * reference to the object you must increment its ref count yourself. + * Callers must Incr part1Ptr if they plan to Decr it. * *---------------------------------------------------------------------- */ @@ -2047,8 +2039,7 @@ TclPtrIncrObjVar( * variable, or -1. Only used when part1Ptr is * NULL. */ { - register Tcl_Obj *varValuePtr, *newValuePtr = NULL; - int duplicated, code; + register Tcl_Obj *varValuePtr; if (TclIsVarInHash(varPtr)) { VarHashRefCount(varPtr)++; @@ -2062,19 +2053,33 @@ TclPtrIncrObjVar( varValuePtr = Tcl_NewIntObj(0); } if (Tcl_IsShared(varValuePtr)) { - duplicated = 1; + /* Copy on write */ varValuePtr = Tcl_DuplicateObj(varValuePtr); + + if (TCL_OK == TclIncrObj(interp, varValuePtr, incrPtr)) { + return TclPtrSetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, + varValuePtr, flags, index); + } else { + Tcl_DecrRefCount(varValuePtr); + return NULL; + } } else { - duplicated = 0; - } - code = TclIncrObj(interp, varValuePtr, incrPtr); - if (code == TCL_OK) { - newValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, part1Ptr, - part2Ptr, varValuePtr, flags, index); - } else if (duplicated) { - Tcl_DecrRefCount(varValuePtr); + /* Unshared - can Incr in place */ + if (TCL_OK == TclIncrObj(interp, varValuePtr, incrPtr)) { + + /* + * This seems dumb to write the incremeted value into the var + * after we just adjusted the value in place, but the spec for + * [incr] requires that write traces fire, and making this call + * is the way to make that happen. + */ + + return TclPtrSetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, + varValuePtr, flags, index); + } else { + return NULL; + } } - return newValuePtr; } /* @@ -2143,13 +2148,10 @@ Tcl_UnsetVar2( * TCL_LEAVE_ERR_MSG. */ { int result; - Tcl_Obj *part1Ptr, *part2Ptr = NULL; + Tcl_Obj *part2Ptr = NULL, *part1Ptr = Tcl_NewStringObj(part1, -1); - part1Ptr = Tcl_NewStringObj(part1, -1); - Tcl_IncrRefCount(part1Ptr); if (part2) { part2Ptr = Tcl_NewStringObj(part2, -1); - Tcl_IncrRefCount(part2Ptr); } /* @@ -3318,6 +3320,7 @@ Tcl_ArrayObjCmd( * * Side effects: * A variable will be created if one does not already exist. + * Callers must Incr arrayNameObj if they pland to Decr it. * *---------------------------------------------------------------------- */ @@ -3485,6 +3488,8 @@ TclArraySet( * The variable given by myName is linked to the variable in framePtr * given by otherP1 and otherP2, so that references to myName are * redirected to the other variable like a symbolic link. + * Callers must Incr myNamePtr if they plan to Decr it. + * Callers must Incr otherP1Ptr if they plan to Decr it. * *---------------------------------------------------------------------- */ @@ -3592,14 +3597,12 @@ TclPtrMakeUpvar( int index) /* If the variable to be linked is an indexed * scalar, this is its index. Otherwise, -1 */ { - Tcl_Obj *myNamePtr; + Tcl_Obj *myNamePtr = NULL; int result; if (myName) { myNamePtr = Tcl_NewStringObj(myName, -1); Tcl_IncrRefCount(myNamePtr); - } else { - myNamePtr = NULL; } result = TclPtrObjMakeUpvar(interp, otherPtr, myNamePtr, myFlags, index); if (myNamePtr) { @@ -3608,6 +3611,8 @@ TclPtrMakeUpvar( return result; } +/* Callers must Incr myNamePtr if they plan to Decr it. */ + int TclPtrObjMakeUpvar( Tcl_Interp *interp, /* Interpreter containing variables. Used for @@ -4425,7 +4430,6 @@ TclDeleteNamespaceVars( for (varPtr = VarHashFirstVar(tablePtr, &search); varPtr != NULL; varPtr = VarHashFirstVar(tablePtr, &search)) { Tcl_Obj *objPtr = Tcl_NewObj(); - Tcl_IncrRefCount(objPtr); VarHashRefCount(varPtr)++; /* Make sure we get to remove from * hash. */ @@ -4689,15 +4693,10 @@ TclVarErrMsg( * e.g. "read", "set", or "unset". */ const char *reason) /* String describing why operation failed. */ { - Tcl_Obj *part1Ptr = NULL, *part2Ptr = NULL; + Tcl_Obj *part2Ptr = NULL, *part1Ptr = Tcl_NewStringObj(part1, -1); - part1Ptr = Tcl_NewStringObj(part1, -1); - Tcl_IncrRefCount(part1Ptr); if (part2) { part2Ptr = Tcl_NewStringObj(part2, -1); - Tcl_IncrRefCount(part2Ptr); - } else { - part2 = NULL; } TclObjVarErrMsg(interp, part1Ptr, part2Ptr, operation, reason, -1); @@ -4965,7 +4964,6 @@ Tcl_FindNamespaceVar( Tcl_Obj *namePtr = Tcl_NewStringObj(name, -1); Tcl_Var var; - Tcl_IncrRefCount(namePtr); var = ObjFindNamespaceVar(interp, namePtr, contextNsPtr, flags); Tcl_DecrRefCount(namePtr); return var; @@ -5060,7 +5058,6 @@ ObjFindNamespaceVar( varPtr = NULL; if (simpleName != name) { simpleNamePtr = Tcl_NewStringObj(simpleName, -1); - Tcl_IncrRefCount(simpleNamePtr); } else { simpleNamePtr = namePtr; } -- cgit v0.12 From 97482cca000b9f31593285d349c05793f79f9863 Mon Sep 17 00:00:00 2001 From: dkf Date: Mon, 17 Dec 2012 14:27:44 +0000 Subject: Slim down the code a bit more; we can make more safe assumptions. --- generic/tclOOInfo.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/generic/tclOOInfo.c b/generic/tclOOInfo.c index 3f37a6d..5be9b01 100644 --- a/generic/tclOOInfo.c +++ b/generic/tclOOInfo.c @@ -100,6 +100,7 @@ TclOOInitInfo( Tcl_Interp *interp) { Tcl_Command infoCmd; + Tcl_Obj *mapDict; /* * Build the ensembles used to implement [info object] and [info class]. @@ -113,19 +114,12 @@ TclOOInitInfo( */ infoCmd = Tcl_FindCommand(interp, "info", NULL, TCL_GLOBAL_ONLY); - if (infoCmd != NULL && Tcl_IsEnsemble(infoCmd)) { - Tcl_Obj *mapDict; - - Tcl_GetEnsembleMappingDict(NULL, infoCmd, &mapDict); - if (mapDict != NULL) { - - Tcl_DictObjPut(NULL, mapDict, Tcl_NewStringObj("object", -1), - Tcl_NewStringObj("::oo::InfoObject", -1)); - Tcl_DictObjPut(NULL, mapDict, Tcl_NewStringObj("class", -1), - Tcl_NewStringObj("::oo::InfoClass", -1)); - Tcl_SetEnsembleMappingDict(interp, infoCmd, mapDict); - } - } + Tcl_GetEnsembleMappingDict(NULL, infoCmd, &mapDict); + Tcl_DictObjPut(NULL, mapDict, Tcl_NewStringObj("object", -1), + Tcl_NewStringObj("::oo::InfoObject", -1)); + Tcl_DictObjPut(NULL, mapDict, Tcl_NewStringObj("class", -1), + Tcl_NewStringObj("::oo::InfoClass", -1)); + Tcl_SetEnsembleMappingDict(interp, infoCmd, mapDict); } /* -- cgit v0.12 From 71500874b393cf7e4a8528218307492dd88d18b7 Mon Sep 17 00:00:00 2001 From: dkf Date: Tue, 18 Dec 2012 09:37:42 +0000 Subject: Generate better code for the common case of subst-ed variables where the variable is a simple scalar or an array with a simple literal element name. --- generic/tclCompCmdsSZ.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c index 9c93fb2..71a1dfc 100644 --- a/generic/tclCompCmdsSZ.c +++ b/generic/tclCompCmdsSZ.c @@ -836,6 +836,21 @@ TclSubstCompile( TclEmitPush(literal, envPtr); count++; continue; + case TCL_TOKEN_VARIABLE: + /* + * Simple variable access; can only generate TCL_OK or TCL_ERROR + * so no need to generate elaborate exception-management code. + */ + + if (tokenPtr->numComponents == 1 || (tokenPtr->numComponents == 2 + && tokenPtr[2].type == TCL_TOKEN_TEXT)) { + envPtr->line = bline; + TclCompileVarSubst(interp, tokenPtr, envPtr); + bline = envPtr->line; + count++; + continue; + } + break; } while (count > 255) { -- cgit v0.12 From ee58f2d325a281f03cf6669e8d7ae2c377a5af2d Mon Sep 17 00:00:00 2001 From: dkf Date: Tue, 18 Dec 2012 10:21:34 +0000 Subject: Better version that can handle simple composite array keys as well. As long as they are free of command substitutions, we can still safely omit the exception processor code. --- generic/tclCompCmdsSZ.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c index 71a1dfc..7bead0d 100644 --- a/generic/tclCompCmdsSZ.c +++ b/generic/tclCompCmdsSZ.c @@ -838,19 +838,32 @@ TclSubstCompile( continue; case TCL_TOKEN_VARIABLE: /* - * Simple variable access; can only generate TCL_OK or TCL_ERROR - * so no need to generate elaborate exception-management code. + * Check for simple variable access; see if we can only generate + * TCL_OK or TCL_ERROR from the substituted variable read; if so, + * there is no need to generate elaborate exception-management + * code. Note that the first component of TCL_TOKEN_VARIABLE is + * always TCL_TOKEN_TEXT... */ - if (tokenPtr->numComponents == 1 || (tokenPtr->numComponents == 2 - && tokenPtr[2].type == TCL_TOKEN_TEXT)) { - envPtr->line = bline; - TclCompileVarSubst(interp, tokenPtr, envPtr); - bline = envPtr->line; - count++; - continue; + if (tokenPtr->numComponents > 1) { + int i, foundCommand = 0; + + for (i=2 ; i<=tokenPtr->numComponents ; i++) { + if (tokenPtr[i].type == TCL_TOKEN_COMMAND) { + foundCommand = 1; + break; + } + } + if (foundCommand) { + break; + } } - break; + + envPtr->line = bline; + TclCompileVarSubst(interp, tokenPtr, envPtr); + bline = envPtr->line; + count++; + continue; } while (count > 255) { -- cgit v0.12 From b59e26b4ebf4d75131241be768955f8ae29e498f Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 21 Dec 2012 08:16:50 +0000 Subject: Turn pkgb.so into a Tcl9 interoperability test library: Whatever Tcl9 looks like, loading pkgb.so in Tcl 9 should either result in an error-message, either succeed, but never crash. Eliminate unnessarcy static HasStubSupport() and isDigit() functions, just do the same inline. --- ChangeLog | 8 ++++++ generic/tclStubLib.c | 33 +++++++---------------- unix/dltest/pkgb.c | 76 ++++++++++++++++++++++++++++------------------------ 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/ChangeLog b/ChangeLog index 092d5f9..204275f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2012-12-21 Jan Nijtmans + + * unix/dltest/pkgb.c: Turn pkgb.so into a Tcl9 interoperability test + library: Whatever Tcl9 looks like, loading pkgb.so in Tcl 9 should + either result in an error-message, either succeed, but never crash. + * generic/tclStubLib.c: Eliminate unnessarcy static HasStubSupport() and + isDigit() functions, just do the same inline. + 2012-12-13 Jan Nijtmans * generic/tcl.h: Fix Tcl_DecrRefCount macro such that it diff --git a/generic/tclStubLib.c b/generic/tclStubLib.c index ceee8f3..7b62f5e 100644 --- a/generic/tclStubLib.c +++ b/generic/tclStubLib.c @@ -19,28 +19,11 @@ TclPlatStubs *tclPlatStubsPtr = NULL; TclIntStubs *tclIntStubsPtr = NULL; TclIntPlatStubs *tclIntPlatStubsPtr = NULL; -static TclStubs * -HasStubSupport(interp) - Tcl_Interp *interp; -{ - Interp *iPtr = (Interp *) interp; - - if (iPtr->stubTable && (iPtr->stubTable->magic == TCL_STUB_MAGIC)) { - return iPtr->stubTable; - } - interp->result = "interpreter uses an incompatible stubs mechanism"; - interp->freeProc = TCL_STATIC; - return NULL; -} - /* - * Use our own isdigit to avoid linking to libc on windows + * Use our own ISDIGIT to avoid linking to libc on windows */ -static int isDigit(const int c) -{ - return (c >= '0' && c <= '9'); -} +#define ISDIGIT(c) (((unsigned)((c)-'0')) <= 9) /* *---------------------------------------------------------------------- @@ -66,9 +49,10 @@ Tcl_InitStubs(interp, version, exact) CONST char *version; int exact; { + Interp *iPtr = (Interp *) interp; CONST char *actualVersion = NULL; ClientData pkgData = NULL; - TclStubs *stubsPtr; + TclStubs *stubsPtr = iPtr->stubTable; /* * We can't optimize this check by caching tclStubsPtr because that @@ -76,8 +60,9 @@ Tcl_InitStubs(interp, version, exact) * times. [Bug 615304] */ - stubsPtr = HasStubSupport(interp); - if (!stubsPtr) { + if (!stubsPtr || (stubsPtr->magic != TCL_STUB_MAGIC)) { + iPtr->result = "interpreter uses an incompatible stubs mechanism"; + iPtr->freeProc = TCL_STATIC; return NULL; } @@ -90,7 +75,7 @@ Tcl_InitStubs(interp, version, exact) int count = 0; while (*p) { - count += !isDigit(*p++); + count += !ISDIGIT(*p++); } if (count == 1) { CONST char *q = actualVersion; @@ -99,7 +84,7 @@ Tcl_InitStubs(interp, version, exact) while (*p && (*p == *q)) { p++; q++; } - if (*p || isDigit(*q)) { + if (*p || ISDIGIT(*q)) { /* Construct error message */ stubsPtr->tcl_PkgRequireEx(interp, "Tcl", version, 1, NULL); return NULL; diff --git a/unix/dltest/pkgb.c b/unix/dltest/pkgb.c index d7a7e5b..0bff98b 100644 --- a/unix/dltest/pkgb.c +++ b/unix/dltest/pkgb.c @@ -1,15 +1,16 @@ -/* +/* * pkgb.c -- * - * This file contains a simple Tcl package "pkgb" that is intended - * for testing the Tcl dynamic loading facilities. It can be used - * in both safe and unsafe interpreters. + * This file contains a simple Tcl package "pkgb" that is intended for + * testing the Tcl dynamic loading facilities. It can be used in both + * safe and unsafe interpreters. * * 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. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ + #include "tcl.h" /* @@ -17,17 +18,17 @@ */ static int Pkgb_SubObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])); + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int Pkgb_UnsafeObjCmd _ANSI_ARGS_((ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])); + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); /* *---------------------------------------------------------------------- * * Pkgb_SubObjCmd -- * - * This procedure is invoked to process the "pkgb_sub" Tcl command. - * It expects two arguments and returns their difference. + * This procedure is invoked to process the "pkgb_sub" Tcl command. It + * expects two arguments and returns their difference. * * Results: * A standard Tcl result. @@ -43,17 +44,17 @@ Pkgb_SubObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ - Tcl_Obj * CONST objv[]; /* Argument objects. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { int first, second; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "num num"); - return TCL_ERROR; + return TCL_ERROR; } if ((Tcl_GetIntFromObj(interp, objv[1], &first) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[2], &second) != TCL_OK)) { - return TCL_ERROR; + return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(first - second)); return TCL_OK; @@ -64,8 +65,8 @@ Pkgb_SubObjCmd(dummy, interp, objc, objv) * * Pkgb_UnsafeObjCmd -- * - * This procedure is invoked to process the "pkgb_unsafe" Tcl command. - * It just returns a constant string. + * This procedure is invoked to process the "pkgb_unsafe" Tcl command. It + * just returns a constant string. * * Results: * A standard Tcl result. @@ -81,10 +82,9 @@ Pkgb_UnsafeObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ - Tcl_Obj * CONST objv[]; /* Argument objects. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - Tcl_SetObjResult(interp, Tcl_NewStringObj("unsafe command invoked", -1)); - return TCL_OK; + return Tcl_EvalEx(interp, "list unsafe command invoked", -1, TCL_EVAL_GLOBAL); } /* @@ -92,8 +92,8 @@ Pkgb_UnsafeObjCmd(dummy, interp, objc, objv) * * Pkgb_Init -- * - * This is a package initialization procedure, which is called - * by Tcl when this package is to be added to an interpreter. + * This is a package initialization procedure, which is called by Tcl + * when this package is to be added to an interpreter. * * Results: * None. @@ -104,17 +104,20 @@ Pkgb_UnsafeObjCmd(dummy, interp, objc, objv) *---------------------------------------------------------------------- */ -int +DLLEXPORT int Pkgb_Init(interp) - Tcl_Interp *interp; /* Interpreter in which the package is - * to be made available. */ + Tcl_Interp *interp; /* Interpreter in which the package is to be + * made available. */ { int code; - if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { - return TCL_ERROR; + if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { + if (Tcl_InitStubs(interp, "8.4-", 0) == NULL) { + return TCL_ERROR; + } + Tcl_ResetResult(interp); } - code = Tcl_PkgProvide(interp, "Pkgb", "2.3"); + code = Tcl_PkgProvideEx(interp, "Pkgb", "2.3", NULL); if (code != TCL_OK) { return code; } @@ -130,8 +133,8 @@ Pkgb_Init(interp) * * Pkgb_SafeInit -- * - * This is a package initialization procedure, which is called - * by Tcl when this package is to be added to an unsafe interpreter. + * This is a package initialization procedure, which is called by Tcl + * when this package is to be added to a safe interpreter. * * Results: * None. @@ -142,19 +145,22 @@ Pkgb_Init(interp) *---------------------------------------------------------------------- */ -int +DLLEXPORT int Pkgb_SafeInit(interp) - Tcl_Interp *interp; /* Interpreter in which the package is - * to be made available. */ + Tcl_Interp *interp; /* Interpreter in which the package is to be + * made available. */ { int code; - if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { - return TCL_ERROR; + if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { + if (Tcl_InitStubs(interp, "8.4-", 0) == NULL) { + return TCL_ERROR; + } + Tcl_ResetResult(interp); } - code = Tcl_PkgProvide(interp, "Pkgb", "2.3"); + code = Tcl_PkgProvideEx(interp, "Pkgb", "2.3", NULL); if (code != TCL_OK) { - return code; + return code; } Tcl_CreateObjCommand(interp, "pkgb_sub", Pkgb_SubObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); -- cgit v0.12 From a40590fd31db326000458a35d4bff19a8f7a3b4d Mon Sep 17 00:00:00 2001 From: ferrieux Date: Sat, 22 Dec 2012 19:05:34 +0000 Subject: Stop leaking allocated space when objifying a zero-length DString. [Bug 3598150] spotted by afredd. --- ChangeLog | 5 +++++ generic/tclUtil.c | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 336da37..49da827 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-12-22 Alexandre Ferrieux + + * generic/tclUtil.c: Stop leaking allocated space when objifying a + zero-length DString. [Bug 3598150] spotted by afredd. + 2012-12-21 Jan Nijtmans * unix/dltest/pkgb.c: Inline compat Tcl_GetDefaultEncodingDir. diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 13e54ec..ddf067b 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -2927,14 +2927,16 @@ TclDStringToObj( { Tcl_Obj *result; - if (dsPtr->length == 0) { - TclNewObj(result); - } else if (dsPtr->string == dsPtr->staticSpace) { - /* - * Static buffer, so must copy. - */ - - TclNewStringObj(result, dsPtr->string, dsPtr->length); + if (dsPtr->string == dsPtr->staticSpace) { + if (dsPtr->length == 0) { + TclNewObj(result); + } else { + /* + * Static buffer, so must copy. + */ + + TclNewStringObj(result, dsPtr->string, dsPtr->length); + } } else { /* * Dynamic buffer, so transfer ownership and reset. -- cgit v0.12 From 42c352d6258bc3ec26c19183c29b5a4ac4301a81 Mon Sep 17 00:00:00 2001 From: dkf Date: Sun, 23 Dec 2012 08:17:17 +0000 Subject: Change back to using an isDigit function. We simply don't need to make any (formally non-portable) assumptions about what happens when an unsigned zero is decremented, and the code isn't in a performance-critical area. Remark by jan.nijtmans: The macro is perfectly portable! Not portable is the exact result of the substraction ('\xB0' - '0' might give 0x80 on some platforms and 0xffffff80 on others), but comparing <= 9 always gives the correct result. We are only checking for digits here! The macro correctly inlines with any compiler, so it's better anyway. Remark by dkf: But it's less clear. In this code, that's more important than a teeny bit of speed from inlining in a non-critical location. --- generic/tclStubLib.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/generic/tclStubLib.c b/generic/tclStubLib.c index f61e0ca..859cbf9 100644 --- a/generic/tclStubLib.c +++ b/generic/tclStubLib.c @@ -24,10 +24,13 @@ const TclIntStubs *tclIntStubsPtr = NULL; const TclIntPlatStubs *tclIntPlatStubsPtr = NULL; /* - * Use our own ISDIGIT to avoid linking to libc on windows + * Use our own isDigit to avoid linking to libc on windows */ -#define ISDIGIT(c) (((unsigned)((c)-'0')) <= 9) +static int isDigit(const int c) +{ + return (c >= '0' && c <= '9'); +} /* *---------------------------------------------------------------------- @@ -79,7 +82,7 @@ Tcl_InitStubs( int count = 0; while (*p) { - count += !ISDIGIT(*p++); + count += !isDigit(*p++); } if (count == 1) { const char *q = actualVersion; @@ -88,7 +91,7 @@ Tcl_InitStubs( while (*p && (*p == *q)) { p++; q++; } - if (*p || ISDIGIT(*q)) { + if (*p || isDigit(*q)) { /* Construct error message */ stubsPtr->tcl_PkgRequireEx(interp, "Tcl", version, 1, NULL); return NULL; -- cgit v0.12 From d525cce307b002900a04c58a4adff1470f24202c Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 26 Dec 2012 09:55:45 +0000 Subject: eliminate dependancy of compat/*.h on tcl.h --- compat/dirent2.h | 10 ++--- compat/dlfcn.h | 19 ++++------ compat/stdlib.h | 51 +++++++++++-------------- compat/string.h | 74 +++++++++++++++--------------------- compat/unistd.h | 112 ++++++++++++++++++++++++++----------------------------- 5 files changed, 115 insertions(+), 151 deletions(-) diff --git a/compat/dirent2.h b/compat/dirent2.h index c00d2f4..5be08ba 100644 --- a/compat/dirent2.h +++ b/compat/dirent2.h @@ -14,10 +14,6 @@ #ifndef _DIRENT #define _DIRENT -#ifndef _TCL -#include -#endif - /* * Dirent structure, which holds information about a single * directory entry. @@ -50,8 +46,8 @@ typedef struct _dirdesc { * Procedures defined for reading directories: */ -extern void closedir _ANSI_ARGS_((DIR *dirp)); -extern DIR * opendir _ANSI_ARGS_((char *name)); -extern struct dirent * readdir _ANSI_ARGS_((DIR *dirp)); +extern void closedir (DIR *dirp); +extern DIR * opendir (char *name); +extern struct dirent * readdir (DIR *dirp); #endif /* _DIRENT */ diff --git a/compat/dlfcn.h b/compat/dlfcn.h index 1a6a118..fb27ea0 100644 --- a/compat/dlfcn.h +++ b/compat/dlfcn.h @@ -1,4 +1,4 @@ -/* +/* * dlfcn.h -- * * This file provides a replacement for the header file "dlfcn.h" @@ -19,7 +19,6 @@ */ /* - * @(#)dlfcn.h 1.4 revision of 95/04/25 09:36:52 * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH * 30159 Hannover, Germany */ @@ -27,10 +26,6 @@ #ifndef __dlfcn_h__ #define __dlfcn_h__ -#ifndef _TCL -#include -#endif - #ifdef __cplusplus extern "C" { #endif @@ -47,14 +42,14 @@ extern "C" { * that contains functions to be called to initialize and terminate. */ struct dl_info { - void (*init) _ANSI_ARGS_((void)); - void (*fini) _ANSI_ARGS_((void)); + void (*init) (void); + void (*fini) (void); }; -VOID *dlopen _ANSI_ARGS_((const char *path, int mode)); -VOID *dlsym _ANSI_ARGS_((void *handle, const char *symbol)); -char *dlerror _ANSI_ARGS_((void)); -int dlclose _ANSI_ARGS_((void *handle)); +void *dlopen (const char *path, int mode); +void *dlsym (void *handle, const char *symbol); +char *dlerror (void); +int dlclose (void *handle); #ifdef __cplusplus } diff --git a/compat/stdlib.h b/compat/stdlib.h index 4d1a386..0ad4c1d 100644 --- a/compat/stdlib.h +++ b/compat/stdlib.h @@ -1,43 +1,36 @@ /* * stdlib.h -- * - * Declares facilities exported by the "stdlib" portion of - * the C library. This file isn't complete in the ANSI-C - * sense; it only declares things that are needed by Tcl. - * This file is needed even on many systems with their own - * stdlib.h (e.g. SunOS) because not all stdlib.h files - * declare all the procedures needed here (such as strtod). + * Declares facilities exported by the "stdlib" portion of the C library. + * This file isn't complete in the ANSI-C sense; it only declares things + * that are needed by Tcl. This file is needed even on many systems with + * their own stdlib.h (e.g. SunOS) because not all stdlib.h files declare + * all the procedures needed here (such as strtod). * * Copyright (c) 1991 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 - * 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. */ #ifndef _STDLIB #define _STDLIB -#include - -extern void abort _ANSI_ARGS_((void)); -extern double atof _ANSI_ARGS_((CONST char *string)); -extern int atoi _ANSI_ARGS_((CONST char *string)); -extern long atol _ANSI_ARGS_((CONST char *string)); -extern char * calloc _ANSI_ARGS_((unsigned int numElements, - unsigned int size)); -extern void exit _ANSI_ARGS_((int status)); -extern int free _ANSI_ARGS_((char *blockPtr)); -extern char * getenv _ANSI_ARGS_((CONST char *name)); -extern char * malloc _ANSI_ARGS_((unsigned int numBytes)); -extern void qsort _ANSI_ARGS_((VOID *base, int n, int size, - int (*compar)(CONST VOID *element1, CONST VOID - *element2))); -extern char * realloc _ANSI_ARGS_((char *ptr, unsigned int numBytes)); -extern double strtod _ANSI_ARGS_((CONST char *string, char **endPtr)); -extern long strtol _ANSI_ARGS_((CONST char *string, char **endPtr, - int base)); -extern unsigned long strtoul _ANSI_ARGS_((CONST char *string, - char **endPtr, int base)); +extern void abort(void); +extern double atof(const char *string); +extern int atoi(const char *string); +extern long atol(const char *string); +extern char * calloc(unsigned int numElements, unsigned int size); +extern void exit(int status); +extern int free(char *blockPtr); +extern char * getenv(const char *name); +extern char * malloc(unsigned int numBytes); +extern void qsort(void *base, int n, int size, int (*compar)( + const void *element1, const void *element2)); +extern char * realloc(char *ptr, unsigned int numBytes); +extern double strtod(const char *string, char **endPtr); +extern long strtol(const char *string, char **endPtr, int base); +extern unsigned long strtoul(const char *string, char **endPtr, int base); #endif /* _STDLIB */ diff --git a/compat/string.h b/compat/string.h index 4eb2b86..42be10c 100644 --- a/compat/string.h +++ b/compat/string.h @@ -6,66 +6,52 @@ * Copyright (c) 1991-1993 The Regents of the University of California. * 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. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _STRING #define _STRING -#include - /* - * The following #include is needed to define size_t. (This used to - * include sys/stdtypes.h but that doesn't exist on older versions - * of SunOS, e.g. 4.0.2, so I'm trying sys/types.h now.... hopefully - * it exists everywhere) + * The following #include is needed to define size_t. (This used to include + * sys/stdtypes.h but that doesn't exist on older versions of SunOS, e.g. + * 4.0.2, so I'm trying sys/types.h now.... hopefully it exists everywhere) */ #include #ifdef __APPLE__ -extern VOID * memchr _ANSI_ARGS_((CONST VOID *s, int c, size_t n)); +extern void * memchr(const void *s, int c, size_t n); #else -extern char * memchr _ANSI_ARGS_((CONST VOID *s, int c, size_t n)); +extern char * memchr(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)); +extern int memcmp(const void *s1, const void *s2, size_t n); +extern char * memcpy(void *t, const void *f, size_t n); #ifdef NO_MEMMOVE -#define memmove(d, s, n) bcopy ((s), (d), (n)) +#define memmove(d,s,n) (bcopy((s), (d), (n))) #else -extern char * memmove _ANSI_ARGS_((VOID *t, CONST VOID *f, - size_t n)); +extern char * memmove(void *t, const void *f, size_t n); #endif -extern char * memset _ANSI_ARGS_((VOID *s, int c, size_t n)); +extern char * memset(void *s, int c, size_t n); -extern int strcasecmp _ANSI_ARGS_((CONST char *s1, - CONST char *s2)); -extern char * strcat _ANSI_ARGS_((char *dst, CONST char *src)); -extern char * strchr _ANSI_ARGS_((CONST char *string, int c)); -extern int strcmp _ANSI_ARGS_((CONST char *s1, CONST char *s2)); -extern char * strcpy _ANSI_ARGS_((char *dst, CONST char *src)); -extern size_t strcspn _ANSI_ARGS_((CONST char *string, - CONST char *chars)); -extern char * strdup _ANSI_ARGS_((CONST char *string)); -extern char * strerror _ANSI_ARGS_((int error)); -extern size_t strlen _ANSI_ARGS_((CONST char *string)); -extern int strncasecmp _ANSI_ARGS_((CONST char *s1, - CONST char *s2, size_t n)); -extern char * strncat _ANSI_ARGS_((char *dst, CONST char *src, - size_t numChars)); -extern int strncmp _ANSI_ARGS_((CONST char *s1, CONST char *s2, - size_t nChars)); -extern char * strncpy _ANSI_ARGS_((char *dst, CONST char *src, - size_t numChars)); -extern char * strpbrk _ANSI_ARGS_((CONST char *string, - CONST char *chars)); -extern char * strrchr _ANSI_ARGS_((CONST char *string, int c)); -extern size_t strspn _ANSI_ARGS_((CONST char *string, - CONST char *chars)); -extern char * strstr _ANSI_ARGS_((CONST char *string, - CONST char *substring)); -extern char * strtok _ANSI_ARGS_((char *s, CONST char *delim)); +extern int strcasecmp(const char *s1, const char *s2); +extern char * strcat(char *dst, const char *src); +extern char * strchr(const char *string, int c); +extern int strcmp(const char *s1, const char *s2); +extern char * strcpy(char *dst, const char *src); +extern size_t strcspn(const char *string, const char *chars); +extern char * strdup(const char *string); +extern char * strerror(int error); +extern size_t strlen(const char *string); +extern int strncasecmp(const char *s1, const char *s2, size_t n); +extern char * strncat(char *dst, const char *src, size_t numChars); +extern int strncmp(const char *s1, const char *s2, size_t nChars); +extern char * strncpy(char *dst, const char *src, size_t numChars); +extern char * strpbrk(const char *string, const char *chars); +extern char * strrchr(const char *string, int c); +extern size_t strspn(const char *string, const char *chars); +extern char * strstr(const char *string, const char *substring); +extern char * strtok(char *s, const char *delim); #endif /* _STRING */ diff --git a/compat/unistd.h b/compat/unistd.h index 1a40e90..2de5bd0 100644 --- a/compat/unistd.h +++ b/compat/unistd.h @@ -1,82 +1,76 @@ /* * unistd.h -- * - * Macros, CONSTants and prototypes for Posix conformance. + * Macros, constants and prototypes for Posix conformance. * - * Copyright 1989 Regents of the University of California - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. The University of California - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. + * Copyright 1989 Regents of the University of California Permission to use, + * copy, modify, and distribute this software and its documentation for any + * purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies. The University of California makes + * no representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. */ #ifndef _UNISTD #define _UNISTD #include -#ifndef _TCL -# include "tcl.h" -#endif #ifndef NULL #define NULL 0 #endif /* - * Strict POSIX stuff goes here. Extensions go down below, in the - * ifndef _POSIX_SOURCE section. + * Strict POSIX stuff goes here. Extensions go down below, in the ifndef + * _POSIX_SOURCE section. */ -extern void _exit _ANSI_ARGS_((int status)); -extern int access _ANSI_ARGS_((CONST char *path, int mode)); -extern int chdir _ANSI_ARGS_((CONST char *path)); -extern int chown _ANSI_ARGS_((CONST char *path, uid_t owner, gid_t group)); -extern int close _ANSI_ARGS_((int fd)); -extern int dup _ANSI_ARGS_((int oldfd)); -extern int dup2 _ANSI_ARGS_((int oldfd, int newfd)); -extern int execl _ANSI_ARGS_((CONST char *path, ...)); -extern int execle _ANSI_ARGS_((CONST char *path, ...)); -extern int execlp _ANSI_ARGS_((CONST char *file, ...)); -extern int execv _ANSI_ARGS_((CONST char *path, char **argv)); -extern int execve _ANSI_ARGS_((CONST char *path, char **argv, char **envp)); -extern int execvp _ANSI_ARGS_((CONST char *file, char **argv)); -extern pid_t fork _ANSI_ARGS_((void)); -extern char *getcwd _ANSI_ARGS_((char *buf, size_t size)); -extern gid_t getegid _ANSI_ARGS_((void)); -extern uid_t geteuid _ANSI_ARGS_((void)); -extern gid_t getgid _ANSI_ARGS_((void)); -extern int getgroups _ANSI_ARGS_((int bufSize, int *buffer)); -extern pid_t getpid _ANSI_ARGS_((void)); -extern uid_t getuid _ANSI_ARGS_((void)); -extern int isatty _ANSI_ARGS_((int fd)); -extern long lseek _ANSI_ARGS_((int fd, long offset, int whence)); -extern int pipe _ANSI_ARGS_((int *fildes)); -extern int read _ANSI_ARGS_((int fd, char *buf, size_t size)); -extern int setgid _ANSI_ARGS_((gid_t group)); -extern int setuid _ANSI_ARGS_((uid_t user)); -extern unsigned sleep _ANSI_ARGS_ ((unsigned seconds)); -extern char *ttyname _ANSI_ARGS_((int fd)); -extern int unlink _ANSI_ARGS_((CONST char *path)); -extern int write _ANSI_ARGS_((int fd, CONST char *buf, size_t size)); +extern void _exit(int status); +extern int access(const char *path, int mode); +extern int chdir(const char *path); +extern int chown(const char *path, uid_t owner, gid_t group); +extern int close(int fd); +extern int dup(int oldfd); +extern int dup2(int oldfd, int newfd); +extern int execl(const char *path, ...); +extern int execle(const char *path, ...); +extern int execlp(const char *file, ...); +extern int execv(const char *path, char **argv); +extern int execve(const char *path, char **argv, char **envp); +extern int execvpw(const char *file, char **argv); +extern pid_t fork(void); +extern char * getcwd(char *buf, size_t size); +extern gid_t getegid(void); +extern uid_t geteuid(void); +extern gid_t getgid(void); +extern int getgroups(int bufSize, int *buffer); +extern pid_t getpid(void); +extern uid_t getuid(void); +extern int isatty(int fd); +extern long lseek(int fd, long offset, int whence); +extern int pipe(int *fildes); +extern int read(int fd, char *buf, size_t size); +extern int setgid(gid_t group); +extern int setuid(uid_t user); +extern unsigned sleep(unsigned seconds); +extern char * ttyname(int fd); +extern int unlink(const char *path); +extern int write(int fd, const char *buf, size_t size); #ifndef _POSIX_SOURCE -extern char *crypt _ANSI_ARGS_((CONST char *, CONST char *)); -extern int fchown _ANSI_ARGS_((int fd, uid_t owner, gid_t group)); -extern int flock _ANSI_ARGS_((int fd, int operation)); -extern int ftruncate _ANSI_ARGS_((int fd, unsigned long length)); -extern int ioctl _ANSI_ARGS_((int fd, int request, ...)); -extern int readlink _ANSI_ARGS_((CONST char *path, char *buf, int bufsize)); -extern int setegid _ANSI_ARGS_((gid_t group)); -extern int seteuid _ANSI_ARGS_((uid_t user)); -extern int setreuid _ANSI_ARGS_((int ruid, int euid)); -extern int symlink _ANSI_ARGS_((CONST char *, CONST char *)); -extern int ttyslot _ANSI_ARGS_((void)); -extern int truncate _ANSI_ARGS_((CONST char *path, unsigned long length)); -extern int vfork _ANSI_ARGS_((void)); +extern char * crypt(const char *, const char *); +extern int fchown(int fd, uid_t owner, gid_t group); +extern int flock(int fd, int operation); +extern int ftruncate(int fd, unsigned long length); +extern int ioctl(int fd, int request, ...); +extern int readlink(const char *path, char *buf, int bufsize); +extern int setegid(gid_t group); +extern int seteuidw(uid_t user); +extern int setreuid(int ruid, int euid); +extern int symlink(const char *, const char *); +extern int ttyslot(void); +extern int truncate(const char *path, unsigned long length); +extern int vfork(void); #endif /* _POSIX_SOURCE */ #endif /* _UNISTD */ - -- cgit v0.12 From b2d00eb8176d84863a75aa771036a478115dbf57 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 26 Dec 2012 10:07:54 +0000 Subject: proposed fix for Bug 3598300 --- generic/tclPort.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/generic/tclPort.h b/generic/tclPort.h index 7021b8d..12a60db 100644 --- a/generic/tclPort.h +++ b/generic/tclPort.h @@ -19,11 +19,10 @@ #endif #if defined(_WIN32) # include "tclWinPort.h" -#endif -#include "tcl.h" -#if !defined(_WIN32) +#else # include "tclUnixPort.h" #endif +#include "tcl.h" #if !defined(LLONG_MIN) # ifdef TCL_WIDE_INT_IS_LONG -- cgit v0.12 From 20253b8c7d3f3c59314380703be48df859cdf9e6 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 27 Dec 2012 14:41:15 +0000 Subject: [Bug 3598580]: Tcl_ListObjReplace may release deleted elements too early Tests!? Where are the tests!?! They are in test listobj-11.1 --- ChangeLog | 5 +++++ generic/tclListObj.c | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 204275f..728b677 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-12-27 Jan Nijtmans + + * generic/tclListObj.c: [Bug 3598580]: Tcl_ListObjReplace may release + deleted elements too early + 2012-12-21 Jan Nijtmans * unix/dltest/pkgb.c: Turn pkgb.so into a Tcl9 interoperability test diff --git a/generic/tclListObj.c b/generic/tclListObj.c index fffe6a2..b4af98a 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -655,6 +655,10 @@ Tcl_ListObjReplace(interp, listPtr, first, count, objc, objv) count = 0; } + for (i = 0; i < objc; i++) { + Tcl_IncrRefCount(objv[i]); + } + numRequired = (numElems - count + objc); if (numRequired <= listRepPtr->maxElemCount) { /* @@ -689,7 +693,6 @@ Tcl_ListObjReplace(interp, listPtr, first, count, objc, objv) for (i = 0, j = first; i < objc; i++, j++) { elemPtrs[j] = objv[i]; - Tcl_IncrRefCount(objv[i]); } /* @@ -745,7 +748,6 @@ Tcl_ListObjReplace(interp, listPtr, first, count, objc, objv) for (i = 0, j = first; i < objc; i++, j++) { newPtrs[j] = objv[i]; - Tcl_IncrRefCount(objv[i]); } listRepPtr->elemCount = numRequired; -- cgit v0.12 From ac61536f6a47bcbaa93399b81a184f647d62a259 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 27 Dec 2012 20:54:31 +0000 Subject: restore old refcounts in TCL_ERROR case. --- generic/tclListObj.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/generic/tclListObj.c b/generic/tclListObj.c index 1166759..97e7152 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -906,6 +906,9 @@ Tcl_ListObjReplace( listRepPtr = AttemptNewList(interp, newMax, NULL); if (listRepPtr == NULL) { + for (i = 0; i < objc; i++) { + objv[i]->refCount--; + } return TCL_ERROR; } -- cgit v0.12 From 7523143f3e7c3a026b3addb99bfeb70dd9adaff5 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sat, 29 Dec 2012 00:06:42 +0000 Subject: For Tcl9, do a real Tcl_DecrRefCount --- generic/tclListObj.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/generic/tclListObj.c b/generic/tclListObj.c index 97e7152..5b73a155 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -907,7 +907,11 @@ Tcl_ListObjReplace( listRepPtr = AttemptNewList(interp, newMax, NULL); if (listRepPtr == NULL) { for (i = 0; i < objc; i++) { +#if TCL_MAJOR_VERSION > 8 + Tcl_DecrRefCount(objv[i]); +#else objv[i]->refCount--; +#endif } return TCL_ERROR; } -- cgit v0.12 From 42b09bbed6f6321e1ef37e138d47cb0a508d3f93 Mon Sep 17 00:00:00 2001 From: dkf Date: Mon, 31 Dec 2012 02:39:40 +0000 Subject: Working towards more efficient treatment of non-bytecoded ensemble subcommands. --- generic/tclCompile.c | 5 ++++ generic/tclCompile.h | 4 ++- generic/tclEnsemble.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++---- generic/tclExecute.c | 57 ++++++++++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+), 6 deletions(-) diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 309682d..c052531 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -529,6 +529,11 @@ InstructionDesc const tclInstructionTable[] = { /* Forces the variable indexed by opnd to be an array. Does not touch * the stack. */ + {"invokeReplace", 5, INT_MIN, 1, {OPERAND_UINT4}}, + /* Invoke command named objv[0], replacing the first two words with + * the word at the top of the stack; + * = */ + {NULL, 0, 0, 0, {OPERAND_NONE}} }; diff --git a/generic/tclCompile.h b/generic/tclCompile.h index 3302f9b..4d8ed65 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -711,8 +711,10 @@ typedef struct ByteCode { #define INST_ARRAY_MAKE_STK 161 #define INST_ARRAY_MAKE_IMM 162 +#define INST_INVOKE_REPLACE 163 + /* The last opcode */ -#define LAST_INST_OPCODE 162 +#define LAST_INST_OPCODE 163 /* * Table describing the Tcl bytecode instructions: their name (for displaying diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index b76c603..8f0d4fe 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -35,6 +35,14 @@ static void MakeCachedEnsembleCommand(Tcl_Obj *objPtr, static void FreeEnsembleCmdRep(Tcl_Obj *objPtr); static void DupEnsembleCmdRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr); static void StringOfEnsembleCmdRep(Tcl_Obj *objPtr); +static int CompileToCompiledCommand(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Tcl_Token *tokenPtr, + int len, Tcl_Obj **elems, Command *cmdPtr, + CompileEnv *envPtr); +static int CompileToInvokedCommand(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Tcl_Token *tokenPtr, + int len, Tcl_Obj **elems, Command *cmdPtr, + CompileEnv *envPtr); /* * The lists of subcommands and options for the [namespace ensemble] command. @@ -2734,7 +2742,6 @@ TclCompileEnsemble( Tcl_Token *tokenPtr; Tcl_Obj *mapObj, *subcmdObj, *targetCmdObj, *listObj, **elems; Tcl_Command ensemble = (Tcl_Command) cmdPtr; - Tcl_Parse synthetic; int len, result, flags = 0, i; unsigned numBytes; const char *word; @@ -2920,7 +2927,7 @@ TclCompileEnsemble( if (Tcl_ListObjGetElements(NULL, targetCmdObj, &len, &elems) != TCL_OK) { return TCL_ERROR; } - if (len > 1 && Tcl_IsSafe(interp)) { + if (len > 1 || Tcl_IsSafe(interp)) { return TCL_ERROR; } targetCmdObj = elems[0]; @@ -2928,7 +2935,7 @@ TclCompileEnsemble( Tcl_IncrRefCount(targetCmdObj); cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, targetCmdObj); TclDecrRefCount(targetCmdObj); - if (cmdPtr == NULL || cmdPtr->compileProc == NULL + if (cmdPtr == NULL || cmdPtr->nsPtr->flags & NS_SUPPRESS_COMPILATION || cmdPtr->flags * CMD_HAS_EXEC_TRACES || ((Interp *)interp)->flags & DONT_COMPILE_CMDS_INLINE) { @@ -2942,10 +2949,39 @@ TclCompileEnsemble( /* * Now we've done the mapping process, can now actually try to compile. - * We do this by handing off to the subcommand's actual compiler. But to - * do that, we have to perform some trickery to rewrite the arguments. + * If there is a subcommand compiler and that successfully produces code, + * we'll use that. Otherwise, we fall back to generating opcodes to do the + * invoke at runtime. */ + if (cmdPtr->compileProc != NULL && + CompileToCompiledCommand(interp, parsePtr, tokenPtr, + len, elems, cmdPtr, envPtr) == TCL_OK) { + return TCL_OK; + } + return CompileToInvokedCommand(interp, parsePtr, tokenPtr, + len, elems, cmdPtr, envPtr); +} + +/* + * How to compile a subcommand using its own command compiler. To do that, we + * have to perform some trickery to rewrite the arguments, as compilers *must* + * have parse tokens that refer to addresses in the original script. + */ + +static int +CompileToCompiledCommand( + Tcl_Interp *interp, + Tcl_Parse *parsePtr, + Tcl_Token *tokenPtr, + int len, + Tcl_Obj **elems, + Command *cmdPtr, + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + Tcl_Parse synthetic; + int result, i; + TclParseInit(interp, NULL, 0, &synthetic); synthetic.numWords = parsePtr->numWords - 2 + len; TclGrowParseTokenArray(&synthetic, 2*len); @@ -3001,6 +3037,41 @@ TclCompileEnsemble( Tcl_FreeParse(&synthetic); return result; } + +static int +CompileToInvokedCommand( + Tcl_Interp *interp, + Tcl_Parse *parsePtr, + Tcl_Token *tokenPtr, + int len, + Tcl_Obj **elems, + Command *cmdPtr, + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + Tcl_Obj *objPtr = Tcl_NewObj(); + char *bytes; + int length, i, literal; + + if (len != 1) { + return TCL_ERROR; + } + + // TODO: Generate magic (with new instruction) for setting up the ensemble + // rewriting... + + for (i=0,tokenPtr=parsePtr->tokenPtr ; inumWords ; i++) { + TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); + tokenPtr = TokenAfter(tokenPtr); + } + Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr); + bytes = Tcl_GetStringFromObj(objPtr, &length); + literal = TclRegisterNewCmdLiteral(envPtr, bytes, length); + TclDecrRefCount(objPtr); + TclEmitPush(literal, envPtr); + TclEmitInstInt4(INST_INVOKE_REPLACE, parsePtr->numWords, envPtr); + TclAdjustStackDepth(-1, envPtr); + return TCL_OK; +} /* * Local Variables: diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 2b5f713..3fab3cc 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2972,6 +2972,63 @@ TEBCresume( Tcl_Panic("TclNRExecuteByteCode: obsolete INST_CALL_FUNC1 found"); #endif + case INST_INVOKE_REPLACE: + objc = TclGetUInt4AtPtr(pc+1); + objPtr = POP_OBJECT(); + objv = &OBJ_AT_DEPTH(objc-1); + cleanup = objc; +#ifdef TCL_COMPILE_DEBUG + if (tclTraceExec >= 2) { + int i; + + if (traceInstructions) { + strncpy(cmdNameBuf, TclGetString(objv[0]), 20); + TRACE(("%u => call (implementation %s) ", + objc, O2S(objPtr))); + } else { + fprintf(stdout, + "%d: (%u) invoking (using implementation %s) ", + iPtr->numLevels, (unsigned)(pc - codePtr->codeStart), + O2S(objPtr)); + } + for (i = 0; i < objc; i++) { + TclPrintObject(stdout, objv[i], 15); + fprintf(stdout, " "); + } + fprintf(stdout, "\n"); + fflush(stdout); + } +#endif /*TCL_COMPILE_DEBUG*/ + { + Tcl_Obj *copyPtr = Tcl_NewListObj(objc - 1, NULL); + register List *listRepPtr = copyPtr->internalRep.twoPtrValue.ptr1; + Tcl_Obj **copyObjv = &listRepPtr->elements; + int i; + + listRepPtr->elemCount = objc - 1; + copyObjv[0] = objPtr; + memcpy(copyObjv+1, objv+2, sizeof(Tcl_Obj *) * (objc - 2)); + for (i=1 ; idata.tebc.pc = (char *) pc; + iPtr->cmdFramePtr = bcFramePtr; + if (iPtr->flags & INTERP_DEBUG_FRAME) { + TclArgumentBCEnter((Tcl_Interp *) iPtr, objv, objc, + codePtr, bcFramePtr, pc - codePtr->codeStart); + } + iPtr->ensembleRewrite.sourceObjs = objv; + iPtr->ensembleRewrite.numRemovedObjs = 2; + iPtr->ensembleRewrite.numInsertedObjs = 1; + DECACHE_STACK_INFO(); + pc += 5; + TEBC_YIELD(); + TclNRAddCallback(interp, TclClearRootEnsemble, NULL,NULL,NULL,NULL); + iPtr->evalFlags |= TCL_EVAL_REDIRECT; + return TclNREvalObjEx(interp, objPtr, TCL_EVAL_INVOKE, NULL, INT_MIN); + /* * ----------------------------------------------------------------- * Start of INST_LOAD instructions. -- cgit v0.12 From 1c7c1c74c471463c45093f14f25a4f69af26211f Mon Sep 17 00:00:00 2001 From: dkf Date: Mon, 31 Dec 2012 12:32:13 +0000 Subject: Marked some string subcommands as obsolete, following discussion on tcl-core. --- ChangeLog | 6 ++++++ doc/string.n | 45 +++++++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 43b6dfa..d814777 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-12-31 Donal K. Fellows + + * doc/string.n: Noted the obsolescence of the 'bytelength', + 'wordstart' and 'wordend' subcommands, and moved them to later in the + file. + 2012-12-27 Jan Nijtmans * generic/tclListObj.c: [Bug 3598580]: Tcl_ListObjReplace may release diff --git a/doc/string.n b/doc/string.n index 6b3cc59..f5eae39 100644 --- a/doc/string.n +++ b/doc/string.n @@ -19,26 +19,6 @@ string \- Manipulate strings Performs one of several string operations, depending on \fIoption\fR. The legal \fIoption\fRs (which may be abbreviated) are: .TP -\fBstring bytelength \fIstring\fR -. -Returns a decimal string giving the number of bytes used to represent -\fIstring\fR in memory. Because UTF\-8 uses one to three bytes to -represent Unicode characters, the byte length will not be the same as -the character length in general. The cases where a script cares about -the byte length are rare. -.RS -.PP -In almost all cases, you should use the -\fBstring length\fR operation (including determining the length of a -Tcl byte array value). Refer to the \fBTcl_NumUtfChars\fR manual -entry for more details on the UTF\-8 representation. -.PP -\fICompatibility note:\fR it is likely that this subcommand will be -withdrawn in a future version of Tcl. It is better to use the -\fBencoding convertto\fR command to convert a string to a known -encoding and then apply \fBstring length\fR to that. -.RE -.TP \fBstring compare\fR ?\fB\-nocase\fR? ?\fB\-length int\fR? \fIstring1 string2\fR . Perform a character-by-character comparison of strings \fIstring1\fR @@ -354,6 +334,31 @@ Returns a value equal to \fIstring\fR except that any trailing characters present in the string given by \fIchars\fR are removed. If \fIchars\fR is not specified then white space is removed (any character for which \fBstring is space\fR returns 1, and "\0"). +.SS "OBSOLETE SUBCOMMANDS" +.PP +These subcommands are currently supported, but are likely to go away in a +future release as their functionality is either virtually never used or highly +misleading. +.TP +\fBstring bytelength \fIstring\fR +. +Returns a decimal string giving the number of bytes used to represent +\fIstring\fR in memory. Because UTF\-8 uses one to three bytes to +represent Unicode characters, the byte length will not be the same as +the character length in general. The cases where a script cares about +the byte length are rare. +.RS +.PP +In almost all cases, you should use the +\fBstring length\fR operation (including determining the length of a +Tcl byte array value). Refer to the \fBTcl_NumUtfChars\fR manual +entry for more details on the UTF\-8 representation. +.PP +\fICompatibility note:\fR it is likely that this subcommand will be +withdrawn in a future version of Tcl. It is better to use the +\fBencoding convertto\fR command to convert a string to a known +encoding and then apply \fBstring length\fR to that. +.RE .TP \fBstring wordend \fIstring charIndex\fR . -- cgit v0.12 From d51a3b0e2cbc83b69e055dfaf9b8d9faa74fec70 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 2 Jan 2013 14:12:40 +0000 Subject: test Tcl_GetErrorLine() forwards/backwards compatibility in pkgb.so as well --- unix/dltest/pkgb.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/unix/dltest/pkgb.c b/unix/dltest/pkgb.c index 0bff98b..99f189f 100644 --- a/unix/dltest/pkgb.c +++ b/unix/dltest/pkgb.c @@ -39,6 +39,10 @@ static int Pkgb_UnsafeObjCmd _ANSI_ARGS_((ClientData clientData, *---------------------------------------------------------------------- */ +#ifndef Tcl_GetErrorLine +# define Tcl_GetErrorLine(interp) ((interp)->errorLine) +#endif + static int Pkgb_SubObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ @@ -54,6 +58,9 @@ Pkgb_SubObjCmd(dummy, interp, objc, objv) } if ((Tcl_GetIntFromObj(interp, objv[1], &first) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[2], &second) != TCL_OK)) { + char buf[TCL_INTEGER_SPACE]; + sprintf(buf, "%d", Tcl_GetErrorLine(interp)); + Tcl_AppendResult(interp, " in line: ", buf, NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(first - second)); -- cgit v0.12 From 27cb36afb649f2c7fc5594e7150b4755ba29599f Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 2 Jan 2013 14:16:03 +0000 Subject: Marked some string subcommands as obsolete, following discussion on tcl-core. --- ChangeLog | 6 ++++++ doc/string.n | 63 ++++++++++++++++++++++++++++++++---------------------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index 728b677..8eb7af6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-12-31 Donal K. Fellows + + * doc/string.n: Noted the obsolescence of the 'bytelength', + 'wordstart' and 'wordend' subcommands, and moved them to later in the + file. + 2012-12-27 Jan Nijtmans * generic/tclListObj.c: [Bug 3598580]: Tcl_ListObjReplace may release diff --git a/doc/string.n b/doc/string.n index ef49f15..2f9d2e7 100644 --- a/doc/string.n +++ b/doc/string.n @@ -20,16 +20,6 @@ string \- Manipulate strings Performs one of several string operations, depending on \fIoption\fR. The legal \fIoption\fRs (which may be abbreviated) are: .TP -\fBstring bytelength \fIstring\fR -Returns a decimal string giving the number of bytes used to represent -\fIstring\fR in memory. Because UTF\-8 uses one to three bytes to -represent Unicode characters, the byte length will not be the same as -the character length in general. The cases where a script cares about -the byte length are rare. In almost all cases, you should use the -\fBstring length\fR operation (including determining the length of a -Tcl ByteArray object). Refer to the \fBTcl_NumUtfChars\fR manual -entry for more details on the UTF\-8 representation. -.TP \fBstring compare\fR ?\fB\-nocase\fR? ?\fB\-length int\fR? \fIstring1 string2\fR Perform a character-by-character comparison of strings \fIstring1\fR and \fIstring2\fR. Returns \-1, 0, or 1, depending on whether @@ -47,13 +37,13 @@ the first \fIlength\fR characters are used in the comparison. If \fB\-length\fR is negative, it is ignored. If \fB\-nocase\fR is specified, then the strings are compared in a case-insensitive manner. .TP -\fBstring first \fIstring1 string2\fR ?\fIstartIndex\fR? -Search \fIstring2\fR for a sequence of characters that exactly match -the characters in \fIstring1\fR. If found, return the index of the -first character in the first such match within \fIstring2\fR. If not +\fBstring first \fIneedleString haystackString\fR ?\fIstartIndex\fR? +Search \fIhaystackString\fR for a sequence of characters that exactly match +the characters in \fIneedleString\fR. If found, return the index of the +first character in the first such match within \fIhaystackString\fR. If not found, return \-1. If \fIstartIndex\fR is specified (in any of the forms accepted by the \fBindex\fR method), then the search is -constrained to start with the character in \fIstring2\fR specified by +constrained to start with the character in \fIhaystackString\fR specified by the index. For example, .RS .CS @@ -80,17 +70,17 @@ The last char of the string minus the specified integer offset (e.g. \fBend\-1\fR would refer to the "c" in "abcd"). .PP If \fIcharIndex\fR is less than 0 or greater than or equal to the -length of the string then an empty string is returned. +length of the string then this command returns an empty string. .RE .TP \fBstring is \fIclass\fR ?\fB\-strict\fR? ?\fB\-failindex \fIvarname\fR? \fIstring\fR Returns 1 if \fIstring\fR is a valid member of the specified character class, otherwise returns 0. If \fB\-strict\fR is specified, then an -empty string returns 0, otherwise and empty string will return 1 on +empty string returns 0, otherwise an empty string will return 1 on any class. If \fB\-failindex\fR is specified, then if the function 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 +will not be set if \fBstring is\fR returns 1. The following character classes are recognized (the class name can be abbreviated): .RS .IP \fBalnum\fR 12 @@ -144,13 +134,13 @@ function will return 0, then the \fIvarname\fR will always be set to 0, due to the varied nature of a valid boolean value. .RE .TP -\fBstring last \fIstring1 string2\fR ?\fIlastIndex\fR? -Search \fIstring2\fR for a sequence of characters that exactly match -the characters in \fIstring1\fR. If found, return the index of the -first character in the last such match within \fIstring2\fR. If there +\fBstring last \fIneedleString haystackString\fR ?\fIlastIndex\fR? +Search \fIhaystackString\fR for a sequence of characters that exactly match +the characters in \fIneedleString\fR. If found, return the index of the +first character in the last such match within \fIhaystackString\fR. If there is no match, then return \-1. If \fIlastIndex\fR is specified (in any of the forms accepted by the \fBindex\fR method), then only the -characters in \fIstring2\fR at or before the specified \fIlastIndex\fR +characters in \fIhaystackString\fR at or before the specified \fIlastIndex\fR will be considered by the search. For example, .RS .CS @@ -198,7 +188,7 @@ it will return the string \fB02c322c222c\fR. .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 +it does not. If \fB\-nocase\fR is specified, then the pattern attempts to match against the string in a case insensitive manner. For the two strings to match, their contents must be identical except that the following special sequences may appear in \fIpattern\fR: @@ -278,21 +268,36 @@ specified as for the \fBindex\fR method. .TP \fBstring trim \fIstring\fR ?\fIchars\fR? Returns a value equal to \fIstring\fR except that any leading or -trailing characters from the set given by \fIchars\fR are removed. If +trailing characters present in the string given by \fIchars\fR are removed. If \fIchars\fR is not specified then white space is removed (spaces, tabs, newlines, and carriage returns). .TP \fBstring trimleft \fIstring\fR ?\fIchars\fR? Returns a value equal to \fIstring\fR except that any leading -characters from the set given by \fIchars\fR are removed. If +characters present in the string given by \fIchars\fR are removed. If \fIchars\fR is not specified then white space is removed (spaces, tabs, newlines, and carriage returns). .TP \fBstring trimright \fIstring\fR ?\fIchars\fR? Returns a value equal to \fIstring\fR except that any trailing -characters from the set given by \fIchars\fR are removed. If +characters present in the string given by \fIchars\fR are removed. If \fIchars\fR is not specified then white space is removed (spaces, tabs, newlines, and carriage returns). +.SH "OBSOLETE SUBCOMMANDS" +.PP +These subcommands are currently supported, but are likely to go away in a +future release as their functionality is either virtually never used or highly +misleading. +.TP +\fBstring bytelength \fIstring\fR +Returns a decimal string giving the number of bytes used to represent +\fIstring\fR in memory. Because UTF\-8 uses one to three bytes to +represent Unicode characters, the byte length will not be the same as +the character length in general. The cases where a script cares about +the byte length are rare. In almost all cases, you should use the +\fBstring length\fR operation (including determining the length of a +Tcl ByteArray object). Refer to the \fBTcl_NumUtfChars\fR manual +entry for more details on the UTF\-8 representation. .TP \fBstring wordend \fIstring charIndex\fR Returns the index of the character just after the last one in the word @@ -315,9 +320,9 @@ prefix of the string \fBfoobar\fR. .CS set length [\fBstring length\fR $string] if {$length == 0} { - set isPrefix 0 + set isPrefix 0 } else { - set isPrefix [\fBstring equal\fR -length $length $string "foobar"] + set isPrefix [\fBstring equal\fR -length $length $string "foobar"] } .CE -- cgit v0.12 From 3f4534b92ba967574dc4106bc346ccbbfed9d638 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 2 Jan 2013 14:18:15 +0000 Subject: Don't free ctrl.script if thread creation fails: it is a constant string "testthread wait" normally. --- generic/tclThreadTest.c | 1 - 1 file changed, 1 deletion(-) diff --git a/generic/tclThreadTest.c b/generic/tclThreadTest.c index d298e5b..9d17f56 100644 --- a/generic/tclThreadTest.c +++ b/generic/tclThreadTest.c @@ -420,7 +420,6 @@ TclCreateThread(interp, script, joinable) TCL_THREAD_STACK_DEFAULT, joinable) != TCL_OK) { Tcl_MutexUnlock(&threadMutex); Tcl_AppendResult(interp,"can't create a new thread",NULL); - ckfree((void*)ctrl.script); return TCL_ERROR; } -- cgit v0.12 From 92d844b187a1a7cd56fc2955b50aa461cd9e0086 Mon Sep 17 00:00:00 2001 From: dkf Date: Wed, 2 Jan 2013 15:10:00 +0000 Subject: Passing more tests. --- generic/tclCompile.c | 2 +- generic/tclEnsemble.c | 119 +++++++++++++++++++++++++++++++++----------------- generic/tclExecute.c | 24 ++++++---- 3 files changed, 94 insertions(+), 51 deletions(-) diff --git a/generic/tclCompile.c b/generic/tclCompile.c index c052531..45a74d7 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -529,7 +529,7 @@ InstructionDesc const tclInstructionTable[] = { /* Forces the variable indexed by opnd to be an array. Does not touch * the stack. */ - {"invokeReplace", 5, INT_MIN, 1, {OPERAND_UINT4}}, + {"invokeReplace", 6, INT_MIN, 2, {OPERAND_UINT4,OPERAND_UINT1}}, /* Invoke command named objv[0], replacing the first two words with * the word at the top of the stack; * = */ diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 8f0d4fe..8cd9717 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -39,9 +39,9 @@ static int CompileToCompiledCommand(Tcl_Interp *interp, Tcl_Parse *parsePtr, Tcl_Token *tokenPtr, int len, Tcl_Obj **elems, Command *cmdPtr, CompileEnv *envPtr); -static int CompileToInvokedCommand(Tcl_Interp *interp, +static void CompileToInvokedCommand(Tcl_Interp *interp, Tcl_Parse *parsePtr, Tcl_Token *tokenPtr, - int len, Tcl_Obj **elems, Command *cmdPtr, + Tcl_Obj *replacements, Command *cmdPtr, CompileEnv *envPtr); /* @@ -2739,24 +2739,24 @@ TclCompileEnsemble( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { - Tcl_Token *tokenPtr; + Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr); Tcl_Obj *mapObj, *subcmdObj, *targetCmdObj, *listObj, **elems; + Tcl_Obj *replaced = Tcl_NewObj(), *replacement; Tcl_Command ensemble = (Tcl_Command) cmdPtr; - int len, result, flags = 0, i; + int len, result, flags = 0, i, depth = 1; unsigned numBytes; const char *word; - if (parsePtr->numWords < 2) { - return TCL_ERROR; + Tcl_IncrRefCount(replaced); + if (parsePtr->numWords < depth + 1) { + goto failed; } - - tokenPtr = TokenAfter(parsePtr->tokenPtr); if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { /* * Too hard. */ - return TCL_ERROR; + goto failed; } word = tokenPtr[1].start; @@ -2775,7 +2775,7 @@ TclCompileEnsemble( * to proceed. */ - return TCL_ERROR; + goto failed; } /* @@ -2789,7 +2789,7 @@ TclCompileEnsemble( * Figuring out how to compile this has become too much. Bail out. */ - return TCL_ERROR; + goto failed; } /* @@ -2812,7 +2812,7 @@ TclCompileEnsemble( Tcl_Obj *matchObj = NULL; if (Tcl_ListObjGetElements(NULL, listObj, &len, &elems) != TCL_OK) { - return TCL_ERROR; + goto failed; } for (i=0 ; i 1 || Tcl_IsSafe(interp)) { - return TCL_ERROR; + goto failed; } targetCmdObj = elems[0]; @@ -2944,7 +2950,12 @@ TclCompileEnsemble( * Cannot compile. */ - return TCL_ERROR; + goto failed; + } + depth++; + + if (cmdPtr->compileProc == TclCompileEnsemble) { + // TODO: Back round the loop to parse the next level down. } /* @@ -2957,10 +2968,23 @@ TclCompileEnsemble( if (cmdPtr->compileProc != NULL && CompileToCompiledCommand(interp, parsePtr, tokenPtr, len, elems, cmdPtr, envPtr) == TCL_OK) { - return TCL_OK; + goto succeeded; + } else if (len != 1) { + goto failed; } - return CompileToInvokedCommand(interp, parsePtr, tokenPtr, - len, elems, cmdPtr, envPtr); + CompileToInvokedCommand(interp, parsePtr, tokenPtr, replaced, + cmdPtr, envPtr); + succeeded: + if (replaced != NULL) { + Tcl_DecrRefCount(replaced); + } + return TCL_OK; + + failed: + if (replaced != NULL) { + Tcl_DecrRefCount(replaced); + } + return TCL_ERROR; } /* @@ -3038,39 +3062,52 @@ CompileToCompiledCommand( return result; } -static int +static void CompileToInvokedCommand( Tcl_Interp *interp, Tcl_Parse *parsePtr, Tcl_Token *tokenPtr, - int len, - Tcl_Obj **elems, + Tcl_Obj *replacements, Command *cmdPtr, CompileEnv *envPtr) /* Holds resulting instructions. */ { - Tcl_Obj *objPtr = Tcl_NewObj(); + Tcl_Token *tokPtr; + Tcl_Obj *objPtr, **words; char *bytes; - int length, i, literal; - - if (len != 1) { - return TCL_ERROR; - } + int length, i, numWords; // TODO: Generate magic (with new instruction) for setting up the ensemble // rewriting... - for (i=0,tokenPtr=parsePtr->tokenPtr ; inumWords ; i++) { - TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); - tokenPtr = TokenAfter(tokenPtr); + Tcl_ListObjGetElements(NULL, replacements, &numWords, &words); + for (i=0,tokPtr=parsePtr->tokenPtr ; inumWords ; i++) { + if (i > 0 && i-1 < numWords) { + bytes = Tcl_GetStringFromObj(words[i-1], &length); + PushLiteral(envPtr, bytes, length); + } else { + TclCompileTokens(interp, tokPtr+1, tokPtr->numComponents, envPtr); + } + tokPtr = TokenAfter(tokPtr); } + + /* + * Push the name of the command we're actually dispatching to as part of + * the implementation. + */ + + objPtr = Tcl_NewObj(); Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr); bytes = Tcl_GetStringFromObj(objPtr, &length); - literal = TclRegisterNewCmdLiteral(envPtr, bytes, length); + PushLiteral(envPtr, bytes, length); TclDecrRefCount(objPtr); - TclEmitPush(literal, envPtr); + + /* + * Do the replacing dispatch. + */ + TclEmitInstInt4(INST_INVOKE_REPLACE, parsePtr->numWords, envPtr); - TclAdjustStackDepth(-1, envPtr); - return TCL_OK; + TclEmitInt1(numWords+1, envPtr); + TclAdjustStackDepth(-1, envPtr); /* Correction to stack depth calcs. */ } /* diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 3fab3cc..b0da17d 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2974,6 +2974,7 @@ TEBCresume( case INST_INVOKE_REPLACE: objc = TclGetUInt4AtPtr(pc+1); + opnd = TclGetUInt1AtPtr(pc+5); objPtr = POP_OBJECT(); objv = &OBJ_AT_DEPTH(objc-1); cleanup = objc; @@ -2983,8 +2984,7 @@ TEBCresume( if (traceInstructions) { strncpy(cmdNameBuf, TclGetString(objv[0]), 20); - TRACE(("%u => call (implementation %s) ", - objc, O2S(objPtr))); + TRACE(("%u => call (implementation %s) ", objc, O2S(objPtr))); } else { fprintf(stdout, "%d: (%u) invoking (using implementation %s) ", @@ -2992,7 +2992,13 @@ TEBCresume( O2S(objPtr)); } for (i = 0; i < objc; i++) { - TclPrintObject(stdout, objv[i], 15); + if (i < opnd) { + fprintf(stdout, "<"); + TclPrintObject(stdout, objv[i], 15); + fprintf(stdout, ">"); + } else { + TclPrintObject(stdout, objv[i], 15); + } fprintf(stdout, " "); } fprintf(stdout, "\n"); @@ -3000,15 +3006,15 @@ TEBCresume( } #endif /*TCL_COMPILE_DEBUG*/ { - Tcl_Obj *copyPtr = Tcl_NewListObj(objc - 1, NULL); + Tcl_Obj *copyPtr = Tcl_NewListObj(objc - opnd + 1, NULL); register List *listRepPtr = copyPtr->internalRep.twoPtrValue.ptr1; Tcl_Obj **copyObjv = &listRepPtr->elements; int i; - listRepPtr->elemCount = objc - 1; + listRepPtr->elemCount = objc - opnd + 1; copyObjv[0] = objPtr; - memcpy(copyObjv+1, objv+2, sizeof(Tcl_Obj *) * (objc - 2)); - for (i=1 ; icodeStart); } iPtr->ensembleRewrite.sourceObjs = objv; - iPtr->ensembleRewrite.numRemovedObjs = 2; + iPtr->ensembleRewrite.numRemovedObjs = opnd; iPtr->ensembleRewrite.numInsertedObjs = 1; DECACHE_STACK_INFO(); - pc += 5; + pc += 6; TEBC_YIELD(); TclNRAddCallback(interp, TclClearRootEnsemble, NULL,NULL,NULL,NULL); iPtr->evalFlags |= TCL_EVAL_REDIRECT; -- cgit v0.12 From 810edde822b6b99b1dcc766be690db919e90e361 Mon Sep 17 00:00:00 2001 From: dkf Date: Wed, 2 Jan 2013 18:33:27 +0000 Subject: All tests pass except one; not sure what's wrong there. --- generic/tclCompCmds.c | 8 +-- generic/tclEnsemble.c | 154 ++++++++++++++++++++++++++++++++------------------ tests/info.test | 26 ++++----- tests/nre.test | 26 +-------- 4 files changed, 118 insertions(+), 96 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 160fa3c..8fa191b 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -5791,7 +5791,7 @@ TclCompileVariableCmd( */ valueTokenPtr = parsePtr->tokenPtr; - for (i=2; i<=numWords; i+=2) { + for (i=1; iextCmdMapPtr; \ + int eclIndex = mapPtr->nuloc - 1 +#define CompileWord(envPtr, tokenPtr, interp, word) \ + if ((tokenPtr)->type == TCL_TOKEN_SIMPLE_WORD) { \ + TclEmitPush(TclRegisterNewLiteral((envPtr), (tokenPtr)[1].start, \ + (tokenPtr)[1].size), (envPtr)); \ + } else { \ + if (mapPtr->loc[eclIndex].next) { \ + envPtr->line = mapPtr->loc[eclIndex].line[word]; \ + envPtr->clNext = mapPtr->loc[eclIndex].next[word]; \ + } \ + TclCompileTokens((interp), (tokenPtr)+1, (tokenPtr)->numComponents, \ + (envPtr)); \ + } static inline Tcl_Obj * NewNsObj( @@ -2743,11 +2761,14 @@ TclCompileEnsemble( Tcl_Obj *mapObj, *subcmdObj, *targetCmdObj, *listObj, **elems; Tcl_Obj *replaced = Tcl_NewObj(), *replacement; Tcl_Command ensemble = (Tcl_Command) cmdPtr; - int len, result, flags = 0, i, depth = 1; + Command *oldCmdPtr = cmdPtr, *newCmdPtr; + int len, result, flags = 0, i, depth = 1, invokeAnyway = 0; + int ourResult = TCL_ERROR; unsigned numBytes; const char *word; Tcl_IncrRefCount(replaced); + checkNextWord: if (parsePtr->numWords < depth + 1) { goto failed; } @@ -2915,6 +2936,7 @@ TclCompileEnsemble( */ if (matched != 1) { + invokeAnyway = 1; goto failed; } } @@ -2933,29 +2955,33 @@ TclCompileEnsemble( if (Tcl_ListObjGetElements(NULL, targetCmdObj, &len, &elems) != TCL_OK) { goto failed; } - if (len > 1 || Tcl_IsSafe(interp)) { + if (len != 1) { goto failed; } targetCmdObj = elems[0]; + oldCmdPtr = cmdPtr; Tcl_IncrRefCount(targetCmdObj); - cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, targetCmdObj); + newCmdPtr = (Command *) Tcl_GetCommandFromObj(interp, targetCmdObj); TclDecrRefCount(targetCmdObj); - if (cmdPtr == NULL - || cmdPtr->nsPtr->flags & NS_SUPPRESS_COMPILATION - || cmdPtr->flags * CMD_HAS_EXEC_TRACES + if (newCmdPtr == NULL || Tcl_IsSafe(interp) + || newCmdPtr->nsPtr->flags & NS_SUPPRESS_COMPILATION + || newCmdPtr->flags & CMD_HAS_EXEC_TRACES || ((Interp *)interp)->flags & DONT_COMPILE_CMDS_INLINE) { /* * Maps to an undefined command or a command without a compiler. * Cannot compile. */ - goto failed; + goto cleanup; } + cmdPtr = newCmdPtr; depth++; if (cmdPtr->compileProc == TclCompileEnsemble) { - // TODO: Back round the loop to parse the next level down. + tokenPtr = TokenAfter(tokenPtr); + ensemble = (Tcl_Command) cmdPtr; + goto checkNextWord; } /* @@ -2965,26 +2991,44 @@ TclCompileEnsemble( * invoke at runtime. */ - if (cmdPtr->compileProc != NULL && - CompileToCompiledCommand(interp, parsePtr, tokenPtr, - len, elems, cmdPtr, envPtr) == TCL_OK) { - goto succeeded; - } else if (len != 1) { - goto failed; - } - CompileToInvokedCommand(interp, parsePtr, tokenPtr, replaced, - cmdPtr, envPtr); - succeeded: - if (replaced != NULL) { - Tcl_DecrRefCount(replaced); + invokeAnyway = 1; + if (cmdPtr->compileProc != NULL) { + if (CompileToCompiledCommand(interp, parsePtr, tokenPtr, depth, + cmdPtr, envPtr) == TCL_OK) { + ourResult = TCL_OK; + goto cleanup; + } } - return TCL_OK; + + /* + * Failed to do a full compile for some reason. Try to do a direct invoke + * instead of going through the ensemble lookup process again. + */ failed: + if (len == 1 && depth < 250) { + if (depth > 1) { + if (!invokeAnyway) { + cmdPtr = oldCmdPtr; + depth--; + } + (void) Tcl_ListObjReplace(NULL, replaced, depth, 2, 0, NULL); + } + CompileToInvokedCommand(interp, parsePtr, replaced, cmdPtr, envPtr); + ourResult = TCL_OK; + } + + /* + * Release the memory we allocated. If we've got here, we've either done + * something useful or we're in a case that we can't compile at all and + * we're just giving up. + */ + + cleanup: if (replaced != NULL) { Tcl_DecrRefCount(replaced); } - return TCL_ERROR; + return ourResult; } /* @@ -2998,46 +3042,44 @@ CompileToCompiledCommand( Tcl_Interp *interp, Tcl_Parse *parsePtr, Tcl_Token *tokenPtr, - int len, - Tcl_Obj **elems, + int depth, Command *cmdPtr, CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Parse synthetic; + Tcl_Token *tokPtr; int result, i; TclParseInit(interp, NULL, 0, &synthetic); - synthetic.numWords = parsePtr->numWords - 2 + len; - TclGrowParseTokenArray(&synthetic, 2*len); - synthetic.numTokens = 2*len; + synthetic.numWords = parsePtr->numWords - depth + 1; + TclGrowParseTokenArray(&synthetic, 2); + synthetic.numTokens = 2; /* - * Now we have the space to work in, install something rewritten. Note - * that we are here praying for all our might that none of these words are - * a script; the error detection code will crash if that happens and there - * is nothing we can do to avoid it! + * Now we have the space to work in, install something rewritten. The + * first word will "officially" be the structured ensemble name. */ - for (i=0 ; itokenPtr[0].start; + synthetic.tokenPtr[0].numComponents = 1; + synthetic.tokenPtr[1].type = TCL_TOKEN_TEXT; + synthetic.tokenPtr[1].start = parsePtr->tokenPtr[0].start; + synthetic.tokenPtr[1].numComponents = 0; + tokPtr = parsePtr->tokenPtr; + for (i=0 ; istart-synthetic.tokenPtr[0].start)+tokPtr->size; + + synthetic.tokenPtr[0].size = sclen; + synthetic.tokenPtr[1].size = sclen; + tokPtr = TokenAfter(tokPtr); } /* * Copy over the real argument tokens. */ - for (i=len; itokenPtr ; inumWords ; i++) { - if (i > 0 && i-1 < numWords) { + if (i > 0 && i < numWords+1) { bytes = Tcl_GetStringFromObj(words[i-1], &length); PushLiteral(envPtr, bytes, length); } else { - TclCompileTokens(interp, tokPtr+1, tokPtr->numComponents, envPtr); + CompileWord(envPtr, tokPtr, interp, i); } tokPtr = TokenAfter(tokPtr); } @@ -3098,7 +3140,9 @@ CompileToInvokedCommand( objPtr = Tcl_NewObj(); Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr); bytes = Tcl_GetStringFromObj(objPtr, &length); - PushLiteral(envPtr, bytes, length); + cmdLit = TclRegisterNewCmdLiteral(envPtr, bytes, length); + TclSetCmdNameObj(interp, envPtr->literalArrayPtr[cmdLit].objPtr, cmdPtr); + TclEmitPush(cmdLit, envPtr); TclDecrRefCount(objPtr); /* diff --git a/tests/info.test b/tests/info.test index 5078e11..ebc853a 100644 --- a/tests/info.test +++ b/tests/info.test @@ -692,31 +692,31 @@ test info-21.5 {miscellaneous error conditions} -returnCodes error -body { ## # ### ### ### ######### ######### ######### ## info frame + ## Helper # For the more complex results we cut the file name down to remove path # dependencies, and we use only part of the first line of the reported # command. The latter is required because otherwise the whole test case may # appear in some results, but the result is part of the testcase. An infinite # string would be required to describe that. The cutting-down breaks this. + proc reduce {frame} { - set pos [lsearch -exact $frame cmd] - incr pos - set cmd [lindex $frame $pos] + set cmd [dict get $frame cmd] if {[regexp \n $cmd]} { - set first [string range [lindex [split $cmd \n] 0] 0 end-4] - set frame [lreplace $frame $pos $pos $first] + dict set frame cmd \ + [string range [lindex [split $cmd \n] 0] 0 end-4] } - set pos [lsearch -exact $frame file] - if {$pos >=0} { - incr pos - set tail [file tail [lindex $frame $pos]] - set frame [lreplace $frame $pos $pos $tail] + if {[dict exists $frame file]} { + dict set frame file \ + [file tail [dict get $frame file]] } - set frame + return $frame } + proc subinterp {} { interp create sub ; interp debug sub -frame 1; interp eval sub [list proc reduce [info args reduce] [info body reduce]] } + ## Helper # Generate a stacktrace from the current location to top. This code # not only depends on the exact location of things, but also on the @@ -1454,9 +1454,9 @@ test info-30.1 {bs+nl in literal words, procedure body, compiled} -body { test info-30.2 {bs+nl in literal words, namespace script} { namespace eval xxx { variable res \ - [reduce [info frame 0]];# line 1457 + [info frame 0];# line 1457 } - return $xxx::res + return [reduce $xxx::res] } {type source line 1457 file info.test cmd {info frame 0} level 0} test info-30.3 {bs+nl in literal words, namespace multi-word script} { diff --git a/tests/nre.test b/tests/nre.test index b8ef2e0..b5eb032 100644 --- a/tests/nre.test +++ b/tests/nre.test @@ -74,7 +74,6 @@ test nre-1.1 {self-recursive procs} -setup { } -constraints { testnrelevels } -result {{0 1 1 1} 0} - test nre-1.2 {self-recursive lambdas} -setup { set a [list i [makebody {apply $::a $i}]] } -body { @@ -85,7 +84,6 @@ test nre-1.2 {self-recursive lambdas} -setup { } -constraints { testnrelevels } -result {{0 1 1 1} 0} - test nre-1.3 {mutually recursive procs and lambdas} -setup { proc a i { apply $::b [incr i] @@ -164,8 +162,7 @@ test nre-5.1 {[namespace eval] is not recursive} -setup { namespace delete ::foo } -constraints { testnrelevels -} -result {{0 3 2 2} 0} - +} -result {{0 2 2 2} 0} test nre-5.2 {[namespace eval] is not recursive} -setup { namespace eval ::foo { setabs @@ -177,7 +174,7 @@ test nre-5.2 {[namespace eval] is not recursive} -setup { namespace delete ::foo } -constraints { testnrelevels -} -result {{0 3 2 2} 0} +} -result {{0 2 2 2} 0} test nre-6.1 {[uplevel] is not recursive} -setup { proc a i [makebody {uplevel 1 [list a $i]}] @@ -189,7 +186,6 @@ test nre-6.1 {[uplevel] is not recursive} -setup { } -constraints { testnrelevels } -result {{0 2 2 0} 0} - test nre-6.2 {[uplevel] is not recursive} -setup { setabs proc a i [makebody {uplevel 1 "set x $i; a $i"}] @@ -211,7 +207,6 @@ test nre-7.1 {[catch] is not recursive} -setup { } -constraints { testnrelevels } -result {{0 3 3 0} 0} - test nre-7.2 {[if] is not recursive} -setup { setabs proc a i [makebody {uplevel 1 "if 1 {a $i}"}] @@ -222,7 +217,6 @@ test nre-7.2 {[if] is not recursive} -setup { } -constraints { testnrelevels } -result {{0 2 2 0} 0} - test nre-7.3 {[while] is not recursive} -setup { setabs proc a i [makebody {uplevel 1 "while 1 {set res \[a $i\]; break}; set res"}] @@ -233,7 +227,6 @@ test nre-7.3 {[while] is not recursive} -setup { } -constraints { testnrelevels } -result {{0 2 2 0} 0} - test nre-7.4 {[for] is not recursive} -setup { setabs proc a i [makebody {uplevel 1 "for {set j 0} {\$j < 10} {incr j} {set res \[a $i\]; break}; set res"}] @@ -244,7 +237,6 @@ test nre-7.4 {[for] is not recursive} -setup { } -constraints { testnrelevels } -result {{0 2 2 0} 0} - test nre-7.5 {[foreach] is not recursive} -setup { # # Enable once [foreach] is NR-enabled @@ -258,7 +250,6 @@ test nre-7.5 {[foreach] is not recursive} -setup { } -constraints { testnrelevels } -result {{0 3 3 0} 0} - test nre-7.6 {[eval] is not recursive} -setup { proc a i [makebody {eval [list a $i]}] } -body { @@ -269,7 +260,6 @@ test nre-7.6 {[eval] is not recursive} -setup { } -constraints { testnrelevels } -result {{0 2 2 1} 0} - test nre-7.7 {[eval] is not recursive} -setup { proc a i [makebody {eval "a $i"}] } -body { @@ -280,7 +270,6 @@ test nre-7.7 {[eval] is not recursive} -setup { } -constraints { testnrelevels } -result {{0 2 2 1} 0} - test nre-7.8 {bug #2910748: switch out of stale BC is not nre-aware} -setup { proc foo args {} foo @@ -295,18 +284,15 @@ test nre-7.8 {bug #2910748: switch out of stale BC is not nre-aware} -setup { } -body { # if switching to plain eval is not nre aware, this will cause a "cannot # yield" error - list [bar] [bar] [bar] } -cleanup { rename bar {} rename foo {} } -result {1 2 3} - test nre-8.1 {nre and {*}} -body { # force an expansion that grows the evaluation stack, check that nre # adapts the TEBCdataPtr. This crashes on failure. - proc inner {} { set long [lrepeat 1000000 1] list {*}$long @@ -321,21 +307,18 @@ test nre-8.2 {nre and {*}, [Bug 2415422]} -body { # force an expansion that grows the evaluation stack, check that nre # adapts the bcFramePtr. This causes an NRE assertion to fail if it is not # done properly. - proc nop {} {} proc crash {} { foreach val [list {*}[lrepeat 100000 x]] { nop } } - crash } -cleanup { rename nop {} rename crash {} } - # # Basic TclOO tests # @@ -351,7 +334,6 @@ test nre-oo.1 {really deep calls in oo - direct} -setup { } -constraints { testnrelevels } -result {{0 1 1 1} 0} - test nre-oo.2 {really deep calls in oo - call via [self]} -setup { oo::object create foo oo::objdefine foo method bar i [makebody {[self] bar $i}] @@ -363,7 +345,6 @@ test nre-oo.2 {really deep calls in oo - call via [self]} -setup { } -constraints { testnrelevels } -result {{0 1 1 1} 0} - test nre-oo.3 {really deep calls in oo - private calls} -setup { oo::object create foo oo::objdefine foo method bar i [makebody {my bar $i}] @@ -375,7 +356,6 @@ test nre-oo.3 {really deep calls in oo - private calls} -setup { } -constraints { testnrelevels } -result {{0 1 1 1} 0} - test nre-oo.4 {really deep calls in oo - overriding} -setup { oo::class create foo { method bar i [makebody {my bar $i}] @@ -392,7 +372,6 @@ test nre-oo.4 {really deep calls in oo - overriding} -setup { } -constraints { testnrelevels } -result {{0 1 1 1} 0} - test nre-oo.5 {really deep calls in oo - forwards} -setup { oo::object create foo set body [makebody {my boo $i}] @@ -409,7 +388,6 @@ test nre-oo.5 {really deep calls in oo - forwards} -setup { testnrelevels } -result {{0 2 1 1} 0} - # # NASTY BUG found by tcllib's interp package # -- cgit v0.12 From 824efe60eb61baf70614388faa035d26131ed1c8 Mon Sep 17 00:00:00 2001 From: mig Date: Wed, 2 Jan 2013 19:20:54 +0000 Subject: remove stray calls to Tcl_Alloc and friends: the core should only use ckalloc to allow MEM_DEBUG to work properly --- ChangeLog | 7 +++++++ generic/tclEnsemble.c | 2 +- generic/tclExecute.c | 6 +++--- generic/tclIORTrans.c | 6 +++--- generic/tclInt.h | 2 +- generic/tclTomMathInterface.c | 6 +++--- 6 files changed, 18 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index d814777..289e10a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-01-02 Miguel Sofer + + * generic/tclEnsemble.c: Remove stray calls to Tcl_Alloc and + * generic/tclExecute.c: friends: the core should only use ckalloc + * generic/tclIORTrans.c: to allow MEM_DEBUG to work properly + * generic/tclTomMathInterface.c: + 2012-12-31 Donal K. Fellows * doc/string.n: Noted the obsolescence of the 'bytelength', diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index b76c603..d8fcf97 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -1579,7 +1579,7 @@ TclMakeEnsemble( Tcl_DStringFree(&buf); Tcl_DStringFree(&hiddenBuf); if (nameParts != NULL) { - Tcl_Free((char *) nameParts); + ckfree((char *) nameParts); } return ensemble; } diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 2b5f713..a9b3fb4 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -1212,7 +1212,7 @@ TclStackFree( Tcl_Obj **markerPtr, *marker; if (iPtr == NULL || iPtr->execEnvPtr == NULL) { - Tcl_Free((char *) freePtr); + ckfree((char *) freePtr); return; } @@ -1272,7 +1272,7 @@ TclStackAlloc( int numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *); if (iPtr == NULL || iPtr->execEnvPtr == NULL) { - return (void *) Tcl_Alloc(numBytes); + return (void *) ckalloc(numBytes); } return (void *) StackAllocWords(interp, numWords); @@ -1291,7 +1291,7 @@ TclStackRealloc( int numWords; if (iPtr == NULL || iPtr->execEnvPtr == NULL) { - return (void *) Tcl_Realloc((char *) ptr, numBytes); + return (void *) ckrealloc((char *) ptr, numBytes); } eePtr = iPtr->execEnvPtr; diff --git a/generic/tclIORTrans.c b/generic/tclIORTrans.c index 2b9efb9..1de635f 100644 --- a/generic/tclIORTrans.c +++ b/generic/tclIORTrans.c @@ -2942,7 +2942,7 @@ ResultClear( return; } - Tcl_Free((char *) rPtr->buf); + ckfree((char *) rPtr->buf); rPtr->buf = NULL; rPtr->allocated = 0; } @@ -2977,10 +2977,10 @@ ResultAdd( if (rPtr->allocated == 0) { rPtr->allocated = toWrite + RB_INCREMENT; - rPtr->buf = UCHARP(Tcl_Alloc(rPtr->allocated)); + rPtr->buf = UCHARP(ckalloc(rPtr->allocated)); } else { rPtr->allocated += toWrite + RB_INCREMENT; - rPtr->buf = UCHARP(Tcl_Realloc((char *) rPtr->buf, + rPtr->buf = UCHARP(ckrealloc((char *) rPtr->buf, rPtr->allocated)); } } diff --git a/generic/tclInt.h b/generic/tclInt.h index 1d04c82..52f1a32 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -4008,7 +4008,7 @@ typedef const char *TclDTraceStr; */ # define TclAllocObjStorageEx(interp, objPtr) \ - (objPtr) = (Tcl_Obj *) Tcl_Alloc(sizeof(Tcl_Obj)) + (objPtr) = (Tcl_Obj *) ckalloc(sizeof(Tcl_Obj)) # define TclFreeObjStorageEx(interp, objPtr) \ ckfree((char *) (objPtr)) diff --git a/generic/tclTomMathInterface.c b/generic/tclTomMathInterface.c index 775e86b..48db8c3 100644 --- a/generic/tclTomMathInterface.c +++ b/generic/tclTomMathInterface.c @@ -111,7 +111,7 @@ extern void * TclBNAlloc( size_t x) { - return (void *) Tcl_Alloc((unsigned int) x); + return (void *) ckalloc((unsigned int) x); } /* @@ -135,7 +135,7 @@ TclBNRealloc( void *p, size_t s) { - return (void *) Tcl_Realloc((char *) p, (unsigned int) s); + return (void *) ckrealloc((char *) p, (unsigned int) s); } /* @@ -161,7 +161,7 @@ extern void TclBNFree( void *p) { - Tcl_Free((char *) p); + ckree((char *) p); } #endif -- cgit v0.12 From 415a324f3cbb26121cb4836b48f68ba5b6b8cf56 Mon Sep 17 00:00:00 2001 From: mig Date: Wed, 2 Jan 2013 19:27:09 +0000 Subject: remove stray calls to Tcl_Alloc and friends: the core should only use ckalloc to allow MEM_DEBUG to work properly --- ChangeLog | 7 +++++++ generic/tclExecute.c | 6 +++--- generic/tclTomMathInterface.c | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index ef01964..4779e0f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-01-02 Miguel Sofer + + * generic/tclEnsemble.c: Remove stray calls to Tcl_Alloc and + * generic/tclExecute.c: friends: the core should only use ckalloc + * generic/tclIORTrans.c: to allow MEM_DEBUG to work properly + * generic/tclTomMathInterface.c: + 2012-12-31 Donal K. Fellows * doc/string.n: Noted the obsolescence of the 'bytelength', diff --git a/generic/tclExecute.c b/generic/tclExecute.c index f2efa0f..229d7c6 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -1063,7 +1063,7 @@ TclStackFree( Tcl_Obj **markerPtr; if (iPtr == NULL || iPtr->execEnvPtr == NULL) { - Tcl_Free((char *) freePtr); + ckfree((char *) freePtr); return; } @@ -1112,7 +1112,7 @@ TclStackAlloc( int numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *); if (iPtr == NULL || iPtr->execEnvPtr == NULL) { - return (void *) Tcl_Alloc(numBytes); + return (void *) ckalloc(numBytes); } return (void *) StackAllocWords(interp, numWords); @@ -1131,7 +1131,7 @@ TclStackRealloc( int numWords; if (iPtr == NULL || iPtr->execEnvPtr == NULL) { - return (void *) Tcl_Realloc((char *) ptr, numBytes); + return (void *) ckrealloc((char *) ptr, numBytes); } eePtr = iPtr->execEnvPtr; diff --git a/generic/tclTomMathInterface.c b/generic/tclTomMathInterface.c index 6e5dac3..89c1132 100644 --- a/generic/tclTomMathInterface.c +++ b/generic/tclTomMathInterface.c @@ -112,7 +112,7 @@ extern void * TclBNAlloc( size_t x) { - return (void *) Tcl_Alloc((unsigned int) x); + return (void *) ckalloc((unsigned int) x); } /* @@ -136,7 +136,7 @@ TclBNRealloc( void *p, size_t s) { - return (void *) Tcl_Realloc((char *) p, (unsigned int) s); + return (void *) ckrealloc((char *) p, (unsigned int) s); } /* @@ -162,7 +162,7 @@ extern void TclBNFree( void *p) { - Tcl_Free((char *) p); + ckfree((char *) p); } #endif -- cgit v0.12 From e82d1f6be8957bb381a19b3663a3e0c34c1480b3 Mon Sep 17 00:00:00 2001 From: dkf Date: Thu, 3 Jan 2013 00:37:29 +0000 Subject: Got the test suite passing cleanly. Excellent. --- generic/tclEnsemble.c | 95 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 35 deletions(-) diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 5bef6e8..d12ffe6 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -4,7 +4,7 @@ * Contains support for ensembles (see TIP#112), which provide simple * mechanism for creating composite commands on top of namespaces. * - * Copyright (c) 2005-2010 Donal K. Fellows. + * Copyright (c) 2005-2013 Donal K. Fellows. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -36,8 +36,8 @@ static void FreeEnsembleCmdRep(Tcl_Obj *objPtr); static void DupEnsembleCmdRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr); static void StringOfEnsembleCmdRep(Tcl_Obj *objPtr); static int CompileToCompiledCommand(Tcl_Interp *interp, - Tcl_Parse *parsePtr, Tcl_Token *tokenPtr, - int depth, Command *cmdPtr, CompileEnv *envPtr); + Tcl_Parse *parsePtr, int depth, Command *cmdPtr, + CompileEnv *envPtr); static void CompileToInvokedCommand(Tcl_Interp *interp, Tcl_Parse *parsePtr, Tcl_Obj *replacements, Command *cmdPtr, CompileEnv *envPtr); @@ -92,18 +92,9 @@ const Tcl_ObjType tclEnsembleCmdType = { #define DefineLineInformation \ ExtCmdLoc *mapPtr = envPtr->extCmdMapPtr; \ int eclIndex = mapPtr->nuloc - 1 -#define CompileWord(envPtr, tokenPtr, interp, word) \ - if ((tokenPtr)->type == TCL_TOKEN_SIMPLE_WORD) { \ - TclEmitPush(TclRegisterNewLiteral((envPtr), (tokenPtr)[1].start, \ - (tokenPtr)[1].size), (envPtr)); \ - } else { \ - if (mapPtr->loc[eclIndex].next) { \ - envPtr->line = mapPtr->loc[eclIndex].line[word]; \ - envPtr->clNext = mapPtr->loc[eclIndex].next[word]; \ - } \ - TclCompileTokens((interp), (tokenPtr)+1, (tokenPtr)->numComponents, \ - (envPtr)); \ - } +#define SetLineInformation(word) \ + envPtr->line = mapPtr->loc[eclIndex].line[(word)]; \ + envPtr->clNext = mapPtr->loc[eclIndex].next[(word)] static inline Tcl_Obj * NewNsObj( @@ -2768,6 +2759,12 @@ TclCompileEnsemble( const char *word; Tcl_IncrRefCount(replaced); + + /* + * This is where we return to if we are parsing multiple nested compiled + * ensembles. [info object] is such a beast. + */ + checkNextWord: if (parsePtr->numWords < depth + 1) { goto failed; @@ -2978,6 +2975,11 @@ TclCompileEnsemble( cmdPtr = newCmdPtr; depth++; + /* + * See whether we have a nested ensemble. If we do, we can go round the + * mulberry bush again, consuming the next word. + */ + if (cmdPtr->compileProc == TclCompileEnsemble) { tokenPtr = TokenAfter(tokenPtr); ensemble = (Tcl_Command) cmdPtr; @@ -2992,12 +2994,10 @@ TclCompileEnsemble( */ invokeAnyway = 1; - if (cmdPtr->compileProc != NULL) { - if (CompileToCompiledCommand(interp, parsePtr, tokenPtr, depth, - cmdPtr, envPtr) == TCL_OK) { - ourResult = TCL_OK; - goto cleanup; - } + if (CompileToCompiledCommand(interp, parsePtr, depth, cmdPtr, + envPtr) == TCL_OK) { + ourResult = TCL_OK; + goto cleanup; } /* @@ -3025,9 +3025,7 @@ TclCompileEnsemble( */ cleanup: - if (replaced != NULL) { - Tcl_DecrRefCount(replaced); - } + Tcl_DecrRefCount(replaced); return ourResult; } @@ -3041,15 +3039,18 @@ static int CompileToCompiledCommand( Tcl_Interp *interp, Tcl_Parse *parsePtr, - Tcl_Token *tokenPtr, int depth, Command *cmdPtr, CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Parse synthetic; - Tcl_Token *tokPtr; + Tcl_Token *tokenPtr; int result, i; + if (cmdPtr->compileProc == NULL) { + return TCL_ERROR; + } + TclParseInit(interp, NULL, 0, &synthetic); synthetic.numWords = parsePtr->numWords - depth + 1; TclGrowParseTokenArray(&synthetic, 2); @@ -3057,7 +3058,9 @@ CompileToCompiledCommand( /* * Now we have the space to work in, install something rewritten. The - * first word will "officially" be the structured ensemble name. + * first word will "officially" be the bytes of the structured ensemble + * name. That's technically wrong, but nobody will care; we just need + * *something* here... */ synthetic.tokenPtr[0].type = TCL_TOKEN_SIMPLE_WORD; @@ -3066,13 +3069,13 @@ CompileToCompiledCommand( synthetic.tokenPtr[1].type = TCL_TOKEN_TEXT; synthetic.tokenPtr[1].start = parsePtr->tokenPtr[0].start; synthetic.tokenPtr[1].numComponents = 0; - tokPtr = parsePtr->tokenPtr; - for (i=0 ; istart-synthetic.tokenPtr[0].start)+tokPtr->size; + for (i=0,tokenPtr=parsePtr->tokenPtr ; istart - synthetic.tokenPtr[0].start) + + tokenPtr->size; synthetic.tokenPtr[0].size = sclen; synthetic.tokenPtr[1].size = sclen; - tokPtr = TokenAfter(tokPtr); + tokenPtr = TokenAfter(tokenPtr); } /* @@ -3082,12 +3085,12 @@ CompileToCompiledCommand( for (i=1; inumComponents + 1; TclGrowParseTokenArray(&synthetic, toCopy); memcpy(synthetic.tokenPtr + synthetic.numTokens, tokenPtr, sizeof(Tcl_Token) * toCopy); synthetic.numTokens += toCopy; + tokenPtr = TokenAfter(tokenPtr); } /* @@ -3104,6 +3107,11 @@ CompileToCompiledCommand( return result; } +/* + * How to compile a subcommand to a _replacing_ invoke of its implementation + * command. + */ + static void CompileToInvokedCommand( Tcl_Interp *interp, @@ -3118,16 +3126,33 @@ CompileToInvokedCommand( int length, i, numWords, cmdLit; DefineLineInformation; - // TODO: Generate magic (with new instruction) for setting up the ensemble - // rewriting... + /* + * Push the words of the command. Take care; the command words may be + * scripts that have backslashes in them, and [info frame 0] can see the + * difference. Hence the call to TclContinuationsEnterDerived... + */ Tcl_ListObjGetElements(NULL, replacements, &numWords, &words); for (i=0,tokPtr=parsePtr->tokenPtr ; inumWords ; i++) { if (i > 0 && i < numWords+1) { bytes = Tcl_GetStringFromObj(words[i-1], &length); PushLiteral(envPtr, bytes, length); + } else if (tokPtr->type == TCL_TOKEN_SIMPLE_WORD) { + int literal = TclRegisterNewLiteral(envPtr, + tokPtr[1].start, tokPtr[1].size); + + if (envPtr->clNext) { + TclContinuationsEnterDerived( + envPtr->literalArrayPtr[literal].objPtr, + tokPtr[1].start - envPtr->source, + mapPtr->loc[eclIndex].next[i]); + } + TclEmitPush(literal, envPtr); } else { - CompileWord(envPtr, tokPtr, interp, i); + if (envPtr->clNext) { + SetLineInformation(i); + } + CompileTokens(envPtr, tokPtr, interp); } tokPtr = TokenAfter(tokPtr); } -- cgit v0.12 From e59a5820dfdb6c77acd3497b07b8236b51bd04d8 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 3 Jan 2013 09:22:04 +0000 Subject: test case for bug-3598580: Tcl_ListObjReplace may release deleted elements too early --- generic/tclTestObj.c | 11 +++++++++++ tests/listObj.test | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/generic/tclTestObj.c b/generic/tclTestObj.c index a55704a..8e9dc93 100644 --- a/generic/tclTestObj.c +++ b/generic/tclTestObj.c @@ -736,6 +736,17 @@ TestobjCmd(clientData, interp, objc, objv) } SetVarToObj(destIndex, varPtr[varIndex]); Tcl_SetObjResult(interp, varPtr[destIndex]); + } else if (strcmp(subCmd, "bug3598580") == 0) { + Tcl_Obj *listObjPtr, *elemObjPtr; + if (objc != 2) { + goto wrongNumArgs; + } + elemObjPtr = Tcl_NewIntObj(123); + listObjPtr = Tcl_NewListObj(1, &elemObjPtr); + /* Replace the single list element through itself, nonsense but legal. */ + Tcl_ListObjReplace(interp, listObjPtr, 0, 1, 1, &elemObjPtr); + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; } else if (strcmp(subCmd, "convert") == 0) { char *typeName; if (objc != 4) { diff --git a/tests/listObj.test b/tests/listObj.test index aa319bb..390ee64 100644 --- a/tests/listObj.test +++ b/tests/listObj.test @@ -181,6 +181,10 @@ test listobj-9.1 {UpdateStringOfList} { string length [list foo\x00help] } 8 +test listobj-11.1 {bug 3598580} { + testobj bug3598580 +} 123 + # cleanup ::tcltest::cleanupTests return -- cgit v0.12 From 09531013443ef55893b05545dc67b5c5c304609e Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 3 Jan 2013 11:40:51 +0000 Subject: suggested fix for Bug 3092089: [file normalize] can remove path component, and for Bug 3587096: startup error message when exe in folder with junction with limited rights --- win/tclWinFile.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/win/tclWinFile.c b/win/tclWinFile.c index a9b321d..a1da83f 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -709,6 +709,12 @@ NativeReadReparse( FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile == INVALID_HANDLE_VALUE) { + hFile = (*tclWinProcs->createFileProc)(linkDirPath, 0, 0, + NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); + } + + if (hFile == INVALID_HANDLE_VALUE) { /* * Error creating directory. */ -- cgit v0.12 From a9a0dc333fa34e4063d416c799dce1c96bb29920 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 3 Jan 2013 14:00:37 +0000 Subject: speling ficks --- generic/tclUtil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 866b6ae..5f4cdae 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -167,7 +167,7 @@ Tcl_ObjType tclEndOffsetType = { * separating whitespace, or a string terminator. It is just * another character in a list element. * - * The interpretaton of a formatted substring as a list element follows + * The interpretation of a formatted substring as a list element follows * rules similar to the parsing of the words of a command in a Tcl script. * Backslash substitution plays a key role, and is defined exactly as it is * in command parsing. The same routine, TclParseBackslash() is used in both @@ -180,7 +180,7 @@ Tcl_ObjType tclEndOffsetType = { * Backslash substitution replaces an "escape sequence" of one or more * characters starting with * \u005c \ BACKSLASH - * with a single character. The one character escape sequent case happens + * with a single character. The one character escape sequence case happens * only when BACKSLASH is the last character in the string. In all other * cases, the escape sequence is at least two characters long. * -- cgit v0.12 From 96dcdfe7ee3f9197034b7488545e57fcf22826dd Mon Sep 17 00:00:00 2001 From: dkf Date: Thu, 3 Jan 2013 14:24:48 +0000 Subject: Channel buffer min size is 1. Issue found by Schelte Bron. --- ChangeLog | 4 ++++ doc/CrtChannel.3 | 2 +- doc/fconfigure.n | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 09a0199..93cf3a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2013-01-03 Donal K. Fellows + * doc/fconfigure.n, doc/CrtChannel.3: Updated to reflect the fact that + the minimum buffer size is one byte, not ten. Identified by Schelte + Bron on the Tcler's Chat. + * generic/tclExecute.c (TEBCresume:INST_INVOKE_REPLACE): * generic/tclEnsemble.c (TclCompileEnsemble): Added new mechanism to allow for more efficient dispatch of non-bytecode-compiled subcommands diff --git a/doc/CrtChannel.3 b/doc/CrtChannel.3 index 55a4024..4e22488 100644 --- a/doc/CrtChannel.3 +++ b/doc/CrtChannel.3 @@ -250,7 +250,7 @@ the default value of 4096 is returned. .PP \fBTcl_SetChannelBufferSize\fR sets the size, in bytes, of buffers that will be allocated in subsequent operations on the channel to store input or -output. The \fIsize\fR argument should be between ten and one million, +output. The \fIsize\fR argument should be between one and one million, allowing buffers of ten bytes to one million bytes. If \fIsize\fR is outside this range, \fBTcl_SetChannelBufferSize\fR sets the buffer size to 4096. diff --git a/doc/fconfigure.n b/doc/fconfigure.n index ac0366c..550d071 100644 --- a/doc/fconfigure.n +++ b/doc/fconfigure.n @@ -72,8 +72,8 @@ initially set to \fBline\fR, and \fBstderr\fR is set to \fBnone\fR. . \fINewvalue\fR must be an integer; its value is used to set the size of buffers, in bytes, subsequently allocated for this channel to store input -or output. \fINewvalue\fR must be between ten and one million, allowing -buffers of ten to one million bytes in size. +or output. \fINewvalue\fR must be between one and one million, allowing +buffers of one to one million bytes in size. .TP \fB\-encoding\fR \fIname\fR . -- cgit v0.12 From f889a9294bd1a1c5df632d4ff4919abf81d72127 Mon Sep 17 00:00:00 2001 From: dkf Date: Thu, 3 Jan 2013 14:35:07 +0000 Subject: "Mine eyes deceive, but others catch me when I fall." -- Someone or other --- doc/CrtChannel.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CrtChannel.3 b/doc/CrtChannel.3 index 4e22488..57bb76e 100644 --- a/doc/CrtChannel.3 +++ b/doc/CrtChannel.3 @@ -251,7 +251,7 @@ the default value of 4096 is returned. \fBTcl_SetChannelBufferSize\fR sets the size, in bytes, of buffers that will be allocated in subsequent operations on the channel to store input or output. The \fIsize\fR argument should be between one and one million, -allowing buffers of ten bytes to one million bytes. If \fIsize\fR is +allowing buffers of one byte to one million bytes. If \fIsize\fR is outside this range, \fBTcl_SetChannelBufferSize\fR sets the buffer size to 4096. .PP -- cgit v0.12 From 047d22960723097544bbeda5eefb066d71b7e38f Mon Sep 17 00:00:00 2001 From: mig Date: Fri, 4 Jan 2013 05:26:40 +0000 Subject: Insure that PURIFY builds cannot exploit the Tcl stack to hide mem defects. --- ChangeLog | 5 +++++ generic/tclExecute.c | 14 +++++++++++++- generic/tclInt.h | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 93cf3a2..3dd2b9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-01-04 Miguel Sofer + + * generic/tclInt.h: Insure that PURIFY builds cannot exploit the + * generic/tclExecute.c: Tcl stack to hide mem defects. + 2013-01-03 Donal K. Fellows * doc/fconfigure.n, doc/CrtChannel.3: Updated to reflect the fact that diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 9fcc8a5..3635bab 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -1048,6 +1048,7 @@ GrowEvaluationStack( return MEMSTART(markerPtr); } } else { +#ifndef PURIFY Tcl_Obj **tmpMarkerPtr = esPtr->tosPtr + 1; int offset = OFFSET(tmpMarkerPtr); @@ -1064,6 +1065,7 @@ GrowEvaluationStack( *esPtr->markerPtr = (Tcl_Obj *) markerPtr; return memStart; } +#endif } /* @@ -1075,8 +1077,9 @@ GrowEvaluationStack( if (move) { moveWords = esPtr->tosPtr - MEMSTART(markerPtr) + 1; } - needed = growth + moveWords + WALLOCALIGN; + needed = growth + moveWords + WALLOCALIGN - 1; + /* * Check if there is enough room in the next stack (if there is one, it * should be both empty and the last one!) @@ -1106,10 +1109,15 @@ GrowEvaluationStack( * including the elements to be copied over and the new marker. */ +#ifndef PURIFY newElems = 2*currElems; while (needed > newElems) { newElems *= 2; } +#else + newElems = needed; +#endif + newBytes = sizeof(ExecStack) + (newElems-1) * sizeof(Tcl_Obj *); oldPtr = esPtr; @@ -1258,6 +1266,10 @@ TclStackFree( } if (esPtr->prevPtr) { eePtr->execStackPtr = esPtr->prevPtr; +#ifdef PURIFY + eePtr->execStackPtr->nextPtr = NULL; + DeleteExecStack(esPtr); +#endif } else { eePtr->execStackPtr = esPtr; } diff --git a/generic/tclInt.h b/generic/tclInt.h index 52f1a32..dd3c1cd 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -4014,6 +4014,7 @@ typedef const char *TclDTraceStr; ckfree((char *) (objPtr)) #undef USE_THREAD_ALLOC +#undef USE_TCLALLOC #elif defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) /* -- cgit v0.12 From aa5bfc6d5bbe02732c290215d4f69c1f1ce37dda Mon Sep 17 00:00:00 2001 From: dkf Date: Fri, 4 Jan 2013 11:06:14 +0000 Subject: Add super-simple compiler to many ensemble subcommands to allow better code generation where we can detect that we're not in the WrongNumArgs case. The compiler just checks that the argument count is in the right range and issues a standard dispatch; that's enough to do an efficient job. --- generic/tclBinary.c | 50 ++++---- generic/tclCmdAH.c | 68 +++++----- generic/tclCmdIL.c | 40 +++--- generic/tclCmdMZ.c | 22 ++-- generic/tclDictObj.c | 12 +- generic/tclEnsemble.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++ generic/tclIOCmd.c | 38 +++--- generic/tclIndexObj.c | 6 +- generic/tclInt.h | 36 ++++++ generic/tclNamesp.c | 20 +-- generic/tclOOInfo.c | 44 +++---- generic/tclVar.c | 16 +-- 12 files changed, 532 insertions(+), 156 deletions(-) diff --git a/generic/tclBinary.c b/generic/tclBinary.c index 5c33308..455b5a6 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -128,6 +128,30 @@ static const char B64Digits[65] = { }; /* + * How to construct the ensembles. + */ + +static const EnsembleImplMap binaryMap[] = { + { "format", BinaryFormatCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0 }, + { "scan", BinaryScanCmd, TclCompileBasicMin2ArgCmd, NULL, NULL, 0 }, + { "encode", NULL, NULL, NULL, NULL, 0 }, + { "decode", NULL, NULL, NULL, NULL, 0 }, + { NULL, NULL, NULL, NULL, NULL, 0 } +}; +static const EnsembleImplMap encodeMap[] = { + { "hex", BinaryEncodeHex, TclCompileBasic1ArgCmd, NULL, (ClientData)HexDigits, 0 }, + { "uuencode", BinaryEncode64, NULL, NULL, (ClientData)UueDigits, 0 }, + { "base64", BinaryEncode64, NULL, NULL, (ClientData)B64Digits, 0 }, + { NULL, NULL, NULL, NULL, NULL, 0 } +}; +static const EnsembleImplMap decodeMap[] = { + { "hex", BinaryDecodeHex, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 }, + { "uuencode", BinaryDecodeUu, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 }, + { "base64", BinaryDecode64, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 }, + { NULL, NULL, NULL, NULL, NULL, 0 } +}; + +/* * 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 formed @@ -688,26 +712,6 @@ TclAppendBytesToByteArray( *---------------------------------------------------------------------- */ -static const EnsembleImplMap binaryMap[] = { -{ "format", BinaryFormatCmd, NULL, NULL, NULL, 0 }, -{ "scan", BinaryScanCmd, NULL, NULL, NULL, 0 }, -{ "encode", NULL, NULL, NULL, NULL, 0 }, -{ "decode", NULL, NULL, NULL, NULL, 0 }, -{ NULL, NULL, NULL, NULL, NULL, 0 } -}; -static const EnsembleImplMap encodeMap[] = { -{ "hex", BinaryEncodeHex, NULL, NULL, (ClientData)HexDigits, 0 }, -{ "uuencode", BinaryEncode64, NULL, NULL, (ClientData)UueDigits, 0 }, -{ "base64", BinaryEncode64, NULL, NULL, (ClientData)B64Digits, 0 }, -{ NULL, NULL, NULL, NULL, NULL, 0 } -}; -static const EnsembleImplMap decodeMap[] = { -{ "hex", BinaryDecodeHex, NULL, NULL, NULL, 0 }, -{ "uuencode", BinaryDecodeUu, NULL, NULL, NULL, 0 }, -{ "base64", BinaryDecode64, NULL, NULL, NULL, 0 }, -{ NULL, NULL, NULL, NULL, NULL, 0 } -}; - Tcl_Command TclInitBinaryCmd( Tcl_Interp *interp) @@ -2357,7 +2361,7 @@ BinaryDecodeHex( static const char *const optStrings[] = { "-strict", NULL }; if (objc < 2 || objc > 3) { - Tcl_WrongNumArgs(interp, 1, objv, "data"); + Tcl_WrongNumArgs(interp, 1, objv, "?options? data"); return TCL_ERROR; } for (i = 1; i < objc-1; ++i) { @@ -2571,7 +2575,7 @@ BinaryDecodeUu( static const char *const optStrings[] = { "-strict", NULL }; if (objc < 2 || objc > 3) { - Tcl_WrongNumArgs(interp, 1, objv, "data"); + Tcl_WrongNumArgs(interp, 1, objv, "?options? data"); return TCL_ERROR; } for (i = 1; i < objc-1; ++i) { @@ -2667,7 +2671,7 @@ BinaryDecode64( static const char *const optStrings[] = { "-strict", NULL }; if (objc < 2 || objc > 3) { - Tcl_WrongNumArgs(interp, 1, objv, "data"); + Tcl_WrongNumArgs(interp, 1, objv, "?options? data"); return TCL_ERROR; } for (i = 1; i < objc-1; ++i) { diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index 133a61b..eb2a303 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -950,40 +950,40 @@ TclInitFileCmd( */ static const EnsembleImplMap initMap[] = { - {"atime", FileAttrAccessTimeCmd, NULL, NULL, NULL, 0}, - {"attributes", TclFileAttrsCmd, NULL, NULL, NULL, 0}, - {"channels", TclChannelNamesCmd, NULL, NULL, NULL, 0}, - {"copy", TclFileCopyCmd, NULL, NULL, NULL, 0}, - {"delete", TclFileDeleteCmd, NULL, NULL, NULL, 0}, - {"dirname", PathDirNameCmd, NULL, NULL, NULL, 0}, - {"executable", FileAttrIsExecutableCmd, NULL, NULL, NULL, 0}, - {"exists", FileAttrIsExistingCmd, NULL, NULL, NULL, 0}, - {"extension", PathExtensionCmd, NULL, NULL, NULL, 0}, - {"isdirectory", FileAttrIsDirectoryCmd, NULL, NULL, NULL, 0}, - {"isfile", FileAttrIsFileCmd, NULL, NULL, NULL, 0}, - {"join", PathJoinCmd, NULL, NULL, NULL, 0}, - {"link", TclFileLinkCmd, NULL, NULL, NULL, 0}, - {"lstat", FileAttrLinkStatCmd, NULL, NULL, NULL, 0}, - {"mtime", FileAttrModifyTimeCmd, NULL, NULL, NULL, 0}, - {"mkdir", TclFileMakeDirsCmd, NULL, NULL, NULL, 0}, - {"nativename", PathNativeNameCmd, NULL, NULL, NULL, 0}, - {"normalize", PathNormalizeCmd, NULL, NULL, NULL, 0}, - {"owned", FileAttrIsOwnedCmd, NULL, NULL, NULL, 0}, - {"pathtype", PathTypeCmd, NULL, NULL, NULL, 0}, - {"readable", FileAttrIsReadableCmd, NULL, NULL, NULL, 0}, - {"readlink", TclFileReadLinkCmd, NULL, NULL, NULL, 0}, - {"rename", TclFileRenameCmd, NULL, NULL, NULL, 0}, - {"rootname", PathRootNameCmd, NULL, NULL, NULL, 0}, - {"separator", FilesystemSeparatorCmd, NULL, NULL, NULL, 0}, - {"size", FileAttrSizeCmd, NULL, NULL, NULL, 0}, - {"split", PathSplitCmd, NULL, NULL, NULL, 0}, - {"stat", FileAttrStatCmd, NULL, NULL, NULL, 0}, - {"system", PathFilesystemCmd, NULL, NULL, NULL, 0}, - {"tail", PathTailCmd, NULL, NULL, NULL, 0}, - {"tempfile", TclFileTemporaryCmd, NULL, NULL, NULL, 0}, - {"type", FileAttrTypeCmd, NULL, NULL, NULL, 0}, - {"volumes", FilesystemVolumesCmd, NULL, NULL, NULL, 0}, - {"writable", FileAttrIsWritableCmd, NULL, NULL, NULL, 0}, + {"atime", FileAttrAccessTimeCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"attributes", TclFileAttrsCmd, NULL, NULL, NULL, 0}, + {"channels", TclChannelNamesCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"copy", TclFileCopyCmd, NULL, NULL, NULL, 0}, + {"delete", TclFileDeleteCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0}, + {"dirname", PathDirNameCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"executable", FileAttrIsExecutableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"exists", FileAttrIsExistingCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"extension", PathExtensionCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"isdirectory", FileAttrIsDirectoryCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"isfile", FileAttrIsFileCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"join", PathJoinCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0}, + {"link", TclFileLinkCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0}, + {"lstat", FileAttrLinkStatCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"mtime", FileAttrModifyTimeCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"mkdir", TclFileMakeDirsCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0}, + {"nativename", PathNativeNameCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"normalize", PathNormalizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"owned", FileAttrIsOwnedCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"pathtype", PathTypeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"readable", FileAttrIsReadableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"readlink", TclFileReadLinkCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"rename", TclFileRenameCmd, NULL, NULL, NULL, 0}, + {"rootname", PathRootNameCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"separator", FilesystemSeparatorCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"size", FileAttrSizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"split", PathSplitCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"stat", FileAttrStatCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"system", PathFilesystemCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"tail", PathTailCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"tempfile", TclFileTemporaryCmd, TclCompileBasic0To2ArgCmd, NULL, NULL, 0}, + {"type", FileAttrTypeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"volumes", FilesystemVolumesCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, + {"writable", FileAttrIsWritableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, NULL, 0} }; return TclMakeEnsemble(interp, "file", initMap); diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index 155e8e4..c70ba23 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -161,30 +161,30 @@ static Tcl_Obj * SelectObjFromSublist(Tcl_Obj *firstPtr, */ static const EnsembleImplMap defaultInfoMap[] = { - {"args", InfoArgsCmd, NULL, NULL, NULL, 0}, - {"body", InfoBodyCmd, NULL, NULL, NULL, 0}, - {"cmdcount", InfoCmdCountCmd, NULL, NULL, NULL, 0}, + {"args", InfoArgsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"body", InfoBodyCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"cmdcount", InfoCmdCountCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, {"commands", InfoCommandsCmd, TclCompileInfoCommandsCmd, NULL, NULL, 0}, - {"complete", InfoCompleteCmd, NULL, NULL, NULL, 0}, + {"complete", InfoCompleteCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"coroutine", TclInfoCoroutineCmd, TclCompileInfoCoroutineCmd, NULL, NULL, 0}, - {"default", InfoDefaultCmd, NULL, NULL, NULL, 0}, - {"errorstack", InfoErrorStackCmd, NULL, NULL, NULL, 0}, + {"default", InfoDefaultCmd, TclCompileBasic3ArgCmd, NULL, NULL, 0}, + {"errorstack", InfoErrorStackCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {"exists", TclInfoExistsCmd, TclCompileInfoExistsCmd, NULL, NULL, 0}, - {"frame", InfoFrameCmd, NULL, NULL, NULL, 0}, - {"functions", InfoFunctionsCmd, NULL, NULL, NULL, 0}, - {"globals", TclInfoGlobalsCmd, NULL, NULL, NULL, 0}, - {"hostname", InfoHostnameCmd, NULL, NULL, NULL, 0}, + {"frame", InfoFrameCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"functions", InfoFunctionsCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"globals", TclInfoGlobalsCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"hostname", InfoHostnameCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, {"level", InfoLevelCmd, TclCompileInfoLevelCmd, NULL, NULL, 0}, - {"library", InfoLibraryCmd, NULL, NULL, NULL, 0}, - {"loaded", InfoLoadedCmd, NULL, NULL, NULL, 0}, - {"locals", TclInfoLocalsCmd, NULL, NULL, NULL, 0}, - {"nameofexecutable", InfoNameOfExecutableCmd, NULL, NULL, NULL, 0}, - {"patchlevel", InfoPatchLevelCmd, NULL, NULL, NULL, 0}, - {"procs", InfoProcsCmd, NULL, NULL, NULL, 0}, - {"script", InfoScriptCmd, NULL, NULL, NULL, 0}, - {"sharedlibextension", InfoSharedlibCmd, NULL, NULL, NULL, 0}, - {"tclversion", InfoTclVersionCmd, NULL, NULL, NULL, 0}, - {"vars", TclInfoVarsCmd, NULL, NULL, NULL, 0}, + {"library", InfoLibraryCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, + {"loaded", InfoLoadedCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"locals", TclInfoLocalsCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"nameofexecutable", InfoNameOfExecutableCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, + {"patchlevel", InfoPatchLevelCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, + {"procs", InfoProcsCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"script", InfoScriptCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"sharedlibextension", InfoSharedlibCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, + {"tclversion", InfoTclVersionCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, + {"vars", TclInfoVarsCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, NULL, 0} }; diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c index fc957c4..95debf8 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.c @@ -3324,7 +3324,7 @@ TclInitStringCmd( Tcl_Interp *interp) /* Current interpreter. */ { static const EnsembleImplMap stringImplMap[] = { - {"bytelength", StringBytesCmd, NULL, NULL, NULL, 0}, + {"bytelength", StringBytesCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"compare", StringCmpCmd, TclCompileStringCmpCmd, NULL, NULL, 0}, {"equal", StringEqualCmd, TclCompileStringEqualCmd, NULL, NULL, 0}, {"first", StringFirstCmd, TclCompileStringFirstCmd, NULL, NULL, 0}, @@ -3335,17 +3335,17 @@ TclInitStringCmd( {"map", StringMapCmd, TclCompileStringMapCmd, NULL, NULL, 0}, {"match", StringMatchCmd, TclCompileStringMatchCmd, NULL, NULL, 0}, {"range", StringRangeCmd, TclCompileStringRangeCmd, NULL, NULL, 0}, - {"repeat", StringReptCmd, NULL, NULL, NULL, 0}, + {"repeat", StringReptCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"replace", StringRplcCmd, NULL, NULL, NULL, 0}, - {"reverse", StringRevCmd, NULL, NULL, NULL, 0}, - {"tolower", StringLowerCmd, NULL, NULL, NULL, 0}, - {"toupper", StringUpperCmd, NULL, NULL, NULL, 0}, - {"totitle", StringTitleCmd, NULL, NULL, NULL, 0}, - {"trim", StringTrimCmd, NULL, NULL, NULL, 0}, - {"trimleft", StringTrimLCmd, NULL, NULL, NULL, 0}, - {"trimright", StringTrimRCmd, NULL, NULL, NULL, 0}, - {"wordend", StringEndCmd, NULL, NULL, NULL, 0}, - {"wordstart", StringStartCmd, NULL, NULL, NULL, 0}, + {"reverse", StringRevCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"tolower", StringLowerCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0}, + {"toupper", StringUpperCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0}, + {"totitle", StringTitleCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0}, + {"trim", StringTrimCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"trimleft", StringTrimLCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"trimright", StringTrimRCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"wordend", StringEndCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"wordstart", StringStartCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, NULL, 0} }; diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index eb3625e..170e744 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -91,22 +91,22 @@ static const EnsembleImplMap implementationMap[] = { {"append", DictAppendCmd, TclCompileDictAppendCmd, NULL, NULL, 0 }, {"create", DictCreateCmd, TclCompileDictCreateCmd, NULL, NULL, 0 }, {"exists", DictExistsCmd, TclCompileDictExistsCmd, NULL, NULL, 0 }, - {"filter", DictFilterCmd, NULL, NULL, NULL, 0 }, + {"filter", DictFilterCmd, NULL, NULL, NULL, 0 }, {"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL, 0 }, {"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL, 0 }, {"incr", DictIncrCmd, TclCompileDictIncrCmd, NULL, NULL, 0 }, - {"info", DictInfoCmd, NULL, NULL, NULL, 0 }, - {"keys", DictKeysCmd, NULL, NULL, NULL, 0 }, + {"info", DictInfoCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 }, + {"keys", DictKeysCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 }, {"lappend", DictLappendCmd, TclCompileDictLappendCmd, NULL, NULL, 0 }, {"map", NULL, TclCompileDictMapCmd, DictMapNRCmd, NULL, 0 }, {"merge", DictMergeCmd, TclCompileDictMergeCmd, NULL, NULL, 0 }, - {"remove", DictRemoveCmd, NULL, NULL, NULL, 0 }, + {"remove", DictRemoveCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0 }, {"replace", DictReplaceCmd, NULL, NULL, NULL, 0 }, {"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 }, - {"size", DictSizeCmd, NULL, NULL, NULL, 0 }, + {"size", DictSizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 }, {"unset", DictUnsetCmd, TclCompileDictUnsetCmd, NULL, NULL, 0 }, {"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL, 0 }, - {"values", DictValuesCmd, NULL, NULL, NULL, 0 }, + {"values", DictValuesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 }, {"with", DictWithCmd, TclCompileDictWithCmd, NULL, NULL, 0 }, {NULL, NULL, NULL, NULL, NULL, 0} }; diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 0cad216..4e2a5cd 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -41,6 +41,9 @@ static int CompileToCompiledCommand(Tcl_Interp *interp, static void CompileToInvokedCommand(Tcl_Interp *interp, Tcl_Parse *parsePtr, Tcl_Obj *replacements, Command *cmdPtr, CompileEnv *envPtr); +static int CompileBasicNArgCommand(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + CompileEnv *envPtr); /* * The lists of subcommands and options for the [namespace ensemble] command. @@ -3182,6 +3185,339 @@ CompileToInvokedCommand( } /* + * Helpers that do issuing of instructions for commands that "don't have + * compilers" (well, they do; these). They all work by just generating base + * code to invoke the command; they're intended for ensemble subcommands so + * that the costs of INST_INVOKE_REPLACE can be avoided where we can work out + * that they're not needed. + * + * Note that these are NOT suitable for commands where there's an argument + * that is a script, as an [info level] or [info frame] in the inner context + * can see the difference. + */ + +static int +CompileBasicNArgCommand( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + Tcl_Token *tokenPtr; + Tcl_Obj *objPtr; + char *bytes; + int length, i, literal; + DefineLineInformation; + + /* + * Push the name of the command we're actually dispatching to as part of + * the implementation. + */ + + objPtr = Tcl_NewObj(); + Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr); + bytes = Tcl_GetStringFromObj(objPtr, &length); + literal = TclRegisterNewCmdLiteral(envPtr, bytes, length); + TclSetCmdNameObj(interp, envPtr->literalArrayPtr[literal].objPtr, cmdPtr); + TclEmitPush(literal, envPtr); + TclDecrRefCount(objPtr); + + /* + * Push the words of the command. + */ + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + for (i=1 ; inumWords ; i++) { + if (envPtr->clNext) { + SetLineInformation(i); + } + if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { + PushLiteral(envPtr, tokenPtr[1].start, tokenPtr[1].size); + } else { + CompileTokens(envPtr, tokenPtr, interp); + } + tokenPtr = TokenAfter(tokenPtr); + } + + /* + * Do the standard dispatch. + */ + + if (i <= 255) { + TclEmitInstInt1(INST_INVOKE_STK1, i, envPtr); + } else { + TclEmitInstInt4(INST_INVOKE_STK4, i, envPtr); + } + return TCL_OK; +} + +int +TclCompileBasic0ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords != 1) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasic1ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords != 2) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasic2ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords != 3) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasic3ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords != 4) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasic0Or1ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords != 1 && parsePtr->numWords != 2) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasic1Or2ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords != 2 && parsePtr->numWords != 3) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasic2Or3ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords != 3 && parsePtr->numWords != 4) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasic0To2ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords < 1 || parsePtr->numWords > 3) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasic1To3ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords < 2 || parsePtr->numWords > 4) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasicMin0ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords < 1) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasicMin1ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords < 2) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +int +TclCompileBasicMin2ArgCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Verify that the number of arguments is correct; that's the only case + * that we know will avoid the call to Tcl_WrongNumArgs() at invoke time, + * which is the only code that sees the shenanigans of ensemble dispatch. + */ + + if (parsePtr->numWords < 3) { + return TCL_ERROR; + } + + return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr); +} + +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c index 005713d..1673bce 100644 --- a/generic/tclIOCmd.c +++ b/generic/tclIOCmd.c @@ -1952,25 +1952,25 @@ TclInitChanCmd( * function at the moment. */ static const EnsembleImplMap initMap[] = { - {"blocked", Tcl_FblockedObjCmd, NULL, NULL, NULL, 0}, - {"close", Tcl_CloseObjCmd, NULL, NULL, NULL, 0}, - {"copy", Tcl_FcopyObjCmd, NULL, NULL, NULL, 0}, - {"create", TclChanCreateObjCmd, NULL, NULL, NULL, 0}, /* TIP #219 */ - {"eof", Tcl_EofObjCmd, NULL, NULL, NULL, 0}, - {"event", Tcl_FileEventObjCmd, NULL, NULL, NULL, 0}, - {"flush", Tcl_FlushObjCmd, NULL, NULL, NULL, 0}, - {"gets", Tcl_GetsObjCmd, NULL, NULL, NULL, 0}, - {"names", TclChannelNamesCmd, NULL, NULL, NULL, 0}, - {"pending", ChanPendingObjCmd, NULL, NULL, NULL, 0}, /* TIP #287 */ - {"pop", TclChanPopObjCmd, NULL, NULL, NULL, 0}, /* TIP #230 */ - {"postevent", TclChanPostEventObjCmd, NULL, NULL, NULL, 0}, /* TIP #219 */ - {"push", TclChanPushObjCmd, NULL, NULL, NULL, 0}, /* TIP #230 */ - {"puts", Tcl_PutsObjCmd, NULL, NULL, NULL, 0}, - {"read", Tcl_ReadObjCmd, NULL, NULL, NULL, 0}, - {"seek", Tcl_SeekObjCmd, NULL, NULL, NULL, 0}, - {"pipe", ChanPipeObjCmd, NULL, NULL, NULL, 0}, /* TIP #304 */ - {"tell", Tcl_TellObjCmd, NULL, NULL, NULL, 0}, - {"truncate", ChanTruncateObjCmd, NULL, NULL, NULL, 0}, /* TIP #208 */ + {"blocked", Tcl_FblockedObjCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"close", Tcl_CloseObjCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"copy", Tcl_FcopyObjCmd, NULL, NULL, NULL, 0}, + {"create", TclChanCreateObjCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, /* TIP #219 */ + {"eof", Tcl_EofObjCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"event", Tcl_FileEventObjCmd, TclCompileBasic2Or3ArgCmd, NULL, NULL, 0}, + {"flush", Tcl_FlushObjCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"gets", Tcl_GetsObjCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"names", TclChannelNamesCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"pending", ChanPendingObjCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, /* TIP #287 */ + {"pipe", ChanPipeObjCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, /* TIP #304 */ + {"pop", TclChanPopObjCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, /* TIP #230 */ + {"postevent", TclChanPostEventObjCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, /* TIP #219 */ + {"push", TclChanPushObjCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, /* TIP #230 */ + {"puts", Tcl_PutsObjCmd, NULL, NULL, NULL, 0}, + {"read", Tcl_ReadObjCmd, NULL, NULL, NULL, 0}, + {"seek", Tcl_SeekObjCmd, TclCompileBasic2Or3ArgCmd, NULL, NULL, 0}, + {"tell", Tcl_TellObjCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"truncate", ChanTruncateObjCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, /* TIP #208 */ {NULL, NULL, NULL, NULL, NULL, 0} }; static const char *const extras[] = { diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index cb345e2..512f5ba 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.c @@ -533,9 +533,9 @@ TclInitPrefixCmd( Tcl_Interp *interp) /* Current interpreter. */ { static const EnsembleImplMap prefixImplMap[] = { - {"all", PrefixAllObjCmd, NULL, NULL, NULL, 0}, - {"longest", PrefixLongestObjCmd, NULL, NULL, NULL, 0}, - {"match", PrefixMatchObjCmd, NULL, NULL, NULL, 0}, + {"all", PrefixAllObjCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"longest", PrefixLongestObjCmd,TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"match", PrefixMatchObjCmd, TclCompileBasicMin2ArgCmd, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, NULL, 0} }; Tcl_Command prefixCmd; diff --git a/generic/tclInt.h b/generic/tclInt.h index 52f1a32..f308a67 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -3716,6 +3716,42 @@ MODULE_SCOPE int TclCompileWhileCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileYieldCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasic0ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasic1ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasic2ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasic3ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasic0Or1ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasic1Or2ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasic2Or3ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasic0To2ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasic1To3ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasicMin0ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasicMin1ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileBasicMin2ArgCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclInvertOpCmd(ClientData clientData, Tcl_Interp *interp, int objc, diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 02d517f..8da4b42 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -160,23 +160,23 @@ static const Tcl_ObjType nsNameType = { */ static const EnsembleImplMap defaultNamespaceMap[] = { - {"children", NamespaceChildrenCmd, NULL, NULL, NULL, 0}, + {"children", NamespaceChildrenCmd, TclCompileBasic0To2ArgCmd, NULL, NULL, 0}, {"code", NamespaceCodeCmd, TclCompileNamespaceCodeCmd, NULL, NULL, 0}, {"current", NamespaceCurrentCmd, TclCompileNamespaceCurrentCmd, NULL, NULL, 0}, - {"delete", NamespaceDeleteCmd, NULL, NULL, NULL, 0}, + {"delete", NamespaceDeleteCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0}, {"ensemble", TclNamespaceEnsembleCmd, NULL, NULL, NULL, 0}, {"eval", NamespaceEvalCmd, NULL, NRNamespaceEvalCmd, NULL, 0}, - {"exists", NamespaceExistsCmd, NULL, NULL, NULL, 0}, - {"export", NamespaceExportCmd, NULL, NULL, NULL, 0}, - {"forget", NamespaceForgetCmd, NULL, NULL, NULL, 0}, - {"import", NamespaceImportCmd, NULL, NULL, NULL, 0}, + {"exists", NamespaceExistsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"export", NamespaceExportCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0}, + {"forget", NamespaceForgetCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0}, + {"import", NamespaceImportCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0}, {"inscope", NamespaceInscopeCmd, NULL, NRNamespaceInscopeCmd, NULL, 0}, - {"origin", NamespaceOriginCmd, NULL, NULL, NULL, 0}, - {"parent", NamespaceParentCmd, NULL, NULL, NULL, 0}, - {"path", NamespacePathCmd, NULL, NULL, NULL, 0}, + {"origin", NamespaceOriginCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"parent", NamespaceParentCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"path", NamespacePathCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {"qualifiers", NamespaceQualifiersCmd, TclCompileNamespaceQualifiersCmd, NULL, NULL, 0}, {"tail", NamespaceTailCmd, TclCompileNamespaceTailCmd, NULL, NULL, 0}, - {"unknown", NamespaceUnknownCmd, NULL, NULL, NULL, 0}, + {"unknown", NamespaceUnknownCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {"upvar", NamespaceUpvarCmd, TclCompileNamespaceUpvarCmd, NULL, NULL, 0}, {"which", NamespaceWhichCmd, TclCompileNamespaceWhichCmd, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, NULL, 0} diff --git a/generic/tclOOInfo.c b/generic/tclOOInfo.c index 5be9b01..3217f98 100644 --- a/generic/tclOOInfo.c +++ b/generic/tclOOInfo.c @@ -48,18 +48,18 @@ static Tcl_ObjCmdProc InfoClassVariablesCmd; */ static const EnsembleImplMap infoObjectCmds[] = { - {"call", InfoObjectCallCmd, NULL, NULL, NULL, 0}, + {"call", InfoObjectCallCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"class", InfoObjectClassCmd, TclCompileInfoObjectClassCmd, NULL, NULL, 0}, - {"definition", InfoObjectDefnCmd, NULL, NULL, NULL, 0}, - {"filters", InfoObjectFiltersCmd, NULL, NULL, NULL, 0}, - {"forward", InfoObjectForwardCmd, NULL, NULL, NULL, 0}, + {"definition", InfoObjectDefnCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"filters", InfoObjectFiltersCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"forward", InfoObjectForwardCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"isa", InfoObjectIsACmd, TclCompileInfoObjectIsACmd, NULL, NULL, 0}, - {"methods", InfoObjectMethodsCmd, NULL, NULL, NULL, 0}, - {"methodtype", InfoObjectMethodTypeCmd, NULL, NULL, NULL, 0}, - {"mixins", InfoObjectMixinsCmd, NULL, NULL, NULL, 0}, + {"methods", InfoObjectMethodsCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0}, + {"methodtype", InfoObjectMethodTypeCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"mixins", InfoObjectMixinsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"namespace", InfoObjectNsCmd, TclCompileInfoObjectNamespaceCmd, NULL, NULL, 0}, - {"variables", InfoObjectVariablesCmd, NULL, NULL, NULL, 0}, - {"vars", InfoObjectVarsCmd, NULL, NULL, NULL, 0}, + {"variables", InfoObjectVariablesCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"vars", InfoObjectVarsCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, NULL, 0} }; @@ -68,19 +68,19 @@ static const EnsembleImplMap infoObjectCmds[] = { */ static const EnsembleImplMap infoClassCmds[] = { - {"call", InfoClassCallCmd, NULL, NULL, NULL, 0}, - {"constructor", InfoClassConstrCmd, NULL, NULL, NULL, 0}, - {"definition", InfoClassDefnCmd, NULL, NULL, NULL, 0}, - {"destructor", InfoClassDestrCmd, NULL, NULL, NULL, 0}, - {"filters", InfoClassFiltersCmd, NULL, NULL, NULL, 0}, - {"forward", InfoClassForwardCmd, NULL, NULL, NULL, 0}, - {"instances", InfoClassInstancesCmd, NULL, NULL, NULL, 0}, - {"methods", InfoClassMethodsCmd, NULL, NULL, NULL, 0}, - {"methodtype", InfoClassMethodTypeCmd, NULL, NULL, NULL, 0}, - {"mixins", InfoClassMixinsCmd, NULL, NULL, NULL, 0}, - {"subclasses", InfoClassSubsCmd, NULL, NULL, NULL, 0}, - {"superclasses", InfoClassSupersCmd, NULL, NULL, NULL, 0}, - {"variables", InfoClassVariablesCmd, NULL, NULL, NULL, 0}, + {"call", InfoClassCallCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"constructor", InfoClassConstrCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"definition", InfoClassDefnCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"destructor", InfoClassDestrCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"filters", InfoClassFiltersCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"forward", InfoClassForwardCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"instances", InfoClassInstancesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"methods", InfoClassMethodsCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0}, + {"methodtype", InfoClassMethodTypeCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"mixins", InfoClassMixinsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"subclasses", InfoClassSubsCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"superclasses", InfoClassSupersCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"variables", InfoClassVariablesCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, NULL, 0} }; diff --git a/generic/tclVar.c b/generic/tclVar.c index 1c01e41..6b67029 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -4222,16 +4222,16 @@ TclInitArrayCmd( Tcl_Interp *interp) /* Current interpreter. */ { static const EnsembleImplMap arrayImplMap[] = { - {"anymore", ArrayAnyMoreCmd, NULL, NULL, NULL, 0}, - {"donesearch", ArrayDoneSearchCmd, NULL, NULL, NULL, 0}, + {"anymore", ArrayAnyMoreCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, + {"donesearch", ArrayDoneSearchCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"exists", ArrayExistsCmd, TclCompileArrayExistsCmd, NULL, NULL, 0}, - {"get", ArrayGetCmd, NULL, NULL, NULL, 0}, - {"names", ArrayNamesCmd, NULL, NULL, NULL, 0}, - {"nextelement", ArrayNextElementCmd, NULL, NULL, NULL, 0}, + {"get", ArrayGetCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"names", ArrayNamesCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0}, + {"nextelement", ArrayNextElementCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"set", ArraySetCmd, TclCompileArraySetCmd, NULL, NULL, 0}, - {"size", ArraySizeCmd, NULL, NULL, NULL, 0}, - {"startsearch", ArrayStartSearchCmd, NULL, NULL, NULL, 0}, - {"statistics", ArrayStatsCmd, NULL, NULL, NULL, 0}, + {"size", ArraySizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"startsearch", ArrayStartSearchCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, + {"statistics", ArrayStatsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"unset", ArrayUnsetCmd, TclCompileArrayUnsetCmd, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, NULL, 0} }; -- cgit v0.12 From 18d9d66f4d3a6a8b468474e25d5bacee500bda85 Mon Sep 17 00:00:00 2001 From: dkf Date: Fri, 4 Jan 2013 14:38:37 +0000 Subject: Fix bad memory access problems found by Miguel Sofer when valgrinding. --- generic/tclCompCmdsSZ.c | 2 +- generic/tclEnsemble.c | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c index 7bead0d..1d04d8b 100644 --- a/generic/tclCompCmdsSZ.c +++ b/generic/tclCompCmdsSZ.c @@ -2737,7 +2737,7 @@ TclCompileUnsetCmd( flags = 1; varTokenPtr = TokenAfter(parsePtr->tokenPtr); leadingWord = Tcl_NewObj(); - if (TclWordKnownAtCompileTime(varTokenPtr, leadingWord)) { + if (numWords > 0 && TclWordKnownAtCompileTime(varTokenPtr, leadingWord)) { int len; const char *bytes = Tcl_GetStringFromObj(leadingWord, &len); diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 4e2a5cd..9a2d598 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -2956,9 +2956,14 @@ TclCompileEnsemble( Tcl_ListObjAppendElement(NULL, replaced, replacement); if (Tcl_ListObjGetElements(NULL, targetCmdObj, &len, &elems) != TCL_OK) { goto failed; - } - if (len != 1) { - goto failed; + } else if (len != 1) { + /* + * Note that at this point we know we can't issue any special + * instruction sequence as the mapping isn't one that we support at + * the compiled level. + */ + + goto cleanup; } targetCmdObj = elems[0]; @@ -3011,7 +3016,7 @@ TclCompileEnsemble( */ failed: - if (len == 1 && depth < 250) { + if (depth < 250) { if (depth > 1) { if (!invokeAnyway) { cmdPtr = oldCmdPtr; -- cgit v0.12 From a2640e1242a6bda25202eb5d73b7cc6a5fa239ef Mon Sep 17 00:00:00 2001 From: dkf Date: Fri, 4 Jan 2013 15:01:57 +0000 Subject: Fix memory leak in [format] compiler. --- generic/tclCompCmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 8fa191b..752db93 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -3082,7 +3082,7 @@ TclCompileFormatCmd( * after our attempt to spot a literal). */ - for (; --i>=0 ;) { + for (; i>=0 ; i--) { Tcl_DecrRefCount(objv[i]); } ckfree(objv); -- cgit v0.12 From f5f116ff983872cb0da47325218d26f0348454f5 Mon Sep 17 00:00:00 2001 From: mig Date: Sat, 5 Jan 2013 00:15:19 +0000 Subject: Add an assertion that checks the stack depth under TCL_COMPILE_DEBUG *before* stack cleanup. It currently triggers at several spots in the testsuite! --- generic/tclExecute.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 3635bab..496bd9b 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -255,9 +255,16 @@ VarHashCreateVar( * and within range. */ -#define NEXT_INST_F(pcAdjustment, nCleanup, resultHandling) \ +#if TCL_COMPILE_DEBUG +#define CHECK_STACK() assert(CURR_DEPTH <= codePtr->maxStackDepth) +#else +#define CHECK_STACK() +#endif + +#define NEXT_INST_F(pcAdjustment, nCleanup, resultHandling) \ do { \ TCL_CT_ASSERT((nCleanup >= 0) && (nCleanup <= 2)); \ + CHECK_STACK(); \ if (nCleanup == 0) { \ if (resultHandling != 0) { \ if ((resultHandling) > 0) { \ @@ -286,7 +293,8 @@ VarHashCreateVar( } \ } while (0) -#define NEXT_INST_V(pcAdjustment, nCleanup, resultHandling) \ +#define NEXT_INST_V(pcAdjustment, nCleanup, resultHandling) \ + CHECK_STACK(); \ do { \ pc += (pcAdjustment); \ cleanup = (nCleanup); \ -- cgit v0.12 From 0498b26260e48f53a79c30db281432e57c78b966 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sat, 5 Jan 2013 00:28:11 +0000 Subject: adjust stub library version number --- doc/InitStubs.3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/InitStubs.3 b/doc/InitStubs.3 index 2cfbb70..e43d23e 100644 --- a/doc/InitStubs.3 +++ b/doc/InitStubs.3 @@ -64,8 +64,8 @@ Define the USE_TCL_STUBS symbol. Typically, you would include the .IP 3) 5 Link the extension with the Tcl stubs library instead of the standard Tcl library. On Unix platforms, the library name is -\fIlibtclstub8.1.a\fR; on Windows platforms, the library name is -\fItclstub81.lib\fR. +\fIlibtclstub8.4.a\fR; on Windows platforms, the library name is +\fItclstub84.lib\fR. .PP If the extension also requires the Tk API, it must also call \fBTk_InitStubs\fR to initialize the Tk stubs interface and link -- cgit v0.12 From 8ed264286869e58830dbd831907ca25189123d6c Mon Sep 17 00:00:00 2001 From: mig Date: Sat, 5 Jan 2013 00:36:25 +0000 Subject: fix the new assertion, it should not trigger when an expansion is in progress --- generic/tclExecute.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 496bd9b..fbf8f6d 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -251,12 +251,15 @@ VarHashCreateVar( * otherwise, push objResultPtr. If (result < 0), objResultPtr already * has the correct reference count. * - * We use the new compile-time assertions to cheack that nCleanup is constant + * We use the new compile-time assertions to check that nCleanup is constant * and within range. */ +/* Verify the stack depth, only when no expansion is in progress */ + #if TCL_COMPILE_DEBUG -#define CHECK_STACK() assert(CURR_DEPTH <= codePtr->maxStackDepth) +#define CHECK_STACK() \ + assert((auxObjList != NULL) || (CURR_DEPTH <= codePtr->maxStackDepth)) #else #define CHECK_STACK() #endif -- cgit v0.12 From a9a9afc838c1d357e9a50c1045a90276f49edb42 Mon Sep 17 00:00:00 2001 From: mig Date: Sat, 5 Jan 2013 03:43:05 +0000 Subject: improved stack checking under TCL_COMPILE_DEBUG --- generic/tclExecute.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index fbf8f6d..8759ec9 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -259,7 +259,8 @@ VarHashCreateVar( #if TCL_COMPILE_DEBUG #define CHECK_STACK() \ - assert((auxObjList != NULL) || (CURR_DEPTH <= codePtr->maxStackDepth)) + ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, \ + /*checkStack*/ auxObjList == NULL) #else #define CHECK_STACK() #endif @@ -696,7 +697,7 @@ static void PrintByteCodeInfo(ByteCode *codePtr); static const char * StringForResultCode(int result); static void ValidatePcAndStackTop(ByteCode *codePtr, const unsigned char *pc, int stackTop, - int stackLowerBound, int checkStack); + int checkStack); #endif /* TCL_COMPILE_DEBUG */ static ByteCode * CompileExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr); static void DeleteExecStack(ExecStack *esPtr); @@ -2254,8 +2255,7 @@ TEBCresume( * Skip the stack depth check if an expansion is in progress. */ - ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, 0, - /*checkStack*/ auxObjList == NULL); + CHECK_STACK(); if (traceInstructions) { fprintf(stdout, "%2d: %2d ", iPtr->numLevels, (int) CURR_DEPTH); TclPrintInstruction(codePtr, pc); @@ -8571,11 +8571,10 @@ ValidatePcAndStackTop( int stackTop, /* Current stack top. Must be between * stackLowerBound and stackUpperBound * (inclusive). */ - int stackLowerBound, /* Smallest legal value for stackTop. */ int checkStack) /* 0 if the stack depth check should be * skipped. */ { - int stackUpperBound = stackLowerBound + codePtr->maxStackDepth; + int stackUpperBound = codePtr->maxStackDepth; /* Greatest legal value for stackTop. */ unsigned relativePc = (unsigned) (pc - codePtr->codeStart); unsigned long codeStart = (unsigned long) codePtr->codeStart; @@ -8593,13 +8592,13 @@ ValidatePcAndStackTop( (unsigned) opCode, relativePc); Tcl_Panic("TclNRExecuteByteCode execution failure: bad opcode"); } - if (checkStack && - ((stackTop < stackLowerBound) || (stackTop > stackUpperBound))) { + if (checkStack && + ((stackTop < 0) || (stackTop > stackUpperBound))) { int numChars; const char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars, NULL); - fprintf(stderr, "\nBad stack top %d at pc %u in TclNRExecuteByteCode (min %i, max %i)", - stackTop, relativePc, stackLowerBound, stackUpperBound); + fprintf(stderr, "\nBad stack top %d at pc %u in TclNRExecuteByteCode (min 0, max %i)", + stackTop, relativePc, stackUpperBound); if (cmd != NULL) { Tcl_Obj *message; -- cgit v0.12 From 4d73199fb21e569752b34938e8155e9e6669538c Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 6 Jan 2013 20:40:57 +0000 Subject: Don't depend on Spencer-specific regexp syntax (/u and /U) any more in unrelated places . Bump http package to 2.8.6. --- ChangeLog | 7 +++++++ library/http/http.tcl | 4 ++-- library/http/pkgIndex.tcl | 2 +- tests/env.test | 2 +- tests/exec.test | 2 +- unix/Makefile.in | 4 ++-- win/Makefile.in | 4 ++-- 7 files changed, 16 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 90a10a6..c112ac3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-01-06 Jan Nijtmans + + * library/http/http.tcl: Don't depend on Spencer-specific regexp + * tests/env.test: syntax (/u and /U) any more in unrelated places. + * tests/exec.test: + Bump http package to 2.8.6. + 2013-01-04 Donal K. Fellows * generic/tclEnsemble.c (CompileBasicNArgCommand): Added very simple diff --git a/library/http/http.tcl b/library/http/http.tcl index d57e3ce..cb221a3 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -11,7 +11,7 @@ package require Tcl 8.6 # Keep this in sync with pkgIndex.tcl and with the install directories in # Makefiles -package provide http 2.8.5 +package provide http 2.8.6 namespace eval http { # Allow resourcing to not clobber existing data @@ -1379,7 +1379,7 @@ proc http::mapReply {string} { } set converted [string map $formMap $string] if {[string match "*\[\u0100-\uffff\]*" $converted]} { - regexp {[\u0100-\uffff]} $converted badChar + 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" diff --git a/library/http/pkgIndex.tcl b/library/http/pkgIndex.tcl index 303d3bd..a8641e1 100644 --- a/library/http/pkgIndex.tcl +++ b/library/http/pkgIndex.tcl @@ -1,2 +1,2 @@ if {![package vsatisfies [package provide Tcl] 8.6]} {return} -package ifneeded http 2.8.5 [list tclPkgSetup $dir http 2.8.5 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] +package ifneeded http 2.8.6 [list tclPkgSetup $dir http 2.8.6 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] diff --git a/tests/env.test b/tests/env.test index 9010f52..e75d517 100644 --- a/tests/env.test +++ b/tests/env.test @@ -70,7 +70,7 @@ set printenvScript [makeFile { } proc mangle s { regsub -all {\[|\\|\]} $s {\\&} s - regsub -all {[\u0000-\u001f\u007f-\uffff]} $s {[manglechar &]} s + regsub -all "\[\u0000-\u001f\u007f-\uffff\]" $s {[manglechar &]} s return [subst -novariables $s] } proc manglechar c { diff --git a/tests/exec.test b/tests/exec.test index 64d3517..871c0c5 100644 --- a/tests/exec.test +++ b/tests/exec.test @@ -157,7 +157,7 @@ test exec-2.6 {redirecting input from immediate source, with UTF} -setup { encoding system iso8859-1 proc quotenonascii s { regsub -all {\[|\\|\]} $s {\\&} s - regsub -all {[\u007f-\uffff]} $s \ + regsub -all "\[\u007f-\uffff\]" $s \ {[apply {c {format {\u%04x} [scan $c %c]}} &]} s return [subst -novariables $s] } diff --git a/unix/Makefile.in b/unix/Makefile.in index df05759..ee31282 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -839,8 +839,8 @@ install-libraries: libraries do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/http1.0; \ done; - @echo "Installing package http 2.8.5 as a Tcl Module"; - @$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.6/http-2.8.5.tm; + @echo "Installing package http 2.8.6 as a Tcl Module"; + @$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.6/http-2.8.6.tm; @echo "Installing package opt0.4 files to $(SCRIPT_INSTALL_DIR)/opt0.4/"; @for i in $(TOP_DIR)/library/opt/*.tcl ; \ do \ diff --git a/win/Makefile.in b/win/Makefile.in index 8cfb68c..39d34dd 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -634,8 +634,8 @@ install-libraries: libraries install-tzdata install-msgs do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/http1.0"; \ done; - @echo "Installing package http 2.8.5 as a Tcl Module"; - @$(COPY) $(ROOT_DIR)/library/http/http.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.6/http-2.8.5.tm; + @echo "Installing package http 2.8.6 as a Tcl Module"; + @$(COPY) $(ROOT_DIR)/library/http/http.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.6/http-2.8.6.tm; @echo "Installing library opt0.4 directory"; @for j in $(ROOT_DIR)/library/opt/*.tcl; \ do \ -- cgit v0.12 From 816ab7a3aa86fad4029569275897b1d8feb0f89d Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 7 Jan 2013 09:59:56 +0000 Subject: Don't call "ulimit" on cygwin: On Cygwin the stack size cannot be modified, and the reported stacksize is much lower than the real one. --- tests/stack.test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/stack.test b/tests/stack.test index e029bbd..44a960b 100644 --- a/tests/stack.test +++ b/tests/stack.test @@ -21,7 +21,8 @@ if {[lsearch [namespace children] ::tcltest] == -1} { # This doesn't catch all cases, for example threads of lower stacksize # can still squeak through. A core check is really needed. -- JH -if {[string equal $::tcl_platform(platform) "unix"]} { +if {[string equal $::tcl_platform(platform) "unix"] + && ![string equal $::tcl_platform(os) "Windows NT"]} { set stackSize [exec /bin/sh -c "ulimit -s"] if {[string is integer $stackSize] && ($stackSize < 2400)} { puts stderr "WARNING: the default application stacksize of $stackSize\ -- cgit v0.12 From 948149043162c4a2fa840e6c242e4bf31fe80dba Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 7 Jan 2013 11:06:16 +0000 Subject: Extend the public and private stub tables with dummy NULL entries, up to the size of the Tcl 8.6 stub tables. This makes it easier to debug extensions which use Tcl 8.5/8.6 features but (erroneously) are attempted to be loaded in Tcl 8.4. --- ChangeLog | 8 +++ generic/tcl.decls | 4 ++ generic/tclDecls.h | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++ generic/tclInt.decls | 35 ++++------ generic/tclIntDecls.h | 155 +++++++++++++++++++++++++++++++++++++++++++ generic/tclStubInit.c | 108 ++++++++++++++++++++++++++++++ 6 files changed, 465 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8eb7af6..a885b3e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2013-01-07 Jan Nijtmans + + * generic/tcl.decls: Extend the public and private stub tables with + * generic/tclInt.decls: dummy NULL entries, up to the size of the + Tcl 8.6 stub tables. This makes it easier to debug extensions which + use Tcl 8.5/8.6 features but (erroneously) are attempted to be loaded + in Tcl 8.4. + 2012-12-31 Donal K. Fellows * doc/string.n: Noted the obsolescence of the 'bytelength', diff --git a/generic/tcl.decls b/generic/tcl.decls index 19bacc3..b8d8d7d 100644 --- a/generic/tcl.decls +++ b/generic/tcl.decls @@ -1795,6 +1795,10 @@ declare 573 { int objc, Tcl_Obj *const objv[], ClientData *clientDataPtr) } +declare 630 { + void TclUnusedStubEntry(void) +} + ############################################################################## # Define the platform specific public Tcl interface. These functions are only diff --git a/generic/tclDecls.h b/generic/tclDecls.h index 29b0eb0..7df9897 100644 --- a/generic/tclDecls.h +++ b/generic/tclDecls.h @@ -1629,6 +1629,64 @@ EXTERN int Tcl_PkgRequireProc _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, int objc, Tcl_Obj *CONST objv[], ClientData *clientDataPtr)); +/* Slot 574 is reserved */ +/* Slot 575 is reserved */ +/* Slot 576 is reserved */ +/* Slot 577 is reserved */ +/* Slot 578 is reserved */ +/* Slot 579 is reserved */ +/* Slot 580 is reserved */ +/* Slot 581 is reserved */ +/* Slot 582 is reserved */ +/* Slot 583 is reserved */ +/* Slot 584 is reserved */ +/* Slot 585 is reserved */ +/* Slot 586 is reserved */ +/* Slot 587 is reserved */ +/* Slot 588 is reserved */ +/* Slot 589 is reserved */ +/* Slot 590 is reserved */ +/* Slot 591 is reserved */ +/* Slot 592 is reserved */ +/* Slot 593 is reserved */ +/* Slot 594 is reserved */ +/* Slot 595 is reserved */ +/* Slot 596 is reserved */ +/* Slot 597 is reserved */ +/* Slot 598 is reserved */ +/* Slot 599 is reserved */ +/* Slot 600 is reserved */ +/* Slot 601 is reserved */ +/* Slot 602 is reserved */ +/* Slot 603 is reserved */ +/* Slot 604 is reserved */ +/* Slot 605 is reserved */ +/* Slot 606 is reserved */ +/* Slot 607 is reserved */ +/* Slot 608 is reserved */ +/* Slot 609 is reserved */ +/* Slot 610 is reserved */ +/* Slot 611 is reserved */ +/* Slot 612 is reserved */ +/* Slot 613 is reserved */ +/* Slot 614 is reserved */ +/* Slot 615 is reserved */ +/* Slot 616 is reserved */ +/* Slot 617 is reserved */ +/* Slot 618 is reserved */ +/* Slot 619 is reserved */ +/* Slot 620 is reserved */ +/* Slot 621 is reserved */ +/* Slot 622 is reserved */ +/* Slot 623 is reserved */ +/* Slot 624 is reserved */ +/* Slot 625 is reserved */ +/* Slot 626 is reserved */ +/* Slot 627 is reserved */ +/* Slot 628 is reserved */ +/* Slot 629 is reserved */ +/* 630 */ +EXTERN void TclUnusedStubEntry _ANSI_ARGS_((void)); typedef struct TclStubHooks { struct TclPlatStubs *tclPlatStubs; @@ -2238,6 +2296,63 @@ typedef struct TclStubs { VOID *reserved571; VOID *reserved572; int (*tcl_PkgRequireProc) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, int objc, Tcl_Obj *CONST objv[], ClientData *clientDataPtr)); /* 573 */ + VOID *reserved574; + VOID *reserved575; + VOID *reserved576; + VOID *reserved577; + VOID *reserved578; + VOID *reserved579; + VOID *reserved580; + VOID *reserved581; + VOID *reserved582; + VOID *reserved583; + VOID *reserved584; + VOID *reserved585; + VOID *reserved586; + VOID *reserved587; + VOID *reserved588; + VOID *reserved589; + VOID *reserved590; + VOID *reserved591; + VOID *reserved592; + VOID *reserved593; + VOID *reserved594; + VOID *reserved595; + VOID *reserved596; + VOID *reserved597; + VOID *reserved598; + VOID *reserved599; + VOID *reserved600; + VOID *reserved601; + VOID *reserved602; + VOID *reserved603; + VOID *reserved604; + VOID *reserved605; + VOID *reserved606; + VOID *reserved607; + VOID *reserved608; + VOID *reserved609; + VOID *reserved610; + VOID *reserved611; + VOID *reserved612; + VOID *reserved613; + VOID *reserved614; + VOID *reserved615; + VOID *reserved616; + VOID *reserved617; + VOID *reserved618; + VOID *reserved619; + VOID *reserved620; + VOID *reserved621; + VOID *reserved622; + VOID *reserved623; + VOID *reserved624; + VOID *reserved625; + VOID *reserved626; + VOID *reserved627; + VOID *reserved628; + VOID *reserved629; + void (*tclUnusedStubEntry) _ANSI_ARGS_((void)); /* 630 */ } TclStubs; #ifdef __cplusplus @@ -4334,10 +4449,72 @@ extern TclStubs *tclStubsPtr; #define Tcl_PkgRequireProc \ (tclStubsPtr->tcl_PkgRequireProc) /* 573 */ #endif +/* Slot 574 is reserved */ +/* Slot 575 is reserved */ +/* Slot 576 is reserved */ +/* Slot 577 is reserved */ +/* Slot 578 is reserved */ +/* Slot 579 is reserved */ +/* Slot 580 is reserved */ +/* Slot 581 is reserved */ +/* Slot 582 is reserved */ +/* Slot 583 is reserved */ +/* Slot 584 is reserved */ +/* Slot 585 is reserved */ +/* Slot 586 is reserved */ +/* Slot 587 is reserved */ +/* Slot 588 is reserved */ +/* Slot 589 is reserved */ +/* Slot 590 is reserved */ +/* Slot 591 is reserved */ +/* Slot 592 is reserved */ +/* Slot 593 is reserved */ +/* Slot 594 is reserved */ +/* Slot 595 is reserved */ +/* Slot 596 is reserved */ +/* Slot 597 is reserved */ +/* Slot 598 is reserved */ +/* Slot 599 is reserved */ +/* Slot 600 is reserved */ +/* Slot 601 is reserved */ +/* Slot 602 is reserved */ +/* Slot 603 is reserved */ +/* Slot 604 is reserved */ +/* Slot 605 is reserved */ +/* Slot 606 is reserved */ +/* Slot 607 is reserved */ +/* Slot 608 is reserved */ +/* Slot 609 is reserved */ +/* Slot 610 is reserved */ +/* Slot 611 is reserved */ +/* Slot 612 is reserved */ +/* Slot 613 is reserved */ +/* Slot 614 is reserved */ +/* Slot 615 is reserved */ +/* Slot 616 is reserved */ +/* Slot 617 is reserved */ +/* Slot 618 is reserved */ +/* Slot 619 is reserved */ +/* Slot 620 is reserved */ +/* Slot 621 is reserved */ +/* Slot 622 is reserved */ +/* Slot 623 is reserved */ +/* Slot 624 is reserved */ +/* Slot 625 is reserved */ +/* Slot 626 is reserved */ +/* Slot 627 is reserved */ +/* Slot 628 is reserved */ +/* Slot 629 is reserved */ +#ifndef TclUnusedStubEntry +#define TclUnusedStubEntry \ + (tclStubsPtr->tclUnusedStubEntry) /* 630 */ +#endif #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ /* !END!: Do not edit above this line. */ +#undef TclUnusedStubEntry + #endif /* _TCLDECLS */ diff --git a/generic/tclInt.decls b/generic/tclInt.decls index bdae099..18d1bdf 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -87,7 +87,7 @@ declare 14 { declare 16 { void TclExprFloatError(Tcl_Interp *interp, double value) } -# Removed in 8.4 +# Removed in 8.4: #declare 17 { # int TclFileAttrsCmd(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) #} @@ -531,19 +531,9 @@ declare 135 { int TclpCheckStackSpace(void) } -# Added in 8.1: - -#declare 137 { -# int TclpChdir(const char *dirName) -#} declare 138 { CONST84_RETURN char *TclGetEnv(const char *name, Tcl_DString *valuePtr) } -#declare 139 { -# int TclpLoadFile(Tcl_Interp *interp, char *fileName, char *sym1, -# char *sym2, Tcl_PackageInitProc **proc1Ptr, -# Tcl_PackageInitProc **proc2Ptr, ClientData *clientDataPtr) -#} declare 140 { int TclLooksLikeInt(const char *bytes, int length) } @@ -579,7 +569,7 @@ declare 149 { void TclHandleRelease(TclHandle handle) } -# Added for Tcl 8.2 +# Added in 8.2: declare 150 { int TclRegAbout(Tcl_Interp *interp, Tcl_RegExp re) @@ -595,7 +585,7 @@ declare 153 { Tcl_Obj *TclGetLibraryPath(void) } -# moved to tclTest.c (static) in 8.3.2/8.4a2 +# moved to tclTest.c (static) in 8.3.2: #declare 154 { # int TclTestChannelCmd(ClientData clientData, # Tcl_Interp *interp, int argc, char **argv) @@ -686,7 +676,7 @@ declare 172 { int TclInThreadExit(void) } -# added for 8.4.2 +# Added in 8.4.2: declare 173 { int TclUniCharMatch(const Tcl_UniChar *string, int strLen, @@ -706,6 +696,10 @@ declare 199 { int TclMatchIsTrivial(const char *pattern) } +declare 249 { + void TclUnusedStubEntry(void) +} + ############################################################################## # Define the platform specific internal Tcl interface. These functions are @@ -758,7 +752,7 @@ declare 9 win { declare 10 win { Tcl_DirEntry *TclpReaddir(DIR *dir) } -# Removed in 8.3.1 (for Win32s only) +# Removed in 8.3.1 (for Win32s only): #declare 10 win { # int TclWinSynchSpawn(void *args, int type, void **trans, Tcl_Pid *pidPtr) #} @@ -807,7 +801,7 @@ declare 20 win { declare 21 win { char *TclpInetNtoa(struct in_addr addr) } -# removed permanently for 8.4 +# Removed in 8.4: #declare 21 win { # void TclpAsyncMark(Tcl_AsyncHandler async) #} @@ -829,20 +823,17 @@ declare 26 win { void TclWinSetInterfaces(int wide) } -# Added in Tcl 8.3.3 / 8.4 +# Added in 8.3.3: declare 27 win { void TclWinFlushDirtyChannels(void) } -# Added in 8.4.2 +# Added in 8.4.2: declare 28 win { void TclWinResetInterfaces(void) } -declare 29 win { - int TclWinCPUID(unsigned int index, unsigned int *regs) -} ################################ # Unix specific functions @@ -903,7 +894,7 @@ declare 12 unix { declare 13 unix { char *TclpInetNtoa(struct in_addr addr) } -declare 29 unix { +declare 29 {win unix} { int TclWinCPUID(unsigned int index, unsigned int *regs) } diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index 91db149..3bb9795 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -505,6 +505,57 @@ EXTERN struct tm * TclpGmtime _ANSI_ARGS_((TclpTime_t_CONST clock)); /* Slot 198 is reserved */ /* 199 */ EXTERN int TclMatchIsTrivial _ANSI_ARGS_((CONST char *pattern)); +/* Slot 200 is reserved */ +/* Slot 201 is reserved */ +/* Slot 202 is reserved */ +/* Slot 203 is reserved */ +/* Slot 204 is reserved */ +/* Slot 205 is reserved */ +/* Slot 206 is reserved */ +/* Slot 207 is reserved */ +/* Slot 208 is reserved */ +/* Slot 209 is reserved */ +/* Slot 210 is reserved */ +/* Slot 211 is reserved */ +/* Slot 212 is reserved */ +/* Slot 213 is reserved */ +/* Slot 214 is reserved */ +/* Slot 215 is reserved */ +/* Slot 216 is reserved */ +/* Slot 217 is reserved */ +/* Slot 218 is reserved */ +/* Slot 219 is reserved */ +/* Slot 220 is reserved */ +/* Slot 221 is reserved */ +/* Slot 222 is reserved */ +/* Slot 223 is reserved */ +/* Slot 224 is reserved */ +/* Slot 225 is reserved */ +/* Slot 226 is reserved */ +/* Slot 227 is reserved */ +/* Slot 228 is reserved */ +/* Slot 229 is reserved */ +/* Slot 230 is reserved */ +/* Slot 231 is reserved */ +/* Slot 232 is reserved */ +/* Slot 233 is reserved */ +/* Slot 234 is reserved */ +/* Slot 235 is reserved */ +/* Slot 236 is reserved */ +/* Slot 237 is reserved */ +/* Slot 238 is reserved */ +/* Slot 239 is reserved */ +/* Slot 240 is reserved */ +/* Slot 241 is reserved */ +/* Slot 242 is reserved */ +/* Slot 243 is reserved */ +/* Slot 244 is reserved */ +/* Slot 245 is reserved */ +/* Slot 246 is reserved */ +/* Slot 247 is reserved */ +/* Slot 248 is reserved */ +/* 249 */ +EXTERN void TclUnusedStubEntry _ANSI_ARGS_((void)); typedef struct TclIntStubs { int magic; @@ -710,6 +761,56 @@ typedef struct TclIntStubs { VOID *reserved197; VOID *reserved198; int (*tclMatchIsTrivial) _ANSI_ARGS_((CONST char *pattern)); /* 199 */ + VOID *reserved200; + VOID *reserved201; + VOID *reserved202; + VOID *reserved203; + VOID *reserved204; + VOID *reserved205; + VOID *reserved206; + VOID *reserved207; + VOID *reserved208; + VOID *reserved209; + VOID *reserved210; + VOID *reserved211; + VOID *reserved212; + VOID *reserved213; + VOID *reserved214; + VOID *reserved215; + VOID *reserved216; + VOID *reserved217; + VOID *reserved218; + VOID *reserved219; + VOID *reserved220; + VOID *reserved221; + VOID *reserved222; + VOID *reserved223; + VOID *reserved224; + VOID *reserved225; + VOID *reserved226; + VOID *reserved227; + VOID *reserved228; + VOID *reserved229; + VOID *reserved230; + VOID *reserved231; + VOID *reserved232; + VOID *reserved233; + VOID *reserved234; + VOID *reserved235; + VOID *reserved236; + VOID *reserved237; + VOID *reserved238; + VOID *reserved239; + VOID *reserved240; + VOID *reserved241; + VOID *reserved242; + VOID *reserved243; + VOID *reserved244; + VOID *reserved245; + VOID *reserved246; + VOID *reserved247; + VOID *reserved248; + void (*tclUnusedStubEntry) _ANSI_ARGS_((void)); /* 249 */ } TclIntStubs; #ifdef __cplusplus @@ -1334,6 +1435,59 @@ extern TclIntStubs *tclIntStubsPtr; #define TclMatchIsTrivial \ (tclIntStubsPtr->tclMatchIsTrivial) /* 199 */ #endif +/* Slot 200 is reserved */ +/* Slot 201 is reserved */ +/* Slot 202 is reserved */ +/* Slot 203 is reserved */ +/* Slot 204 is reserved */ +/* Slot 205 is reserved */ +/* Slot 206 is reserved */ +/* Slot 207 is reserved */ +/* Slot 208 is reserved */ +/* Slot 209 is reserved */ +/* Slot 210 is reserved */ +/* Slot 211 is reserved */ +/* Slot 212 is reserved */ +/* Slot 213 is reserved */ +/* Slot 214 is reserved */ +/* Slot 215 is reserved */ +/* Slot 216 is reserved */ +/* Slot 217 is reserved */ +/* Slot 218 is reserved */ +/* Slot 219 is reserved */ +/* Slot 220 is reserved */ +/* Slot 221 is reserved */ +/* Slot 222 is reserved */ +/* Slot 223 is reserved */ +/* Slot 224 is reserved */ +/* Slot 225 is reserved */ +/* Slot 226 is reserved */ +/* Slot 227 is reserved */ +/* Slot 228 is reserved */ +/* Slot 229 is reserved */ +/* Slot 230 is reserved */ +/* Slot 231 is reserved */ +/* Slot 232 is reserved */ +/* Slot 233 is reserved */ +/* Slot 234 is reserved */ +/* Slot 235 is reserved */ +/* Slot 236 is reserved */ +/* Slot 237 is reserved */ +/* Slot 238 is reserved */ +/* Slot 239 is reserved */ +/* Slot 240 is reserved */ +/* Slot 241 is reserved */ +/* Slot 242 is reserved */ +/* Slot 243 is reserved */ +/* Slot 244 is reserved */ +/* Slot 245 is reserved */ +/* Slot 246 is reserved */ +/* Slot 247 is reserved */ +/* Slot 248 is reserved */ +#ifndef TclUnusedStubEntry +#define TclUnusedStubEntry \ + (tclIntStubsPtr->tclUnusedStubEntry) /* 249 */ +#endif #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ @@ -1344,5 +1498,6 @@ extern TclIntStubs *tclIntStubsPtr; # undef TclSockMinimumBuffers # define TclSockMinimumBuffers(a,b) TclSockMinimumBuffersOld((int)(a),b) #endif +#undef TclUnusedStubEntry #endif /* _TCLINTDECLS */ diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index c601256..85dfe1c 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -33,6 +33,7 @@ #undef Tcl_CreateHashEntry #undef TclpGetPid #undef TclSockMinimumBuffers +#define TclUnusedStubEntry NULL /* * Keep a record of the original Notifier procedures, created in the @@ -405,6 +406,56 @@ TclIntStubs tclIntStubs = { NULL, /* 197 */ NULL, /* 198 */ TclMatchIsTrivial, /* 199 */ + NULL, /* 200 */ + NULL, /* 201 */ + NULL, /* 202 */ + NULL, /* 203 */ + NULL, /* 204 */ + NULL, /* 205 */ + NULL, /* 206 */ + NULL, /* 207 */ + NULL, /* 208 */ + NULL, /* 209 */ + NULL, /* 210 */ + NULL, /* 211 */ + NULL, /* 212 */ + NULL, /* 213 */ + NULL, /* 214 */ + NULL, /* 215 */ + NULL, /* 216 */ + NULL, /* 217 */ + NULL, /* 218 */ + NULL, /* 219 */ + NULL, /* 220 */ + NULL, /* 221 */ + NULL, /* 222 */ + NULL, /* 223 */ + NULL, /* 224 */ + NULL, /* 225 */ + NULL, /* 226 */ + NULL, /* 227 */ + NULL, /* 228 */ + NULL, /* 229 */ + NULL, /* 230 */ + NULL, /* 231 */ + NULL, /* 232 */ + NULL, /* 233 */ + NULL, /* 234 */ + NULL, /* 235 */ + NULL, /* 236 */ + NULL, /* 237 */ + NULL, /* 238 */ + NULL, /* 239 */ + NULL, /* 240 */ + NULL, /* 241 */ + NULL, /* 242 */ + NULL, /* 243 */ + NULL, /* 244 */ + NULL, /* 245 */ + NULL, /* 246 */ + NULL, /* 247 */ + NULL, /* 248 */ + TclUnusedStubEntry, /* 249 */ }; TclIntPlatStubs tclIntPlatStubs = { @@ -1128,6 +1179,63 @@ TclStubs tclStubs = { NULL, /* 571 */ NULL, /* 572 */ Tcl_PkgRequireProc, /* 573 */ + NULL, /* 574 */ + NULL, /* 575 */ + NULL, /* 576 */ + NULL, /* 577 */ + NULL, /* 578 */ + NULL, /* 579 */ + NULL, /* 580 */ + NULL, /* 581 */ + NULL, /* 582 */ + NULL, /* 583 */ + NULL, /* 584 */ + NULL, /* 585 */ + NULL, /* 586 */ + NULL, /* 587 */ + NULL, /* 588 */ + NULL, /* 589 */ + NULL, /* 590 */ + NULL, /* 591 */ + NULL, /* 592 */ + NULL, /* 593 */ + NULL, /* 594 */ + NULL, /* 595 */ + NULL, /* 596 */ + NULL, /* 597 */ + NULL, /* 598 */ + NULL, /* 599 */ + NULL, /* 600 */ + NULL, /* 601 */ + NULL, /* 602 */ + NULL, /* 603 */ + NULL, /* 604 */ + NULL, /* 605 */ + NULL, /* 606 */ + NULL, /* 607 */ + NULL, /* 608 */ + NULL, /* 609 */ + NULL, /* 610 */ + NULL, /* 611 */ + NULL, /* 612 */ + NULL, /* 613 */ + NULL, /* 614 */ + NULL, /* 615 */ + NULL, /* 616 */ + NULL, /* 617 */ + NULL, /* 618 */ + NULL, /* 619 */ + NULL, /* 620 */ + NULL, /* 621 */ + NULL, /* 622 */ + NULL, /* 623 */ + NULL, /* 624 */ + NULL, /* 625 */ + NULL, /* 626 */ + NULL, /* 627 */ + NULL, /* 628 */ + NULL, /* 629 */ + TclUnusedStubEntry, /* 630 */ }; /* !END!: Do not edit above this line. */ -- cgit v0.12 From f6f2a3b144eb75edbc33ea0c15c40bc40e0158bd Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 7 Jan 2013 14:40:56 +0000 Subject: Restrict the stub library to only use Tcl_PkgRequireEx, Tcl_ResetResult and Tcl_AppendResult, not any other function. This puts least restrictions on eventual Tcl 9 stubs re-organization, and it works on the widest range of Tcl versions. --- ChangeLog | 8 +++++ generic/tclOOStubLib.c | 72 ++++++++++++++++++--------------------------- generic/tclTomMathStubLib.c | 32 +++++++------------- 3 files changed, 47 insertions(+), 65 deletions(-) diff --git a/ChangeLog b/ChangeLog index c112ac3..801ce5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2013-01-07 Jan Nijtmans + + * generic/tclOOStubLib.c: Restrict the stub library to only use + * generic/tclTomMathStubLib.c: Tcl_PkgRequireEx, Tcl_ResetResult + and Tcl_AppendResult, not any other function. This puts least + restrictions on eventual Tcl 9 stubs re-organization, and it + works on the widest range of Tcl versions. + 2013-01-06 Jan Nijtmans * library/http/http.tcl: Don't depend on Spencer-specific regexp diff --git a/generic/tclOOStubLib.c b/generic/tclOOStubLib.c index 55f2378..921aced 100644 --- a/generic/tclOOStubLib.c +++ b/generic/tclOOStubLib.c @@ -2,19 +2,6 @@ * ORIGINAL SOURCE: tk/generic/tkStubLib.c, version 1.9 2004/03/17 */ -/* - * We need to ensure that we use the tcl stub macros so that this file - * contains no references to any of the tcl stub functions. - */ - -#undef USE_TCL_STUBS -#define USE_TCL_STUBS - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define USE_TCLOO_STUBS 1 #include "tclOOInt.h" MODULE_SCOPE const TclOOStubs *tclOOStubsPtr; @@ -35,51 +22,48 @@ const TclOOIntStubs *tclOOIntStubsPtr = NULL; * to indicate that an error occurred. * * Side effects: - * Sets the stub table pointer. + * Sets the stub table pointers. * *---------------------------------------------------------------------- */ MODULE_SCOPE const char * TclOOInitializeStubs( - Tcl_Interp *interp, const char *version) + Tcl_Interp *interp, + const char *version) { int exact = 0; const char *packageName = "TclOO"; const char *errMsg = NULL; - ClientData clientData = NULL; - const char *actualVersion = - Tcl_PkgRequireEx(interp, packageName,version, exact, &clientData); + TclOOStubs *stubsPtr = NULL; + const char *actualVersion = tclStubsPtr->tcl_PkgRequireEx(interp, + packageName, version, exact, &stubsPtr); - if (clientData == NULL) { - Tcl_ResetResult(interp); - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "error loading %s package; package not present or incomplete", - packageName)); + if (actualVersion == NULL) { return NULL; + } + if (stubsPtr == NULL) { + errMsg = "missing stub table pointer"; } else { - const TclOOStubs * const stubsPtr = clientData; - const TclOOIntStubs * const intStubsPtr = stubsPtr->hooks ? - stubsPtr->hooks->tclOOIntStubs : NULL; - - if (!actualVersion) { - return NULL; - } - - if (!stubsPtr || !intStubsPtr) { - errMsg = "missing stub table pointer"; - goto error; - } - tclOOStubsPtr = stubsPtr; - tclOOIntStubsPtr = intStubsPtr; + if (stubsPtr->hooks) { + tclOOIntStubsPtr = stubsPtr->hooks->tclOOIntStubs; + } else { + tclOOIntStubsPtr = NULL; + } return actualVersion; - - error: - Tcl_ResetResult(interp); - Tcl_SetObjResult(interp, Tcl_ObjPrintf("Error loading %s package" - " (requested version '%s', loaded version '%s'): %s", - packageName, version, actualVersion, errMsg)); - return NULL; } + tclStubsPtr->tcl_ResetResult(interp); + tclStubsPtr->tcl_AppendResult(interp, "Error loading ", packageName, + " (requested version ", version, ", actual version ", + actualVersion, "): ", errMsg, NULL); + return NULL; } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/generic/tclTomMathStubLib.c b/generic/tclTomMathStubLib.c index a3bc4b3..324f2a3 100644 --- a/generic/tclTomMathStubLib.c +++ b/generic/tclTomMathStubLib.c @@ -11,15 +11,6 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -/* - * 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 to - * build an extension that references Tcl_InitStubs but doesn't end up - * including the rest of the stub functions. - */ - -#define USE_TCL_STUBS - #include "tclInt.h" MODULE_SCOPE const TclTomMathStubs *tclTomMathStubsPtr; @@ -55,31 +46,30 @@ TclTomMathInitializeStubs( int exact = 0; const char *packageName = "tcl::tommath"; const char *errMsg = NULL; - ClientData pkgClientData = NULL; - const char *actualVersion = - Tcl_PkgRequireEx(interp, packageName, version, exact, &pkgClientData); - const TclTomMathStubs *stubsPtr = pkgClientData; + TclTomMathStubs *stubsPtr = NULL; + const char *actualVersion = tclStubsPtr->tcl_PkgRequireEx(interp, + packageName, version, exact, &stubsPtr); if (actualVersion == NULL) { return NULL; } - if (pkgClientData == NULL) { + if (stubsPtr == NULL) { errMsg = "missing stub table pointer"; - } else if ((stubsPtr->tclBN_epoch)() != epoch) { + } else if(stubsPtr->tclBN_epoch() != epoch) { errMsg = "epoch number mismatch"; - } else if ((stubsPtr->tclBN_revision)() != revision) { + } else if(stubsPtr->tclBN_revision() != revision) { errMsg = "requires a later revision"; } else { tclTomMathStubsPtr = stubsPtr; return actualVersion; } - - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "error loading %s (requested version %s, actual version %s): %s", - packageName, version, actualVersion, errMsg)); + tclStubsPtr->tcl_ResetResult(interp); + tclStubsPtr->tcl_AppendResult(interp, "Error loading ", packageName, + " (requested version ", version, ", actual version ", + actualVersion, "): ", errMsg, NULL); return NULL; } - + /* * Local Variables: * mode: c -- cgit v0.12 From 5e04de18570772af42f7d32958d178bf85737430 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 8 Jan 2013 08:08:28 +0000 Subject: mSys doesn't have $PWD. Reported by Rene Zaumseil on Tcl Core list --- win/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/Makefile.in b/win/Makefile.in index 39d34dd..9c57083 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -751,7 +751,7 @@ packages: if [ ! -f $(PKG_DIR)/$$pkg/Makefile ]; then \ ( cd $(PKG_DIR)/$$pkg; \ echo "Configuring package '$$i' wd = `pwd -P`"; \ - $$i/configure --with-tcl=$(PWD) --with-tclinclude=$(GENERIC_DIR) $(PKG_CFG_ARGS) --enable-shared --enable-threads; ) \ + $$i/configure --with-tcl=$(builddir) --with-tclinclude=$(GENERIC_DIR) $(PKG_CFG_ARGS) --enable-shared --enable-threads; ) \ fi ; \ echo "Building package '$$pkg'"; \ ( cd $(PKG_DIR)/$$pkg; $(MAKE); ) \ -- cgit v0.12 From 6eb9921283977c60251e6768c633fac4e6fbb4b5 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 8 Jan 2013 08:44:33 +0000 Subject: new attempt for better fix --- win/tclWinFile.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/win/tclWinFile.c b/win/tclWinFile.c index a1da83f..7da19ce 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -190,7 +190,7 @@ static unsigned short NativeStatMode(DWORD attr, int checkLinks, int isExec); static int NativeIsExec(const TCHAR *path); static int NativeReadReparse(const TCHAR *LinkDirectory, - REPARSE_DATA_BUFFER *buffer); + REPARSE_DATA_BUFFER *buffer, DWORD desiredAccess); static int NativeWriteReparse(const TCHAR *LinkDirectory, REPARSE_DATA_BUFFER *buffer); static int NativeMatchType(int isDrive, DWORD attr, @@ -481,7 +481,7 @@ TclWinSymLinkCopyDirectory( DUMMY_REPARSE_BUFFER dummy; REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy; - if (NativeReadReparse(linkOrigPath, reparseBuffer)) { + if (NativeReadReparse(linkOrigPath, reparseBuffer, GENERIC_READ)) { return -1; } return NativeWriteReparse(linkCopyPath, reparseBuffer); @@ -580,7 +580,7 @@ WinReadLinkDirectory( if (!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) { goto invalidError; } - if (NativeReadReparse(linkDirPath, reparseBuffer)) { + if (NativeReadReparse(linkDirPath, reparseBuffer, 0)) { return NULL; } @@ -699,22 +699,17 @@ WinReadLinkDirectory( static int NativeReadReparse( const TCHAR *linkDirPath, /* The junction to read */ - REPARSE_DATA_BUFFER *buffer)/* Pointer to buffer. Cannot be NULL */ + REPARSE_DATA_BUFFER *buffer,/* Pointer to buffer. Cannot be NULL */ + DWORD desiredAccess) { HANDLE hFile; DWORD returnedLength; - hFile = (*tclWinProcs->createFileProc)(linkDirPath, GENERIC_READ, 0, + hFile = (*tclWinProcs->createFileProc)(linkDirPath, desiredAccess, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile == INVALID_HANDLE_VALUE) { - hFile = (*tclWinProcs->createFileProc)(linkDirPath, 0, 0, - NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); - } - - if (hFile == INVALID_HANDLE_VALUE) { /* * Error creating directory. */ -- cgit v0.12 From 0e6d90dd95ae50fb0c0d21372528bac15a3a9599 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 8 Jan 2013 13:03:01 +0000 Subject: $builddir is a local variable --- win/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/Makefile.in b/win/Makefile.in index 9c57083..d0e14c6 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -751,7 +751,7 @@ packages: if [ ! -f $(PKG_DIR)/$$pkg/Makefile ]; then \ ( cd $(PKG_DIR)/$$pkg; \ echo "Configuring package '$$i' wd = `pwd -P`"; \ - $$i/configure --with-tcl=$(builddir) --with-tclinclude=$(GENERIC_DIR) $(PKG_CFG_ARGS) --enable-shared --enable-threads; ) \ + $$i/configure --with-tcl=$$builddir --with-tclinclude=$(GENERIC_DIR) $(PKG_CFG_ARGS) --enable-shared --enable-threads; ) \ fi ; \ echo "Building package '$$pkg'"; \ ( cd $(PKG_DIR)/$$pkg; $(MAKE); ) \ -- cgit v0.12 From c509f61617b25dc0e12c07ca27b5b44bce13cb5f Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 9 Jan 2013 14:00:15 +0000 Subject: [Bug 3599395]: http assumes status line is a proper tcl list. Bump http package to 2.7.11. --- ChangeLog | 8 +++++++- library/http/http.tcl | 4 ++-- library/http/pkgIndex.tcl | 2 +- unix/Makefile.in | 4 ++-- win/Makefile.in | 4 ++-- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5a025f9..e1373fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,14 @@ +2013-01-09 Jan Nijtmans + + * library/http/http.tcl: [Bug 3599395]: http assumes status line + is a proper tcl list. + Bump http package to 2.7.11. + 2013-01-08 Jan Nijtmans * win/tclWinFile.c: [Bug 3092089]: [file normalize] can remove path components. [Bug 3587096] win vista/7: "can't find init.tcl" when - called via junction. + called via junction without folder list access. 2013-01-07 Jan Nijtmans diff --git a/library/http/http.tcl b/library/http/http.tcl index fa0425d..6b82894 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -11,7 +11,7 @@ package require Tcl 8.4 # Keep this in sync with pkgIndex.tcl and with the install directories in # Makefiles -package provide http 2.7.10 +package provide http 2.7.11 namespace eval http { # Allow resourcing to not clobber existing data @@ -974,7 +974,7 @@ proc http::Event {sock token} { } elseif {$n == 0} { # We have now read all headers # We ignore HTTP/1.1 100 Continue returns. RFC2616 sec 8.2.3 - if {$state(http) == "" || [lindex $state(http) 1] == 100} { + if {$state(http) == "" || ([regexp {^\S+\s(\d+)} $state(http) {} x] && $x == 100)} { return } diff --git a/library/http/pkgIndex.tcl b/library/http/pkgIndex.tcl index 0b5cdeb..73b2f36 100644 --- a/library/http/pkgIndex.tcl +++ b/library/http/pkgIndex.tcl @@ -1,4 +1,4 @@ # Tcl package index file, version 1.1 if {![package vsatisfies [package provide Tcl] 8.4]} {return} -package ifneeded http 2.7.10 [list tclPkgSetup $dir http 2.7.10 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] +package ifneeded http 2.7.11 [list tclPkgSetup $dir http 2.7.11 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] diff --git a/unix/Makefile.in b/unix/Makefile.in index e43c252..3daad96 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -766,8 +766,8 @@ install-libraries: libraries $(INSTALL_TZDATA) install-msgs do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/http1.0; \ done; - @echo "Installing package http 2.7.10 as a Tcl Module"; - @$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.4/http-2.7.10.tm; + @echo "Installing package http 2.7.11 as a Tcl Module"; + @$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.4/http-2.7.11.tm; @echo "Installing package opt0.4 files to $(SCRIPT_INSTALL_DIR)/opt0.4/"; @for i in $(TOP_DIR)/library/opt/*.tcl ; \ do \ diff --git a/win/Makefile.in b/win/Makefile.in index 4949c70..23f5a2b 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -637,8 +637,8 @@ install-libraries: libraries install-tzdata install-msgs do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/http1.0"; \ done; - @echo "Installing package http 2.7.10 as a Tcl Module"; - @$(COPY) $(ROOT_DIR)/library/http/http.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/http-2.7.10.tm; + @echo "Installing package http 2.7.11 as a Tcl Module"; + @$(COPY) $(ROOT_DIR)/library/http/http.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/http-2.7.11.tm; @echo "Installing library opt0.4 directory"; @for j in $(ROOT_DIR)/library/opt/*.tcl; \ do \ -- cgit v0.12 From 193ad73d549eeb177bd467a9d894e21ff53845e9 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 9 Jan 2013 15:43:54 +0000 Subject: Backported [Bug 2882342]: correct struct _REPARSE_DATA_BUFFER in tcl 8.4 --- win/tclWinFile.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/win/tclWinFile.c b/win/tclWinFile.c index 4abd215..d1078f5 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -117,6 +117,7 @@ typedef struct _REPARSE_DATA_BUFFER { WORD SubstituteNameLength; WORD PrintNameOffset; WORD PrintNameLength; + ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { @@ -359,18 +360,18 @@ WinSymLinkDirectory(LinkDirectory, LinkTarget) /* Build the reparse info */ memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER)); reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; - reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength = + reparseBuffer->MountPointReparseBuffer.SubstituteNameLength = wcslen(nativeTarget) * sizeof(WCHAR); reparseBuffer->Reserved = 0; - reparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength = 0; - reparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = - reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + reparseBuffer->MountPointReparseBuffer.PrintNameLength = 0; + reparseBuffer->MountPointReparseBuffer.PrintNameOffset = + reparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR); - memcpy(reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, nativeTarget, + memcpy(reparseBuffer->MountPointReparseBuffer.PathBuffer, nativeTarget, sizeof(WCHAR) - + reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength); + + reparseBuffer->MountPointReparseBuffer.SubstituteNameLength); reparseBuffer->ReparseDataLength = - reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + 12; + reparseBuffer->MountPointReparseBuffer.SubstituteNameLength + 12; return NativeWriteReparse(LinkDirectory, reparseBuffer); } @@ -505,10 +506,10 @@ WinReadLinkDirectory(LinkDirectory) * that changes in the future, this code will have to be * generalised. */ - if (reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer[0] + if (reparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') { /* Check whether this is a mounted volume */ - if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, + if (wcsncmp(reparseBuffer->MountPointReparseBuffer.PathBuffer, L"\\??\\Volume{",11) == 0) { char drive; /* @@ -516,14 +517,14 @@ WinReadLinkDirectory(LinkDirectory) * we have to fix here. It doesn't seem very well * documented. */ - reparseBuffer->SymbolicLinkReparseBuffer + reparseBuffer->MountPointReparseBuffer .PathBuffer[1] = L'\\'; /* * Check if a corresponding drive letter exists, and * use that if it is found */ drive = TclWinDriveLetterForVolMountPoint(reparseBuffer - ->SymbolicLinkReparseBuffer.PathBuffer); + ->MountPointReparseBuffer.PathBuffer); if (drive != -1) { char driveSpec[3] = { drive, ':', '\0' @@ -544,11 +545,11 @@ WinReadLinkDirectory(LinkDirectory) */ Tcl_SetErrno(EINVAL); return NULL; - } else if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer + } else if (wcsncmp(reparseBuffer->MountPointReparseBuffer .PathBuffer, L"\\\\?\\",4) == 0) { /* Strip off the prefix */ offset = 4; - } else if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer + } else if (wcsncmp(reparseBuffer->MountPointReparseBuffer .PathBuffer, L"\\??\\",4) == 0) { /* Strip off the prefix */ offset = 4; @@ -556,8 +557,8 @@ WinReadLinkDirectory(LinkDirectory) } Tcl_WinTCharToUtf( - (CONST char*)reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, - (int)reparseBuffer->SymbolicLinkReparseBuffer + (CONST char*)reparseBuffer->MountPointReparseBuffer.PathBuffer, + (int)reparseBuffer->MountPointReparseBuffer .SubstituteNameLength, &ds); copy = Tcl_DStringValue(&ds)+offset; -- cgit v0.12 From 41c09d7b4d37c2b2fc7cec61aaaa3ca59a56a7c5 Mon Sep 17 00:00:00 2001 From: mig Date: Thu, 10 Jan 2013 18:17:33 +0000 Subject: fix off-by-one error introduced in bd7d7a2061 --- generic/tclExecute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 8759ec9..ade71f6 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -1089,7 +1089,7 @@ GrowEvaluationStack( if (move) { moveWords = esPtr->tosPtr - MEMSTART(markerPtr) + 1; } - needed = growth + moveWords + WALLOCALIGN - 1; + needed = growth + moveWords + WALLOCALIGN; /* -- cgit v0.12 From e89dea9b9b819e7b5ddc8d171127b749e237af35 Mon Sep 17 00:00:00 2001 From: mig Date: Thu, 10 Jan 2013 21:18:52 +0000 Subject: tailcall now running in a simpler model, with no eval-flags and no nre-stack rewriting; yieldto also requires one fewer bounce. Mostly from mig-nre-mods --- generic/tclBasic.c | 142 +++++++++++++++++++++++------------------------- generic/tclCompCmdsSZ.c | 4 +- generic/tclEnsemble.c | 4 +- generic/tclExecute.c | 20 +++---- generic/tclInt.h | 36 +----------- generic/tclInterp.c | 4 +- generic/tclNamesp.c | 4 +- 7 files changed, 87 insertions(+), 127 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 562cca6..55014ec 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -160,10 +160,7 @@ static Tcl_NRPostProc TEOV_Exception; static Tcl_NRPostProc TEOV_NotFoundCallback; static Tcl_NRPostProc TEOV_RestoreVarFrame; static Tcl_NRPostProc TEOV_RunLeaveTraces; -static Tcl_NRPostProc YieldToCallback; -static void ClearTailcall(Tcl_Interp *interp, - struct NRE_callback *tailcallPtr); static Tcl_ObjCmdProc NRCoroInjectObjCmd; MODULE_SCOPE const TclStubs tclStubs; @@ -4161,7 +4158,8 @@ TclNREvalObjv( int result; Namespace *lookupNsPtr = iPtr->lookupNsPtr; Command **cmdPtrPtr; - + NRE_callback *callbackPtr; + iPtr->lookupNsPtr = NULL; /* @@ -4174,15 +4172,17 @@ TclNREvalObjv( * finishes the source command and not just the target. */ - if (iPtr->evalFlags & TCL_EVAL_REDIRECT) { - TclNRAddCallback(interp, NRCommand, NULL, INT2PTR(1), INT2PTR(objc), objv); - iPtr->evalFlags &= ~TCL_EVAL_REDIRECT; + if (iPtr->deferredCallbacks) { + callbackPtr = iPtr->deferredCallbacks; + iPtr->deferredCallbacks = NULL; } else { - TclNRAddCallback(interp, NRCommand, NULL, NULL, INT2PTR(objc), objv); + TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL); + callbackPtr = TOP_CB(interp); } - cmdPtrPtr = (Command **) &(TOP_CB(interp)->data[0]); + cmdPtrPtr = (Command **) &(callbackPtr->data[0]); - TclNRSpliceDeferred(interp); + callbackPtr->data[2] = INT2PTR(objc); + callbackPtr->data[3] = (ClientData) objv; iPtr->numLevels++; result = TclInterpReady(interp); @@ -4368,6 +4368,14 @@ NRCommand( } ((Interp *)interp)->numLevels--; + /* + * If there is a tailcall, schedule it + */ + + if (data[1] && (data[1] != INT2PTR(1))) { + TclNRAddCallback(interp, TclNRTailcallEval, data[1], NULL, NULL, NULL); + } + /* OPT ?? * Do not interrupt a series of cleanups with async or limit checks: * just check at the end? @@ -4625,9 +4633,9 @@ TEOV_NotFound( savedNsPtr = varFramePtr->nsPtr; varFramePtr->nsPtr = lookupNsPtr; } - TclNRDeferCallback(interp, TEOV_NotFoundCallback, INT2PTR(handlerObjc), + TclDeferCallbacks(interp, 1); + TclNRAddCallback(interp, TEOV_NotFoundCallback, INT2PTR(handlerObjc), newObjv, savedNsPtr, NULL); - iPtr->evalFlags |= TCL_EVAL_REDIRECT; return TclNREvalObjv(interp, newObjc, newObjv, TCL_EVAL_NOERR, NULL); } @@ -6012,7 +6020,8 @@ TclNREvalObjEx( iPtr->cmdFramePtr = eoFramePtr; } - TclNRDeferCallback(interp, TEOEx_ListCallback, listPtr, eoFramePtr, + TclDeferCallbacks(interp, 0); + TclNRAddCallback(interp, TEOEx_ListCallback, listPtr, eoFramePtr, NULL, NULL); ListObjGetElements(listPtr, objc, objv); @@ -8269,29 +8278,43 @@ Tcl_NRCmdSwap( */ void -TclSpliceTailcall( +TclDeferCallbacks( Tcl_Interp *interp, - NRE_callback *tailcallPtr) + int skipTailcalls) +{ + Interp *iPtr = (Interp *) interp; + + if (iPtr->deferredCallbacks == NULL) { + TclNRAddCallback(interp, NRCommand, NULL, INT2PTR(skipTailcalls != 0), + NULL, NULL); + iPtr->deferredCallbacks = TOP_CB(interp); + } else if (skipTailcalls) { + iPtr->deferredCallbacks->data[1] = INT2PTR(skipTailcalls != 0); + } +} + +void +TclSetTailcall( + Tcl_Interp *interp, + Tcl_Obj *listPtr) { /* * Find the splicing spot: right before the NRCommand of the thing - * being tailcalled. Note that we skip NRCommands marked in data[1] + * being tailcalled. Note that we skip NRCommands marked by a 1 in data[1] * (used by command redirectors). */ NRE_callback *runPtr; for (runPtr = TOP_CB(interp); runPtr; runPtr = runPtr->nextPtr) { - if (((runPtr->procPtr) == NRCommand) && !runPtr->data[1]) { + if (((runPtr->procPtr) == NRCommand) && !runPtr->data[1]) { break; } } if (!runPtr) { Tcl_Panic("tailcall cannot find the right splicing spot: should not happen!"); } - - tailcallPtr->nextPtr = runPtr->nextPtr; - runPtr->nextPtr = tailcallPtr; + runPtr->data[1] = listPtr; } int @@ -8321,7 +8344,7 @@ TclNRTailcallObjCmd( */ if (iPtr->varFramePtr->tailcallPtr) { - ClearTailcall(interp, iPtr->varFramePtr->tailcallPtr); + Tcl_DecrRefCount(iPtr->varFramePtr->tailcallPtr); iPtr->varFramePtr->tailcallPtr = NULL; } @@ -8336,23 +8359,20 @@ TclNRTailcallObjCmd( Tcl_Obj *listPtr, *nsObjPtr; Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr; Tcl_Namespace *ns1Ptr; - NRE_callback *tailcallPtr; - listPtr = Tcl_NewListObj(objc-1, objv+1); - Tcl_IncrRefCount(listPtr); + /* The tailcall data is in a Tcl list: the first element is the + * namespace, the rest the command to be tailcalled. */ + + listPtr = Tcl_NewListObj(objc, objv); nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1); if ((TCL_OK != TclGetNamespaceFromObj(interp, nsObjPtr, &ns1Ptr)) || (nsPtr != ns1Ptr)) { Tcl_Panic("Tailcall failed to find the proper namespace"); } - Tcl_IncrRefCount(nsObjPtr); - - TclNRAddCallback(interp, TclNRTailcallEval, listPtr, nsObjPtr, - NULL, NULL); - tailcallPtr = TOP_CB(interp); - TOP_CB(interp) = tailcallPtr->nextPtr; - iPtr->varFramePtr->tailcallPtr = tailcallPtr; + TclListObjSetElement(interp, listPtr, 0, nsObjPtr); + + iPtr->varFramePtr->tailcallPtr = listPtr; } return TCL_RETURN; } @@ -8364,12 +8384,14 @@ TclNRTailcallEval( int result) { Interp *iPtr = (Interp *) interp; - Tcl_Obj *listPtr = data[0]; - Tcl_Obj *nsObjPtr = data[1]; + Tcl_Obj *listPtr = data[0], *nsObjPtr; Tcl_Namespace *nsPtr; int objc; Tcl_Obj **objv; + Tcl_ListObjGetElements(interp, listPtr, &objc, &objv); + nsObjPtr = objv[0]; + if (result == TCL_OK) { result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr); } @@ -8388,10 +8410,10 @@ TclNRTailcallEval( * Perform the tailcall */ - TclNRDeferCallback(interp, TailcallCleanup, listPtr, nsObjPtr, NULL,NULL); + TclDeferCallbacks(interp, 0); + TclNRAddCallback(interp, TailcallCleanup, listPtr, NULL, NULL,NULL); iPtr->lookupNsPtr = (Namespace *) nsPtr; - ListObjGetElements(listPtr, objc, objv); - return TclNREvalObjv(interp, objc, objv, 0, NULL); + return TclNREvalObjv(interp, objc-1, objv+1, 0, NULL); } static int @@ -8401,19 +8423,9 @@ TailcallCleanup( int result) { Tcl_DecrRefCount((Tcl_Obj *) data[0]); - Tcl_DecrRefCount((Tcl_Obj *) data[1]); return result; } -static void -ClearTailcall( - Tcl_Interp *interp, - NRE_callback *tailcallPtr) -{ - TailcallCleanup(tailcallPtr->data, interp, TCL_OK); - TCLNR_FREE(interp, tailcallPtr); -} - void Tcl_NRAddCallback( @@ -8515,50 +8527,32 @@ TclNRYieldToObjCmd( * This is essentially code from TclNRTailcallObjCmd */ - listPtr = Tcl_NewListObj(objc-1, objv+1); - Tcl_IncrRefCount(listPtr); + /* + * Add the tailcall in the caller env, then just yield. + * + * This is essentially code from TclNRTailcallObjCmd + */ + + listPtr = Tcl_NewListObj(objc, objv); nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1); if ((TCL_OK != TclGetNamespaceFromObj(interp, nsObjPtr, &ns1Ptr)) || (nsPtr != ns1Ptr)) { Tcl_Panic("yieldto failed to find the proper namespace"); } - Tcl_IncrRefCount(nsObjPtr); + TclListObjSetElement(interp, listPtr, 0, nsObjPtr); + /* * Add the callback in the caller's env, then instruct TEBC to yield. */ iPtr->execEnvPtr = corPtr->callerEEPtr; - TclNRAddCallback(interp, YieldToCallback, corPtr, listPtr, nsObjPtr, - NULL); + TclSetTailcall(interp, listPtr); iPtr->execEnvPtr = corPtr->eePtr; return TclNRYieldObjCmd(INT2PTR(CORO_ACTIVATE_YIELDM), interp, 1, objv); } - -static int -YieldToCallback( - ClientData data[], - Tcl_Interp *interp, - int result) -{ - /* CoroutineData *corPtr = data[0];*/ - Tcl_Obj *listPtr = data[1]; - ClientData nsPtr = data[2]; - NRE_callback *cbPtr; - - /* - * yieldTo: invoke the command using tailcall tech. - */ - - TclNRAddCallback(interp, TclNRTailcallEval, listPtr, nsPtr, NULL, NULL); - cbPtr = TOP_CB(interp); - TOP_CB(interp) = cbPtr->nextPtr; - - TclSpliceTailcall(interp, cbPtr); - return TCL_OK; -} static int RewindCoroutineCallback( diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c index 1d04d8b..6e31481 100644 --- a/generic/tclCompCmdsSZ.c +++ b/generic/tclCompCmdsSZ.c @@ -1953,11 +1953,13 @@ TclCompileTailcallCmd( return TCL_ERROR; } + /* make room for the nsObjPtr */ + CompileWord(envPtr, tokenPtr, interp, 0); for (i=1 ; inumWords ; i++) { tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp, i); } - TclEmitInstInt1( INST_TAILCALL, parsePtr->numWords-1, envPtr); + TclEmitInstInt1( INST_TAILCALL, parsePtr->numWords, envPtr); return TCL_OK; } diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 9a2d598..2753876 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -1914,7 +1914,7 @@ NsEnsembleImplementationCmdNR( * Hand off to the target command. */ - iPtr->evalFlags |= TCL_EVAL_REDIRECT; + TclDeferCallbacks(interp, /* skip tailcalls */ 1); return TclNREvalObjEx(interp, copyPtr, TCL_EVAL_INVOKE, NULL,INT_MIN); } @@ -2122,7 +2122,7 @@ EnsembleUnknownCallback( */ Tcl_Preserve(ensemblePtr); - ((Interp *) interp)->evalFlags |= TCL_EVAL_REDIRECT; + TclDeferCallbacks (interp, /*skip tailcalls */ 1); result = Tcl_EvalObjv(interp, paramc, paramv, 0); if ((result == TCL_OK) && (ensemblePtr->flags & ENSEMBLE_DEAD)) { if (!Tcl_InterpDeleted(interp)) { diff --git a/generic/tclExecute.c b/generic/tclExecute.c index ade71f6..af60a95 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2399,7 +2399,6 @@ TEBCresume( case INST_TAILCALL: { Tcl_Obj *listPtr, *nsObjPtr; - NRE_callback *tailcallPtr; opnd = TclGetUInt1AtPtr(pc+1); @@ -2433,18 +2432,12 @@ TEBCresume( listPtr = Tcl_NewListObj(opnd, &OBJ_AT_DEPTH(opnd-1)); nsObjPtr = Tcl_NewStringObj(iPtr->varFramePtr->nsPtr->fullName, -1); - Tcl_IncrRefCount(listPtr); - Tcl_IncrRefCount(nsObjPtr); - TclNRAddCallback(interp, TclNRTailcallEval, listPtr, nsObjPtr, - NULL, NULL); - - /* - * Unstitch ourselves and do a [return]. - */ + TclListObjSetElement(interp, listPtr, 0, nsObjPtr); + if (iPtr->varFramePtr->tailcallPtr) { + Tcl_DecrRefCount(iPtr->varFramePtr->tailcallPtr); + } + iPtr->varFramePtr->tailcallPtr = listPtr; - tailcallPtr = TOP_CB(interp); - TOP_CB(interp) = tailcallPtr->nextPtr; - iPtr->varFramePtr->tailcallPtr = tailcallPtr; result = TCL_RETURN; cleanup = opnd; goto processExceptionReturn; @@ -3054,8 +3047,9 @@ TEBCresume( DECACHE_STACK_INFO(); pc += 6; TEBC_YIELD(); + TclNRAddCallback(interp, TclClearRootEnsemble, NULL,NULL,NULL,NULL); - iPtr->evalFlags |= TCL_EVAL_REDIRECT; + TclDeferCallbacks(interp, /*skip tailcalls */ 1); return TclNREvalObjEx(interp, objPtr, TCL_EVAL_INVOKE, NULL, INT_MIN); /* diff --git a/generic/tclInt.h b/generic/tclInt.h index 537afb3..6cf594e 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1154,7 +1154,7 @@ typedef struct CallFrame { * meaning of the value is, which we do not * specify. */ LocalCache *localCachePtr; - struct NRE_callback *tailcallPtr; + Tcl_Obj *tailcallPtr; /* NULL if no tailcall is scheduled */ } CallFrame; @@ -2250,7 +2250,6 @@ typedef struct InterpList { #define TCL_ALLOW_EXCEPTIONS 4 #define TCL_EVAL_FILE 2 #define TCL_EVAL_CTX 8 -#define TCL_EVAL_REDIRECT 16 /* * Flag bits for Interp structures: @@ -2805,8 +2804,8 @@ MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldmObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldToObjCmd; -MODULE_SCOPE void TclSpliceTailcall(Tcl_Interp *interp, - struct NRE_callback *tailcallPtr); +MODULE_SCOPE void TclSetTailcall(Tcl_Interp *interp, Tcl_Obj *tailcallPtr); +MODULE_SCOPE void TclDeferCallbacks(Tcl_Interp *interp, int skipTailcall); /* * This structure holds the data for the various iteration callbacks used to @@ -4808,35 +4807,6 @@ typedef struct NRE_callback { TOP_CB(interp) = callbackPtr; \ } while (0) -#define TclNRDeferCallback(interp,postProcPtr,data0,data1,data2,data3) \ - do { \ - NRE_callback *callbackPtr; \ - TCLNR_ALLOC((interp), (callbackPtr)); \ - callbackPtr->procPtr = (postProcPtr); \ - callbackPtr->data[0] = (ClientData)(data0); \ - callbackPtr->data[1] = (ClientData)(data1); \ - callbackPtr->data[2] = (ClientData)(data2); \ - callbackPtr->data[3] = (ClientData)(data3); \ - callbackPtr->nextPtr = ((Interp *)interp)->deferredCallbacks; \ - ((Interp *)interp)->deferredCallbacks = callbackPtr; \ - } while (0) - -#define TclNRSpliceCallbacks(interp, topPtr) \ - do { \ - NRE_callback *bottomPtr = topPtr; \ - while (bottomPtr->nextPtr) { \ - bottomPtr = bottomPtr->nextPtr; \ - } \ - bottomPtr->nextPtr = TOP_CB(interp); \ - TOP_CB(interp) = topPtr; \ - } while (0) - -#define TclNRSpliceDeferred(interp) \ - if (((Interp *)interp)->deferredCallbacks) { \ - TclNRSpliceCallbacks(interp, ((Interp *)interp)->deferredCallbacks); \ - ((Interp *)interp)->deferredCallbacks = NULL; \ - } - #if NRE_USE_SMALL_ALLOC #define TCLNR_ALLOC(interp, ptr) \ TclSmallAllocEx(interp, sizeof(NRE_callback), (ptr)) diff --git a/generic/tclInterp.c b/generic/tclInterp.c index 0b0f652..2e90caf 100644 --- a/generic/tclInterp.c +++ b/generic/tclInterp.c @@ -1798,9 +1798,9 @@ AliasNRCmd( */ if (isRootEnsemble) { - TclNRDeferCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL); + TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL); } - iPtr->evalFlags |= TCL_EVAL_REDIRECT; + TclDeferCallbacks(interp, /* skip tailcalls */ 1); return Tcl_NREvalObj(interp, listPtr, flags); } diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 8da4b42..ee8aaa6 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -423,7 +423,7 @@ Tcl_PopCallFrame( framePtr->nsPtr = NULL; if (framePtr->tailcallPtr) { - TclSpliceTailcall(interp, framePtr->tailcallPtr); + TclSetTailcall(interp, framePtr->tailcallPtr); } } @@ -1945,7 +1945,7 @@ InvokeImportedNRCmd( ImportedCmdData *dataPtr = clientData; Command *realCmdPtr = dataPtr->realCmdPtr; - ((Interp *) interp)->evalFlags |= TCL_EVAL_REDIRECT; + TclDeferCallbacks(interp, /* skip tailcalls */ 1); return Tcl_NRCmdSwap(interp, (Tcl_Command) realCmdPtr, objc, objv, 0); } -- cgit v0.12 From 0c2d5031a205445ac91209816f31a8a943b3921a Mon Sep 17 00:00:00 2001 From: mig Date: Fri, 11 Jan 2013 12:42:14 +0000 Subject: Name functions according to 'what' instead of 'how' in the [tailcall] machinery, in view of making public some parts of it. --- generic/tclBasic.c | 41 ++++++++++++++++++++++++----------------- generic/tclEnsemble.c | 4 ++-- generic/tclExecute.c | 2 +- generic/tclInt.h | 7 +++++-- generic/tclInterp.c | 2 +- generic/tclNamesp.c | 2 +- 6 files changed, 34 insertions(+), 24 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 55014ec..b511d07 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -4309,14 +4309,6 @@ TclNREvalObjv( } } -void -TclPushTailcallPoint( - Tcl_Interp *interp) -{ - TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL); - ((Interp *) interp)->numLevels++; -} - int TclNRRunCallbacks( Tcl_Interp *interp, @@ -4633,7 +4625,7 @@ TEOV_NotFound( savedNsPtr = varFramePtr->nsPtr; varFramePtr->nsPtr = lookupNsPtr; } - TclDeferCallbacks(interp, 1); + TclSkipTailcall(interp); TclNRAddCallback(interp, TEOV_NotFoundCallback, INT2PTR(handlerObjc), newObjv, savedNsPtr, NULL); return TclNREvalObjv(interp, newObjc, newObjv, TCL_EVAL_NOERR, NULL); @@ -6020,7 +6012,7 @@ TclNREvalObjEx( iPtr->cmdFramePtr = eoFramePtr; } - TclDeferCallbacks(interp, 0); + TclMarkTailcall(interp); TclNRAddCallback(interp, TEOEx_ListCallback, listPtr, eoFramePtr, NULL, NULL); @@ -8278,22 +8270,37 @@ Tcl_NRCmdSwap( */ void -TclDeferCallbacks( - Tcl_Interp *interp, - int skipTailcalls) +TclMarkTailcall( + Tcl_Interp *interp) { Interp *iPtr = (Interp *) interp; if (iPtr->deferredCallbacks == NULL) { - TclNRAddCallback(interp, NRCommand, NULL, INT2PTR(skipTailcalls != 0), + TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL); iPtr->deferredCallbacks = TOP_CB(interp); - } else if (skipTailcalls) { - iPtr->deferredCallbacks->data[1] = INT2PTR(skipTailcalls != 0); } } void +TclSkipTailcall( + Tcl_Interp *interp) +{ + Interp *iPtr = (Interp *) interp; + + TclMarkTailcall(interp); + iPtr->deferredCallbacks->data[1] = INT2PTR(1); +} + +void +TclPushTailcallPoint( + Tcl_Interp *interp) +{ + TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL); + ((Interp *) interp)->numLevels++; +} + +void TclSetTailcall( Tcl_Interp *interp, Tcl_Obj *listPtr) @@ -8410,7 +8417,7 @@ TclNRTailcallEval( * Perform the tailcall */ - TclDeferCallbacks(interp, 0); + TclMarkTailcall(interp); TclNRAddCallback(interp, TailcallCleanup, listPtr, NULL, NULL,NULL); iPtr->lookupNsPtr = (Namespace *) nsPtr; return TclNREvalObjv(interp, objc-1, objv+1, 0, NULL); diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 2753876..058590a 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -1914,7 +1914,7 @@ NsEnsembleImplementationCmdNR( * Hand off to the target command. */ - TclDeferCallbacks(interp, /* skip tailcalls */ 1); + TclSkipTailcall(interp); return TclNREvalObjEx(interp, copyPtr, TCL_EVAL_INVOKE, NULL,INT_MIN); } @@ -2122,7 +2122,7 @@ EnsembleUnknownCallback( */ Tcl_Preserve(ensemblePtr); - TclDeferCallbacks (interp, /*skip tailcalls */ 1); + TclSkipTailcall(interp); result = Tcl_EvalObjv(interp, paramc, paramv, 0); if ((result == TCL_OK) && (ensemblePtr->flags & ENSEMBLE_DEAD)) { if (!Tcl_InterpDeleted(interp)) { diff --git a/generic/tclExecute.c b/generic/tclExecute.c index af60a95..303bafd 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -3049,7 +3049,7 @@ TEBCresume( TEBC_YIELD(); TclNRAddCallback(interp, TclClearRootEnsemble, NULL,NULL,NULL,NULL); - TclDeferCallbacks(interp, /*skip tailcalls */ 1); + TclSkipTailcall(interp); return TclNREvalObjEx(interp, objPtr, TCL_EVAL_INVOKE, NULL, INT_MIN); /* diff --git a/generic/tclInt.h b/generic/tclInt.h index 6cf594e..18768d9 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2805,7 +2805,11 @@ MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldmObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldToObjCmd; MODULE_SCOPE void TclSetTailcall(Tcl_Interp *interp, Tcl_Obj *tailcallPtr); -MODULE_SCOPE void TclDeferCallbacks(Tcl_Interp *interp, int skipTailcall); +MODULE_SCOPE void TclPushTailcallPoint(Tcl_Interp *interp); + +/* These two can be considered for the public api */ +MODULE_SCOPE void TclMarkTailcall(Tcl_Interp *interp); +MODULE_SCOPE void TclSkipTailcall(Tcl_Interp *interp); /* * This structure holds the data for the various iteration callbacks used to @@ -2880,7 +2884,6 @@ MODULE_SCOPE void TclAppendBytesToByteArray(Tcl_Obj *objPtr, const unsigned char *bytes, int len); MODULE_SCOPE int TclNREvalCmd(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); -MODULE_SCOPE void TclPushTailcallPoint(Tcl_Interp *interp); MODULE_SCOPE void TclAdvanceContinuations(int *line, int **next, int loc); MODULE_SCOPE void TclAdvanceLines(int *line, const char *start, diff --git a/generic/tclInterp.c b/generic/tclInterp.c index 2e90caf..d5d43ed 100644 --- a/generic/tclInterp.c +++ b/generic/tclInterp.c @@ -1800,7 +1800,7 @@ AliasNRCmd( if (isRootEnsemble) { TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL); } - TclDeferCallbacks(interp, /* skip tailcalls */ 1); + TclSkipTailcall(interp); return Tcl_NREvalObj(interp, listPtr, flags); } diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index ee8aaa6..304487b 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -1945,7 +1945,7 @@ InvokeImportedNRCmd( ImportedCmdData *dataPtr = clientData; Command *realCmdPtr = dataPtr->realCmdPtr; - TclDeferCallbacks(interp, /* skip tailcalls */ 1); + TclSkipTailcall(interp); return Tcl_NRCmdSwap(interp, (Tcl_Command) realCmdPtr, objc, objv, 0); } -- cgit v0.12 From b1cd450bf53330939e3b7515f282a29383c347a2 Mon Sep 17 00:00:00 2001 From: dkf Date: Fri, 11 Jan 2013 14:04:33 +0000 Subject: First attempt at fixing problems caused by [array set] inside [namespace eval], which caused partial bytecode generation followed by a reject which triggered the issuing of generic ensemble code with an extra push of the variable name at the start (which got the stack depth wrong). --- generic/tclCompCmds.c | 21 +++++++++++++++------ generic/tclEnsemble.c | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 752db93..503f339 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -107,6 +107,7 @@ static int CompileDictEachCmd(Tcl_Interp *interp, */ #define TCL_NO_LARGE_INDEX 1 /* Do not return localIndex value > 255 */ +#define TCL_NO_ELEMENT 2 /* Do not push the array element. */ /* * The structures below define the AuxData types defined in this file. @@ -259,7 +260,7 @@ TclCompileArrayExistsCmd( } tokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(interp, tokenPtr, envPtr, 0, + PushVarNameWord(interp, tokenPtr, envPtr, TCL_NO_ELEMENT, &localIndex, &simpleVarName, &isScalar, 1); if (!isScalar) { return TCL_ERROR; @@ -294,7 +295,14 @@ TclCompileArraySetCmd( } tokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(interp, tokenPtr, envPtr, 0, + if (envPtr->procPtr == NULL) { + Tcl_Token *tokPtr = TokenAfter(tokenPtr); + + if (tokPtr->type != TCL_TOKEN_SIMPLE_WORD || tokPtr[1].size != 0) { + return TCL_ERROR; + } + } + PushVarNameWord(interp, tokenPtr, envPtr, TCL_NO_ELEMENT, &localIndex, &simpleVarName, &isScalar, 1); if (!isScalar) { return TCL_ERROR; @@ -437,7 +445,7 @@ TclCompileArrayUnsetCmd( return TCL_ERROR; } - PushVarNameWord(interp, tokenPtr, envPtr, 0, + PushVarNameWord(interp, tokenPtr, envPtr, TCL_NO_ELEMENT, &localIndex, &simpleVarName, &isScalar, 1); if (!isScalar) { return TCL_ERROR; @@ -6006,7 +6014,7 @@ PushVarName( Tcl_Interp *interp, /* Used for error reporting. */ Tcl_Token *varTokenPtr, /* Points to a variable token. */ CompileEnv *envPtr, /* Holds resulting instructions. */ - int flags, /* TCL_NO_LARGE_INDEX. */ + int flags, /* TCL_NO_LARGE_INDEX | TCL_NO_ELEMENT. */ int *localIndexPtr, /* Must not be NULL. */ int *simpleVarNamePtr, /* Must not be NULL. */ int *isScalarPtr, /* Must not be NULL. */ @@ -6187,10 +6195,11 @@ PushVarName( } /* - * Compile the element script, if any. + * Compile the element script, if any, and only if not inhibited. [Bug + * 3600328] */ - if (elName != NULL) { + if (elName != NULL && !(flags & TCL_NO_ELEMENT)) { if (elNameChars) { envPtr->line = line; envPtr->clNext = clNext; diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 2753876..835c9ad 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -3056,6 +3056,9 @@ CompileToCompiledCommand( Tcl_Parse synthetic; Tcl_Token *tokenPtr; int result, i; + int savedNumCmds = envPtr->numCommands; + int savedStackDepth = envPtr->currStackDepth; + unsigned savedCodeNext = envPtr->codeNext - envPtr->codeStart; if (cmdPtr->compileProc == NULL) { return TCL_ERROR; @@ -3110,6 +3113,17 @@ CompileToCompiledCommand( result = cmdPtr->compileProc(interp, &synthetic, cmdPtr, envPtr); /* + * If our target fails to compile, revert the number of commands and the + * pointer to the place to issue the next instruction. [Bug 3600328] + */ + + if (result != TCL_OK) { + envPtr->numCommands = savedNumCmds; + envPtr->currStackDepth = savedStackDepth; + envPtr->codeNext = envPtr->codeStart + savedCodeNext; + } + + /* * Clean up if necessary. */ -- cgit v0.12 From 496f711ae9cf8d67deb17e52f10b5b3ae39646f7 Mon Sep 17 00:00:00 2001 From: mig Date: Fri, 11 Jan 2013 15:37:10 +0000 Subject: testing a cheaper(?) INST_START_COMMAND --- generic/tclExecute.c | 97 ++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 303bafd..ae9d0c7 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2309,6 +2309,18 @@ TEBCresume( * reduces total obj size. */ + if (*pc == INST_START_CMD) { + iPtr->cmdCount += TclGetUInt4AtPtr(pc+5); + if (checkInterp) { + checkInterp = 0; + if ((codePtr->compileEpoch != iPtr->compileEpoch) + || (codePtr->nsEpoch != iPtr->varFramePtr->nsPtr->resolverEpoch)) { + goto instStartCmdFailed; + } + } + pc += 9; + } + if (*pc == INST_LOAD_SCALAR1) { goto instLoadScalar1; } else if (*pc == INST_PUSH1) { @@ -2499,57 +2511,8 @@ TEBCresume( */ pc++; -#if !TCL_COMPILE_DEBUG - if (*pc == INST_START_CMD) { - TCL_DTRACE_INST_NEXT(); - goto instStartCmdPeephole; - } -#endif NEXT_INST_F(0, 0, 0); - case INST_START_CMD: -#if !TCL_COMPILE_DEBUG - instStartCmdPeephole: -#endif - /* - * Remark that if the interpreter is marked for deletion its - * compileEpoch is modified, so that the epoch check also verifies - * that the interp is not deleted. If no outside call has been made - * since the last check, it is safe to omit the check. - */ - - iPtr->cmdCount += TclGetUInt4AtPtr(pc+5); - if (!checkInterp) { - goto instStartCmdOK; - } else if (((codePtr->compileEpoch == iPtr->compileEpoch) - && (codePtr->nsEpoch == iPtr->varFramePtr->nsPtr->resolverEpoch)) - || (codePtr->flags & TCL_BYTECODE_PRECOMPILED)) { - checkInterp = 0; - instStartCmdOK: - NEXT_INST_F(9, 0, 0); - } else { - const char *bytes; - - length = 0; - - /* - * We used to switch to direct eval; for NRE-awareness we now - * compile and eval the command so that this evaluation does not - * add a new TEBC instance. [Bug 2910748] - */ - - if (TclInterpReady(interp) == TCL_ERROR) { - goto gotError; - } - - codePtr->flags |= TCL_BYTECODE_RECOMPILE; - bytes = GetSrcInfoForPc(pc, codePtr, &length, NULL); - opnd = TclGetUInt4AtPtr(pc+1); - pc += (opnd-1); - PUSH_OBJECT(Tcl_NewStringObj(bytes, length)); - goto instEvalStk; - } - case INST_NOP: pc += 1; goto cleanup0; @@ -7102,6 +7065,42 @@ TEBCresume( TclStackFree(interp, TD); /* free my stack */ return result; + + /* + * INST_START_CMD failure case removed where it doesn't bother that much + */ + /* case INST_START_CMD: + * + * Remark that if the interpreter is marked for deletion its + * compileEpoch is modified, so that the epoch check also verifies + * that the interp is not deleted. If no outside call has been made + * since the last check, it is safe to omit the check. + */ + + instStartCmdFailed: + { + const char *bytes; + + length = 0; + + /* + * We used to switch to direct eval; for NRE-awareness we now + * compile and eval the command so that this evaluation does not + * add a new TEBC instance. [Bug 2910748] + */ + + if (TclInterpReady(interp) == TCL_ERROR) { + goto gotError; + } + + codePtr->flags |= TCL_BYTECODE_RECOMPILE; + bytes = GetSrcInfoForPc(pc, codePtr, &length, NULL); + opnd = TclGetUInt4AtPtr(pc+1); + pc += (opnd-1); + PUSH_OBJECT(Tcl_NewStringObj(bytes, length)); + goto instEvalStk; + NEXT_INST_F(9, 0, 0); + } } #undef codePtr -- cgit v0.12 From 1092d1065d97d23b48062e4390604b39ff939aca Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 11 Jan 2013 17:27:38 +0000 Subject: Test for Bug 1884496 (not buggy on trunk). --- tests/parse.test | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/parse.test b/tests/parse.test index 0f76d64..bc4107d 100644 --- a/tests/parse.test +++ b/tests/parse.test @@ -26,6 +26,7 @@ testConstraint testparsevarname [llength [info commands testparsevarname]] testConstraint testparsevar [llength [info commands testparsevar]] testConstraint testasync [llength [info commands testasync]] testConstraint testcmdtrace [llength [info commands testcmdtrace]] +testConstraint testevent [llength [info commands testevent]] test parse-1.1 {Tcl_ParseCommand procedure, computing string length} testparser { testparser [bytestring "foo\0 bar"] -1 @@ -1090,6 +1091,14 @@ test parse-20.12 {TclParseBackslash: truncated escape} testparser { testparser {\x12X} 5 } {- {\x12X} 1 word {\x12X} 2 backslash {\x12} 0 text X 0 {}} +test parse-21.0 {Bug 1884496} testevent { + set ::script {set a [p]; return -level 0 $a} + proc ::p {} {string first s $::script} + testevent queue a head $::script + update +} {} + + cleanupTests } -- cgit v0.12 From f531d3de422a79dcc477d10d83f2badbbc27e8ea Mon Sep 17 00:00:00 2001 From: mig Date: Fri, 11 Jan 2013 18:05:50 +0000 Subject: fix for consecutive ISC (produced by [while 1 {...}) --- generic/tclExecute.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index ae9d0c7..bc755e8 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2300,16 +2300,10 @@ TEBCresume( TCL_DTRACE_INST_NEXT(); - /* - * These two instructions account for 26% of all instructions (according - * to measurements on tclbench by Ben Vitale - * [http://www.cs.toronto.edu/syslab/pubs/tcl2005-vitale-zaleski.pdf] - * Resolving them before the switch reduces the cost of branch - * mispredictions, seems to improve runtime by 5% to 15%, and (amazingly!) - * reduces total obj size. - */ - - if (*pc == INST_START_CMD) { + while (*pc == INST_START_CMD) { +#ifdef TCL_COMPILE_STATS + iPtr->stats.instructionCount[*pc]++; +#endif iPtr->cmdCount += TclGetUInt4AtPtr(pc+5); if (checkInterp) { checkInterp = 0; @@ -2321,6 +2315,15 @@ TEBCresume( pc += 9; } + /* + * These two instructions account for 26% of all instructions (according + * to measurements on tclbench by Ben Vitale + * [http://www.cs.toronto.edu/syslab/pubs/tcl2005-vitale-zaleski.pdf] + * Resolving them before the switch reduces the cost of branch + * mispredictions, seems to improve runtime by 5% to 15%, and (amazingly!) + * reduces total obj size. + */ + if (*pc == INST_LOAD_SCALAR1) { goto instLoadScalar1; } else if (*pc == INST_PUSH1) { @@ -2503,19 +2506,10 @@ TEBCresume( TRACE_WITH_OBJ(("=> discarding "), OBJ_AT_TOS); objPtr = POP_OBJECT(); TclDecrRefCount(objPtr); - - /* - * Runtime peephole optimisation: an INST_POP is scheduled at the end - * of most commands. If the next instruction is an INST_START_CMD, - * fall through to it. - */ - - pc++; - NEXT_INST_F(0, 0, 0); + NEXT_INST_F(1, 0, 0); case INST_NOP: - pc += 1; - goto cleanup0; + NEXT_INST_F(1, 0, 0); case INST_DUP: objResultPtr = OBJ_AT_TOS; @@ -7081,6 +7075,7 @@ TEBCresume( { const char *bytes; + checkInterp = 1; length = 0; /* -- cgit v0.12 From e5fc72423c12d157618f81231cc5ae12e0e8fc76 Mon Sep 17 00:00:00 2001 From: mig Date: Fri, 11 Jan 2013 21:16:07 +0000 Subject: better comments --- generic/tclExecute.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index bc755e8..1ed8949 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2301,6 +2301,10 @@ TEBCresume( TCL_DTRACE_INST_NEXT(); while (*pc == INST_START_CMD) { + /* + * Peephole: do not run INST_START_CMD, just skip it + */ + #ifdef TCL_COMPILE_STATS iPtr->stats.instructionCount[*pc]++; #endif @@ -7062,13 +7066,13 @@ TEBCresume( /* * INST_START_CMD failure case removed where it doesn't bother that much - */ - /* case INST_START_CMD: * * Remark that if the interpreter is marked for deletion its * compileEpoch is modified, so that the epoch check also verifies * that the interp is not deleted. If no outside call has been made * since the last check, it is safe to omit the check. + + * case INST_START_CMD: */ instStartCmdFailed: -- cgit v0.12 From 6e7718395efb2bf299224e5188b32da47efe0883 Mon Sep 17 00:00:00 2001 From: mig Date: Sat, 12 Jan 2013 10:14:06 +0000 Subject: even better ... or so I hope: also inlining INST_PUSH1 in the peephole, checking for ISC after LOAD1 and PUSH1 --- generic/tclExecute.c | 93 ++++++++++++++++++++++------------------------------ 1 file changed, 40 insertions(+), 53 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 1ed8949..4d758f6 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2250,23 +2250,6 @@ TEBCresume( } cleanup0: -#ifdef TCL_COMPILE_DEBUG - /* - * Skip the stack depth check if an expansion is in progress. - */ - - CHECK_STACK(); - if (traceInstructions) { - fprintf(stdout, "%2d: %2d ", iPtr->numLevels, (int) CURR_DEPTH); - TclPrintInstruction(codePtr, pc); - fflush(stdout); - } -#endif /* TCL_COMPILE_DEBUG */ - -#ifdef TCL_COMPILE_STATS - iPtr->stats.instructionCount[*pc]++; -#endif - /* * Check for asynchronous handlers [Bug 746722]; we do the check every * ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-1). @@ -2298,16 +2281,51 @@ TEBCresume( CACHE_STACK_INFO(); } + /* + * These two instructions account for 26% of all instructions (according + * to measurements on tclbench by Ben Vitale + * [http://www.cs.toronto.edu/syslab/pubs/tcl2005-vitale-zaleski.pdf] + * Resolving them before the switch reduces the cost of branch + * mispredictions, seems to improve runtime by 5% to 15%, and (amazingly!) + * reduces total obj size. + */ + + peepholeStart: +#ifdef TCL_COMPILE_STATS + iPtr->stats.instructionCount[*pc]++; +#endif + +#ifdef TCL_COMPILE_DEBUG + /* + * Skip the stack depth check if an expansion is in progress. + */ + + CHECK_STACK(); + if (traceInstructions) { + fprintf(stdout, "%2d: %2d ", iPtr->numLevels, (int) CURR_DEPTH); + TclPrintInstruction(codePtr, pc); + fflush(stdout); + } +#endif /* TCL_COMPILE_DEBUG */ + TCL_DTRACE_INST_NEXT(); + + if (*pc == INST_LOAD_SCALAR1) { + goto instLoadScalar1; + } - while (*pc == INST_START_CMD) { + if (*pc == INST_PUSH1) { + PUSH_OBJECT(codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)]); + TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), OBJ_AT_TOS); + pc += 2; + goto peepholeStart; + } + + if (*pc == INST_START_CMD) { /* * Peephole: do not run INST_START_CMD, just skip it */ -#ifdef TCL_COMPILE_STATS - iPtr->stats.instructionCount[*pc]++; -#endif iPtr->cmdCount += TclGetUInt4AtPtr(pc+5); if (checkInterp) { checkInterp = 0; @@ -2317,23 +2335,9 @@ TEBCresume( } } pc += 9; + goto peepholeStart; } - /* - * These two instructions account for 26% of all instructions (according - * to measurements on tclbench by Ben Vitale - * [http://www.cs.toronto.edu/syslab/pubs/tcl2005-vitale-zaleski.pdf] - * Resolving them before the switch reduces the cost of branch - * mispredictions, seems to improve runtime by 5% to 15%, and (amazingly!) - * reduces total obj size. - */ - - if (*pc == INST_LOAD_SCALAR1) { - goto instLoadScalar1; - } else if (*pc == INST_PUSH1) { - goto instPush1Peephole; - } - switch (*pc) { case INST_SYNTAX: case INST_RETURN_IMM: { @@ -2484,23 +2488,6 @@ TEBCresume( (void) POP_OBJECT(); goto abnormalReturn; - case INST_PUSH1: - instPush1Peephole: - PUSH_OBJECT(codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)]); - TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), OBJ_AT_TOS); - pc += 2; -#if !TCL_COMPILE_DEBUG - /* - * Runtime peephole optimisation: check if we are pushing again. - */ - - if (*pc == INST_PUSH1) { - TCL_DTRACE_INST_NEXT(); - goto instPush1Peephole; - } -#endif - NEXT_INST_F(0, 0, 0); - case INST_PUSH4: objResultPtr = codePtr->objArrayPtr[TclGetUInt4AtPtr(pc+1)]; TRACE_WITH_OBJ(("%u => ", TclGetUInt4AtPtr(pc+1)), objResultPtr); -- cgit v0.12 From ab85720d9820b140486e1517a6bff19cfacffd32 Mon Sep 17 00:00:00 2001 From: mig Date: Sat, 12 Jan 2013 10:49:25 +0000 Subject: discouraging the compiler from re-reading *pc in the peephole loop --- generic/tclExecute.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 4d758f6..5bf0e79 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2084,7 +2084,8 @@ TEBCresume( Tcl_Obj **tosPtr; /* Cached pointer to top of evaluation * stack. */ const unsigned char *pc; /* The current program counter. */ - + unsigned char inst; /* The currently running instruction */ + /* * Transfer variables - needed only between opcodes, but not while * executing an instruction. @@ -2290,6 +2291,8 @@ TEBCresume( * reduces total obj size. */ + inst = *pc; + peepholeStart: #ifdef TCL_COMPILE_STATS iPtr->stats.instructionCount[*pc]++; @@ -2310,18 +2313,18 @@ TEBCresume( TCL_DTRACE_INST_NEXT(); - if (*pc == INST_LOAD_SCALAR1) { + if (inst == INST_LOAD_SCALAR1) { goto instLoadScalar1; } - if (*pc == INST_PUSH1) { + if (inst == INST_PUSH1) { PUSH_OBJECT(codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)]); TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), OBJ_AT_TOS); - pc += 2; + inst = *(pc += 2); goto peepholeStart; } - if (*pc == INST_START_CMD) { + if (inst == INST_START_CMD) { /* * Peephole: do not run INST_START_CMD, just skip it */ @@ -2334,11 +2337,11 @@ TEBCresume( goto instStartCmdFailed; } } - pc += 9; + inst = *(pc += 9); goto peepholeStart; } - switch (*pc) { + switch (inst) { case INST_SYNTAX: case INST_RETURN_IMM: { int code = TclGetInt4AtPtr(pc+1); -- cgit v0.12 From 71ccd57a94c21d7e36abe8550f656e6f082a2907 Mon Sep 17 00:00:00 2001 From: mig Date: Sat, 12 Jan 2013 10:53:23 +0000 Subject: discouraging the compiler from re-reading *pc in the peephole loop, part2 (any diff?) --- generic/tclExecute.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 5bf0e79..628dfe7 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2315,16 +2315,12 @@ TEBCresume( if (inst == INST_LOAD_SCALAR1) { goto instLoadScalar1; - } - - if (inst == INST_PUSH1) { + } else if (inst == INST_PUSH1) { PUSH_OBJECT(codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)]); TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), OBJ_AT_TOS); inst = *(pc += 2); goto peepholeStart; - } - - if (inst == INST_START_CMD) { + } else if (inst == INST_START_CMD) { /* * Peephole: do not run INST_START_CMD, just skip it */ -- cgit v0.12 From 84b9c7728c8f168edce68d529ddac68a5056e766 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sat, 12 Jan 2013 21:57:24 +0000 Subject: Put back TclBackgroundException in internal stub table, so extensions using this, compiled against 8.5 headers still run in Tcl 8.6. --- ChangeLog | 6 ++++++ generic/tclInt.decls | 6 +++--- generic/tclIntDecls.h | 10 +++++++--- generic/tclStubInit.c | 3 ++- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1655e15..5db7896 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2013-01-12 Jan Nijtmans + + * generic/tclInt.decls: Put back TclBackgroundException in + internal stub table, so extensions using this, compiled + against 8.5 headers still run in Tcl 8.6. + 2013-01-09 Jan Nijtmans * library/http/http.tcl: [Bug 3599395]: http assumes status line diff --git a/generic/tclInt.decls b/generic/tclInt.decls index f215d32..948cc01 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -941,9 +941,9 @@ declare 235 { # TIP 337 made this one public -#declare 236 { -# void TclBackgroundException(Tcl_Interp *interp, int code) -#} +declare 236 { + void TclBackgroundException(Tcl_Interp *interp, int code) +} # TIP #285: Script cancellation support. declare 237 { diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index df5ac97..6cf0beb 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -557,7 +557,8 @@ EXTERN Var * TclVarHashCreateVar(TclVarHashTable *tablePtr, /* 235 */ EXTERN void TclInitVarHashTable(TclVarHashTable *tablePtr, Namespace *nsPtr); -/* Slot 236 is reserved */ +/* 236 */ +EXTERN void TclBackgroundException(Tcl_Interp *interp, int code); /* 237 */ EXTERN int TclResetCancellation(Tcl_Interp *interp, int force); /* 238 */ @@ -842,7 +843,7 @@ typedef struct TclIntStubs { void (*tclGetSrcInfoForPc) (CmdFrame *contextPtr); /* 233 */ Var * (*tclVarHashCreateVar) (TclVarHashTable *tablePtr, const char *key, int *newPtr); /* 234 */ void (*tclInitVarHashTable) (TclVarHashTable *tablePtr, Namespace *nsPtr); /* 235 */ - void (*reserved236)(void); + void (*tclBackgroundException) (Tcl_Interp *interp, int code); /* 236 */ int (*tclResetCancellation) (Tcl_Interp *interp, int force); /* 237 */ int (*tclNRInterpProc) (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* 238 */ int (*tclNRInterpProcCore) (Tcl_Interp *interp, Tcl_Obj *procNameObj, int skip, ProcErrorProc *errorProc); /* 239 */ @@ -1252,7 +1253,8 @@ extern const TclIntStubs *tclIntStubsPtr; (tclIntStubsPtr->tclVarHashCreateVar) /* 234 */ #define TclInitVarHashTable \ (tclIntStubsPtr->tclInitVarHashTable) /* 235 */ -/* Slot 236 is reserved */ +#define TclBackgroundException \ + (tclIntStubsPtr->tclBackgroundException) /* 236 */ #define TclResetCancellation \ (tclIntStubsPtr->tclResetCancellation) /* 237 */ #define TclNRInterpProc \ @@ -1289,4 +1291,6 @@ extern const TclIntStubs *tclIntStubsPtr; #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT +#undef TclBackgroundException + #endif /* _TCLINTDECLS */ diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 88ada19..14c838f 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -41,6 +41,7 @@ #undef Tcl_FindExecutable #undef TclpGetPid #undef TclSockMinimumBuffers +#define TclBackgroundException Tcl_BackgroundException /* See bug 510001: TclSockMinimumBuffers needs plat imp */ #ifdef _WIN64 @@ -425,7 +426,7 @@ static const TclIntStubs tclIntStubs = { TclGetSrcInfoForPc, /* 233 */ TclVarHashCreateVar, /* 234 */ TclInitVarHashTable, /* 235 */ - 0, /* 236 */ + TclBackgroundException, /* 236 */ TclResetCancellation, /* 237 */ TclNRInterpProc, /* 238 */ TclNRInterpProcCore, /* 239 */ -- cgit v0.12 From 7d3155c6e360cfbc4c9d6e98244622435eb470b9 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 13 Jan 2013 09:04:10 +0000 Subject: If TCL_NO_DEPRECATED is defined, make sure that TIP #139 functions all are taken from the public stub table, even if the inclusion is through tclInt.h. --- ChangeLog | 6 ++++++ generic/tclIntDecls.h | 52 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index e1373fb..5e6f47b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2013-01-13 Jan Nijtmans + + * generic/tclIntDecls.h: If TCL_NO_DEPRECATED is defined, make + sure that TIP #139 functions all are taken from the public stub + table, even if the inclusion is through tclInt.h. + 2013-01-09 Jan Nijtmans * library/http/http.tcl: [Bug 3599395]: http assumes status line diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index 3ccc50a..1dc797a 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -29,19 +29,18 @@ #endif /* [Bug #803489] Tcl_FindNamespace problem in the Stubs table */ -#undef Tcl_AppendExportList #undef Tcl_CreateNamespace #undef Tcl_DeleteNamespace +#undef Tcl_AppendExportList #undef Tcl_Export -#undef Tcl_FindCommand -#undef Tcl_FindNamespace -#undef Tcl_FindNamespaceVar +#undef Tcl_Import #undef Tcl_ForgetImport -#undef Tcl_GetCommandFromObj -#undef Tcl_GetCommandFullName #undef Tcl_GetCurrentNamespace #undef Tcl_GetGlobalNamespace -#undef Tcl_Import +#undef Tcl_FindNamespace +#undef Tcl_FindCommand +#undef Tcl_GetCommandFromObj +#undef Tcl_GetCommandFullName /* * WARNING: This file is automatically generated by the tools/genStubs.tcl @@ -2053,4 +2052,43 @@ extern TclIntStubs *tclIntStubsPtr; #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT +#if defined(USE_TCL_STUBS) && defined(TCL_NO_DEPRECATED) +# undef Tcl_CreateNamespace +# define Tcl_CreateNamespace \ + (tclStubsPtr->tcl_CreateNamespace) /* 506 */ +# undef Tcl_DeleteNamespace +# define Tcl_DeleteNamespace \ + (tclStubsPtr->tcl_DeleteNamespace) /* 507 */ +# undef Tcl_AppendExportList +# define Tcl_AppendExportList \ + (tclStubsPtr->tcl_AppendExportList) /* 508 */ +# undef Tcl_Export +# define Tcl_Export \ + (tclStubsPtr->tcl_Export) /* 509 */ +# undef Tcl_Import +# define Tcl_Import \ + (tclStubsPtr->tcl_Import) /* 510 */ +# undef Tcl_ForgetImport +# define Tcl_ForgetImport \ + (tclStubsPtr->tcl_ForgetImport) /* 511 */ +# undef Tcl_GetCurrentNamespace +# define Tcl_GetCurrentNamespace \ + (tclStubsPtr->tcl_GetCurrentNamespace) /* 512 */ +# undef Tcl_GetGlobalNamespace +# define Tcl_GetGlobalNamespace \ + (tclStubsPtr->tcl_GetGlobalNamespace) /* 513 */ +# undef Tcl_FindNamespace +# define Tcl_FindNamespace \ + (tclStubsPtr->tcl_FindNamespace) /* 514 */ +# undef Tcl_FindCommand +# define Tcl_FindCommand \ + (tclStubsPtr->tcl_FindCommand) /* 515 */ +# undef Tcl_GetCommandFromObj +# define Tcl_GetCommandFromObj \ + (tclStubsPtr->tcl_GetCommandFromObj) /* 516 */ +# undef Tcl_GetCommandFullName +# define Tcl_GetCommandFullName \ + (tclStubsPtr->tcl_GetCommandFullName) /* 517 */ +#endif + #endif /* _TCLINTDECLS */ -- cgit v0.12 From bba96eb5807020d22f0456cfdec86e4364265944 Mon Sep 17 00:00:00 2001 From: ferrieux Date: Sun, 13 Jan 2013 18:12:41 +0000 Subject: Clarify readable fileevent "false positives" in the case of multibyte encodings/transforms [Bug 3436609]. --- ChangeLog | 4 ++++ doc/fileevent.n | 17 ++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9cfa769..83e7053 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-01-13 Alexandre Ferrieux + * doc/fileevent.n: Clarify readable fileevent "false positives" in + the case of multibyte encodings/transforms [Bug 3436609]. + 2013-01-13 Jan Nijtmans * generic/tclIntDecls.h: If TCL_NO_DEPRECATED is defined, make diff --git a/doc/fileevent.n b/doc/fileevent.n index df48d2a..e453748 100644 --- a/doc/fileevent.n +++ b/doc/fileevent.n @@ -80,13 +80,16 @@ A channel is considered to be writable if at least one byte of data can be written to the underlying file or device without blocking, or if an error condition is present on the underlying file or device. .PP -Event-driven I/O works best for channels that have been -placed into nonblocking mode with the \fBfconfigure\fR command. -In blocking mode, a \fBputs\fR command may block if you give it -more data than the underlying file or device can accept, and a -\fBgets\fR or \fBread\fR command will block if you attempt to read -more data than is ready; no events will be processed while the -commands block. +Event-driven I/O works best for channels that have been placed into +nonblocking mode with the \fBfconfigure\fR command. In blocking mode, +a \fBputs\fR command may block if you give it more data than the +underlying file or device can accept, and a \fBgets\fR or \fBread\fR +command will block if you attempt to read more data than is ready; a +readable underlying file or device may not even guarantee that a +blocking [read 1] will succeed (counter-examples being multi-byte +encodings, compression or encryption transforms ). In all such cases, +no events will be processed while the commands block. +.PP In nonblocking mode \fBputs\fR, \fBread\fR, and \fBgets\fR never block. See the documentation for the individual commands for information on how they handle blocking and nonblocking channels. -- cgit v0.12 From a8dc97056d6b68ef14637bf9e6672707b32745b3 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 14 Jan 2013 15:19:18 +0000 Subject: Put back Tcl_[GS]etStartupScript in internal stub table, so extensions using this, compiled against 8.5 headers still run in Tcl 8.6. --- ChangeLog | 6 ++++++ generic/tclInt.decls | 14 +++++++------- generic/tclIntDecls.h | 23 +++++++++++++++++------ generic/tclStubInit.c | 4 ++-- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 83e7053..d9b7df4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2013-01-14 Jan Nijtmans + + * generic/tclInt.decls: Put back Tcl_[GS]etStartupScript in + internal stub table, so extensions using this, compiled + against 8.5 headers still run in Tcl 8.6. + 2013-01-13 Alexandre Ferrieux * doc/fileevent.n: Clarify readable fileevent "false positives" in the case of multibyte encodings/transforms [Bug 3436609]. diff --git a/generic/tclInt.decls b/generic/tclInt.decls index 948cc01..58dab42 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -731,13 +731,13 @@ declare 177 { void TclVarErrMsg(Tcl_Interp *interp, const char *part1, const char *part2, const char *operation, const char *reason) } -# TIP 338 made these public - now declared in tcl.h -#declare 178 { -# void Tcl_SetStartupScript(Tcl_Obj *pathPtr, const char *encodingName) -#} -#declare 179 { -# Tcl_Obj *Tcl_GetStartupScript(const char **encodingNamePtr) -#} +# TIP 338 made these public - now declared in tcl.h too +declare 178 { + void Tcl_SetStartupScript(Tcl_Obj *pathPtr, const char *encodingName) +} +declare 179 { + Tcl_Obj *Tcl_GetStartupScript(const char **encodingNamePtr) +} # REMOVED # Allocate lists without copying arrays diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index d788ee0..b76d2e0 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -41,6 +41,8 @@ #undef Tcl_FindCommand #undef Tcl_GetCommandFromObj #undef Tcl_GetCommandFullName +#undef Tcl_SetStartupScript +#undef Tcl_GetStartupScript /* * WARNING: This file is automatically generated by the tools/genStubs.tcl @@ -446,8 +448,11 @@ EXTERN void TclCleanupVar(Var *varPtr, Var *arrayPtr); EXTERN void TclVarErrMsg(Tcl_Interp *interp, const char *part1, const char *part2, const char *operation, const char *reason); -/* Slot 178 is reserved */ -/* Slot 179 is reserved */ +/* 178 */ +EXTERN void Tcl_SetStartupScript(Tcl_Obj *pathPtr, + const char *encodingName); +/* 179 */ +EXTERN Tcl_Obj * Tcl_GetStartupScript(const char **encodingNamePtr); /* Slot 180 is reserved */ /* Slot 181 is reserved */ /* 182 */ @@ -784,8 +789,8 @@ typedef struct TclIntStubs { int (*tclCallVarTraces) (Interp *iPtr, Var *arrayPtr, Var *varPtr, const char *part1, const char *part2, int flags, int leaveErrMsg); /* 175 */ void (*tclCleanupVar) (Var *varPtr, Var *arrayPtr); /* 176 */ void (*tclVarErrMsg) (Tcl_Interp *interp, const char *part1, const char *part2, const char *operation, const char *reason); /* 177 */ - void (*reserved178)(void); - void (*reserved179)(void); + void (*tcl_SetStartupScript) (Tcl_Obj *pathPtr, const char *encodingName); /* 178 */ + Tcl_Obj * (*tcl_GetStartupScript) (const char **encodingNamePtr); /* 179 */ void (*reserved180)(void); void (*reserved181)(void); struct tm * (*tclpLocaltime) (const time_t *clock); /* 182 */ @@ -1164,8 +1169,10 @@ extern const TclIntStubs *tclIntStubsPtr; (tclIntStubsPtr->tclCleanupVar) /* 176 */ #define TclVarErrMsg \ (tclIntStubsPtr->tclVarErrMsg) /* 177 */ -/* Slot 178 is reserved */ -/* Slot 179 is reserved */ +#define Tcl_SetStartupScript \ + (tclIntStubsPtr->tcl_SetStartupScript) /* 178 */ +#define Tcl_GetStartupScript \ + (tclIntStubsPtr->tcl_GetStartupScript) /* 179 */ /* Slot 180 is reserved */ /* Slot 181 is reserved */ #define TclpLocaltime \ @@ -1293,6 +1300,10 @@ extern const TclIntStubs *tclIntStubsPtr; #undef TclBackgroundException #if defined(USE_TCL_STUBS) && defined(TCL_NO_DEPRECATED) +# define Tcl_SetStartupScript \ + (tclStubsPtr->tcl_SetStartupScript) /* 622 */ +# define Tcl_GetStartupScript \ + (tclStubsPtr->tcl_GetStartupScript) /* 623 */ # undef Tcl_CreateNamespace # define Tcl_CreateNamespace \ (tclStubsPtr->tcl_CreateNamespace) /* 506 */ diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 14c838f..1d1fe15 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -368,8 +368,8 @@ static const TclIntStubs tclIntStubs = { TclCallVarTraces, /* 175 */ TclCleanupVar, /* 176 */ TclVarErrMsg, /* 177 */ - 0, /* 178 */ - 0, /* 179 */ + Tcl_SetStartupScript, /* 178 */ + Tcl_GetStartupScript, /* 179 */ 0, /* 180 */ 0, /* 181 */ TclpLocaltime, /* 182 */ -- cgit v0.12 From d3dab183a137c6da919356663f688a0a7df0df26 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 14 Jan 2013 15:23:41 +0000 Subject: forgot two #undef's --- generic/tclIntDecls.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index b76d2e0..092225e 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -1300,8 +1300,10 @@ extern const TclIntStubs *tclIntStubsPtr; #undef TclBackgroundException #if defined(USE_TCL_STUBS) && defined(TCL_NO_DEPRECATED) +# undef Tcl_SetStartupScript # define Tcl_SetStartupScript \ (tclStubsPtr->tcl_SetStartupScript) /* 622 */ +# undef Tcl_GetStartupScript # define Tcl_GetStartupScript \ (tclStubsPtr->tcl_GetStartupScript) /* 623 */ # undef Tcl_CreateNamespace -- cgit v0.12 From a232873402bb9f847fdff9033a824fb7f62dd4b1 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 14 Jan 2013 20:13:41 +0000 Subject: More flexible search for win32 tclConfig.sh, backported from TEA (not actually used in Tcl, only for Tk) --- ChangeLog | 5 ++ win/tcl.m4 | 228 +++++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 191 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5e6f47b..54ba830 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-01-14 Jan Nijtmans + + * win/tcl.m4: More flexible search for win32 tclConfig.sh, + backported from TEA (not actually used in Tcl, only for Tk) + 2013-01-13 Jan Nijtmans * generic/tclIntDecls.h: If TCL_NO_DEPRECATED is defined, make diff --git a/win/tcl.m4 b/win/tcl.m4 index 2f2964b..7559591 100644 --- a/win/tcl.m4 +++ b/win/tcl.m4 @@ -3,50 +3,120 @@ # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags -# Currently a no-op for Windows # # Arguments: -# PATCH_LEVEL The patch level for Tcl if any. +# none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # -# Sets the following vars: -# TCL_BIN_DIR Full path to the tclConfig.sh file +# Defines the following vars: +# TCL_BIN_DIR Full path to the directory containing +# the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([SC_PATH_TCLCONFIG], [ - AC_MSG_CHECKING([the location of tclConfig.sh]) + # + # Ok, lets find the tcl configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tcl + # - if test -d ../../tcl8.5$1/win; then - TCL_BIN_DIR_DEFAULT=../../tcl8.5$1/win - elif test -d ../../tcl8.5/win; then - TCL_BIN_DIR_DEFAULT=../../tcl8.5/win - else - TCL_BIN_DIR_DEFAULT=../../tcl/win - fi + if test x"${no_tcl}" = x ; then + # we reset no_tcl in case something fails here + no_tcl=true + AC_ARG_WITH(tcl, + AC_HELP_STRING([--with-tcl], + [directory containing tcl configuration (tclConfig.sh)]), + with_tclconfig="${withval}") + AC_MSG_CHECKING([for Tcl configuration]) + AC_CACHE_VAL(ac_cv_c_tclconfig,[ + + # First check to see if --with-tcl was specified. + if test x"${with_tclconfig}" != x ; then + case "${with_tclconfig}" in + */tclConfig.sh ) + if test -f "${with_tclconfig}"; then + AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) + with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" + else + AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) + fi + fi - AC_ARG_WITH(tcl, [ --with-tcl=DIR use Tcl 8.5 binaries from DIR], - TCL_BIN_DIR=$withval, TCL_BIN_DIR=`cd $TCL_BIN_DIR_DEFAULT; pwd`) - if test ! -d $TCL_BIN_DIR; then - AC_MSG_ERROR(Tcl directory $TCL_BIN_DIR does not exist) - fi - if test ! -f $TCL_BIN_DIR/tclConfig.sh; then - if test ! -f $TCL_BIN_DIR/../unix/tclConfig.sh; then - AC_MSG_ERROR(There is no tclConfig.sh in $TCL_BIN_DIR: perhaps you did not specify the Tcl *build* directory (not the toplevel Tcl directory) or you forgot to configure Tcl?) + # then check for a private Tcl installation + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ../tcl \ + `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tcl \ + `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tcl \ + `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d C:/Tcl/lib 2>/dev/null` \ + `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + done + fi + ]) + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) + else + no_tcl= + TCL_BIN_DIR="${ac_cv_c_tclconfig}" + AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi - TCL_BIN_DIR=`cd ${TCL_BIN_DIR}/../unix; pwd` fi - AC_MSG_RESULT($TCL_BIN_DIR/tclConfig.sh) ]) #------------------------------------------------------------------------ # SC_PATH_TKCONFIG -- # # Locate the tkConfig.sh file -# Currently a no-op for Windows # # Arguments: # none @@ -56,31 +126,105 @@ AC_DEFUN([SC_PATH_TCLCONFIG], [ # Adds the following arguments to configure: # --with-tk=... # -# Sets the following vars: -# TK_BIN_DIR Full path to the tkConfig.sh file +# Defines the following vars: +# TK_BIN_DIR Full path to the directory containing +# the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([SC_PATH_TKCONFIG], [ - AC_MSG_CHECKING([the location of tkConfig.sh]) + # + # Ok, lets find the tk configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tk + # - if test -d ../../tk8.5$1/win; then - TK_BIN_DIR_DEFAULT=../../tk8.5$1/win - elif test -d ../../tk8.5/win; then - TK_BIN_DIR_DEFAULT=../../tk8.5/win - else - TK_BIN_DIR_DEFAULT=../../tk/win - fi + if test x"${no_tk}" = x ; then + # we reset no_tk in case something fails here + no_tk=true + AC_ARG_WITH(tk, + AC_HELP_STRING([--with-tk], + [directory containing tk configuration (tkConfig.sh)]), + with_tkconfig="${withval}") + AC_MSG_CHECKING([for Tk configuration]) + AC_CACHE_VAL(ac_cv_c_tkconfig,[ + + # First check to see if --with-tkconfig was specified. + if test x"${with_tkconfig}" != x ; then + case "${with_tkconfig}" in + */tkConfig.sh ) + if test -f "${with_tkconfig}"; then + AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) + with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tkconfig}/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" + else + AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) + fi + fi - AC_ARG_WITH(tk, [ --with-tk=DIR use Tk 8.5 binaries from DIR], - TK_BIN_DIR=$withval, TK_BIN_DIR=`cd $TK_BIN_DIR_DEFAULT; pwd`) - if test ! -d $TK_BIN_DIR; then - AC_MSG_ERROR(Tk directory $TK_BIN_DIR does not exist) - fi - if test ! -f $TK_BIN_DIR/tkConfig.sh; then - AC_MSG_ERROR(There is no tkConfig.sh in $TK_BIN_DIR: perhaps you did not specify the Tk *build* directory (not the toplevel Tk directory) or you forgot to configure Tk?) - fi + # then check for a private Tk library + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ../tk \ + `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tk \ + `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tk \ + `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + done + fi - AC_MSG_RESULT([$TK_BIN_DIR/tkConfig.sh]) + # check in a few common install locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d C:/Tcl/lib 2>/dev/null` \ + `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ${srcdir}/../tk \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + done + fi + ]) + + if test x"${ac_cv_c_tkconfig}" = x ; then + TK_BIN_DIR="# no Tk configs found" + AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) + else + no_tk= + TK_BIN_DIR="${ac_cv_c_tkconfig}" + AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) + fi + fi ]) #------------------------------------------------------------------------ -- cgit v0.12 -- cgit v0.12 From 2f176f6d8c9cf73aa834e6204cffd10e209c283b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 16 Jan 2013 08:52:59 +0000 Subject: Allow win32 build with -DTCL_NO_DEPRECATED, just as the UNIX build, off by default. Define Tcl_EvalObj and Tcl_GlobalEvalObj as macros, even when TCL_NO_DEPRECATED is defined, so Tk can benefit from it too (this is not what TCL_NO_DEPRECATED is supposed to do). --- generic/tcl.h | 11 ----------- generic/tclBasic.c | 2 -- generic/tclDecls.h | 12 ++++++++++++ win/Makefile.in | 7 ++++++- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/generic/tcl.h b/generic/tcl.h index 9dd6ff0..5f47734 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -2278,17 +2278,6 @@ typedef unsigned short Tcl_UniChar; /* - * Deprecated Tcl procedures: - */ -#ifndef TCL_NO_DEPRECATED -# define Tcl_EvalObj(interp,objPtr) \ - Tcl_EvalObjEx((interp),(objPtr),0) -# define Tcl_GlobalEvalObj(interp,objPtr) \ - Tcl_EvalObjEx((interp),(objPtr),TCL_EVAL_GLOBAL) -#endif - - -/* * These function have been renamed. The old names are deprecated, but we * define these macros for backwards compatibilty. */ diff --git a/generic/tclBasic.c b/generic/tclBasic.c index bd4ad5d..134deac 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -4923,7 +4923,6 @@ Tcl_Eval(interp, string) *---------------------------------------------------------------------- */ -#undef Tcl_EvalObj int Tcl_EvalObj(interp, objPtr) Tcl_Interp * interp; @@ -4932,7 +4931,6 @@ Tcl_EvalObj(interp, objPtr) return Tcl_EvalObjEx(interp, objPtr, 0); } -#undef Tcl_GlobalEvalObj int Tcl_GlobalEvalObj(interp, objPtr) Tcl_Interp * interp; diff --git a/generic/tclDecls.h b/generic/tclDecls.h index 7df9897..8d9f635 100644 --- a/generic/tclDecls.h +++ b/generic/tclDecls.h @@ -4516,5 +4516,17 @@ extern TclStubs *tclStubsPtr; #undef TclUnusedStubEntry +/* + * Deprecated Tcl procedures: + */ +#if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) +# undef Tcl_EvalObj +# define Tcl_EvalObj(interp,objPtr) \ + Tcl_EvalObjEx((interp),(objPtr),0) +# undef Tcl_GlobalEvalObj +# define Tcl_GlobalEvalObj(interp,objPtr) \ + Tcl_EvalObjEx((interp),(objPtr),TCL_EVAL_GLOBAL) +#endif + #endif /* _TCLDECLS */ diff --git a/win/Makefile.in b/win/Makefile.in index af4ca68..b9ae5ad 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -129,6 +129,11 @@ SHARED_LIBRARIES = $(TCL_DLL_FILE) $(TCL_STUB_LIB_FILE) \ $(DDE_DLL_FILE) $(REG_DLL_FILE) $(PIPE_DLL_FILE) STATIC_LIBRARIES = $(TCL_LIB_FILE) $(REG_LIB_FILE) $(DDE_LIB_FILE) +# To compile without backward compatibility and deprecated code +# uncomment the following +NO_DEPRECATED_FLAGS = +#NO_DEPRECATED_FLAGS = -DTCL_NO_DEPRECATED + # TCL_EXE is the name of a tclsh executable that is available *BEFORE* # running make for the first time. Certain build targets (make genstubs) # need it to be available on the PATH. This executable should *NOT* be @@ -184,7 +189,7 @@ COPY = cp CC_SWITCHES = ${CFLAGS} ${CFLAGS_WARNING} ${TCL_SHLIB_CFLAGS} \ -I"${GENERIC_DIR_NATIVE}" -I"${WIN_DIR_NATIVE}" ${AC_FLAGS} \ -${COMPILE_DEBUG_FLAGS} +${COMPILE_DEBUG_FLAGS} ${NO_DEPRECATED_FLAGS} CC_OBJNAME = @CC_OBJNAME@ CC_EXENAME = @CC_EXENAME@ -- cgit v0.12 From 096fcb63ad03e22727db52eba9d7926194f673ae Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 16 Jan 2013 08:55:17 +0000 Subject: and changelog --- ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index f14699c..2ee5bbe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2013-01-16 Jan Nijtmans + + * Makefile.in: Enable win32 build with -DTCL_NO_DEPRECATED, just + * generic/tcl.h: as the UNIX build. Define Tcl_EvalObj and + * generic/tclDecls.h: Tcl_GlobalEvalObj as macros, even when + * generic/tclBasic.c: TCL_NO_DEPRECATED is defined, so Tk + can benefit from it too. + 2013-01-08 Jan Nijtmans * win/tclWinFile.c: [Bug 3092089]: [file normalize] can remove path -- cgit v0.12 From 445ffe85310c4a5853d313305b11a4323605c29c Mon Sep 17 00:00:00 2001 From: dkf Date: Wed, 16 Jan 2013 11:01:46 +0000 Subject: [Bug 3601086]: Register zlib config as iso8859-1 (a superset of ascii) as that is an encoding we guarantee to support without loading encoding files. --- ChangeLog | 53 ++++++++++++++++++++++++++++++----------------------- generic/tclZlib.c | 2 +- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index fa41721..968057f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,15 @@ +2013-01-16 Donal K. Fellows + + * generic/tclZlib.c (TclZlibInit): [Bug 3601086]: Register the config + info in the iso8859-1 encoding as that is guaranteed to be present. + 2013-01-16 Jan Nijtmans - * Makefile.in: Enable win32 build with -DTCL_NO_DEPRECATED, just - * generic/tcl.h: as the UNIX build. Define Tcl_EvalObj and + * Makefile.in: Enable win32 build with -DTCL_NO_DEPRECATED, just as + * generic/tcl.h: in the UNIX build. Define Tcl_EvalObj and * generic/tclDecls.h: Tcl_GlobalEvalObj as macros, even when - * generic/tclBasic.c: TCL_NO_DEPRECATED is defined, so Tk - can benefit from it too. + * generic/tclBasic.c: TCL_NO_DEPRECATED is defined, so Tk can benefit + from it too. 2013-01-15 Jan Nijtmans @@ -13,35 +18,36 @@ 2013-01-14 Jan Nijtmans - * win/tcl.m4: More flexible search for win32 tclConfig.sh, - backported from TEA (not actually used in Tcl, only for Tk) + * win/tcl.m4: More flexible search for win32 tclConfig.sh, backported + from TEA (not actually used in Tcl, only for Tk) 2013-01-14 Jan Nijtmans - * generic/tclInt.decls: Put back Tcl_[GS]etStartupScript in - internal stub table, so extensions using this, compiled - against 8.5 headers still run in Tcl 8.6. + * generic/tclInt.decls: Put back Tcl_[GS]etStartupScript in internal + stub table, so extensions using this, compiled against 8.5 headers + still run in Tcl 8.6. 2013-01-13 Alexandre Ferrieux - * doc/fileevent.n: Clarify readable fileevent "false positives" in - the case of multibyte encodings/transforms [Bug 3436609]. + + * doc/fileevent.n: [Bug 3436609]: Clarify readable fileevent "false + positives" in the case of multibyte encodings/transforms. 2013-01-13 Jan Nijtmans - * generic/tclIntDecls.h: If TCL_NO_DEPRECATED is defined, make - sure that TIP #139 functions all are taken from the public stub - table, even if the inclusion is through tclInt.h. + * generic/tclIntDecls.h: If TCL_NO_DEPRECATED is defined, make sure + that TIP #139 functions all are taken from the public stub table, even + if the inclusion is through tclInt.h. 2013-01-12 Jan Nijtmans - * generic/tclInt.decls: Put back TclBackgroundException in - internal stub table, so extensions using this, compiled - against 8.5 headers still run in Tcl 8.6. + * generic/tclInt.decls: Put back TclBackgroundException in internal + stub table, so extensions using this, compiled against 8.5 headers + still run in Tcl 8.6. 2013-01-09 Jan Nijtmans - * library/http/http.tcl: [Bug 3599395]: http assumes status line - is a proper tcl list. + * library/http/http.tcl: [Bug 3599395]: http assumes status line is a + proper Tcl list. 2013-01-08 Jan Nijtmans @@ -52,10 +58,10 @@ 2013-01-07 Jan Nijtmans * generic/tclOOStubLib.c: Restrict the stub library to only use - * generic/tclTomMathStubLib.c: Tcl_PkgRequireEx, Tcl_ResetResult - and Tcl_AppendResult, not any other function. This puts least - restrictions on eventual Tcl 9 stubs re-organization, and it - works on the widest range of Tcl versions. + * generic/tclTomMathStubLib.c: Tcl_PkgRequireEx, Tcl_ResetResult and + Tcl_AppendResult, not any other function. This puts least restrictions + on eventual Tcl 9 stubs re-organization, and it works on the widest + range of Tcl versions. 2013-01-06 Jan Nijtmans @@ -4152,6 +4158,7 @@ * generic/*Decls.h: (regenerated) 2010-08-18 Miguel Sofer + * generic/tclBasic.c: New redesign of [tailcall]: find * generic/tclExecute.c: errors early on, so that errorInfo * generic/tclInt.h: contains the proper info [Bug 3047235] diff --git a/generic/tclZlib.c b/generic/tclZlib.c index 9c1176e..47091de 100644 --- a/generic/tclZlib.c +++ b/generic/tclZlib.c @@ -3865,7 +3865,7 @@ TclZlibInit( cfg[0].key = "zlibVersion"; cfg[0].value = zlibVersion(); cfg[1].key = NULL; - Tcl_RegisterConfig(interp, "zlib", cfg, "ascii"); + Tcl_RegisterConfig(interp, "zlib", cfg, "iso8859-1"); /* * Formally provide the package as a Tcl built-in. -- cgit v0.12 From 6fe554cad0f2191435d30324f3e2b0caf121f891 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 17 Jan 2013 08:28:41 +0000 Subject: revert [8abba84224], and make sure that every source file that uses Tcl_StatBuf has an "#include " before including tcl.h --- ChangeLog | 5 ----- generic/tclCmdAH.c | 1 + generic/tclEncoding.c | 1 + generic/tclFCmd.c | 1 + generic/tclFileName.c | 1 + generic/tclIOUtil.c | 4 +--- generic/tclPort.h | 5 +++-- generic/tclTest.c | 1 + macosx/tclMacOSXFCmd.c | 1 + unix/tclUnixFCmd.c | 1 + unix/tclUnixFile.c | 1 + unix/tclUnixInit.c | 1 + unix/tclUnixPort.h | 4 +--- win/tclWinFile.c | 2 +- 14 files changed, 15 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 09c88db..3cbdd1a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,11 +6,6 @@ * generic/tclBasic.c: TCL_NO_DEPRECATED is defined, so Tk can benefit from it too. -2013-01-15 Jan Nijtmans - - * generic/tclPort.h: [Bug 3598300]: unix: tcl.h does not include - * unix/tclUnixPort.h: sys/stat.h - 2013-01-14 Jan Nijtmans * win/tcl.m4: More flexible search for win32 tclConfig.sh, diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index 44f08a3..9b03eab 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -11,6 +11,7 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +#include #include "tclInt.h" #include diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c index fb2f134..eb4950a 100644 --- a/generic/tclEncoding.c +++ b/generic/tclEncoding.c @@ -9,6 +9,7 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +#include #include "tclInt.h" typedef size_t (LengthProc)(const char *src); diff --git a/generic/tclFCmd.c b/generic/tclFCmd.c index c57a4ff..2a579c6 100644 --- a/generic/tclFCmd.c +++ b/generic/tclFCmd.c @@ -15,6 +15,7 @@ # define _USE_32BIT_TIME_T #endif +#include #include "tclInt.h" /* diff --git a/generic/tclFileName.c b/generic/tclFileName.c index 07757d9..0f32d2b 100644 --- a/generic/tclFileName.c +++ b/generic/tclFileName.c @@ -11,6 +11,7 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +#include #include "tclInt.h" #include "tclRegexp.h" #include "tclFileSystem.h" /* For TclGetPathType() */ diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index f90bf0d..488cbb8 100644 --- a/generic/tclIOUtil.c +++ b/generic/tclIOUtil.c @@ -18,9 +18,7 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -#if defined(HAVE_SYS_STAT_H) && !defined _WIN32 -# include -#endif +#include #include "tclInt.h" #ifdef __WIN32__ # include "tclWinInt.h" diff --git a/generic/tclPort.h b/generic/tclPort.h index 12a60db..7021b8d 100644 --- a/generic/tclPort.h +++ b/generic/tclPort.h @@ -19,10 +19,11 @@ #endif #if defined(_WIN32) # include "tclWinPort.h" -#else -# include "tclUnixPort.h" #endif #include "tcl.h" +#if !defined(_WIN32) +# include "tclUnixPort.h" +#endif #if !defined(LLONG_MIN) # ifdef TCL_WIDE_INT_IS_LONG diff --git a/generic/tclTest.c b/generic/tclTest.c index 3c39a40..a96785a 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -21,6 +21,7 @@ #endif #define TCL_TEST +#include #include "tclInt.h" #include diff --git a/macosx/tclMacOSXFCmd.c b/macosx/tclMacOSXFCmd.c index 09ee96d..d034886 100644 --- a/macosx/tclMacOSXFCmd.c +++ b/macosx/tclMacOSXFCmd.c @@ -10,6 +10,7 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +#include #include "tclInt.h" #ifdef HAVE_GETATTRLIST diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index a96a81a..79f115e 100644 --- a/unix/tclUnixFCmd.c +++ b/unix/tclUnixFCmd.c @@ -40,6 +40,7 @@ * DAMAGE. */ +#include #include "tclInt.h" #include #include diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c index 4a34b0b..40434a0 100644 --- a/unix/tclUnixFile.c +++ b/unix/tclUnixFile.c @@ -10,6 +10,7 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +#include #include "tclInt.h" #include "tclFileSystem.h" diff --git a/unix/tclUnixInit.c b/unix/tclUnixInit.c index f9015b7..8ebd069 100644 --- a/unix/tclUnixInit.c +++ b/unix/tclUnixInit.c @@ -8,6 +8,7 @@ * All rights reserved. */ +#include #include "tclInt.h" #include #include diff --git a/unix/tclUnixPort.h b/unix/tclUnixPort.h index 32d14e1..4668707 100644 --- a/unix/tclUnixPort.h +++ b/unix/tclUnixPort.h @@ -116,9 +116,7 @@ typedef off_t Tcl_SeekOffset; #ifdef HAVE_SYS_SELECT_H # include #endif -#ifdef HAVE_SYS_STAT_H -# include -#endif +#include #if TIME_WITH_SYS_TIME # include # include diff --git a/win/tclWinFile.c b/win/tclWinFile.c index 7da19ce..7224345 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -12,10 +12,10 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +#include #include "tclWinInt.h" #include "tclFileSystem.h" #include -#include #include #include /* For TclpGetUserHome(). */ -- cgit v0.12 From a5cfbafa9098e5ae4018b3142702fd8138417776 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 17 Jan 2013 13:29:07 +0000 Subject: Proposed fix, by kakaroto, for Bug 2911139: http::geturl abuses vwait on async call --- library/http/http.tcl | 64 ++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index 6b82894..4a517ac 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -528,11 +528,10 @@ proc http::geturl {url args} { # If a timeout is specified we set up the after event and arrange for an # asynchronous socket connection. - set sockopts [list] + set sockopts [list -async] if {$state(-timeout) > 0} { set state(after) [after $state(-timeout) \ [list http::reset $token timeout]] - lappend sockopts -async } # If we are using the proxy, we must pass in the full URL that includes @@ -588,10 +587,15 @@ proc http::geturl {url args} { set socketmap($state(socketinfo)) $sock } - # Wait for the connection to complete. + if {![info exists phost]} { + set phost "" + } + fileevent $sock writable [list http::Connect $token $proto $phost $srvurl] - if {$state(-timeout) > 0} { - fileevent $sock writable [list http::Connect $token] + # Wait for the connection to complete. + if {![info exists state(-command)]} { + # geturl does EVERYTHING asynchronously, so if the user + # calls it synchronously, we just do a wait here. http::wait $token if {![info exists state]} { @@ -607,13 +611,29 @@ proc http::geturl {url args} { set err [lindex $state(error) 0] cleanup $token return -code error $err - } elseif {$state(status) ne "connect"} { - # Likely to be connection timeout - return $token } - set state(status) "" } + return $token +} + + +proc http::Connected { token proto phost srvurl} { + variable http + variable urlTypes + + variable $token + upvar 0 $token state + + # Set back the variables needed here + set sock $state(sock) + set isQueryChannel [info exists state(-querychannel)] + set isQuery [info exists state(-query)] + set host [lindex [split $state(socketinfo) :] 0] + set port [lindex [split $state(socketinfo) :] 1] + + set defport [lindex $urlTypes($proto) 0] + # Send data in cr-lf format, but accept any line terminators fconfigure $sock -translation {auto crlf} -buffersize $state(-blocksize) @@ -746,35 +766,17 @@ proc http::geturl {url args} { fileevent $sock readable [list http::Event $sock $token] } - if {![info exists state(-command)]} { - # geturl does EVERYTHING asynchronously, so if the user calls it - # synchronously, we just do a wait here. - - wait $token - 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]} then { # 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 {$state(status) ne "error"} { - Finish $token $err 1 + Finish $token $err } - cleanup $token - return -code error $err } - return $token } # Data access functions: @@ -858,7 +860,7 @@ proc http::cleanup {token} { # Sets the status of the connection, which unblocks # the waiting geturl call -proc http::Connect {token} { +proc http::Connect {token proto phost srvurl} { variable $token upvar 0 $token state set err "due to unexpected EOF" @@ -866,10 +868,10 @@ proc http::Connect {token} { [eof $state(sock)] || [set err [fconfigure $state(sock) -error]] ne "" } then { - Finish $token "connect failed $err" 1 + Finish $token "connect failed $err" } else { - set state(status) connect fileevent $state(sock) writable {} + ::http::Connected $token $proto $phost $srvurl } return } -- cgit v0.12 From 0c7be9daeb83147f81ecd891b80398293c36e92a Mon Sep 17 00:00:00 2001 From: mig Date: Thu, 17 Jan 2013 15:13:40 +0000 Subject: COMPILE_DEBUG big: fix bug in stack verification for {*} --- generic/tclExecute.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 628dfe7..8a68e9b 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -259,8 +259,11 @@ VarHashCreateVar( #if TCL_COMPILE_DEBUG #define CHECK_STACK() \ - ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, \ - /*checkStack*/ auxObjList == NULL) + do { \ + ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, \ + /*checkStack*/ !(starting || auxObjList)); \ + starting = 0; \ + } while (0) #else #define CHECK_STACK() #endif @@ -2110,6 +2113,7 @@ TEBCresume( #endif #ifdef TCL_COMPILE_DEBUG + int starting = 1; traceInstructions = (tclTraceExec == 3); #endif -- cgit v0.12 From b97db66908c73a912c7b14f9502bad2fd6f7971a Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 18 Jan 2013 13:58:32 +0000 Subject: [Bug 3598300]: unix: tcl.h does not include sys/stat.h. (with an exception for OSX, for now) --- ChangeLog | 5 +++++ generic/tclPort.h | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 3cbdd1a..9328946 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-01-18 Jan Nijtmans + + * generic/tclPort.h: [Bug 3598300]: unix: tcl.h does not include + sys/stat.h + 2013-01-16 Jan Nijtmans * Makefile.in: Enable win32 build with -DTCL_NO_DEPRECATED, just diff --git a/generic/tclPort.h b/generic/tclPort.h index 7021b8d..198ee76 100644 --- a/generic/tclPort.h +++ b/generic/tclPort.h @@ -19,9 +19,11 @@ #endif #if defined(_WIN32) # include "tclWinPort.h" +#elif !defined(MAC_OSX_TCL) +# include "tclUnixPort.h" #endif #include "tcl.h" -#if !defined(_WIN32) +#if defined(MAC_OSX_TCL) # include "tclUnixPort.h" #endif -- cgit v0.12 From f50af0e8c33d29a694f03efedfc7bf1ae18b3e16 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 18 Jan 2013 14:30:25 +0000 Subject: ... and fix cygwin build --- unix/tclUnixFile.c | 6 ++++-- unix/tclUnixPort.h | 34 +++++++++++++++------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c index 40434a0..5abac9d 100644 --- a/unix/tclUnixFile.c +++ b/unix/tclUnixFile.c @@ -1183,8 +1183,9 @@ TclpUtime( return utime(Tcl_FSGetNativePath(pathPtr), tval); } #ifdef __CYGWIN__ -int TclOSstat(const char *name, Tcl_StatBuf *statBuf) { +int TclOSstat(const char *name, void *cygstat) { struct stat buf; + Tcl_StatBuf *statBuf = cygstat; int result = stat(name, &buf); statBuf->st_mode = buf.st_mode; statBuf->st_ino = buf.st_ino; @@ -1199,8 +1200,9 @@ int TclOSstat(const char *name, Tcl_StatBuf *statBuf) { statBuf->st_ctime = buf.st_ctime; return result; } -int TclOSlstat(const char *name, Tcl_StatBuf *statBuf) { +int TclOSlstat(const char *name, void *cygstat) { struct stat buf; + Tcl_StatBuf *statBuf = cygstat; int result = lstat(name, &buf); statBuf->st_mode = buf.st_mode; statBuf->st_ino = buf.st_ino; diff --git a/unix/tclUnixPort.h b/unix/tclUnixPort.h index 4668707..99c564b 100644 --- a/unix/tclUnixPort.h +++ b/unix/tclUnixPort.h @@ -22,10 +22,6 @@ #ifndef _TCLUNIXPORT #define _TCLUNIXPORT - -#ifndef MODULE_SCOPE -#define MODULE_SCOPE extern -#endif /* *--------------------------------------------------------------------------- @@ -89,21 +85,21 @@ typedef off_t Tcl_SeekOffset; # define HINSTANCE void * # define SOCKET unsigned int # define WSAEWOULDBLOCK 10035 - DLLIMPORT extern __stdcall int GetModuleHandleExW(unsigned int, const char *, void *); - DLLIMPORT extern __stdcall int GetModuleFileNameW(void *, const char *, int); - DLLIMPORT extern __stdcall int WideCharToMultiByte(int, int, const char *, int, + __declspec(dllimport) extern __stdcall int GetModuleHandleExW(unsigned int, const char *, void *); + __declspec(dllimport) extern __stdcall int GetModuleFileNameW(void *, const char *, int); + __declspec(dllimport) extern __stdcall int WideCharToMultiByte(int, int, const char *, int, const char *, int, const char *, const char *); - DLLIMPORT extern int cygwin_conv_path(int, const void *, void *, int); - DLLIMPORT extern int cygwin_conv_path_list(int, const void *, void *, int); + __declspec(dllimport) extern int cygwin_conv_path(int, const void *, void *, int); + __declspec(dllimport) extern int cygwin_conv_path_list(int, const void *, void *, int); # define USE_PUTENV 1 # define USE_PUTENV_FOR_UNSET 1 /* On Cygwin, the environment is imported from the Cygwin DLL. */ # define environ __cygwin_environ # define timezone _timezone - DLLIMPORT extern char **__cygwin_environ; - MODULE_SCOPE int TclOSstat(const char *name, Tcl_StatBuf *statBuf); - MODULE_SCOPE int TclOSlstat(const char *name, Tcl_StatBuf *statBuf); + extern char **__cygwin_environ; + extern int TclOSstat(const char *name, void *statBuf); + extern int TclOSlstat(const char *name, void *statBuf); #elif defined(HAVE_STRUCT_STAT64) # define TclOSstat stat64 # define TclOSlstat lstat64 @@ -147,7 +143,7 @@ typedef off_t Tcl_SeekOffset; # include "../compat/unistd.h" #endif -MODULE_SCOPE int TclUnixSetBlockingMode(int fd, int mode); +extern int TclUnixSetBlockingMode(int fd, int mode); #include @@ -658,11 +654,11 @@ extern int pthread_getattr_np (pthread_t, pthread_attr_t *); #include -MODULE_SCOPE struct passwd* TclpGetPwNam(const char *name); -MODULE_SCOPE struct group* TclpGetGrNam(const char *name); -MODULE_SCOPE struct passwd* TclpGetPwUid(uid_t uid); -MODULE_SCOPE struct group* TclpGetGrGid(gid_t gid); -MODULE_SCOPE struct hostent* TclpGetHostByName(const char *name); -MODULE_SCOPE struct hostent* TclpGetHostByAddr(const char *addr, int length, int type); +extern struct passwd* TclpGetPwNam(const char *name); +extern struct group* TclpGetGrNam(const char *name); +extern struct passwd* TclpGetPwUid(uid_t uid); +extern struct group* TclpGetGrGid(gid_t gid); +extern struct hostent* TclpGetHostByName(const char *name); +extern struct hostent* TclpGetHostByAddr(const char *addr, int length, int type); #endif /* _TCLUNIXPORT */ -- cgit v0.12 From 62a66095ee80918300cf2d26a7cbecf8fdfab4e1 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 18 Jan 2013 15:07:18 +0000 Subject: Proposed solution for Bug 3598300 on MacOSX --- generic/tcl.h | 3 +-- generic/tclPort.h | 5 +---- unix/tclUnixFCmd.c | 2 +- unix/tclUnixPort.h | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/generic/tcl.h b/generic/tcl.h index 33730d4..5b23694 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -327,7 +327,6 @@ typedef long LONG; # undef TCL_WIDE_INT_IS_LONG # undef TCL_CFG_DO64BIT # endif /* __LP64__ */ -# undef HAVE_STRUCT_STAT64 #endif /* __APPLE__ */ /* @@ -436,7 +435,7 @@ typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt; struct {long tv_sec;} st_ctim; /* Here is a 4-byte gap */ } Tcl_StatBuf; -#elif defined(HAVE_STRUCT_STAT64) +#elif defined(HAVE_STRUCT_STAT64) && !defined(__APPLE__) typedef struct stat64 Tcl_StatBuf; #else typedef struct stat Tcl_StatBuf; diff --git a/generic/tclPort.h b/generic/tclPort.h index 198ee76..12a60db 100644 --- a/generic/tclPort.h +++ b/generic/tclPort.h @@ -19,13 +19,10 @@ #endif #if defined(_WIN32) # include "tclWinPort.h" -#elif !defined(MAC_OSX_TCL) +#else # include "tclUnixPort.h" #endif #include "tcl.h" -#if defined(MAC_OSX_TCL) -# include "tclUnixPort.h" -#endif #if !defined(LLONG_MIN) # ifdef TCL_WIDE_INT_IS_LONG diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index 79f115e..d655990 100644 --- a/unix/tclUnixFCmd.c +++ b/unix/tclUnixFCmd.c @@ -232,7 +232,7 @@ MODULE_SCOPE long tclMacOSXDarwinRelease; #endif /* NO_REALPATH */ #ifdef HAVE_FTS -#ifdef HAVE_STRUCT_STAT64 +#if defined(HAVE_STRUCT_STAT64) && !defined(__APPLE__) /* fts doesn't do stat64 */ #define noFtsStat 1 #elif defined(__APPLE__) && defined(__LP64__) && \ diff --git a/unix/tclUnixPort.h b/unix/tclUnixPort.h index 99c564b..7cfeec0 100644 --- a/unix/tclUnixPort.h +++ b/unix/tclUnixPort.h @@ -100,7 +100,7 @@ typedef off_t Tcl_SeekOffset; extern char **__cygwin_environ; extern int TclOSstat(const char *name, void *statBuf); extern int TclOSlstat(const char *name, void *statBuf); -#elif defined(HAVE_STRUCT_STAT64) +#elif defined(HAVE_STRUCT_STAT64) && !defined(__APPLE__) # define TclOSstat stat64 # define TclOSlstat lstat64 #else -- cgit v0.12 From e0e07babd25d3b621d8ffcc7c2b636aea32876d2 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 21 Jan 2013 13:51:11 +0000 Subject: Put back Tcl[GS]etStartupScript(Path|FileName) in private stub table, so extensions using this (like Tk 8.4) will continue to work in all Tcl 8.x versions. Extensions using this still cannot be compiled against Tcl 8.6 headers. --- ChangeLog | 7 +++++++ generic/tclInt.decls | 32 ++++++++++++++++---------------- generic/tclIntDecls.h | 36 ++++++++++++++++++++++++------------ generic/tclStubInit.c | 33 +++++++++++++++++++++++++++++---- 4 files changed, 76 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index f62d6ea..1532676 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-01-21 Jan Nijtmans + + * generic/tclInt.decls: Put back Tcl[GS]etStartupScript(Path|FileName) + in private stub table, so extensions using this (like Tk 8.4) will + continue to work in all Tcl 8.x versions. Extensions using this + still cannot be compiled against Tcl 8.6 headers. + 2013-01-18 Jan Nijtmans * generic/tclPort.h: [Bug 3598300]: unix: tcl.h does not include diff --git a/generic/tclInt.decls b/generic/tclInt.decls index 58dab42..f0e907f 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -626,14 +626,14 @@ declare 156 { declare 157 { Var *TclVarTraceExists(Tcl_Interp *interp, const char *varName) } -# REMOVED - use public Tcl_SetStartupScript() -#declare 158 { -# void TclSetStartupScriptFileName(const char *filename) -#} -# REMOVED - use public Tcl_GetStartupScript() -#declare 159 { -# const char *TclGetStartupScriptFileName(void) -#} +# REMOVED (except from stub table) - use public Tcl_SetStartupScript() +declare 158 { + void TclSetStartupScriptFileName(const char *filename) +} +# REMOVED (except from stub table) - use public Tcl_GetStartupScript() +declare 159 { + const char *TclGetStartupScriptFileName(void) +} #declare 160 { # int TclpMatchFilesTypes(Tcl_Interp *interp, char *separators, # Tcl_DString *dirPtr, char *pattern, char *tail, @@ -678,14 +678,14 @@ declare 166 { } # VFS-aware versions of Tcl*StartupScriptFileName (158 and 159 above) -# REMOVED - use public Tcl_SetStartupScript() -#declare 167 { -# void TclSetStartupScriptPath(Tcl_Obj *pathPtr) -#} -# REMOVED - use public Tcl_GetStartupScript() -#declare 168 { -# Tcl_Obj *TclGetStartupScriptPath(void) -#} +# REMOVED (except from stub table) - use public Tcl_SetStartupScript() +declare 167 { + void TclSetStartupScriptPath(Tcl_Obj *pathPtr) +} +# REMOVED (except from stub table) - use public Tcl_GetStartupScript() +declare 168 { + Tcl_Obj *TclGetStartupScriptPath(void) +} # variant of Tcl_UtfNCmp that takes n as bytes, not chars declare 169 { int TclpUtfNcmp2(const char *s1, const char *s2, unsigned long n) diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index 092225e..cf88e5f 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -396,8 +396,10 @@ EXTERN void TclRegError(Tcl_Interp *interp, const char *msg, /* 157 */ EXTERN Var * TclVarTraceExists(Tcl_Interp *interp, const char *varName); -/* Slot 158 is reserved */ -/* Slot 159 is reserved */ +/* 158 */ +EXTERN void TclSetStartupScriptFileName(const char *filename); +/* 159 */ +EXTERN const char * TclGetStartupScriptFileName(void); /* Slot 160 is reserved */ /* 161 */ EXTERN int TclChannelTransform(Tcl_Interp *interp, @@ -415,8 +417,10 @@ EXTERN void TclpSetInitialEncodings(void); EXTERN int TclListObjSetElement(Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj *valuePtr); -/* Slot 167 is reserved */ -/* Slot 168 is reserved */ +/* 167 */ +EXTERN void TclSetStartupScriptPath(Tcl_Obj *pathPtr); +/* 168 */ +EXTERN Tcl_Obj * TclGetStartupScriptPath(void); /* 169 */ EXTERN int TclpUtfNcmp2(const char *s1, const char *s2, unsigned long n); @@ -769,8 +773,8 @@ typedef struct TclIntStubs { void (*reserved155)(void); void (*tclRegError) (Tcl_Interp *interp, const char *msg, int status); /* 156 */ Var * (*tclVarTraceExists) (Tcl_Interp *interp, const char *varName); /* 157 */ - void (*reserved158)(void); - void (*reserved159)(void); + void (*tclSetStartupScriptFileName) (const char *filename); /* 158 */ + const char * (*tclGetStartupScriptFileName) (void); /* 159 */ void (*reserved160)(void); int (*tclChannelTransform) (Tcl_Interp *interp, Tcl_Channel chan, Tcl_Obj *cmdObjPtr); /* 161 */ void (*tclChannelEventScriptInvoker) (ClientData clientData, int flags); /* 162 */ @@ -778,8 +782,8 @@ typedef struct TclIntStubs { void (*tclExpandCodeArray) (void *envPtr); /* 164 */ void (*tclpSetInitialEncodings) (void); /* 165 */ int (*tclListObjSetElement) (Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj *valuePtr); /* 166 */ - void (*reserved167)(void); - void (*reserved168)(void); + void (*tclSetStartupScriptPath) (Tcl_Obj *pathPtr); /* 167 */ + Tcl_Obj * (*tclGetStartupScriptPath) (void); /* 168 */ int (*tclpUtfNcmp2) (const char *s1, const char *s2, unsigned long n); /* 169 */ int (*tclCheckInterpTraces) (Tcl_Interp *interp, const char *command, int numChars, Command *cmdPtr, int result, int traceFlags, int objc, Tcl_Obj *const objv[]); /* 170 */ int (*tclCheckExecutionTraces) (Tcl_Interp *interp, const char *command, int numChars, Command *cmdPtr, int result, int traceFlags, int objc, Tcl_Obj *const objv[]); /* 171 */ @@ -1135,8 +1139,10 @@ extern const TclIntStubs *tclIntStubsPtr; (tclIntStubsPtr->tclRegError) /* 156 */ #define TclVarTraceExists \ (tclIntStubsPtr->tclVarTraceExists) /* 157 */ -/* Slot 158 is reserved */ -/* Slot 159 is reserved */ +#define TclSetStartupScriptFileName \ + (tclIntStubsPtr->tclSetStartupScriptFileName) /* 158 */ +#define TclGetStartupScriptFileName \ + (tclIntStubsPtr->tclGetStartupScriptFileName) /* 159 */ /* Slot 160 is reserved */ #define TclChannelTransform \ (tclIntStubsPtr->tclChannelTransform) /* 161 */ @@ -1150,8 +1156,10 @@ extern const TclIntStubs *tclIntStubsPtr; (tclIntStubsPtr->tclpSetInitialEncodings) /* 165 */ #define TclListObjSetElement \ (tclIntStubsPtr->tclListObjSetElement) /* 166 */ -/* Slot 167 is reserved */ -/* Slot 168 is reserved */ +#define TclSetStartupScriptPath \ + (tclIntStubsPtr->tclSetStartupScriptPath) /* 167 */ +#define TclGetStartupScriptPath \ + (tclIntStubsPtr->tclGetStartupScriptPath) /* 168 */ #define TclpUtfNcmp2 \ (tclIntStubsPtr->tclpUtfNcmp2) /* 169 */ #define TclCheckInterpTraces \ @@ -1297,6 +1305,10 @@ extern const TclIntStubs *tclIntStubsPtr; #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT +#undef TclGetStartupScriptFileName +#undef TclSetStartupScriptFileName +#undef TclGetStartupScriptPath +#undef TclSetStartupScriptPath #undef TclBackgroundException #if defined(USE_TCL_STUBS) && defined(TCL_NO_DEPRECATED) diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 1d1fe15..1dbdc09 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -54,6 +54,31 @@ static int TclSockMinimumBuffersOld(int sock, int size) } #endif +#define TclSetStartupScriptPath setStartupScriptPath +static void TclSetStartupScriptPath(Tcl_Obj *path) +{ + Tcl_SetStartupScript(path, NULL); +} +#define TclGetStartupScriptPath getStartupScriptPath +static Tcl_Obj *TclGetStartupScriptPath(void) +{ + return Tcl_GetStartupScript(NULL); +} +#define TclSetStartupScriptFileName setStartupScriptFileName +static void TclSetStartupScriptFileName( + const char *fileName) +{ + Tcl_SetStartupScript(Tcl_NewStringObj(fileName,-1), NULL); +} +#define TclGetStartupScriptFileName getStartupScriptFileName +static const char *TclGetStartupScriptFileName(void) +{ + Tcl_Obj *path = Tcl_GetStartupScript(NULL); + if (path == NULL) { + return NULL; + } + return Tcl_GetStringFromObj(path, NULL); +} #if defined(_WIN32) || defined(__CYGWIN__) #undef TclWinNToHS @@ -348,8 +373,8 @@ static const TclIntStubs tclIntStubs = { 0, /* 155 */ TclRegError, /* 156 */ TclVarTraceExists, /* 157 */ - 0, /* 158 */ - 0, /* 159 */ + TclSetStartupScriptFileName, /* 158 */ + TclGetStartupScriptFileName, /* 159 */ 0, /* 160 */ TclChannelTransform, /* 161 */ TclChannelEventScriptInvoker, /* 162 */ @@ -357,8 +382,8 @@ static const TclIntStubs tclIntStubs = { TclExpandCodeArray, /* 164 */ TclpSetInitialEncodings, /* 165 */ TclListObjSetElement, /* 166 */ - 0, /* 167 */ - 0, /* 168 */ + TclSetStartupScriptPath, /* 167 */ + TclGetStartupScriptPath, /* 168 */ TclpUtfNcmp2, /* 169 */ TclCheckInterpTraces, /* 170 */ TclCheckExecutionTraces, /* 171 */ -- cgit v0.12 From 0389d9d276a16e5f11a8ec823cb2334e4b5d119a Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 22 Jan 2013 08:16:44 +0000 Subject: Fix test-case http-4.14 --- tests/http.test | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/http.test b/tests/http.test index 3a9d4ba..b03df88 100644 --- a/tests/http.test +++ b/tests/http.test @@ -465,8 +465,7 @@ test http-4.14 {http::Event} -body { } http::wait $token http::status $token - # error code varies among platforms. -} -returnCodes 1 -match regexp -result {(connect failed|couldn't open socket)} +} -result {timeout} # Bogus host test http-4.15 {http::Event} -body { # This test may fail if you use a proxy server. That is to be -- cgit v0.12 From 21be09ba34563c7d9fd3b0d013fe643c63f00174 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 22 Jan 2013 21:56:27 +0000 Subject: Bug [3601804]: platformCPUID segmentation fault on Darwin --- unix/tclUnixCompat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/tclUnixCompat.c b/unix/tclUnixCompat.c index 71bd846..1969d1c 100644 --- a/unix/tclUnixCompat.c +++ b/unix/tclUnixCompat.c @@ -698,7 +698,7 @@ TclWinCPUID( "mov %%ebx, %%esi \n\t" /* save what cpuid just put in %ebx */ "mov %%edi, %%ebx \n\t" /* restore the old %ebx */ : "=a"(regsPtr[0]), "=S"(regsPtr[1]), "=c"(regsPtr[2]), "=d"(regsPtr[3]) - : "a"(index) : "edi"); + : "a"(index) : "edi","ebx"); status = TCL_OK; #endif return status; -- cgit v0.12 From ae2b9cd377978ef7018b95e2d16b17042e2eb76b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 22 Jan 2013 22:53:26 +0000 Subject: Now really fix test-case http-4.14 --- tests/http.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/http.test b/tests/http.test index b03df88..3ec0a6f 100644 --- a/tests/http.test +++ b/tests/http.test @@ -464,8 +464,8 @@ test http-4.14 {http::Event} -body { error "bogus return from http::geturl" } http::wait $token - http::status $token -} -result {timeout} + lindex [http::error $token] 0 +} -result {connect failed connection refused} # Bogus host test http-4.15 {http::Event} -body { # This test may fail if you use a proxy server. That is to be -- cgit v0.12 From c58c25ef079a96e684e2be9bdf78040c84c3cf9b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 23 Jan 2013 13:57:30 +0000 Subject: Protect Tcl_GetIndexFromObjStruct from invalid "offset" values, like 0 or -1. Undocumented, because I don't want to promote people start using that. --- generic/tclIndexObj.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index cc50fd3..0103cdb 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.c @@ -144,7 +144,7 @@ Tcl_GetIndexFromObj(interp, objPtr, tablePtr, msg, flags, indexPtr) * returned and an error message is left in interp's result (unless * interp is NULL). The msg argument is used in the error * message; for example, if msg has the value "option" then the - * error message will say something flag 'bad option "foo": must be + * error message will say something like 'bad option "foo": must be * ...' * * Side effects: @@ -176,6 +176,10 @@ Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, Tcl_Obj *resultPtr; IndexRep *indexRep; + /* Protect against invalid values, like -1 or 0. */ + if (offset < (int)sizeof(char *)) { + offset = (int)sizeof(char *); + } /* * See if there is a valid cached result from a previous lookup. */ -- cgit v0.12 From 94605ca2706bce3bfe127eb4168ca135fd02b609 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 24 Jan 2013 18:47:18 +0000 Subject: Silence some compiler warnings. --- generic/tclCkalloc.c | 4 ++++ generic/tclExecute.c | 3 +++ generic/tclFileName.c | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/generic/tclCkalloc.c b/generic/tclCkalloc.c index a9d98ec..6de9720 100644 --- a/generic/tclCkalloc.c +++ b/generic/tclCkalloc.c @@ -149,6 +149,10 @@ TclInitDbCkalloc() if (!ckallocInit) { ckallocInit = 1; ckallocMutexPtr = Tcl_GetAllocMutex(); +#ifndef TCL_THREADS + /* Silence compiler warning */ + (void)ckallocMutexPtr; +#endif } } diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 2a9f8bb..c09b73e 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -5118,6 +5118,9 @@ VerifyExprObjType(interp, objPtr) long i; Tcl_WideInt w; GET_WIDE_OR_INT(result, objPtr, i, w); + /* Quiet cranky old compilers that complain about + * setting i, but not using it. */ + (void)i; } else { double d; result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, objPtr, &d); diff --git a/generic/tclFileName.c b/generic/tclFileName.c index 046eaef..bcaadd4 100644 --- a/generic/tclFileName.c +++ b/generic/tclFileName.c @@ -1784,13 +1784,17 @@ TclDoGlob(interp, separators, headPtr, tail, types) int baseLength, quoted, count; int result = TCL_OK; char *name, *p, *openBrace, *closeBrace, *firstSpecialChar, savedChar; + /* char lastChar = 0; + */ int length = Tcl_DStringLength(headPtr); + /* if (length > 0) { lastChar = Tcl_DStringValue(headPtr)[length-1]; } + */ /* * Consume any leading directory separators, leaving tail pointing -- cgit v0.12 From 8d7d6d8cfd4c9f0670d5c20f115e9a69364f3cef Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 24 Jan 2013 21:28:43 +0000 Subject: revert [273bbe926d]: it doesn't work on i386 --- unix/tclUnixCompat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/tclUnixCompat.c b/unix/tclUnixCompat.c index 1969d1c..71bd846 100644 --- a/unix/tclUnixCompat.c +++ b/unix/tclUnixCompat.c @@ -698,7 +698,7 @@ TclWinCPUID( "mov %%ebx, %%esi \n\t" /* save what cpuid just put in %ebx */ "mov %%edi, %%ebx \n\t" /* restore the old %ebx */ : "=a"(regsPtr[0]), "=S"(regsPtr[1]), "=c"(regsPtr[2]), "=d"(regsPtr[3]) - : "a"(index) : "edi","ebx"); + : "a"(index) : "edi"); status = TCL_OK; #endif return status; -- cgit v0.12 From 2ad8238512c29b86039ba28d5e489ffd77069793 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 24 Jan 2013 22:00:50 +0000 Subject: new version of cpuid, which doesn't use the edi register any more. Hopefully that works better on some Darwin. --- unix/tclUnixCompat.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/unix/tclUnixCompat.c b/unix/tclUnixCompat.c index 71bd846..5a3ccd4 100644 --- a/unix/tclUnixCompat.c +++ b/unix/tclUnixCompat.c @@ -693,12 +693,11 @@ TclWinCPUID( /* See: */ #if defined(HAVE_CPUID) - __asm__ __volatile__("mov %%ebx, %%edi \n\t" /* save %ebx */ + __asm__ __volatile__("mov %%ebx, %%esi \n\t" /* save %ebx */ "cpuid \n\t" - "mov %%ebx, %%esi \n\t" /* save what cpuid just put in %ebx */ - "mov %%edi, %%ebx \n\t" /* restore the old %ebx */ + "xchg %%esi, %%ebx \n\t" /* restore the old %ebx */ : "=a"(regsPtr[0]), "=S"(regsPtr[1]), "=c"(regsPtr[2]), "=d"(regsPtr[3]) - : "a"(index) : "edi"); + : "a"(index)); status = TCL_OK; #endif return status; -- cgit v0.12 From 1a19e1f67d4039692837657d71be3d35b40a9662 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 25 Jan 2013 11:48:29 +0000 Subject: Eliminate some unneeded usages of Tcl_SetResult, Tcl_AddObjErrorInfo Fix "make test-packages" on cygwin --- generic/tclAssembly.c | 9 ++++----- generic/tclEnsemble.c | 2 +- generic/tclExecute.c | 4 ++-- generic/tclOO.c | 2 +- generic/tclResult.c | 2 +- generic/tclThreadTest.c | 2 +- generic/tclTrace.c | 2 +- generic/tclVar.c | 4 ++-- unix/Makefile.in | 2 +- unix/tclUnixTest.c | 10 +++++----- win/tclWinTest.c | 2 +- 11 files changed, 20 insertions(+), 21 deletions(-) diff --git a/generic/tclAssembly.c b/generic/tclAssembly.c index 7833105..99bdf43 100644 --- a/generic/tclAssembly.c +++ b/generic/tclAssembly.c @@ -798,12 +798,11 @@ TclNRAssembleObjCmd( if (codePtr == NULL) { Tcl_AddErrorInfo(interp, "\n (\""); - Tcl_AddErrorInfo(interp, Tcl_GetString(objv[0])); + Tcl_AppendObjToErrorInfo(interp, objv[0]); Tcl_AddErrorInfo(interp, "\" body, line "); backtrace = Tcl_NewIntObj(Tcl_GetErrorLine(interp)); Tcl_IncrRefCount(backtrace); - Tcl_AddErrorInfo(interp, Tcl_GetString(backtrace)); - Tcl_DecrRefCount(backtrace); + Tcl_AppendObjToErrorInfo(interp, backtrace); Tcl_AddErrorInfo(interp, ")"); return TCL_ERROR; } @@ -4270,11 +4269,11 @@ AddBasicBlockRangeToErrorInfo( Tcl_AddErrorInfo(interp, "\n in assembly code between lines "); lineNo = Tcl_NewIntObj(bbPtr->startLine); Tcl_IncrRefCount(lineNo); - Tcl_AddErrorInfo(interp, Tcl_GetString(lineNo)); + Tcl_AppendObjToErrorInfo(interp, lineNo); Tcl_AddErrorInfo(interp, " and "); if (bbPtr->successor1 != NULL) { Tcl_SetIntObj(lineNo, bbPtr->successor1->startLine); - Tcl_AddErrorInfo(interp, Tcl_GetString(lineNo)); + Tcl_AppendObjToErrorInfo(interp, lineNo); } else { Tcl_AddErrorInfo(interp, "end of assembly code"); } diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 88de9f3..f392cad 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -2196,7 +2196,7 @@ EnsembleUnknownCallback( } Tcl_AddErrorInfo(interp, "\n result of " "ensemble unknown subcommand handler: "); - Tcl_AddErrorInfo(interp, TclGetString(unknownCmd)); + Tcl_AppendObjToErrorInfo(interp, unknownCmd); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "UNKNOWN_RESULT", NULL); } else { diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 978d026..c2cef2a 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -3464,8 +3464,8 @@ TEBCresume( varPtr = TclObjLookupVarEx(interp, objPtr, part2Ptr, TCL_LEAVE_ERR_MSG, "read", 1, 1, &arrayPtr); if (!varPtr) { - Tcl_AddObjErrorInfo(interp, - "\n (reading value of variable to increment)", -1); + Tcl_AddErrorInfo(interp, + "\n (reading value of variable to increment)"); TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); Tcl_DecrRefCount(incrPtr); goto gotError; diff --git a/generic/tclOO.c b/generic/tclOO.c index d6d2d6a..cb22de6 100644 --- a/generic/tclOO.c +++ b/generic/tclOO.c @@ -843,7 +843,7 @@ ObjectRenamedTrace( result = Tcl_NRCallObjProc(interp, TclOOInvokeContext, contextPtr, 0, NULL); if (result != TCL_OK) { - Tcl_BackgroundError(interp); + Tcl_BackgroundException(interp, result); } Tcl_RestoreInterpState(interp, state); TclOODeleteContext(contextPtr); diff --git a/generic/tclResult.c b/generic/tclResult.c index 9707f20..07f6819 100644 --- a/generic/tclResult.c +++ b/generic/tclResult.c @@ -1587,7 +1587,7 @@ Tcl_GetReturnOptions( } if (result == TCL_ERROR) { - Tcl_AddObjErrorInfo(interp, "", -1); + Tcl_AddErrorInfo(interp, ""); Tcl_DictObjPut(NULL, options, keys[KEY_ERRORSTACK], iPtr->errorStack); } if (iPtr->errorCode) { diff --git a/generic/tclThreadTest.c b/generic/tclThreadTest.c index b90e33d..1115ff0 100644 --- a/generic/tclThreadTest.c +++ b/generic/tclThreadTest.c @@ -926,7 +926,7 @@ ThreadSend( ckfree(resultPtr->errorInfo); } } - Tcl_SetResult(interp, resultPtr->result, TCL_DYNAMIC); + Tcl_AppendResult(interp, resultPtr->result, NULL); Tcl_ConditionFinalize(&resultPtr->done); code = resultPtr->code; diff --git a/generic/tclTrace.c b/generic/tclTrace.c index 519f201..0f297a4 100644 --- a/generic/tclTrace.c +++ b/generic/tclTrace.c @@ -1322,7 +1322,7 @@ TraceCommandProc( Tcl_DStringLength(&cmd), 0); if (code != TCL_OK) { /* We ignore errors in these traced commands */ - /*** QUESTION: Use Tcl_BackgroundError(interp); instead? ***/ + /*** QUESTION: Use Tcl_BackgroundException(interp, code); instead? ***/ } Tcl_DStringFree(&cmd); } diff --git a/generic/tclVar.c b/generic/tclVar.c index 9b8527c..2d1479d 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -2036,8 +2036,8 @@ TclIncrObjVar2( varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, flags, "read", 1, 1, &arrayPtr); if (varPtr == NULL) { - Tcl_AddObjErrorInfo(interp, - "\n (reading value of variable to increment)", -1); + Tcl_AddErrorInfo(interp, + "\n (reading value of variable to increment)"); return NULL; } return TclPtrIncrObjVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, diff --git a/unix/Makefile.in b/unix/Makefile.in index ee31282..f8dd67c 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -1718,7 +1718,7 @@ install-packages: packages fi; \ done -test-packages: tcltest packages +test-packages: ${TCLTEST_EXE} packages @for i in $(PKGS_DIR)/*; do \ if [ -d $$i ]; then \ pkg=`basename $$i`; \ diff --git a/unix/tclUnixTest.c b/unix/tclUnixTest.c index 46fc972..c10225d 100644 --- a/unix/tclUnixTest.c +++ b/unix/tclUnixTest.c @@ -200,7 +200,7 @@ TestfilehandlerCmd( return TCL_ERROR; } sprintf(buf, "%d %d", pipePtr->readCount, pipePtr->writeCount); - Tcl_SetResult(interp, buf, TCL_VOLATILE); + Tcl_AppendResult(interp, buf, NULL); } else if (strcmp(argv[1], "create") == 0) { if (argc != 5) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", @@ -217,8 +217,8 @@ TestfilehandlerCmd( fcntl(GetFd(pipePtr->readFile), F_SETFL, O_NONBLOCK); fcntl(GetFd(pipePtr->writeFile), F_SETFL, O_NONBLOCK); #else - Tcl_SetResult(interp, "can't make pipes non-blocking", - TCL_STATIC); + Tcl_AppendResult(interp, "can't make pipes non-blocking", + NULL); return TCL_ERROR; #endif } @@ -281,7 +281,7 @@ TestfilehandlerCmd( memset(buffer, 'b', 10); TclFormatInt(buf, write(GetFd(pipePtr->writeFile), buffer, 10)); - Tcl_SetResult(interp, buf, TCL_VOLATILE); + Tcl_AppendResult(interp, buf, NULL); } else if (strcmp(argv[1], "oneevent") == 0) { Tcl_DoOneEvent(TCL_FILE_EVENTS|TCL_DONT_WAIT); } else if (strcmp(argv[1], "wait") == 0) { @@ -390,7 +390,7 @@ TestfilewaitCmd( if (Tcl_GetChannelHandle(channel, (mask & TCL_READABLE) ? TCL_READABLE : TCL_WRITABLE, (ClientData*) &data) != TCL_OK) { - Tcl_SetResult(interp, "couldn't get channel file", TCL_STATIC); + Tcl_AppendResult(interp, "couldn't get channel file", NULL); return TCL_ERROR; } fd = PTR2INT(data); diff --git a/win/tclWinTest.c b/win/tclWinTest.c index 136c4db..b83c0ba 100644 --- a/win/tclWinTest.c +++ b/win/tclWinTest.c @@ -211,7 +211,7 @@ TestvolumetypeCmd( TclWinConvertError(GetLastError()); return TCL_ERROR; } - Tcl_SetResult(interp, volType, TCL_VOLATILE); + Tcl_AppendResult(interp, volType, NULL); return TCL_OK; #undef VOL_BUF_SIZE } -- cgit v0.12 From 328fa692fbd773527e3f656e71f312717a9daed9 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 25 Jan 2013 11:53:41 +0000 Subject: fix minor memory leak --- generic/tclAssembly.c | 1 - 1 file changed, 1 deletion(-) diff --git a/generic/tclAssembly.c b/generic/tclAssembly.c index 99bdf43..c4eeded 100644 --- a/generic/tclAssembly.c +++ b/generic/tclAssembly.c @@ -801,7 +801,6 @@ TclNRAssembleObjCmd( Tcl_AppendObjToErrorInfo(interp, objv[0]); Tcl_AddErrorInfo(interp, "\" body, line "); backtrace = Tcl_NewIntObj(Tcl_GetErrorLine(interp)); - Tcl_IncrRefCount(backtrace); Tcl_AppendObjToErrorInfo(interp, backtrace); Tcl_AddErrorInfo(interp, ")"); return TCL_ERROR; -- cgit v0.12 From 3cf091e2d8b739ba3dfaabe7e178b28abe80e00e Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 25 Jan 2013 13:07:59 +0000 Subject: Another memory leak, and one Tcl_Free -> ckfree --- generic/tclThreadTest.c | 1 + unix/tclUnixTime.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/generic/tclThreadTest.c b/generic/tclThreadTest.c index 1115ff0..8708f9a 100644 --- a/generic/tclThreadTest.c +++ b/generic/tclThreadTest.c @@ -930,6 +930,7 @@ ThreadSend( Tcl_ConditionFinalize(&resultPtr->done); code = resultPtr->code; + ckfree(resultPtr->result); ckfree(resultPtr); return code; diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c index c7921fe..926e8f4 100644 --- a/unix/tclUnixTime.c +++ b/unix/tclUnixTime.c @@ -503,7 +503,7 @@ SetTZIfNecessary(void) if (lastTZ == NULL) { Tcl_CreateExitHandler(CleanupMemory, NULL); } else { - Tcl_Free(lastTZ); + ckfree(lastTZ); } lastTZ = ckalloc(strlen(newTZ) + 1); strcpy(lastTZ, newTZ); -- cgit v0.12 From b1e276db9c365ef451ad9d795468ea5daad0e5a0 Mon Sep 17 00:00:00 2001 From: mig Date: Fri, 25 Jan 2013 18:47:45 +0000 Subject: remove unused code --- generic/tclBasic.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 6c53547..4d5b715 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -4181,9 +4181,6 @@ TclNREvalObjv( } cmdPtrPtr = (Command **) &(callbackPtr->data[0]); - callbackPtr->data[2] = INT2PTR(objc); - callbackPtr->data[3] = (ClientData) objv; - iPtr->numLevels++; result = TclInterpReady(interp); -- cgit v0.12 From 16fde830643c564edad1860bb44ba4a943fe2873 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sat, 26 Jan 2013 16:50:22 +0000 Subject: [Bug 3601804]: platformCPUID segmentation fault on Darwin --- ChangeLog | 5 +++++ unix/tclUnixCompat.c | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2ee5bbe..941edb0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-01-26 Jan Nijtmans + + * unix/tclUnixCompat.c: [Bug 3601804]: platformCPUID segmentation + fault on Darwin. + 2013-01-16 Jan Nijtmans * Makefile.in: Enable win32 build with -DTCL_NO_DEPRECATED, just diff --git a/unix/tclUnixCompat.c b/unix/tclUnixCompat.c index 5a3ccd4..4ca7da9 100644 --- a/unix/tclUnixCompat.c +++ b/unix/tclUnixCompat.c @@ -693,11 +693,19 @@ TclWinCPUID( /* See: */ #if defined(HAVE_CPUID) +#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) + __asm__ __volatile__("movq %%rbx, %%rsi \n\t" /* save %rbx */ + "cpuid \n\t" + "xchgq %%rsi, %%rbx \n\t" /* restore the old %rbx */ + : "=a"(regsPtr[0]), "=S"(regsPtr[1]), "=c"(regsPtr[2]), "=d"(regsPtr[3]) + : "a"(index)); +#else __asm__ __volatile__("mov %%ebx, %%esi \n\t" /* save %ebx */ "cpuid \n\t" "xchg %%esi, %%ebx \n\t" /* restore the old %ebx */ : "=a"(regsPtr[0]), "=S"(regsPtr[1]), "=c"(regsPtr[2]), "=d"(regsPtr[3]) : "a"(index)); +#endif status = TCL_OK; #endif return status; -- cgit v0.12 From 2f6c7fe7a30a6a9a76b3f6da23c7df3829062523 Mon Sep 17 00:00:00 2001 From: dkf Date: Mon, 28 Jan 2013 01:27:32 +0000 Subject: Slightly better compilation of some [array] cases. --- generic/tclCompCmds.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 503f339..0a66f1c 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -304,10 +304,10 @@ TclCompileArraySetCmd( } PushVarNameWord(interp, tokenPtr, envPtr, TCL_NO_ELEMENT, &localIndex, &simpleVarName, &isScalar, 1); + tokenPtr = TokenAfter(tokenPtr); if (!isScalar) { return TCL_ERROR; } - tokenPtr = TokenAfter(tokenPtr); /* * Special case: literal empty value argument is just an "ensure array" @@ -333,13 +333,33 @@ TclCompileArraySetCmd( return TCL_OK; } + if (envPtr->procPtr == NULL) { + /* + * Right number of arguments, but not compilable as we can't allocate + * (unnamed) local variables to manage the internal iteration. + */ + + Tcl_Obj *objPtr = Tcl_NewObj(); + char *bytes; + int length, cmdLit; + + Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr); + bytes = Tcl_GetStringFromObj(objPtr, &length); + cmdLit = TclRegisterNewCmdLiteral(envPtr, bytes, length); + TclSetCmdNameObj(interp, envPtr->literalArrayPtr[cmdLit].objPtr, + cmdPtr); + TclEmitPush(cmdLit, envPtr); + TclDecrRefCount(objPtr); + TclEmitInstInt4(INST_REVERSE, 2, envPtr); + CompileWord(envPtr, tokenPtr, interp, 2); + TclEmitInstInt1(INST_INVOKE_STK1, 3, envPtr); + return TCL_OK; + } + /* * Prepare for the internal foreach. */ - if (envPtr->procPtr == NULL) { - return TCL_ERROR; - } dataVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); iterVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); keyVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); @@ -442,7 +462,7 @@ TclCompileArrayUnsetCmd( int simpleVarName, isScalar, localIndex, savedStackDepth; if (parsePtr->numWords != 2) { - return TCL_ERROR; + return TclCompileBasic2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } PushVarNameWord(interp, tokenPtr, envPtr, TCL_NO_ELEMENT, -- cgit v0.12 From e566dc080bf933404305587e4290769e7e620460 Mon Sep 17 00:00:00 2001 From: dkf Date: Mon, 28 Jan 2013 11:43:59 +0000 Subject: More extensive use of the techniques to improve other edge cases in ensemble compilation. --- doc/namespace.n | 2 +- doc/string.n | 4 +-- generic/tclCompCmds.c | 78 +++++++++++++++++++++++-------------------------- generic/tclCompCmdsSZ.c | 10 +++---- 4 files changed, 45 insertions(+), 49 deletions(-) diff --git a/doc/namespace.n b/doc/namespace.n index b06d27a..f2812b2 100644 --- a/doc/namespace.n +++ b/doc/namespace.n @@ -287,7 +287,7 @@ This command is the complement of the \fBnamespace qualifiers\fR command. It does not check whether the namespace names are, in fact, the names of currently defined namespaces. .TP -\fBnamespace upvar\fR \fInamespace\fR ?\fIotherVar myVar \fR... +\fBnamespace upvar\fR \fInamespace\fR ?\fIotherVar myVar \fR...? . This command arranges for zero or more local variables in the current procedure to refer to variables in \fInamespace\fR. The namespace name is diff --git a/doc/string.n b/doc/string.n index f5eae39..351c865 100644 --- a/doc/string.n +++ b/doc/string.n @@ -19,7 +19,7 @@ string \- Manipulate strings Performs one of several string operations, depending on \fIoption\fR. The legal \fIoption\fRs (which may be abbreviated) are: .TP -\fBstring compare\fR ?\fB\-nocase\fR? ?\fB\-length int\fR? \fIstring1 string2\fR +\fBstring compare\fR ?\fB\-nocase\fR? ?\fB\-length\fI length\fR? \fIstring1 string2\fR . Perform a character-by-character comparison of strings \fIstring1\fR and \fIstring2\fR. Returns \-1, 0, or 1, depending on whether @@ -29,7 +29,7 @@ first \fIlength\fR characters are used in the comparison. If \fB\-length\fR is negative, it is ignored. If \fB\-nocase\fR is specified, then the strings are compared in a case-insensitive manner. .TP -\fBstring equal\fR ?\fB\-nocase\fR? ?\fB\-length int\fR? \fIstring1 string2\fR +\fBstring equal\fR ?\fB\-nocase\fR? ?\fB\-length\fI length\fR? \fIstring1 string2\fR . Perform a character-by-character comparison of strings \fIstring1\fR and \fIstring2\fR. Returns 1 if \fIstring1\fR and \fIstring2\fR are diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 0a66f1c..389c1ee 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -295,13 +295,6 @@ TclCompileArraySetCmd( } tokenPtr = TokenAfter(parsePtr->tokenPtr); - if (envPtr->procPtr == NULL) { - Tcl_Token *tokPtr = TokenAfter(tokenPtr); - - if (tokPtr->type != TCL_TOKEN_SIMPLE_WORD || tokPtr[1].size != 0) { - return TCL_ERROR; - } - } PushVarNameWord(interp, tokenPtr, envPtr, TCL_NO_ELEMENT, &localIndex, &simpleVarName, &isScalar, 1); tokenPtr = TokenAfter(tokenPtr); @@ -956,7 +949,7 @@ TclCompileDictIncrCmd( incrTokenPtr = TokenAfter(keyTokenPtr); if (incrTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; + return TclCompileBasic2Or3ArgCmd(interp, parsePtr,cmdPtr, envPtr); } word = incrTokenPtr[1].start; numBytes = incrTokenPtr[1].size; @@ -966,7 +959,7 @@ TclCompileDictIncrCmd( code = TclGetIntFromObj(NULL, intObj, &incrAmount); TclDecrRefCount(intObj); if (code != TCL_OK) { - return TCL_ERROR; + return TclCompileBasic2Or3ArgCmd(interp, parsePtr,cmdPtr, envPtr); } } else { incrAmount = 1; @@ -979,16 +972,16 @@ TclCompileDictIncrCmd( */ if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; + return TclCompileBasic2Or3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } name = varTokenPtr[1].start; nameChars = varTokenPtr[1].size; if (!TclIsLocalScalar(name, nameChars)) { - return TCL_ERROR; + return TclCompileBasic2Or3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr); if (dictVarIndex < 0) { - return TCL_ERROR; + return TclCompileBasic2Or3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } /* @@ -1106,16 +1099,16 @@ TclCompileDictUnsetCmd( tokenPtr = TokenAfter(parsePtr->tokenPtr); if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } name = tokenPtr[1].start; nameChars = tokenPtr[1].size; if (!TclIsLocalScalar(name, nameChars)) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr); if (dictVarIndex < 0) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } /* @@ -1206,7 +1199,7 @@ TclCompileDictCreateCmd( nonConstant: worker = TclFindCompiledLocal(NULL, 0, 1, envPtr); if (worker < 0) { - return TCL_ERROR; + return TclCompileBasicMin0ArgCmd(interp, parsePtr, cmdPtr, envPtr); } PushLiteral(envPtr, "", 0); @@ -1267,7 +1260,7 @@ TclCompileDictMergeCmd( workerIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr); if (workerIndex < 0) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } infoIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr); @@ -1393,11 +1386,11 @@ CompileDictEachCmd( Tcl_DString buffer; /* - * There must be at least three argument after the command. + * There must be three arguments after the command. */ if (parsePtr->numWords != 4) { - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } varsTokenPtr = TokenAfter(parsePtr->tokenPtr); @@ -1405,7 +1398,7 @@ CompileDictEachCmd( bodyTokenPtr = TokenAfter(dictTokenPtr); if (varsTokenPtr->type != TCL_TOKEN_SIMPLE_WORD || bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } /* @@ -1417,7 +1410,7 @@ CompileDictEachCmd( collectVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1, envPtr); if (collectVar < 0) { - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } } @@ -1431,31 +1424,31 @@ CompileDictEachCmd( if (Tcl_SplitList(NULL, Tcl_DStringValue(&buffer), &numVars, &argv) != TCL_OK) { Tcl_DStringFree(&buffer); - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } Tcl_DStringFree(&buffer); if (numVars != 2) { ckfree(argv); - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } nameChars = strlen(argv[0]); if (!TclIsLocalScalar(argv[0], nameChars)) { ckfree(argv); - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } keyVarIndex = TclFindCompiledLocal(argv[0], nameChars, 1, envPtr); nameChars = strlen(argv[1]); if (!TclIsLocalScalar(argv[1], nameChars)) { ckfree(argv); - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } valueVarIndex = TclFindCompiledLocal(argv[1], nameChars, 1, envPtr); ckfree(argv); if ((keyVarIndex < 0) || (valueVarIndex < 0)) { - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } /* @@ -1467,7 +1460,7 @@ CompileDictEachCmd( infoIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr); if (infoIndex < 0) { - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } /* @@ -1664,16 +1657,16 @@ TclCompileDictUpdateCmd( dictVarTokenPtr = TokenAfter(parsePtr->tokenPtr); if (dictVarTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } name = dictVarTokenPtr[1].start; nameChars = dictVarTokenPtr[1].size; if (!TclIsLocalScalar(name, nameChars)) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } dictIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr); if (dictIndex < 0) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } /* @@ -1724,7 +1717,7 @@ TclCompileDictUpdateCmd( failedUpdateInfoAssembly: ckfree(duiPtr); TclStackFree(interp, keyTokenPtrs); - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } bodyTokenPtr = tokenPtr; @@ -1822,17 +1815,17 @@ TclCompileDictAppendCmd( tokenPtr = TokenAfter(parsePtr->tokenPtr); if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } else { register const char *name = tokenPtr[1].start; register int nameChars = tokenPtr[1].size; if (!TclIsLocalScalar(name, nameChars)) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr,cmdPtr, envPtr); } dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr); if (dictVarIndex < 0) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr,cmdPtr, envPtr); } } @@ -1883,16 +1876,16 @@ TclCompileDictLappendCmd( keyTokenPtr = TokenAfter(varTokenPtr); valueTokenPtr = TokenAfter(keyTokenPtr); if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } name = varTokenPtr[1].start; nameChars = varTokenPtr[1].size; if (!TclIsLocalScalar(name, nameChars)) { - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr); if (dictVarIndex < 0) { - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } CompileWord(envPtr, keyTokenPtr, interp, 3); CompileWord(envPtr, valueTokenPtr, interp, 4); @@ -1936,7 +1929,7 @@ TclCompileDictWithCmd( tokenPtr = TokenAfter(tokenPtr); } if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } /* @@ -1948,7 +1941,8 @@ TclCompileDictWithCmd( for (ptr=tokenPtr[1].start,end=ptr+tokenPtr[1].size ; ptr!=end ; ptr++) { if (*ptr!=' ' && *ptr!='\t' && *ptr!='\n' && *ptr!='\r') { if (envPtr->procPtr == NULL) { - return TCL_ERROR; + return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, + envPtr); } bodyIsEmpty = 0; break; @@ -3775,7 +3769,9 @@ TclCompileInfoCommandsCmd( * We require one compile-time known argument for the case we can compile. */ - if (parsePtr->numWords != 2) { + if (parsePtr->numWords == 1) { + return TclCompileBasic0ArgCmd(interp, parsePtr, cmdPtr, envPtr); + } else if (parsePtr->numWords != 2) { return TCL_ERROR; } tokenPtr = TokenAfter(parsePtr->tokenPtr); @@ -3812,7 +3808,7 @@ TclCompileInfoCommandsCmd( notCompilable: Tcl_DecrRefCount(objPtr); - return TCL_ERROR; + return TclCompileBasic1ArgCmd(interp, parsePtr, cmdPtr, envPtr); } int diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c index 6e31481..f73beca 100644 --- a/generic/tclCompCmdsSZ.c +++ b/generic/tclCompCmdsSZ.c @@ -448,7 +448,7 @@ TclCompileStringMatchCmd( if (parsePtr->numWords == 4) { if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } str = tokenPtr[1].start; length = tokenPtr[1].size; @@ -457,7 +457,7 @@ TclCompileStringMatchCmd( * Fail at run time, not in compilation. */ - return TCL_ERROR; + return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr); } nocase = 1; tokenPtr = TokenAfter(tokenPtr); @@ -578,13 +578,13 @@ TclCompileStringMapCmd( Tcl_IncrRefCount(mapObj); if (!TclWordKnownAtCompileTime(mapTokenPtr, mapObj)) { Tcl_DecrRefCount(mapObj); - return TCL_ERROR; + return TclCompileBasic2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } else if (Tcl_ListObjGetElements(NULL, mapObj, &len, &objv) != TCL_OK) { Tcl_DecrRefCount(mapObj); - return TCL_ERROR; + return TclCompileBasic2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } else if (len != 2) { Tcl_DecrRefCount(mapObj); - return TCL_ERROR; + return TclCompileBasic2ArgCmd(interp, parsePtr, cmdPtr, envPtr); } /* -- cgit v0.12 From 75972077579a3e9bf1363e817260d11f17d60266 Mon Sep 17 00:00:00 2001 From: mig Date: Tue, 29 Jan 2013 09:24:44 +0000 Subject: Remove one trampoline bounce in EvalObjv. --- generic/tclBasic.c | 29 ++++++----------------------- generic/tclExecute.c | 1 + 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 4d5b715..c8cfb49 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -135,7 +135,6 @@ static Tcl_NRPostProc NRCoroutineCallerCallback; static Tcl_NRPostProc NRCoroutineExitCallback; static int NRCommand(ClientData data[], Tcl_Interp *interp, int result); -static Tcl_NRPostProc NRRunObjProc; static Tcl_ObjCmdProc OldMathFuncProc; static void OldMathFuncDeleteProc(ClientData clientData); static void ProcessUnexpectedResult(Tcl_Interp *interp, @@ -4293,14 +4292,11 @@ TclNREvalObjv( cmdPtr->refCount++; /* - * Find the objProc to call: nreProc if available, objProc otherwise. Push - * a callback to do the actual running. + * Find the objProc to call: nreProc if available, objProc otherwise. */ if (cmdPtr->nreProc) { - TclNRAddCallback(interp, NRRunObjProc, cmdPtr, - INT2PTR(objc), (ClientData) objv, NULL); - return TCL_OK; + return cmdPtr->nreProc(cmdPtr->objClientData, interp, objc, objv); } else { return cmdPtr->objProc(cmdPtr->objClientData, interp, objc, objv); } @@ -4382,22 +4378,6 @@ NRCommand( return result; } - -static int -NRRunObjProc( - ClientData data[], - Tcl_Interp *interp, - int result) -{ - /* OPT: do not call? */ - - Command* cmdPtr = data[0]; - int objc = PTR2INT(data[1]); - Tcl_Obj **objv = data[2]; - - return cmdPtr->nreProc(cmdPtr->objClientData, interp, objc, objv); -} - /* *---------------------------------------------------------------------- @@ -9007,7 +8987,6 @@ TclNRCoroutineObjCmd( corPtr->running.varFramePtr = iPtr->rootFramePtr; corPtr->running.cmdFramePtr = NULL; corPtr->running.lineLABCPtr = corPtr->lineLABCPtr; - corPtr->stackLevel = NULL; corPtr->auxNumLevels = 0; /* @@ -9027,11 +9006,15 @@ TclNRCoroutineObjCmd( TclNRAddCallback(interp, NRCoroutineExitCallback, corPtr, NULL, NULL, NULL); + /* Mark the coro as 'not suspended' while scheduling the command */ + corPtr->stackLevel = INT2PTR(1); + /* insure that the command is looked up in the correct namespace */ iPtr->lookupNsPtr = lookupNsPtr; Tcl_NREvalObj(interp, Tcl_NewListObj(objc-2, objv+2), 0); iPtr->numLevels--; + corPtr->stackLevel = NULL; SAVE_CONTEXT(corPtr->running); RESTORE_CONTEXT(corPtr->caller); iPtr->execEnvPtr = corPtr->callerEEPtr; diff --git a/generic/tclExecute.c b/generic/tclExecute.c index c2cef2a..7d4f47a 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2393,6 +2393,7 @@ TEBCresume( NULL); goto gotError; } + NRE_ASSERT(!COR_IS_SUSPENDED(corPtr)); #ifdef TCL_COMPILE_DEBUG TRACE_WITH_OBJ(("yield, result="), iPtr->objResultPtr); -- cgit v0.12