Tcl Source Code

Check-in [a8711ad508]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:merge trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tip-400-impl
Files: files | file ages | folders
SHA1: a8711ad50898c39334260e97f1069a830b3c1c34
User & Date: dkf 2012-04-10 08:13:40
Context
2012-04-11
07:16
towards dictionary setting on transforms check-in: 584e69e4d2 user: dkf tags: tip-400-impl
2012-04-10
08:13
merge trunk check-in: a8711ad508 user: dkf tags: tip-400-impl
07:29
Argument parsing update check-in: a853fd68ae user: dkf tags: tip-400-impl
2012-04-09
21:38
Fix [Bug 3396896] check-in: 8c8cfe9c98 user: dkf tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.












1
2
3
4
5
6
7











2012-04-04  Donal K. Fellows  <[email protected]>

	* generic/tclOO.c (Tcl_NewObjectInstance, TclNRNewObjectInstance):
	[Bug 3514761]: Fixed bogosity with automated argument description
	handling when constructing an instance of a class that is itself a
	member of an ensemble. Thanks to Andreas Kupries for identifying that
	this was a problem case at all!
>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2012-04-09  Donal K. Fellows  <[email protected]>

	* 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  <[email protected]>

	* generic/tclOO.c (Tcl_NewObjectInstance, TclNRNewObjectInstance):
	[Bug 3514761]: Fixed bogosity with automated argument description
	handling when constructing an instance of a class that is itself a
	member of an ensemble. Thanks to Andreas Kupries for identifying that
	this was a problem case at all!

Changes to generic/tcl.decls.

770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
}
declare 216 {
    void Tcl_Release(ClientData clientData)
}
declare 217 {
    void Tcl_ResetResult(Tcl_Interp *interp)
}
declare 218 generic {
    int Tcl_ScanElement(const char *src, int *flagPtr)
}
declare 219 generic {
    int Tcl_ScanCountedElement(const char *src, int length, int *flagPtr)
}
# Obsolete
declare 220 {
    int Tcl_SeekOld(Tcl_Channel chan, int offset, int mode)
}
declare 221 {







|


|







770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
}
declare 216 {
    void Tcl_Release(ClientData clientData)
}
declare 217 {
    void Tcl_ResetResult(Tcl_Interp *interp)
}
declare 218 {
    int Tcl_ScanElement(const char *src, int *flagPtr)
}
declare 219 {
    int Tcl_ScanCountedElement(const char *src, int length, int *flagPtr)
}
# Obsolete
declare 220 {
    int Tcl_SeekOld(Tcl_Channel chan, int offset, int mode)
}
declare 221 {

Changes to generic/tclEnv.c.

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
static char *		EnvTraceProc(ClientData clientData, Tcl_Interp *interp,
			    const char *name1, const char *name2, int flags);
static void		ReplaceString(const char *oldStr, char *newStr);
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);
#endif

/*
 *----------------------------------------------------------------------
 *
 * TclSetupEnv --
 *







<
|
<
|
<







41
42
43
44
45
46
47

48

49

50
51
52
53
54
55
56
static char *		EnvTraceProc(ClientData clientData, Tcl_Interp *interp,
			    const char *name1, const char *name2, int flags);
static void		ReplaceString(const char *oldStr, char *newStr);
MODULE_SCOPE void	TclSetEnv(const char *name, const char *value);
MODULE_SCOPE void	TclUnsetEnv(const char *name);

#if defined(__CYGWIN__)

    static void TclCygwinPutenv(char *string);

#   define putenv TclCygwinPutenv

#endif

/*
 *----------------------------------------------------------------------
 *
 * TclSetupEnv --
 *
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
    if (strcmp(name, "PATH") != 0) {
	/*
	 * If this is Path, eliminate any PATH variable, to prevent any
	 * confusion.
	 */

	if (strcmp(name, "Path") == 0) {
#ifdef __WIN32__
	    SetEnvironmentVariableA("PATH", NULL);
#endif
	    unsetenv("PATH");
	}

#ifdef __WIN32__
	SetEnvironmentVariableA(name, value);
