diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2012-04-10 08:13:40 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2012-04-10 08:13:40 (GMT) |
commit | 656f3951340642cf7d3ce37e1e9b1aa7141784e9 (patch) | |
tree | cc5369ca591b2a5961da9383f070b4a1a185ed18 | |
parent | 67d714cab480480fb736bb1a1c6fa30f9b2d845c (diff) | |
parent | ba795792d6185008b4de5f9c0463f26fa2ddab0a (diff) | |
download | tcl-656f3951340642cf7d3ce37e1e9b1aa7141784e9.zip tcl-656f3951340642cf7d3ce37e1e9b1aa7141784e9.tar.gz tcl-656f3951340642cf7d3ce37e1e9b1aa7141784e9.tar.bz2 |
merge trunk
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | generic/tcl.decls | 4 | ||||
-rw-r--r-- | generic/tclEnv.c | 15 | ||||
-rw-r--r-- | generic/tclOO.c | 1 | ||||
-rw-r--r-- | generic/tclOODefineCmds.c | 52 | ||||
-rw-r--r-- | generic/tclPort.h | 7 | ||||
-rw-r--r-- | generic/tclVar.c | 52 | ||||
-rw-r--r-- | tests/oo.test | 86 |
8 files changed, 201 insertions, 27 deletions
@@ -1,3 +1,14 @@ +2012-04-09 Donal K. Fellows <dkf@users.sf.net> + + * generic/tclOODefineCmds.c (ClassVarsSet, ObjVarsSet): [Bug 3396896]: + Ensure that the lists of variable names used to drive variable + resolution will never have the same name twice. + + * generic/tclVar.c (AppendLocals): [Bug 2712377]: Fix problem with + reporting of declared variables in methods. It's really a problem with + how [info vars] interacts with variable resolvers; this is just a bit + of a hack so it is no longer a big problem. + 2012-04-04 Donal K. Fellows <dkf@users.sf.net> * generic/tclOO.c (Tcl_NewObjectInstance, TclNRNewObjectInstance): diff --git a/generic/tcl.decls b/generic/tcl.decls index c6cbe96..afeae51 100644 --- a/generic/tcl.decls +++ b/generic/tcl.decls @@ -774,10 +774,10 @@ declare 216 { declare 217 { void Tcl_ResetResult(Tcl_Interp *interp) } -declare 218 generic { +declare 218 { int Tcl_ScanElement(const char *src, int *flagPtr) } -declare 219 generic { +declare 219 { int Tcl_ScanCountedElement(const char *src, int length, int *flagPtr) } # Obsolete diff --git a/generic/tclEnv.c b/generic/tclEnv.c index 980a785..72d6fba 100644 --- a/generic/tclEnv.c +++ b/generic/tclEnv.c @@ -45,11 +45,8 @@ MODULE_SCOPE void TclSetEnv(const char *name, const char *value); MODULE_SCOPE void TclUnsetEnv(const char *name); #if defined(__CYGWIN__) -/* On Cygwin, the environment is imported from the Cygwin DLL. */ - DLLIMPORT extern int cygwin_posix_to_win32_path_list_buf_size(char *value); - DLLIMPORT extern void cygwin_posix_to_win32_path_list(char *buf, char *value); -# define putenv TclCygwinPutenv -static void TclCygwinPutenv(char *string); + static void TclCygwinPutenv(char *string); +# define putenv TclCygwinPutenv #endif /* @@ -754,15 +751,11 @@ TclCygwinPutenv( */ if (strcmp(name, "Path") == 0) { -#ifdef __WIN32__ SetEnvironmentVariableA("PATH", NULL); -#endif unsetenv("PATH"); } -#ifdef __WIN32__ SetEnvironmentVariableA(name, value); -#endif } else { char *buf; @@ -770,9 +763,7 @@ TclCygwinPutenv( * Eliminate any Path variable, to prevent any confusion. */ -#ifdef __WIN32__ SetEnvironmentVariableA("Path", NULL); -#endif unsetenv("Path"); if (value == NULL) { @@ -785,9 +776,7 @@ TclCygwinPutenv( cygwin_posix_to_win32_path_list(value, buf); } -#ifdef __WIN32__ SetEnvironmentVariableA(name, buf); -#endif } } #endif /* __CYGWIN__ */ diff --git a/generic/tclOO.c b/generic/tclOO.c index 1d1276d..d5cc6e1 100644 --- a/generic/tclOO.c +++ b/generic/tclOO.c @@ -1780,7 +1780,6 @@ FinalizeAlloc( Object *oPtr = data[1]; Tcl_InterpState state = data[2]; Tcl_Object *objectPtr = data[3]; - //int flags = oPtr->flags; /* * It's an error if the object was whacked in the constructor. Force this diff --git a/generic/tclOODefineCmds.c b/generic/tclOODefineCmds.c index 926966b..3d72690 100644 --- a/generic/tclOODefineCmds.c +++ b/generic/tclOODefineCmds.c @@ -2306,11 +2306,32 @@ ClassVarsSet( ckalloc(sizeof(Tcl_Obj *) * varc); } } + + oPtr->classPtr->variables.num = 0; if (varc > 0) { - memcpy(oPtr->classPtr->variables.list, varv, - sizeof(Tcl_Obj *) * varc); + int created, n; + Tcl_HashTable uniqueTable; + + Tcl_InitObjHashTable(&uniqueTable); + for (i=n=0 ; i<varc ; i++) { + Tcl_CreateHashEntry(&uniqueTable, varv[i], &created); + if (created) { + oPtr->classPtr->variables.list[n++] = varv[i]; + } else { + Tcl_DecrRefCount(varv[i]); + } + } + oPtr->classPtr->variables.num = n; + + /* + * Shouldn't be necessary, but maintain num/list invariant. + */ + + oPtr->classPtr->variables.list = (Tcl_Obj **) + ckrealloc((char *) oPtr->classPtr->variables.list, + sizeof(Tcl_Obj *) * n); + Tcl_DeleteHashTable(&uniqueTable); } - oPtr->classPtr->variables.num = varc; return TCL_OK; } @@ -2563,10 +2584,31 @@ ObjVarsSet( ckalloc(sizeof(Tcl_Obj *) * varc); } } + oPtr->variables.num = 0; if (varc > 0) { - memcpy(oPtr->variables.list, varv, sizeof(Tcl_Obj *)*varc); + int created, n; + Tcl_HashTable uniqueTable; + + Tcl_InitObjHashTable(&uniqueTable); + for (i=n=0 ; i<varc ; i++) { + Tcl_CreateHashEntry(&uniqueTable, varv[i], &created); + if (created) { + oPtr->variables.list[n++] = varv[i]; + } else { + Tcl_DecrRefCount(varv[i]); + } + } + oPtr->variables.num = n; + + /* + * Shouldn't be necessary, but maintain num/list invariant. + */ + + oPtr->variables.list = (Tcl_Obj **) + ckrealloc((char *) oPtr->variables.list, + sizeof(Tcl_Obj *) * n); + Tcl_DeleteHashTable(&uniqueTable); } - oPtr->variables.num = varc; return TCL_OK; } diff --git a/generic/tclPort.h b/generic/tclPort.h index 23c6191..79bea88 100644 --- a/generic/tclPort.h +++ b/generic/tclPort.h @@ -29,10 +29,13 @@ # define USE_PUTENV 1 # define USE_PUTENV_FOR_UNSET 1 /* On Cygwin, the environment is imported from the Cygwin DLL. */ - DLLIMPORT extern char **__cygwin_environ; - DLLIMPORT extern int cygwin_conv_to_win32_path(const char *, char *); # define environ __cygwin_environ # define timezone _timezone + DLLIMPORT extern char **__cygwin_environ; + DLLIMPORT extern int cygwin_conv_to_win32_path(const char *, char *); + DLLIMPORT extern int cygwin_posix_to_win32_path_list_buf_size(char *value); + DLLIMPORT extern void cygwin_posix_to_win32_path_list(char *buf, char *value); + DLLIMPORT extern void __stdcall SetEnvironmentVariableA(const char*, const char *); #endif #if !defined(LLONG_MIN) diff --git a/generic/tclVar.c b/generic/tclVar.c index 1bf4abc..e92dc5f 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -18,6 +18,7 @@ */ #include "tclInt.h" +#include "tclOOInt.h" /* * Prototypes for the variable hash key methods. @@ -6083,7 +6084,7 @@ TclInfoVarsCmd( } } } - } else if (((Interp *)interp)->varFramePtr->procPtr != NULL) { + } else if (iPtr->varFramePtr->procPtr != NULL) { AppendLocals(interp, listPtr, simplePatternPtr, 1); } @@ -6269,17 +6270,21 @@ AppendLocals( { Interp *iPtr = (Interp *) interp; Var *varPtr; - int i, localVarCt; + int i, localVarCt, added; Tcl_Obj **varNamePtr, *objNamePtr; const char *varName; TclVarHashTable *localVarTablePtr; Tcl_HashSearch search; + Tcl_HashTable addedTable; const char *pattern = patternPtr? TclGetString(patternPtr) : NULL; localVarCt = iPtr->varFramePtr->numCompiledLocals; varPtr = iPtr->varFramePtr->compiledLocals; localVarTablePtr = iPtr->varFramePtr->varTablePtr; varNamePtr = &iPtr->varFramePtr->localCachePtr->varName0; + if (includeLinks) { + Tcl_InitObjHashTable(&addedTable); + } for (i = 0; i < localVarCt; i++, varNamePtr++) { /* @@ -6291,6 +6296,9 @@ AppendLocals( varName = TclGetString(*varNamePtr); if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { Tcl_ListObjAppendElement(interp, listPtr, *varNamePtr); + if (includeLinks) { + Tcl_CreateHashEntry(&addedTable, *varNamePtr, &added); + } } } varPtr++; @@ -6301,7 +6309,7 @@ AppendLocals( */ if (localVarTablePtr == NULL) { - return; + goto objectVars; } /* @@ -6315,9 +6323,13 @@ AppendLocals( && (includeLinks || !TclIsVarLink(varPtr))) { Tcl_ListObjAppendElement(interp, listPtr, VarHashGetKey(varPtr)); + if (includeLinks) { + Tcl_CreateHashEntry(&addedTable, VarHashGetKey(varPtr), + &added); + } } } - return; + goto objectVars; } /* @@ -6333,9 +6345,41 @@ AppendLocals( varName = TclGetString(objNamePtr); if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { Tcl_ListObjAppendElement(interp, listPtr, objNamePtr); + if (includeLinks) { + Tcl_CreateHashEntry(&addedTable, objNamePtr, &added); + } + } + } + } + + objectVars: + if (!includeLinks) { + return; + } + + if (iPtr->varFramePtr->isProcCallFrame & FRAME_IS_METHOD) { + CallContext *contextPtr = iPtr->varFramePtr->clientData; + Method *mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr; + + if (mPtr->declaringObjectPtr) { + FOREACH(objNamePtr, mPtr->declaringObjectPtr->variables) { + Tcl_CreateHashEntry(&addedTable, objNamePtr, &added); + if (added && (!pattern || + Tcl_StringMatch(TclGetString(objNamePtr), pattern))) { + Tcl_ListObjAppendElement(interp, listPtr, objNamePtr); + } + } + } else { + FOREACH(objNamePtr, mPtr->declaringClassPtr->variables) { + Tcl_CreateHashEntry(&addedTable, objNamePtr, &added); + if (added && (!pattern || + Tcl_StringMatch(TclGetString(objNamePtr), pattern))) { + Tcl_ListObjAppendElement(interp, listPtr, objNamePtr); + } } } } + Tcl_DeleteHashTable(&addedTable); } /* diff --git a/tests/oo.test b/tests/oo.test index 8c5aeb3..f3c0bda 100644 --- a/tests/oo.test +++ b/tests/oo.test @@ -2946,6 +2946,92 @@ test oo-27.18 {variables declaration - multiple use} -setup { foo create bar list [bar boo] [bar boo] } -returnCodes error -match glob -result {unknown method "-?": must be *} +test oo-27.19 {variables declaration and [info vars]: Bug 2712377} -setup { + oo::class create Foo + set result {} +} -body { + # This is really a test of problems to do with Tcl's introspection when a + # variable resolver is present... + oo::define Foo { + variable foo bar + method setvars {f b} { + set foo $f + set bar $b + } + method dump1 {} { + lappend ::result <1> + foreach v [lsort [info vars *]] { + lappend ::result $v=[set $v] + } + lappend ::result [info locals] [info locals *] + } + method dump2 {} { + lappend ::result <2> + foreach v [lsort [info vars *]] { + lappend ::result $v=[set $v] + } + lappend ::result | foo=$foo [info locals] [info locals *] + } + } + Foo create stuff + stuff setvars what ever + stuff dump1 + stuff dump2 + return $result +} -cleanup { + Foo destroy +} -result {<1> bar=ever foo=what v v <2> bar=ever foo=what | foo=what v v} +test oo-27.20 {variables declaration and [info vars]: Bug 2712377} -setup { + oo::class create Foo + set result {} +} -body { + # This is really a test of problems to do with Tcl's introspection when a + # variable resolver is present... + oo::define Foo { + variable foo bar + method setvars {f b} { + set foo $f + set bar $b + } + method dump1 {} { + lappend ::result <1> + foreach v [lsort [info vars *o]] { + lappend ::result $v=[set $v] + } + lappend ::result [info locals] [info locals *] + } + method dump2 {} { + lappend ::result <2> + foreach v [lsort [info vars *o]] { + lappend ::result $v=[set $v] + } + lappend ::result | foo=$foo [info locals] [info locals *] + } + } + Foo create stuff + stuff setvars what ever + stuff dump1 + stuff dump2 + return $result +} -cleanup { + Foo destroy +} -result {<1> foo=what v v <2> foo=what | foo=what v v} +test oo-27.21 {variables declaration uniqueifies: Bug 3396896} -setup { + oo::class create Foo +} -body { + oo::define Foo variable v v v t t v t + info class variable Foo +} -cleanup { + Foo destroy +} -result {v t} +test oo-27.22 {variables declaration uniqueifies: Bug 3396896} -setup { + oo::object create foo +} -body { + oo::objdefine foo variable v v v t t v t + info object variable foo +} -cleanup { + foo destroy +} -result {v t} # A feature that's not supported because the mechanism may change without # warning, but is supposed to work... |