#endif
    } else {
	char *buf;

	/*
	 * Eliminate any Path variable, to prevent any confusion.
	 */

#ifdef __WIN32__
	SetEnvironmentVariableA("Path", NULL);
#endif
	unsetenv("Path");

	if (value == NULL) {
	    buf = NULL;
	} else {
	    int size;

	    size = cygwin_posix_to_win32_path_list_buf_size(value);
	    buf = alloca(size + 1);
	    cygwin_posix_to_win32_path_list(value, buf);
	}

#ifdef __WIN32__
	SetEnvironmentVariableA(name, buf);
#endif
    }
}
#endif /* __CYGWIN__ */

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







<

<



<

<







<

<












<

<











747
748
749
750
751
752
753

754

755
756
757

758

759
760
761
762
763
764
765

766

767
768
769
770
771
772
773
774
775
776
777
778

779

780
781
782
783
784
785
786
787
788
789
790
    if (strcmp(name, "PATH") != 0) {
	/*
	 * If this is Path, eliminate any PATH variable, to prevent any
	 * confusion.
	 */

	if (strcmp(name, "Path") == 0) {

	    SetEnvironmentVariableA("PATH", NULL);

	    unsetenv("PATH");
	}


	SetEnvironmentVariableA(name, value);

    } else {
	char *buf;

	/*
	 * Eliminate any Path variable, to prevent any confusion.
	 */


	SetEnvironmentVariableA("Path", NULL);

	unsetenv("Path");

	if (value == NULL) {
	    buf = NULL;
	} else {
	    int size;

	    size = cygwin_posix_to_win32_path_list_buf_size(value);
	    buf = alloca(size + 1);
	    cygwin_posix_to_win32_path_list(value, buf);
	}


	SetEnvironmentVariableA(name, buf);

    }
}
#endif /* __CYGWIN__ */

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to generic/tclOO.c.

1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
    Tcl_Interp *interp,
    int result)
{
    CallContext *contextPtr = data[0];
    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
     * if it isn't already an error (don't want to lose errors by accident...)
     * [Bug 2903011]
     */








<







1776
1777
1778
1779
1780
1781
1782

1783
1784
1785
1786
1787
1788
1789
    Tcl_Interp *interp,
    int result)
{
    CallContext *contextPtr = data[0];
    Object *oPtr = data[1];
    Tcl_InterpState state = data[2];
    Tcl_Object *objectPtr = data[3];


    /*
     * It's an error if the object was whacked in the constructor. Force this
     * if it isn't already an error (don't want to lose errors by accident...)
     * [Bug 2903011]
     */

Changes to generic/tclOODefineCmds.c.

2302
2303
2304
2305
2306
2307
2308


2309







2310





2311



2312
2313




2314
2315
2316
2317
2318
2319
2320
		    ckrealloc((char *) oPtr->classPtr->variables.list,
		    sizeof(Tcl_Obj *) * varc);
	} else {
	    oPtr->classPtr->variables.list = (Tcl_Obj **)
		    ckalloc(sizeof(Tcl_Obj *) * varc);
	}
    }


    if (varc > 0) {







	memcpy(oPtr->classPtr->variables.list, varv,





		sizeof(Tcl_Obj *) * varc);



    }
    oPtr->classPtr->variables.num = varc;




    return TCL_OK;
}

/*
 * ----------------------------------------------------------------------
 *
 * ObjectFilterGet, ObjectFilterSet --







>
>

>
>
>
>
>
>
>
|
>
>
>
>
>
|
>
>
>
|
|
>
>
>
>







2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
		    ckrealloc((char *) oPtr->classPtr->variables.list,
		    sizeof(Tcl_Obj *) * varc);
	} else {
	    oPtr->classPtr->variables.list = (Tcl_Obj **)
		    ckalloc(sizeof(Tcl_Obj *) * varc);
	}
    }

    oPtr->classPtr->variables.num = 0;
    if (varc > 0) {
	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);
    }
    return TCL_OK;
}

/*
 * ----------------------------------------------------------------------
 *
 * ObjectFilterGet, ObjectFilterSet --
2559
2560
2561
2562
2563
2564
2565

2566







2567


2568

2569










2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
		    ckrealloc((char *) oPtr->variables.list,
		    sizeof(Tcl_Obj *) * varc);
	} else {
	    oPtr->variables.list = (Tcl_Obj **)
		    ckalloc(sizeof(Tcl_Obj *) * varc);
	}
    }

    if (varc > 0) {







	memcpy(oPtr->variables.list, varv, sizeof(Tcl_Obj *)*varc);


    }

    oPtr->variables.num = varc;










    return TCL_OK;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







>

>
>
>
>
>
>
>
|
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>










2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
		    ckrealloc((char *) oPtr->variables.list,
		    sizeof(Tcl_Obj *) * varc);
	} else {
	    oPtr->variables.list = (Tcl_Obj **)
		    ckalloc(sizeof(Tcl_Obj *) * varc);
	}
    }
    oPtr->variables.num = 0;
    if (varc > 0) {
	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);
    }
    return TCL_OK;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to generic/tclPort.h.

25
26
27
28
29
30
31


32
33
34
35


36
37
38
39
40
41
42
#   include "tclUnixPort.h"
#endif

#if defined(__CYGWIN__)
#   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


#endif

#if !defined(LLONG_MIN)
#   ifdef TCL_WIDE_INT_IS_LONG
#      define LLONG_MIN LONG_MIN
#   else
#      ifdef LLONG_BIT







>
>


|
<
>
>







25
26
27
28
29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
44
45
#   include "tclUnixPort.h"
#endif

#if defined(__CYGWIN__)
#   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;
    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)
#   ifdef TCL_WIDE_INT_IS_LONG
#      define LLONG_MIN LONG_MIN
#   else
#      ifdef LLONG_BIT

Changes to generic/tclVar.c.

14
15
16
17
18
19
20

21
22
23
24
25
26
27
 * Copyright (c) 2007 Miguel Sofer
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tclInt.h"


/*
 * Prototypes for the variable hash key methods.
 */

static Tcl_HashEntry *	AllocVarEntry(Tcl_HashTable *tablePtr, void *keyPtr);
static void		FreeVarEntry(Tcl_HashEntry *hPtr);







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 * Copyright (c) 2007 Miguel Sofer
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tclInt.h"
#include "tclOOInt.h"

/*
 * Prototypes for the variable hash key methods.
 */

static Tcl_HashEntry *	AllocVarEntry(Tcl_HashTable *tablePtr, void *keyPtr);
static void		FreeVarEntry(Tcl_HashEntry *hPtr);
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
			    }
			}
		    }
		    varPtr = VarHashNextVar(&search);
		}
	    }
	}
    } else if (((Interp *)interp)->varFramePtr->procPtr != NULL) {
	AppendLocals(interp, listPtr, simplePatternPtr, 1);
    }

    if (simplePatternPtr) {
	Tcl_DecrRefCount(simplePatternPtr);
    }
    Tcl_SetObjResult(interp, listPtr);







|







6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
			    }
			}
		    }
		    varPtr = VarHashNextVar(&search);
		}
	    }
	}
    } else if (iPtr->varFramePtr->procPtr != NULL) {
	AppendLocals(interp, listPtr, simplePatternPtr, 1);
    }

    if (simplePatternPtr) {
	Tcl_DecrRefCount(simplePatternPtr);
    }
    Tcl_SetObjResult(interp, listPtr);
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276

6277
6278
6279
6280
6281
6282



6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293



6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317



6318
6319
6320


6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335


6336
6337
6338






























6339
6340
6341
6342
6343
6344
6345
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Obj *listPtr,		/* List object to append names to. */
    Tcl_Obj *patternPtr,	/* Pattern to match against. */
    int includeLinks)		/* 1 if upvars should be included, else 0. */
{
    Interp *iPtr = (Interp *) interp;
    Var *varPtr;
    int i, localVarCt;
    Tcl_Obj **varNamePtr, *objNamePtr;
    const char *varName;
    TclVarHashTable *localVarTablePtr;
    Tcl_HashSearch search;

    const char *pattern = patternPtr? TclGetString(patternPtr) : NULL;

    localVarCt = iPtr->varFramePtr->numCompiledLocals;
    varPtr = iPtr->varFramePtr->compiledLocals;
    localVarTablePtr = iPtr->varFramePtr->varTablePtr;
    varNamePtr = &iPtr->varFramePtr->localCachePtr->varName0;




    for (i = 0; i < localVarCt; i++, varNamePtr++) {
	/*
	 * Skip nameless (temporary) variables and undefined variables.
	 */

	if (*varNamePtr && !TclIsVarUndefined(varPtr)
		&& (includeLinks || !TclIsVarLink(varPtr))) {
	    varName = TclGetString(*varNamePtr);
	    if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) {
		Tcl_ListObjAppendElement(interp, listPtr, *varNamePtr);



	    }
	}
	varPtr++;
    }

    /*
     * Do nothing if no local variables.
     */

    if (localVarTablePtr == NULL) {
	return;
    }

    /*
     * Check for the simple and fast case.
     */

    if ((pattern != NULL) && TclMatchIsTrivial(pattern)) {
	varPtr = VarHashFindVar(localVarTablePtr, patternPtr);
	if (varPtr != NULL) {
	    if (!TclIsVarUndefined(varPtr)
		    && (includeLinks || !TclIsVarLink(varPtr))) {
		Tcl_ListObjAppendElement(interp, listPtr,
			VarHashGetKey(varPtr));



	    }
	}
	return;


    }

    /*
     * Scan over and process all local variables.
     */

    for (varPtr = VarHashFirstVar(localVarTablePtr, &search);
	    varPtr != NULL;
	    varPtr = VarHashNextVar(&search)) {
	if (!TclIsVarUndefined(varPtr)
		&& (includeLinks || !TclIsVarLink(varPtr))) {
	    objNamePtr = VarHashGetKey(varPtr);
	    varName = TclGetString(objNamePtr);
	    if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) {
		Tcl_ListObjAppendElement(interp, listPtr, objNamePtr);


	    }
	}
    }






























}

/*
 * Hash table implementation - first, just copy and adapt the obj key stuff
 */

void







|




>






>
>
>











>
>
>










|













>
>
>
|
|
<
>
>















>
>
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330

6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Obj *listPtr,		/* List object to append names to. */
    Tcl_Obj *patternPtr,	/* Pattern to match against. */
    int includeLinks)		/* 1 if upvars should be included, else 0. */
{
    Interp *iPtr = (Interp *) interp;
    Var *varPtr;
    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++) {
	/*
	 * Skip nameless (temporary) variables and undefined variables.
	 */

	if (*varNamePtr && !TclIsVarUndefined(varPtr)
		&& (includeLinks || !TclIsVarLink(varPtr))) {
	    varName = TclGetString(*varNamePtr);
	    if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) {
		Tcl_ListObjAppendElement(interp, listPtr, *varNamePtr);
		if (includeLinks) {
		    Tcl_CreateHashEntry(&addedTable, *varNamePtr, &added);
		}
	    }
	}
	varPtr++;
    }

    /*
     * Do nothing if no local variables.
     */

    if (localVarTablePtr == NULL) {
	goto objectVars;
    }

    /*
     * Check for the simple and fast case.
     */

    if ((pattern != NULL) && TclMatchIsTrivial(pattern)) {
	varPtr = VarHashFindVar(localVarTablePtr, patternPtr);
	if (varPtr != NULL) {
	    if (!TclIsVarUndefined(varPtr)
		    && (includeLinks || !TclIsVarLink(varPtr))) {
		Tcl_ListObjAppendElement(interp, listPtr,
			VarHashGetKey(varPtr));
		if (includeLinks) {
		    Tcl_CreateHashEntry(&addedTable, VarHashGetKey(varPtr),
			    &added);
		}
	    }

	}
	goto objectVars;
    }

    /*
     * Scan over and process all local variables.
     */

    for (varPtr = VarHashFirstVar(localVarTablePtr, &search);
	    varPtr != NULL;
	    varPtr = VarHashNextVar(&search)) {
	if (!TclIsVarUndefined(varPtr)
		&& (includeLinks || !TclIsVarLink(varPtr))) {
	    objNamePtr = VarHashGetKey(varPtr);
	    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);
}

/*
 * Hash table implementation - first, just copy and adapt the obj key stuff
 */

void

Changes to tests/oo.test.

2942
2943
2944
2945
2946
2947
2948






















































































2949
2950
2951
2952
2953
2954
2955
	method boo {} {
	    return [incr x],[incr y]
	}
    }
    foo create bar
    list [bar boo] [bar boo]
} -returnCodes error -match glob -result {unknown method "-?": must be *}























































































# A feature that's not supported because the mechanism may change without
# warning, but is supposed to work...
test oo-28.1 {scripted extensions to oo::define} -setup {
    interp create foo
    foo eval {oo::class create cls {export eval}}
} -cleanup {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
	method boo {} {
	    return [incr x],[incr y]
	}
    }
    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...
test oo-28.1 {scripted extensions to oo::define} -setup {
    interp create foo
    foo eval {oo::class create cls {export eval}}
} -cleanup {