Tcl Source Code

Check-in [7c305a2ec0]
Login

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

Overview
Comment:Forward jumps, mostly tests, some code. Plus 1428, 1118.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | activestate-nre-excised-variant-1-roll-forward
Files: files | file ages | folders
SHA1: 7c305a2ec0039a799a3af168e3ad3762bb0c370f
User & Date: andreask 2010-12-01 12:27:23.000
Context
2010-12-01
13:39
@864 + jumps check-in: 0dbcc4b3c6 user: andreask tags: activestate-nre-excised-variant-1-roll-forward
12:27
Forward jumps, mostly tests, some code. Plus 1428, 1118. check-in: 7c305a2ec0 user: andreask tags: activestate-nre-excised-variant-1-roll-forward
2010-11-30
16:27
More tests jumping. check-in: 0748568581 user: andreask tags: activestate-nre-excised-variant-1-roll-forward
Changes
Unified Diff Ignore Whitespace Patch
Changes to generic/tclInt.decls.
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
declare 40 generic {
    int TclGetOpenMode(Tcl_Interp *interp, const char *str, int *seekFlagPtr)
}
declare 41 generic {
    Tcl_Command TclGetOriginalCommand(Tcl_Command command)
}
declare 42 generic {
    char *TclpGetUserHome(const char *name, Tcl_DString *bufferPtr)
}
# Removed in Tcl 8.5a2
#declare 43 generic {
#    int TclGlobalInvoke(Tcl_Interp *interp, int argc, const char **argv,
#	    int flags)
#}
declare 44 generic {







|







182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
declare 40 generic {
    int TclGetOpenMode(Tcl_Interp *interp, const char *str, int *seekFlagPtr)
}
declare 41 generic {
    Tcl_Command TclGetOriginalCommand(Tcl_Command command)
}
declare 42 generic {
    CONST86 char *TclpGetUserHome(const char *name, Tcl_DString *bufferPtr)
}
# Removed in Tcl 8.5a2
#declare 43 generic {
#    int TclGlobalInvoke(Tcl_Interp *interp, int argc, const char **argv,
#	    int flags)
#}
declare 44 generic {
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
#}
# Removed in 8.4b2:
#declare 100 generic {
#    Tcl_Obj *TclSetIndexedScalar(Tcl_Interp *interp, int localIndex,
#	    Tcl_Obj *objPtr, int flags)
#}
declare 101 generic {
    char *TclSetPreInitScript(char *string)
}
declare 102 generic {
    void TclSetupEnv(Tcl_Interp *interp)
}
declare 103 generic {
    int TclSockGetPort(Tcl_Interp *interp, const char *str, const char *proto,
	    int *portPtr)







|







408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
#}
# Removed in 8.4b2:
#declare 100 generic {
#    Tcl_Obj *TclSetIndexedScalar(Tcl_Interp *interp, int localIndex,
#	    Tcl_Obj *objPtr, int flags)
#}
declare 101 generic {
    CONST86 char *TclSetPreInitScript(const char *string)
}
declare 102 generic {
    void TclSetupEnv(Tcl_Interp *interp)
}
declare 103 generic {
    int TclSockGetPort(Tcl_Interp *interp, const char *str, const char *proto,
	    int *portPtr)
Changes to generic/tclInt.h.
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
#ifndef TCL_NO_STACK_CHECK
MODULE_SCOPE int        TclpGetCStackParams(int **stackBoundPtr);
#endif
MODULE_SCOPE int	TclpObjLstat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf);
MODULE_SCOPE Tcl_Obj *	TclpTempFileName(void);
MODULE_SCOPE Tcl_Obj *	TclNewFSPathObj(Tcl_Obj *dirPtr, const char *addStrRep,
			    int len);
MODULE_SCOPE int	TclpDeleteFile(const char *path);
MODULE_SCOPE void	TclpFinalizeCondition(Tcl_Condition *condPtr);
MODULE_SCOPE void	TclpFinalizeMutex(Tcl_Mutex *mutexPtr);
MODULE_SCOPE void	TclpFinalizePipes(void);
MODULE_SCOPE void	TclpFinalizeSockets(void);
MODULE_SCOPE int	TclpThreadCreate(Tcl_ThreadId *idPtr,
			    Tcl_ThreadCreateProc proc, ClientData clientData,
			    int stackSize, int flags);







|







2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
#ifndef TCL_NO_STACK_CHECK
MODULE_SCOPE int        TclpGetCStackParams(int **stackBoundPtr);
#endif
MODULE_SCOPE int	TclpObjLstat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf);
MODULE_SCOPE Tcl_Obj *	TclpTempFileName(void);
MODULE_SCOPE Tcl_Obj *	TclNewFSPathObj(Tcl_Obj *dirPtr, const char *addStrRep,
			    int len);
MODULE_SCOPE int	TclpDeleteFile(const void *path);
MODULE_SCOPE void	TclpFinalizeCondition(Tcl_Condition *condPtr);
MODULE_SCOPE void	TclpFinalizeMutex(Tcl_Mutex *mutexPtr);
MODULE_SCOPE void	TclpFinalizePipes(void);
MODULE_SCOPE void	TclpFinalizeSockets(void);
MODULE_SCOPE int	TclpThreadCreate(Tcl_ThreadId *idPtr,
			    Tcl_ThreadCreateProc proc, ClientData clientData,
			    int stackSize, int flags);
Changes to generic/tclIntDecls.h.
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
EXTERN TclObjCmdProcType TclGetObjInterpProc(void);
/* 40 */
EXTERN int		TclGetOpenMode(Tcl_Interp *interp, const char *str,
				int *seekFlagPtr);
/* 41 */
EXTERN Tcl_Command	TclGetOriginalCommand(Tcl_Command command);
/* 42 */
EXTERN char *		TclpGetUserHome(const char *name,
				Tcl_DString *bufferPtr);
/* Slot 43 is reserved */
/* 44 */
EXTERN int		TclGuessPackageName(const char *fileName,
				Tcl_DString *bufPtr);
/* 45 */
EXTERN int		TclHideUnsafeCommands(Tcl_Interp *interp);







|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
EXTERN TclObjCmdProcType TclGetObjInterpProc(void);
/* 40 */
EXTERN int		TclGetOpenMode(Tcl_Interp *interp, const char *str,
				int *seekFlagPtr);
/* 41 */
EXTERN Tcl_Command	TclGetOriginalCommand(Tcl_Command command);
/* 42 */
EXTERN CONST86 char *	TclpGetUserHome(const char *name,
				Tcl_DString *bufferPtr);
/* Slot 43 is reserved */
/* 44 */
EXTERN int		TclGuessPackageName(const char *fileName,
				Tcl_DString *bufPtr);
/* 45 */
EXTERN int		TclHideUnsafeCommands(Tcl_Interp *interp);
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
EXTERN void		TclResetShadowedCmdRefs(Tcl_Interp *interp,
				Command *newCmdPtr);
/* 98 */
EXTERN int		TclServiceIdle(void);
/* Slot 99 is reserved */
/* Slot 100 is reserved */
/* 101 */
EXTERN char *		TclSetPreInitScript(char *string);
/* 102 */
EXTERN void		TclSetupEnv(Tcl_Interp *interp);
/* 103 */
EXTERN int		TclSockGetPort(Tcl_Interp *interp, const char *str,
				const char *proto, int *portPtr);
/* 104 */
EXTERN int		TclSockMinimumBuffers(int sock, int size);







|







238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
EXTERN void		TclResetShadowedCmdRefs(Tcl_Interp *interp,
				Command *newCmdPtr);
/* 98 */
EXTERN int		TclServiceIdle(void);
/* Slot 99 is reserved */
/* Slot 100 is reserved */
/* 101 */
EXTERN CONST86 char *	TclSetPreInitScript(const char *string);
/* 102 */
EXTERN void		TclSetupEnv(Tcl_Interp *interp);
/* 103 */
EXTERN int		TclSockGetPort(Tcl_Interp *interp, const char *str,
				const char *proto, int *portPtr);
/* 104 */
EXTERN int		TclSockMinimumBuffers(int sock, int size);
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
    void (*reserved35)(void);
    void (*reserved36)(void);
    int (*tclGetLoadedPackages) (Tcl_Interp *interp, const char *targetName); /* 37 */
    int (*tclGetNamespaceForQualName) (Tcl_Interp *interp, const char *qualName, Namespace *cxtNsPtr, int flags, Namespace **nsPtrPtr, Namespace **altNsPtrPtr, Namespace **actualCxtPtrPtr, const char **simpleNamePtr); /* 38 */
    TclObjCmdProcType (*tclGetObjInterpProc) (void); /* 39 */
    int (*tclGetOpenMode) (Tcl_Interp *interp, const char *str, int *seekFlagPtr); /* 40 */
    Tcl_Command (*tclGetOriginalCommand) (Tcl_Command command); /* 41 */
    char * (*tclpGetUserHome) (const char *name, Tcl_DString *bufferPtr); /* 42 */
    void (*reserved43)(void);
    int (*tclGuessPackageName) (const char *fileName, Tcl_DString *bufPtr); /* 44 */
    int (*tclHideUnsafeCommands) (Tcl_Interp *interp); /* 45 */
    int (*tclInExit) (void); /* 46 */
    void (*reserved47)(void);
    void (*reserved48)(void);
    void (*reserved49)(void);







|







574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
    void (*reserved35)(void);
    void (*reserved36)(void);
    int (*tclGetLoadedPackages) (Tcl_Interp *interp, const char *targetName); /* 37 */
    int (*tclGetNamespaceForQualName) (Tcl_Interp *interp, const char *qualName, Namespace *cxtNsPtr, int flags, Namespace **nsPtrPtr, Namespace **altNsPtrPtr, Namespace **actualCxtPtrPtr, const char **simpleNamePtr); /* 38 */
    TclObjCmdProcType (*tclGetObjInterpProc) (void); /* 39 */
    int (*tclGetOpenMode) (Tcl_Interp *interp, const char *str, int *seekFlagPtr); /* 40 */
    Tcl_Command (*tclGetOriginalCommand) (Tcl_Command command); /* 41 */
    CONST86 char * (*tclpGetUserHome) (const char *name, Tcl_DString *bufferPtr); /* 42 */
    void (*reserved43)(void);
    int (*tclGuessPackageName) (const char *fileName, Tcl_DString *bufPtr); /* 44 */
    int (*tclHideUnsafeCommands) (Tcl_Interp *interp); /* 45 */
    int (*tclInExit) (void); /* 46 */
    void (*reserved47)(void);
    void (*reserved48)(void);
    void (*reserved49)(void);
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
    void (*reserved94)(void);
    void (*reserved95)(void);
    int (*tclRenameCommand) (Tcl_Interp *interp, const char *oldName, const char *newName); /* 96 */
    void (*tclResetShadowedCmdRefs) (Tcl_Interp *interp, Command *newCmdPtr); /* 97 */
    int (*tclServiceIdle) (void); /* 98 */
    void (*reserved99)(void);
    void (*reserved100)(void);
    char * (*tclSetPreInitScript) (char *string); /* 101 */
    void (*tclSetupEnv) (Tcl_Interp *interp); /* 102 */
    int (*tclSockGetPort) (Tcl_Interp *interp, const char *str, const char *proto, int *portPtr); /* 103 */
    int (*tclSockMinimumBuffers) (int sock, int size); /* 104 */
    void (*reserved105)(void);
    void (*reserved106)(void);
    void (*reserved107)(void);
    void (*tclTeardownNamespace) (Namespace *nsPtr); /* 108 */







|







633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
    void (*reserved94)(void);
    void (*reserved95)(void);
    int (*tclRenameCommand) (Tcl_Interp *interp, const char *oldName, const char *newName); /* 96 */
    void (*tclResetShadowedCmdRefs) (Tcl_Interp *interp, Command *newCmdPtr); /* 97 */
    int (*tclServiceIdle) (void); /* 98 */
    void (*reserved99)(void);
    void (*reserved100)(void);
    CONST86 char * (*tclSetPreInitScript) (const char *string); /* 101 */
    void (*tclSetupEnv) (Tcl_Interp *interp); /* 102 */
    int (*tclSockGetPort) (Tcl_Interp *interp, const char *str, const char *proto, int *portPtr); /* 103 */
    int (*tclSockMinimumBuffers) (int sock, int size); /* 104 */
    void (*reserved105)(void);
    void (*reserved106)(void);
    void (*reserved107)(void);
    void (*tclTeardownNamespace) (Namespace *nsPtr); /* 108 */
Changes to generic/tclInterp.c.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

/*
 * A pointer to a string that holds an initialization script that if non-NULL
 * is evaluated in Tcl_Init() prior to the built-in initialization script
 * above. This variable can be modified by the function below.
 */

static char *tclPreInitScript = NULL;

/* Forward declaration */
struct Target;

/*
 * struct Alias:
 *







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

/*
 * A pointer to a string that holds an initialization script that if non-NULL
 * is evaluated in Tcl_Init() prior to the built-in initialization script
 * above. This variable can be modified by the function below.
 */

static const char *tclPreInitScript = NULL;

/* Forward declaration */
struct Target;

/*
 * struct Alias:
 *
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
 *
 * Side effects:
 *	Changes the way Tcl_Init() routine behaves.
 *
 *----------------------------------------------------------------------
 */

char *
TclSetPreInitScript(
    char *string)		/* Pointer to a script. */
{
    char *prevString = tclPreInitScript;
    tclPreInitScript = string;
    return(prevString);
}

/*
 *----------------------------------------------------------------------
 *







|

|

|







259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
 *
 * Side effects:
 *	Changes the way Tcl_Init() routine behaves.
 *
 *----------------------------------------------------------------------
 */

const char *
TclSetPreInitScript(
    const char *string)		/* Pointer to a script. */
{
    const char *prevString = tclPreInitScript;
    tclPreInitScript = string;
    return(prevString);
}

/*
 *----------------------------------------------------------------------
 *
Changes to generic/tclTest.c.
2166
2167
2168
2169
2170
2171
2172

2173
2174
2175



2176
2177
2178
2179
2180
2181
2182

2183
2184
2185



2186
2187
2188
2189
2190
2191
2192
}

static void
ExitProcOdd(
    ClientData clientData)	/* Integer value to print. */
{
    char buf[16 + TCL_INTEGER_SPACE];


    sprintf(buf, "odd %d\n", PTR2INT(clientData));
    (void)write(1, buf, strlen(buf));



}

static void
ExitProcEven(
    ClientData clientData)	/* Integer value to print. */
{
    char buf[16 + TCL_INTEGER_SPACE];


    sprintf(buf, "even %d\n", PTR2INT(clientData));
    (void)write(1, buf, strlen(buf));



}

/*
 *----------------------------------------------------------------------
 *
 * TestexprlongCmd --
 *







>


|
>
>
>







>


|
>
>
>







2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
}

static void
ExitProcOdd(
    ClientData clientData)	/* Integer value to print. */
{
    char buf[16 + TCL_INTEGER_SPACE];
    size_t len;

    sprintf(buf, "odd %d\n", PTR2INT(clientData));
    len = strlen(buf);
    if (len != (size_t) write(1, buf, len)) {
		Tcl_Panic("ExitProcOdd: unable to write to stdout");
    }
}

static void
ExitProcEven(
    ClientData clientData)	/* Integer value to print. */
{
    char buf[16 + TCL_INTEGER_SPACE];
    size_t len;

    sprintf(buf, "even %d\n", PTR2INT(clientData));
    len = strlen(buf);
    if (len != (size_t) write(1, buf, len)) {
		Tcl_Panic("ExitProcEven: unable to write to stdout");
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TestexprlongCmd --
 *
Changes to tests/apply.test.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
}

if {[info commands ::apply] eq {}} {
    return
}

testConstraint memory [llength [info commands memory]]

# Tests for wrong number of arguments

test apply-1.1 {too few arguments} {
    set res [catch apply msg]
    list $res $msg
} {1 {wrong # args: should be "apply lambdaExpr ?arg ...?"}}

# Tests for malformed lambda

test apply-2.0 {malformed lambda} {
    set lambda a
    set res [catch {apply $lambda} msg]
    list $res $msg
} {1 {can't interpret "a" as a lambda expression}}
test apply-2.1 {malformed lambda} {
    set lambda [list a b c d]
    set res [catch {apply $lambda} msg]
    list $res $msg
} {1 {can't interpret "a b c d" as a lambda expression}}
test apply-2.2 {malformed lambda} {
    set lambda [list {{}} boo]
    set res [catch {apply $lambda} msg]
    list $res $msg $::errorInfo
} {1 {argument with no name} {argument with no name
    (parsing lambda expression "{{}} boo")
    invoked from within
"apply $lambda"}}
test apply-2.3 {malformed lambda} {
    set lambda [list {{a b c}} boo]
    set res [catch {apply $lambda} msg]
    list $res $msg $::errorInfo
} {1 {too many fields in argument specifier "a b c"} {too many fields in argument specifier "a b c"
    (parsing lambda expression "{{a b c}} boo")
    invoked from within
"apply $lambda"}}
test apply-2.4 {malformed lambda} {
    set lambda [list a(1) boo]
    set res [catch {apply $lambda} msg]
    list $res $msg $::errorInfo
} {1 {formal parameter "a(1)" is an array element} {formal parameter "a(1)" is an array element
    (parsing lambda expression "a(1) boo")
    invoked from within
"apply $lambda"}}
test apply-2.5 {malformed lambda} {
    set lambda [list a::b boo]
    set res [catch {apply $lambda} msg]
    list $res $msg $::errorInfo
} {1 {formal parameter "a::b" is not a simple name} {formal parameter "a::b" is not a simple name
    (parsing lambda expression "a::b boo")
    invoked from within
"apply $lambda"}}

# Tests for runtime errors in the lambda expression








|


|
|
<
|



|

|
<
|
|

|
<
|


|
<






|
<






|
<






|
<







20
21
22
23
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38

39
40
41
42

43
44
45
46

47
48
49
50
51
52
53

54
55
56
57
58
59
60

61
62
63
64
65
66
67

68
69
70
71
72
73
74
}

if {[info commands ::apply] eq {}} {
    return
}

testConstraint memory [llength [info commands memory]]

# Tests for wrong number of arguments

test apply-1.1 {too few arguments} -returnCodes error -body {
    apply

} -result {wrong # args: should be "apply lambdaExpr ?arg ...?"}

# Tests for malformed lambda

test apply-2.0 {malformed lambda} -returnCodes error -body {
    set lambda a
    apply $lambda

} -result {can't interpret "a" as a lambda expression}
test apply-2.1 {malformed lambda} -returnCodes error -body {
    set lambda [list a b c d]
    apply $lambda

} -result {can't interpret "a b c d" as a lambda expression}
test apply-2.2 {malformed lambda} {
    set lambda [list {{}} boo]
    list [catch {apply $lambda} msg] $msg $::errorInfo

} {1 {argument with no name} {argument with no name
    (parsing lambda expression "{{}} boo")
    invoked from within
"apply $lambda"}}
test apply-2.3 {malformed lambda} {
    set lambda [list {{a b c}} boo]
    list [catch {apply $lambda} msg] $msg $::errorInfo

} {1 {too many fields in argument specifier "a b c"} {too many fields in argument specifier "a b c"
    (parsing lambda expression "{{a b c}} boo")
    invoked from within
"apply $lambda"}}
test apply-2.4 {malformed lambda} {
    set lambda [list a(1) boo]
    list [catch {apply $lambda} msg] $msg $::errorInfo

} {1 {formal parameter "a(1)" is an array element} {formal parameter "a(1)" is an array element
    (parsing lambda expression "a(1) boo")
    invoked from within
"apply $lambda"}}
test apply-2.5 {malformed lambda} {
    set lambda [list a::b boo]
    list [catch {apply $lambda} msg] $msg $::errorInfo

} {1 {formal parameter "a::b" is not a simple name} {formal parameter "a::b" is not a simple name
    (parsing lambda expression "a::b boo")
    invoked from within
"apply $lambda"}}

# Tests for runtime errors in the lambda expression

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

117
118
119
120
121
122

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

142
143
144
145
146
147
148
149
150
    namespace eval ::NONEXIST::FOR::SURE {}
    set lambda [list x {set x 1} NONEXIST::FOR::SURE]
    apply $lambda x
    namespace delete ::NONEXIST
    apply $lambda x
} -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found}

test apply-4.1 {error in arguments to lambda expression} {
    set lambda [list x {set x 1}]
    set res [catch {apply $lambda} msg]
    list $res $msg
} {1 {wrong # args: should be "apply {x {set x 1}} x"}}
test apply-4.2 {error in arguments to lambda expression} {
    set lambda [list x {set x 1}]
    set res [catch {apply $lambda a b} msg]
    list $res $msg
} {1 {wrong # args: should be "apply {x {set x 1}} x"}}
test apply-4.3 {error in arguments to lambda expression} {
    set lambda [list x {set x 1}]
    interp alias {} foo {} ::apply $lambda
    set res [catch {foo a b} msg]

    list $res $msg [rename foo {}]
} {1 {wrong # args: should be "foo x"} {}}
test apply-4.4 {error in arguments to lambda expression} {
    set lambda [list x {set x 1}]
    interp alias {} foo {} ::apply $lambda a
    set res [catch {foo b} msg]

    list $res $msg [rename foo {}]
} {1 {wrong # args: should be "foo"} {}}
test apply-4.5 {error in arguments to lambda expression} {
    set lambda [list x {set x 1}]
    namespace eval a {
	namespace ensemble create -command ::bar -map {id {::a::const foo}}
	proc const val { return $val }
	proc alias {object slot = command args} {
	    set map [namespace ensemble configure $object -map]
	    dict set map $slot [linsert $args 0 $command]
	    namespace ensemble configure $object -map $map
	}
	proc method {object name params body} {
	    set params [linsert $params 0 self]
	    alias $object $name = ::apply [list $params $body] $object
	}
	method ::bar boo x {return "[expr {$x*$x}] - $self"}
    }
    set res [catch {bar boo} msg]

    list $res $msg [namespace delete ::a]
} {1 {wrong # args: should be "bar boo x"} {}}

test apply-5.1 {runtime error in lambda expression} {
    set lambda [list {} {error foo}]
    set res [catch {apply $lambda}]
    list $res $::errorInfo
} {1 {foo
    while executing







|

|
<
|
|

|
<
|
|
<
|
|
>
|
|
|
<
|
|
>
|
|
|















|
>
|
|







89
90
91
92
93
94
95
96
97
98

99
100
101
102

103
104

105
106
107
108
109
110

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
    namespace eval ::NONEXIST::FOR::SURE {}
    set lambda [list x {set x 1} NONEXIST::FOR::SURE]
    apply $lambda x
    namespace delete ::NONEXIST
    apply $lambda x
} -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found}

test apply-4.1 {error in arguments to lambda expression} -body {
    set lambda [list x {set x 1}]
    apply $lambda

} -returnCodes error -result {wrong # args: should be "apply lambdaExpr x"}
test apply-4.2 {error in arguments to lambda expression} -body {
    set lambda [list x {set x 1}]
    apply $lambda a b

} -returnCodes error -result {wrong # args: should be "apply lambdaExpr x"}
test apply-4.3 {error in arguments to lambda expression} -body {

    interp alias {} foo {} ::apply [list x {set x 1}]
    foo a b
} -cleanup {
    rename foo {}
} -returnCodes error -result {wrong # args: should be "foo x"}
test apply-4.4 {error in arguments to lambda expression} -body {

    interp alias {} foo {} ::apply [list x {set x 1}] a
    foo b
} -cleanup {
    rename foo {}
} -returnCodes error -result {wrong # args: should be "foo"}
test apply-4.5 {error in arguments to lambda expression} -body {
    set lambda [list x {set x 1}]
    namespace eval a {
	namespace ensemble create -command ::bar -map {id {::a::const foo}}
	proc const val { return $val }
	proc alias {object slot = command args} {
	    set map [namespace ensemble configure $object -map]
	    dict set map $slot [linsert $args 0 $command]
	    namespace ensemble configure $object -map $map
	}
	proc method {object name params body} {
	    set params [linsert $params 0 self]
	    alias $object $name = ::apply [list $params $body] $object
	}
	method ::bar boo x {return "[expr {$x*$x}] - $self"}
    }
    bar boo
} -cleanup {
    namespace delete ::a
} -returnCodes error -result {wrong # args: should be "bar boo x"}

test apply-5.1 {runtime error in lambda expression} {
    set lambda [list {} {error foo}]
    set res [catch {apply $lambda}]
    list $res $::errorInfo
} {1 {foo
    while executing
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314

315
316
317
318
319
320
321
322
323
324





	::apply [lrange $lam 0 end]
	set tmp $end
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $tmp}]
} -cleanup {
    rename getbytes {}
    unset lam
} -result 0
test apply-9.2 {leaking internal rep} -setup {
    proc getbytes {} {
	set lines [split [memory info] "\n"]
	lindex $lines 3 3
    }
} -constraints memory -body {
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {
	::apply [list {} {set a 1}]
	set tmp $end
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $tmp}]
} -cleanup {
    rename getbytes {}

} -result 0
test apply-9.3 {leaking internal rep} -setup {
    proc getbytes {} {
	set lines [split [memory info] "\n"]
	lindex $lines 3 3
    }
} -constraints memory -body {
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {
	set x [list {} {set a 1} ::NS::THAT::DOES::NOT::EXIST]
	catch {::apply $x}
	set x {}
	set tmp $end
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $tmp}]
} -cleanup {
    rename getbytes {}

} -result 0

# Tests for the avoidance of recompilation

# cleanup

namespace delete testApply

::tcltest::cleanupTests
return












|
















>


















>



|






>
>
>
>
>
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
	::apply [lrange $lam 0 end]
	set tmp $end
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $tmp}]
} -cleanup {
    rename getbytes {}
    unset -nocomplain lam end i tmp leakedBytes
} -result 0
test apply-9.2 {leaking internal rep} -setup {
    proc getbytes {} {
	set lines [split [memory info] "\n"]
	lindex $lines 3 3
    }
} -constraints memory -body {
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {
	::apply [list {} {set a 1}]
	set tmp $end
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $tmp}]
} -cleanup {
    rename getbytes {}
    unset -nocomplain end i tmp leakedBytes
} -result 0
test apply-9.3 {leaking internal rep} -setup {
    proc getbytes {} {
	set lines [split [memory info] "\n"]
	lindex $lines 3 3
    }
} -constraints memory -body {
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {
	set x [list {} {set a 1} ::NS::THAT::DOES::NOT::EXIST]
	catch {::apply $x}
	set x {}
	set tmp $end
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $tmp}]
} -cleanup {
    rename getbytes {}
    unset -nocomplain end i x tmp leakedBytes
} -result 0

# Tests for the avoidance of recompilation

# cleanup

namespace delete testApply

::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# fill-column: 78
# End:
Changes to tests/basic.test.
627
628
629
630
631
632
633
634


635
636
637
638
639
640
641
642
} -cleanup {
    removeFile BREAKtest
} -returnCodes error -match glob -result {command returned bad code: 2
    while executing
"return -code return"
    (file "*BREAKtest" line 2)}

test basic-47.1 {Tcl_EvalEx: check for missing close-bracket} -body {


    subst {a[set b [format cd]}
} -returnCodes error -result {missing close-bracket}

# Some lists for expansion tests to work with
set l1 [list a {b b} c d]
set l2 [list e f {g g} h]
proc l3 {} {
    list i j k {l l}







|
>
>
|







627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
} -cleanup {
    removeFile BREAKtest
} -returnCodes error -match glob -result {command returned bad code: 2
    while executing
"return -code return"
    (file "*BREAKtest" line 2)}

test basic-47.1 {Tcl_EvalEx: check for missing close-bracket} -constraints {
    testevalex
} -body {
    testevalex {a[set b [format cd]}
} -returnCodes error -result {missing close-bracket}

# Some lists for expansion tests to work with
set l1 [list a {b b} c d]
set l2 [list e f {g g} h]
proc l3 {} {
    list i j k {l l}
Changes to tests/binary.test.
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
	default {
	    return 0
	}
    }
}

testConstraint ieeeFloatingPoint [testIEEE]

# ----------------------------------------------------------------------

test binary-0.1 {DupByteArrayInternalRep} {
    set hdr [binary format cc 0 0316]
    set buf hellomatt
    set data $hdr
    append data $buf







|







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
	default {
	    return 0
	}
    }
}

testConstraint ieeeFloatingPoint [testIEEE]

# ----------------------------------------------------------------------

test binary-0.1 {DupByteArrayInternalRep} {
    set hdr [binary format cc 0 0316]
    set buf hellomatt
    set data $hdr
    append data $buf
2469
2470
2471
2472
2473
2474
2475



2476
2477
2478
2479
2480
2481
2482
test binary-71.8 {binary decode hex} -body {
    binary decode hex -strict "61 61"
} -returnCodes error -result {invalid hexadecimal digit " " at position 2}
test binary-71.9 {binary decode hex} -body {
    set r [binary decode hex "6"]
    list [string length $r] $r
} -result {0 {}}




test binary-72.1 {binary encode base64} -body {
    binary encode base64
} -returnCodes error -match glob -result "wrong # args: *"
test binary-72.2 {binary encode base64} -body {
    binary encode base64 abc
} -result {YWJj}







>
>
>







2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
test binary-71.8 {binary decode hex} -body {
    binary decode hex -strict "61 61"
} -returnCodes error -result {invalid hexadecimal digit " " at position 2}
test binary-71.9 {binary decode hex} -body {
    set r [binary decode hex "6"]
    list [string length $r] $r
} -result {0 {}}
test binary-71.10 {binary decode hex} -body {
    string length [binary decode hex " "]
} -result 0

test binary-72.1 {binary encode base64} -body {
    binary encode base64
} -returnCodes error -match glob -result "wrong # args: *"
test binary-72.2 {binary encode base64} -body {
    binary encode base64 abc
} -result {YWJj}
2617
2618
2619
2620
2621
2622
2623



2624
2625
2626
2627
2628
2629
2630
    set r [binary decode base64 YWJ]
    list [string length $r] $r
} -result {2 ab}
test binary-73.23 {binary decode base64} -body {
    set r [binary decode base64 YWJj]
    list [string length $r] $r
} -result {3 abc}




test binary-74.1 {binary encode uuencode} -body {
    binary encode uuencode
} -returnCodes error -match glob -result "wrong # args: *"
test binary-74.2 {binary encode uuencode} -body {
    binary encode uuencode abc
} -result {86)C}







>
>
>







2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
    set r [binary decode base64 YWJ]
    list [string length $r] $r
} -result {2 ab}
test binary-73.23 {binary decode base64} -body {
    set r [binary decode base64 YWJj]
    list [string length $r] $r
} -result {3 abc}
test binary-73.24 {binary decode base64} -body {
    string length [binary decode base64 " "]
} -result 0

test binary-74.1 {binary encode uuencode} -body {
    binary encode uuencode
} -returnCodes error -match glob -result "wrong # args: *"
test binary-74.2 {binary encode uuencode} -body {
    binary encode uuencode abc
} -result {86)C}
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
} -result {abc}
test binary-75.3 {binary decode uuencode} -body {
    binary decode uuencode {}
} -result {}
test binary-75.4 {binary decode uuencode} -body {
    binary decode uuencode [string repeat "86)C" 20]
} -result [string repeat abc 20]
test binary-75.5 {binary encode uuencode} -body {
    binary decode uuencode "``\$\"`P0``0(#"
} -result "\0\1\2\3\4\0\1\2\3"
test binary-75.6 {binary encode uuencode} -body {
    string length [binary decode uuencode {`}]
} -result 0
test binary-75.7 {binary encode uuencode} -body {
    string length [binary decode uuencode {``}]
} -result 1
test binary-75.8 {binary encode uuencode} -body {
    string length [binary decode uuencode {```}]
} -result 2
test binary-75.9 {binary encode uuencode} -body {
    string length [binary decode uuencode {````}]
} -result 3
test binary-75.10 {binary decode uuencode} -body {
    set s "[string repeat 86)C 10]\n[string repeat 86)C 10]"
    binary decode uuencode $s
} -result [string repeat abc 20]
test binary-75.11 {binary decode uuencode} -body {







|


|


|


|


|







2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
} -result {abc}
test binary-75.3 {binary decode uuencode} -body {
    binary decode uuencode {}
} -result {}
test binary-75.4 {binary decode uuencode} -body {
    binary decode uuencode [string repeat "86)C" 20]
} -result [string repeat abc 20]
test binary-75.5 {binary decode uuencode} -body {
    binary decode uuencode "``\$\"`P0``0(#"
} -result "\0\1\2\3\4\0\1\2\3"
test binary-75.6 {binary decode uuencode} -body {
    string length [binary decode uuencode {`}]
} -result 0
test binary-75.7 {binary decode uuencode} -body {
    string length [binary decode uuencode {``}]
} -result 1
test binary-75.8 {binary decode uuencode} -body {
    string length [binary decode uuencode {```}]
} -result 2
test binary-75.9 {binary decode uuencode} -body {
    string length [binary decode uuencode {````}]
} -result 3
test binary-75.10 {binary decode uuencode} -body {
    set s "[string repeat 86)C 10]\n[string repeat 86)C 10]"
    binary decode uuencode $s
} -result [string repeat abc 20]
test binary-75.11 {binary decode uuencode} -body {
2722
2723
2724
2725
2726
2727
2728



2729




















2730

2731
2732
2733
2734
2735
2736
    set s "04)\# "
    binary decode uuencode $s
} -result ABC
test binary-75.25 {binary decode uuencode} -body {
    set s "04)\#z"
    binary decode uuencode $s
} -returnCodes error -match glob -result {invalid uuencode character "z" at position 4}
























# cleanup

::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







>
>
>

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

>






2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
    set s "04)\# "
    binary decode uuencode $s
} -result ABC
test binary-75.25 {binary decode uuencode} -body {
    set s "04)\#z"
    binary decode uuencode $s
} -returnCodes error -match glob -result {invalid uuencode character "z" at position 4}
test binary-75.26 {binary decode uuencode} -body {
    string length [binary decode uuencode " "]
} -result 0

test binary-76.1 {binary string appending growth algorithm} unix {
    # Create zero-length byte array first
    set f [open /dev/null rb]
    chan configure $f -blocking 0
    set str [read $f 2]
    close $f
    # Append to it
    string length [append str [binary format a* foo]]
} 3
test binary-76.2 {binary string appending growth algorithm} win {
    # Create zero-length byte array first
    set f [open NUL rb]
    chan configure $f -blocking 0
    set str [read $f 2]
    close $f
    # Append to it
    string length [append str [binary format a* foo]]
} 3

# ----------------------------------------------------------------------
# cleanup

::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/chanio.test.
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
    chan close $f
    chan close $f2
    set result
} {{
out
} {err
}}
# This test relies on the fact that the smallest available fd is used first.
test chan-io-14.4 {Tcl_SetStdChannel & Tcl_GetStdChannel} {exec unix} {
    set f [open $path(test1) w]
    chan puts -nonewline $f { chan close stdin
	chan close stdout
	chan close stderr
	set f  [}
    chan puts $f [list open $path(test1) r]]
    chan puts $f "set f2 \[[list open $path(test2) w]]"







|
|







1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
    chan close $f
    chan close $f2
    set result
} {{
out
} {err
}}
# This test relies on the fact that stdout is used before stderr.
test chan-io-14.4 {Tcl_SetStdChannel & Tcl_GetStdChannel} {exec} {
    set f [open $path(test1) w]
    chan puts -nonewline $f { chan close stdin
	chan close stdout
	chan close stderr
	set f  [}
    chan puts $f [list open $path(test1) r]]
    chan puts $f "set f2 \[[list open $path(test2) w]]"
1593
1594
1595
1596
1597
1598
1599
1600

1601
1602
1603
1604
1605
1606
1607
1608
    set f  [open $path(test2) r]
    set f2 [open $path(test3) r]
    lappend result [chan read $f] [chan read $f2]
    chan close $f
    chan close $f2
    set result
} {{ chan close stdin
file1

} {file2
}}
catch {interp delete z}
test chan-io-14.5 {Tcl_GetChannel: stdio name translation} -setup {
    interp create z
} -body {
    chan eof stdin
    catch {z eval chan flush stdin} msg1







<
>
|







1593
1594
1595
1596
1597
1598
1599

1600
1601
1602
1603
1604
1605
1606
1607
1608
    set f  [open $path(test2) r]
    set f2 [open $path(test3) r]
    lappend result [chan read $f] [chan read $f2]
    chan close $f
    chan close $f2
    set result
} {{ chan close stdin

stdout
} {stderr
}}
catch {interp delete z}
test chan-io-14.5 {Tcl_GetChannel: stdio name translation} -setup {
    interp create z
} -body {
    chan eof stdin
    catch {z eval chan flush stdin} msg1
2111
2112
2113
2114
2115
2116
2117
2118
2119

2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
    chan close $f
    lappend l [lsort [testchannel open]]
    set x [list $consoleFileNames \
		[lsort [list {*}$consoleFileNames $f]] \
		$consoleFileNames]
    string compare $l $x
} 0
test chan-io-28.5 {Tcl_Chan Close vs standard handles} {stdio unix testchannel openpipe} {
    file delete $path(script)

    set f [open $path(script) w]
    chan puts $f {
	chan close stdin
	chan puts [testchannel open]
    }
    chan close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    set l [chan gets $f]
    chan close $f
    set l
} {file1 file2}
test chan-io-28.6 {Tcl_CloseEx (half-close) pipe} -setup {
    set cat [makeFile {
	fconfigure stdout -buffering line
	while {[gets stdin line]>=0} {puts $line}
	puts DONE
	exit 0
    } cat.tcl]







|

>









|
|







2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
    chan close $f
    lappend l [lsort [testchannel open]]
    set x [list $consoleFileNames \
		[lsort [list {*}$consoleFileNames $f]] \
		$consoleFileNames]
    string compare $l $x
} 0
test chan-io-28.5 {Tcl_Chan Close vs standard handles} -setup {
    file delete $path(script)
} -constraints {stdio unix testchannel openpipe} -body {
    set f [open $path(script) w]
    chan puts $f {
	chan close stdin
	chan puts [testchannel open]
    }
    chan close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    set l [chan gets $f]
    chan close $f
    lsort $l
} -result {file1 file2}
test chan-io-28.6 {Tcl_CloseEx (half-close) pipe} -setup {
    set cat [makeFile {
	fconfigure stdout -buffering line
	while {[gets stdin line]>=0} {puts $line}
	puts DONE
	exit 0
    } cat.tcl]
Changes to tests/cmdAH.test.
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
	$errorCode
} {1 {could not read "_bogus_": no such file or directory} {POSIX ENOENT {no such file or directory}}}
test cmdAH-23.6 {Tcl_FileObjCmd: lstat errors} -setup {
    catch {unset x}
} -body {
    set x 44
    list [catch {file lstat $gorpfile x} msg] $msg $errorCode
} -result {1 {can't set "x(dev)": variable isn't array} {TCL LOOKUP VARNAME}}
catch {unset stat}
# mkdir
set dirA [file join [temporaryDirectory] a]
set dirB [file join [temporaryDirectory] a]
test cmdAH-23.7 {Tcl_FileObjCmd: mkdir} -setup {
    catch {file delete -force $dirA}
} -body {







|







1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
	$errorCode
} {1 {could not read "_bogus_": no such file or directory} {POSIX ENOENT {no such file or directory}}}
test cmdAH-23.6 {Tcl_FileObjCmd: lstat errors} -setup {
    catch {unset x}
} -body {
    set x 44
    list [catch {file lstat $gorpfile x} msg] $msg $errorCode
} -result {1 {can't set "x(dev)": variable isn't array} {TCL LOOKUP VARNAME x}}
catch {unset stat}
# mkdir
set dirA [file join [temporaryDirectory] a]
set dirB [file join [temporaryDirectory] a]
test cmdAH-23.7 {Tcl_FileObjCmd: mkdir} -setup {
    catch {file delete -force $dirA}
} -body {
1291
1292
1293
1294
1295
1296
1297

1298
1299

1300
1301
1302
1303
1304
1305
1306
    file stat _bogus_
} -result {wrong # args: should be "file stat name varName"}
test cmdAH-28.2 {Tcl_FileObjCmd: stat} -returnCodes error -body {
    file stat _bogus_ a b
} -result {wrong # args: should be "file stat name varName"}
test cmdAH-28.3 {Tcl_FileObjCmd: stat} -setup {
    catch {unset stat}

} -body {
    file stat $gorpfile stat

    lsort [array names stat]
} -result {atime ctime dev gid ino mode mtime nlink size type uid}
test cmdAH-28.4 {Tcl_FileObjCmd: stat} -setup {
    catch {unset stat}
} -body {
    file stat $gorpfile stat
    list $stat(nlink) $stat(size) $stat(type)







>


>







1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
    file stat _bogus_
} -result {wrong # args: should be "file stat name varName"}
test cmdAH-28.2 {Tcl_FileObjCmd: stat} -returnCodes error -body {
    file stat _bogus_ a b
} -result {wrong # args: should be "file stat name varName"}
test cmdAH-28.3 {Tcl_FileObjCmd: stat} -setup {
    catch {unset stat}
    set stat(blocks) [set stat(blksize) {}]
} -body {
    file stat $gorpfile stat
    unset stat(blocks) stat(blksize); # Ignore these fields; not always set
    lsort [array names stat]
} -result {atime ctime dev gid ino mode mtime nlink size type uid}
test cmdAH-28.4 {Tcl_FileObjCmd: stat} -setup {
    catch {unset stat}
} -body {
    file stat $gorpfile stat
    list $stat(nlink) $stat(size) $stat(type)
Changes to tests/cmdMZ.test.
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

# Some tests for Tcl_ReturnObjCmd are in proc-old.test

test cmdMZ-return-1.0 {return checks for bad option values} -body {
    return -options foo
} -returnCodes error -match glob -result {bad -options value:*}
test cmdMZ-return-1.1 {return checks for bad option values} -body {
    return -code foo
} -returnCodes error -match glob -result {bad completion code*}
test cmdMZ-return-1.2 {return checks for bad option values} -body {
    return -code 0x100000000
} -returnCodes error -match glob -result {bad completion code*}
test cmdMZ-return-1.3 {return checks for bad option values} -body {
    return -level foo
} -returnCodes error -match glob -result {bad -level value: *}
test cmdMZ-return-1.4 {return checks for bad option values} -body {
    return -level -1
} -returnCodes error -match glob -result {bad -level value: *}
test cmdMZ-return-1.5 {return checks for bad option values} -body {







|
|


|







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

# Some tests for Tcl_ReturnObjCmd are in proc-old.test

test cmdMZ-return-1.0 {return checks for bad option values} -body {
    return -options foo
} -returnCodes error -match glob -result {bad -options value:*}
test cmdMZ-return-1.1 {return checks for bad option values} -body {
    return -code err
} -returnCodes error -match glob -result {bad completion code "err": must be ok, error, return, break, continue*, or an integer}
test cmdMZ-return-1.2 {return checks for bad option values} -body {
    return -code 0x100000000
} -returnCodes error -match glob -result {bad completion code "0x100000000": must be ok, error, return, break, continue*, or an integer}
test cmdMZ-return-1.3 {return checks for bad option values} -body {
    return -level foo
} -returnCodes error -match glob -result {bad -level value: *}
test cmdMZ-return-1.4 {return checks for bad option values} -body {
    return -level -1
} -returnCodes error -match glob -result {bad -level value: *}
test cmdMZ-return-1.5 {return checks for bad option values} -body {
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
} -returnCodes continue -result {}
test cmdMZ-return-2.8 {return option handling} -body {
    return -level 0 -code -1
} -returnCodes -1 -result {}
test cmdMZ-return-2.9 {return option handling} -body {
    return -level 0 -code 10
} -returnCodes 10 -result {}
test cmdMZ-return-2.10 {return option handling} {
    list [catch {return -level 0 -code error} -> foo] [dictSort $foo]
} {1 {-code 1 -errorcode NONE -errorinfo {
    while executing
"return -level 0 -code error"} -errorline 1 -level 0}}
test cmdMZ-return-2.11 {return option handling} {
    list [catch {return -level 0 -code break} -> foo] [dictSort $foo]
} {3 {-code 3 -level 0}}
test cmdMZ-return-2.12 {return option handling} -body {
    return -level 0 -code error -options {-code ok}
} -returnCodes ok -result {}
test cmdMZ-return-2.13 {return option handling} -body {
    return -level 0 -code error -options {-code foo}
} -returnCodes error -match glob -result {bad completion code*}
test cmdMZ-return-2.14 {return option handling} -body {
    return -level 0 -code error -options {-code foo -options {-code break}}
} -returnCodes break -result {}
test cmdMZ-return-2.15 {return opton handling} -setup {
    proc p {} {
	return -code error -errorcode {a b} c
    }







|

|

|







|
|







145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
} -returnCodes continue -result {}
test cmdMZ-return-2.8 {return option handling} -body {
    return -level 0 -code -1
} -returnCodes -1 -result {}
test cmdMZ-return-2.9 {return option handling} -body {
    return -level 0 -code 10
} -returnCodes 10 -result {}
test cmdMZ-return-2.10 {return option handling} -body {
    list [catch {return -level 0 -code error} -> foo] [dictSort $foo]
} -match glob -result {1 {-code 1 -errorcode NONE -errorinfo {
    while executing
"return -level 0 -code error"} -errorline 1 -errorstack * -level 0}}
test cmdMZ-return-2.11 {return option handling} {
    list [catch {return -level 0 -code break} -> foo] [dictSort $foo]
} {3 {-code 3 -level 0}}
test cmdMZ-return-2.12 {return option handling} -body {
    return -level 0 -code error -options {-code ok}
} -returnCodes ok -result {}
test cmdMZ-return-2.13 {return option handling} -body {
    return -level 0 -code error -options {-code err}
} -returnCodes error -match glob -result {bad completion code "err": must be ok, error, return, break, continue*, or an integer}
test cmdMZ-return-2.14 {return option handling} -body {
    return -level 0 -code error -options {-code foo -options {-code break}}
} -returnCodes break -result {}
test cmdMZ-return-2.15 {return opton handling} -setup {
    proc p {} {
	return -code error -errorcode {a b} c
    }
189
190
191
192
193
194
195



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

214
215
216
217
218
219
220
	return -code error -errorcode a\ b c
    }
} -body {
    list [catch p result] $result $::errorCode
} -cleanup {
    rename p {}
} -result {1 c {a b}}




# Check that the result of a [return -options $opts $result] is
# indistinguishable from that of the originally caught script, no matter what
# the script is/does. (TIP 90)
foreach {testid script} {
    cmdMZ-return-3.0 {}
    cmdMZ-return-3.1 {format x}
    cmdMZ-return-3.2 {set}
    cmdMZ-return-3.3 {set a 1}
    cmdMZ-return-3.4 {error}
    cmdMZ-return-3.5 {error foo}
    cmdMZ-return-3.6 {error foo bar}
    cmdMZ-return-3.7 {error foo bar baz}
    cmdMZ-return-3.8 {return -level 0}
    cmdMZ-return-3.9 {return -code error}
    cmdMZ-return-3.10 {return -code error -errorinfo foo}
    cmdMZ-return-3.11 {return -code error -errorinfo foo -errorcode bar}
    cmdMZ-return-3.12 {return -code error -errorinfo foo -errorcode bar -errorline 10}

    cmdMZ-return-3.13 {return -options {x y z 2}}
    cmdMZ-return-3.14 {return -level 3 -code break sdf}
} {
    test $testid "check that return after a catch is same:\n$script" {
	set one [list [catch $script foo bar] $foo [dictSort $bar] \
		$::errorCode $::errorInfo]
	set two [list [catch {return -options $bar $foo} foo2 bar2] \







>
>
>


















>







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
	return -code error -errorcode a\ b c
    }
} -body {
    list [catch p result] $result $::errorCode
} -cleanup {
    rename p {}
} -result {1 c {a b}}
test cmdMZ-return-2.18 {return option handling} {
    list [catch {return -code error -errorstack [list CALL a CALL b] yo} -> foo] [dictSort $foo] [info errorstack]
} {2 {-code 1 -errorcode NONE -errorstack {CALL a CALL b} -level 1} {CALL a CALL b}}

# Check that the result of a [return -options $opts $result] is
# indistinguishable from that of the originally caught script, no matter what
# the script is/does. (TIP 90)
foreach {testid script} {
    cmdMZ-return-3.0 {}
    cmdMZ-return-3.1 {format x}
    cmdMZ-return-3.2 {set}
    cmdMZ-return-3.3 {set a 1}
    cmdMZ-return-3.4 {error}
    cmdMZ-return-3.5 {error foo}
    cmdMZ-return-3.6 {error foo bar}
    cmdMZ-return-3.7 {error foo bar baz}
    cmdMZ-return-3.8 {return -level 0}
    cmdMZ-return-3.9 {return -code error}
    cmdMZ-return-3.10 {return -code error -errorinfo foo}
    cmdMZ-return-3.11 {return -code error -errorinfo foo -errorcode bar}
    cmdMZ-return-3.12 {return -code error -errorinfo foo -errorcode bar -errorline 10}
    cmdMZ-return-3.12.1 {return -code error -errorinfo foo -errorcode bar -errorline 10 -errorstack baz}
    cmdMZ-return-3.13 {return -options {x y z 2}}
    cmdMZ-return-3.14 {return -level 3 -code break sdf}
} {
    test $testid "check that return after a catch is same:\n$script" {
	set one [list [catch $script foo bar] $foo [dictSort $bar] \
		$::errorCode $::errorInfo]
	set two [list [catch {return -options $bar $foo} foo2 bar2] \
Changes to tests/compile.test.
124
125
126
127
128
129
130






























131
132
133
134
135
136
137
	    if {[a]} {
		if b {}
	    }   
	}   
    }
    list [catch foo msg] $msg
} {0 1}































test compile-4.1 {TclCompileForCmd: command substituted test expression} {
    set i 0
    set j 0
    # Should be "forever"
    for {} [expr $i < 3] {} {
	set j [incr i]







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







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
	    if {[a]} {
		if b {}
	    }   
	}   
    }
    list [catch foo msg] $msg
} {0 1}
test compile-3.6 {TclCompileCatchCmd: error in storing result [Bug 3098302]} {*}{
     -setup {
	 namespace eval catchtest {
	     variable result1 {}
	 }
	 trace add variable catchtest::result1 write catchtest::failtrace
	 proc catchtest::failtrace {n1 n2 op} {
	     return -code error "trace on $n1 fails by request"
	 }
     }
    -body {
	proc catchtest::x {} {
	    variable result1
	    set count 0
	    for {set i 0} {$i < 10} {incr i} {
		set status2 [catch {
		    set status1 [catch {
			return -code error -level 0 "original failure"
		    } result1 options1]
		} result2 options2]
		incr count
	    }
	    list $count $result2
	}
	catchtest::x
    }
    -result {10 {can't set "result1": trace on result1 fails by request}}
    -cleanup {namespace delete catchtest}
}


test compile-4.1 {TclCompileForCmd: command substituted test expression} {
    set i 0
    set j 0
    # Should be "forever"
    for {} [expr $i < 3] {} {
	set j [incr i]
292
293
294
295
296
297
298

299
300
301
302
303
304
305
	interp delete foo
	set tmp $end
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $tmp}]
} -cleanup {
    rename getbytes {}

} -result 0
# Special test for a memory error in a preliminary fix of [Bug 467523]. 
# It requires executing a helpfile.  Presumably the child process is
# used because when this test fails, it crashes.
test compile-12.2 {testing error on literal deletion} -constraints {memory exec} -body {
    set sourceFile [makeFile {
	for {set i 0} {$i < 5} {incr i} {







>







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
	interp delete foo
	set tmp $end
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $tmp}]
} -cleanup {
    rename getbytes {}
    unset -nocomplain end i tmp leakedBytes
} -result 0
# Special test for a memory error in a preliminary fix of [Bug 467523]. 
# It requires executing a helpfile.  Presumably the child process is
# used because when this test fails, it crashes.
test compile-12.2 {testing error on literal deletion} -constraints {memory exec} -body {
    set sourceFile [makeFile {
	for {set i 0} {$i < 5} {incr i} {
Changes to tests/dict.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75


76
77
78
79
80
81
82
# This test file covers the dictionary object type and the dict
# command used to work with values of that type.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands. Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 2003 Donal K. Fellows
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: dict.test,v 1.29 2008/05/09 03:51:33 kennykb Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Used for constraining memory leak tests
testConstraint memory [llength [info commands memory]]








# Procedure to help check the contents of a dictionary.  Note that we
# can't just compare the string version because the order of the
# elements is (deliberately) not defined.  This is because it is
# dependent on the underlying hash table implementation and also
# potentially on the history of the value itself.  Net result: you
# cannot safely assume anything about the ordering of values.
proc getOrder {dictVal args} {
    foreach key $args {
	lappend result $key [dict get $dictVal $key]
    }
    lappend result [dict size $dictVal]
    return $result
}

test dict-1.1 {dict command basic syntax} -returnCodes error -body {
    dict
} -result {wrong # args: should be "dict subcommand ?arg ...?"}
test dict-1.2 {dict command basic syntax} -returnCodes error -body {
    dict ?
} -match glob -result {unknown or ambiguous subcommand "?": must be *}

test dict-2.1 {dict create command} {
    dict create
} {}
test dict-2.2 {dict create command} {
    dict create a b
} {a b}
test dict-2.3 {dict create command} {
    set result {}
    set dict [dict create a b c d]
    # Can't compare directly as ordering of values is undefined
    foreach key {a c} {
	set idx [lsearch -exact $dict $key]
	if {$idx & 1} {
	    error "found $key at odd index $idx in $dict"
	}
	lappend result [lindex $dict [expr {$idx+1}]]
    }


    set result
} {b d}
test dict-2.4 {dict create command} -returnCodes error -body {
    dict create a
} -result {wrong # args: should be "dict create ?key value ...?"}
test dict-2.5 {dict create command} -returnCodes error -body {
    dict create a b c
} -result {wrong # args: should be "dict create ?key value ...?"}
test dict-2.6 {dict create command - initialse refcount field!} {
    # Bug 715751 will show up in memory debuggers like purify
    for {set i 0} {$i<10} {incr i} {
	set dictv [dict create a 0]
	set share [dict values $dictv]
	list [dict incr dictv a]
    }
} {}


test dict-2.7 {dict create command - #-quoting in string rep} {
    dict create # #comment
} {{#} #comment}
test dict-2.8 {dict create command - #-quoting in string rep} -body {
    dict create #a x #b x
} -match glob -result {{#?} x #? x}

|
|

|
|
|

|
|
|










>
>
>
>
>
>
>
|
<
<
<
<
<
<
<
<
|

<
<

|













|










>
>
|
|






|






|
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28








29
30


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# This test file covers the dictionary object type and the dict command used
# to work with values of that type.
#
# This file contains a collection of tests for one or more of the Tcl built-in
# commands. Sourcing this file into Tcl runs the tests and generates output
# for errors.  No output means no errors were found.
#
# Copyright (c) 2003-2009 Donal K. Fellows
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: dict.test,v 1.29 2008/05/09 03:51:33 kennykb Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Used for constraining memory leak tests
testConstraint memory [llength [info commands memory]]
if {[testConstraint memory]} {
    proc memtest script {
	set end [lindex [split [memory info] \n] 3 3]
	for {set i 0} {$i < 5} {incr i} {
	    uplevel 1 $script
	    set tmp $end
	    set end [lindex [split [memory info] \n] 3 3]
	}








	expr {$end - $tmp}
    }


}

test dict-1.1 {dict command basic syntax} -returnCodes error -body {
    dict
} -result {wrong # args: should be "dict subcommand ?arg ...?"}
test dict-1.2 {dict command basic syntax} -returnCodes error -body {
    dict ?
} -match glob -result {unknown or ambiguous subcommand "?": must be *}

test dict-2.1 {dict create command} {
    dict create
} {}
test dict-2.2 {dict create command} {
    dict create a b
} {a b}
test dict-2.3 {dict create command} -body {
    set result {}
    set dict [dict create a b c d]
    # Can't compare directly as ordering of values is undefined
    foreach key {a c} {
	set idx [lsearch -exact $dict $key]
	if {$idx & 1} {
	    error "found $key at odd index $idx in $dict"
	}
	lappend result [lindex $dict [expr {$idx+1}]]
    }
    return $result
} -cleanup {
    unset result dict key idx
} -result {b d}
test dict-2.4 {dict create command} -returnCodes error -body {
    dict create a
} -result {wrong # args: should be "dict create ?key value ...?"}
test dict-2.5 {dict create command} -returnCodes error -body {
    dict create a b c
} -result {wrong # args: should be "dict create ?key value ...?"}
test dict-2.6 {dict create command - initialse refcount field!} -body {
    # Bug 715751 will show up in memory debuggers like purify
    for {set i 0} {$i<10} {incr i} {
	set dictv [dict create a 0]
	set share [dict values $dictv]
	list [dict incr dictv a]
    }
} -cleanup {
    unset i dictv share
} -result {}
test dict-2.7 {dict create command - #-quoting in string rep} {
    dict create # #comment
} {{#} #comment}
test dict-2.8 {dict create command - #-quoting in string rep} -body {
    dict create #a x #b x
} -match glob -result {{#?} x #? x}

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112


113
114
115
116
117
118
119
120
121


122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
test dict-3.10 {dict get command} -returnCodes error -body {
    dict get {a {p q r s} b {u v x y}} c z
} -result {key "c" not known in dictionary}
test dict-3.11 {dict get command} {dict get [dict create a b c d] a} b
test dict-3.12 {dict get command} -returnCodes error -body {
    dict get
} -result {wrong # args: should be "dict get dictionary ?key ...?"}
test dict-3.13 {dict get command} {
    set dict [dict get {a b c d}]
    if {$dict eq "a b c d"} {
	subst OK
    } elseif {$dict eq "c d a b"} {
	subst OK
    } else {
	set dict
    }
} OK


test dict-3.14 {dict get command} -returnCodes error -body {
    dict get {a b c d} a c
} -result {missing value to go with key}
test dict-3.15 {compiled dict get error cleanliness - Bug 2431847} -body {
    apply {{} {
	dict set a(z) b c
	dict get $a(z) d
    }}
} -returnCodes error -result {key "d" not known in dictionary}



test dict-4.1 {dict replace command} {
    getOrder [dict replace {a b c d}] a c
} {a b c d 2}
test dict-4.2 {dict replace command} {
    getOrder [dict replace {a b c d} e f] a c e
} {a b c d e f 3}
test dict-4.3 {dict replace command} {
    getOrder [dict replace {a b c d} c f] a c
} {a b c f 2}
test dict-4.4 {dict replace command} {
    getOrder [dict replace {a b c d} c x a y] a c
} {a y c x 2}
test dict-4.5 {dict replace command} -returnCodes error -body {
    dict replace
} -result {wrong # args: should be "dict replace dictionary ?key value ...?"}
test dict-4.6 {dict replace command} -returnCodes error -body {
    dict replace {a a} a
} -result {wrong # args: should be "dict replace dictionary ?key value ...?"}
test dict-4.7 {dict replace command} -returnCodes error -body {
    dict replace {a a a} a b
} -result {missing value to go with key}
test dict-4.8 {dict replace command} -returnCodes error -body {
    dict replace [list a a a] a b
} -result {missing value to go with key}
test dict-4.9 {dict replace command} {dict replace [list a a] a b} {a b}
test dict-4.10 {dict replace command} {dict replace [list a a] a b a c} {a c}

test dict-5.1 {dict remove command} {dict remove {a b c d} a} {c d}
test dict-5.2 {dict remove command} {dict remove {a b c d} c} {a b}
test dict-5.3 {dict remove command} {dict remove {a b c d} a c} {}
test dict-5.4 {dict remove command} {dict remove {a b c d} c a} {}
test dict-5.5 {dict remove command} {
    getOrder [dict remove {a b c d}] a c
} {a b c d 2}
test dict-5.6 {dict remove command} {dict remove {a b} c} {a b}
test dict-5.7 {dict remove command} -returnCodes error -body {
    dict remove
} -result {wrong # args: should be "dict remove dictionary ?key ...?"}

test dict-6.1 {dict keys command} {dict keys {a b}} a
test dict-6.2 {dict keys command} {dict keys {c d}} c







|


|

|

|

|
>
>









>
>


|
|

|
|

|
|

|
|




















|
|







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
test dict-3.10 {dict get command} -returnCodes error -body {
    dict get {a {p q r s} b {u v x y}} c z
} -result {key "c" not known in dictionary}
test dict-3.11 {dict get command} {dict get [dict create a b c d] a} b
test dict-3.12 {dict get command} -returnCodes error -body {
    dict get
} -result {wrong # args: should be "dict get dictionary ?key ...?"}
test dict-3.13 {dict get command} -body {
    set dict [dict get {a b c d}]
    if {$dict eq "a b c d"} {
	return OK
    } elseif {$dict eq "c d a b"} {
	return reordered
    } else {
	return $dict
    }
} -cleanup {
    unset dict
} -result OK
test dict-3.14 {dict get command} -returnCodes error -body {
    dict get {a b c d} a c
} -result {missing value to go with key}
test dict-3.15 {compiled dict get error cleanliness - Bug 2431847} -body {
    apply {{} {
	dict set a(z) b c
	dict get $a(z) d
    }}
} -returnCodes error -result {key "d" not known in dictionary}
test dict-3.16 {dict/list shimmering - Bug 3004007} {set l [list p 1 p 2 q 3];dict get $l q;set l} {p 1 p 2 q 3}
test dict-3.17 {dict/list shimmering - Bug 3004007} {set l [list p 1 p 2 q 3];dict get $l q;llength $l} 6

test dict-4.1 {dict replace command} {
    dict replace {a b c d}
} {a b c d}
test dict-4.2 {dict replace command} {
    dict replace {a b c d} e f
} {a b c d e f}
test dict-4.3 {dict replace command} {
    dict replace {a b c d} c f
} {a b c f}
test dict-4.4 {dict replace command} {
    dict replace {a b c d} c x a y
} {a y c x}
test dict-4.5 {dict replace command} -returnCodes error -body {
    dict replace
} -result {wrong # args: should be "dict replace dictionary ?key value ...?"}
test dict-4.6 {dict replace command} -returnCodes error -body {
    dict replace {a a} a
} -result {wrong # args: should be "dict replace dictionary ?key value ...?"}
test dict-4.7 {dict replace command} -returnCodes error -body {
    dict replace {a a a} a b
} -result {missing value to go with key}
test dict-4.8 {dict replace command} -returnCodes error -body {
    dict replace [list a a a] a b
} -result {missing value to go with key}
test dict-4.9 {dict replace command} {dict replace [list a a] a b} {a b}
test dict-4.10 {dict replace command} {dict replace [list a a] a b a c} {a c}

test dict-5.1 {dict remove command} {dict remove {a b c d} a} {c d}
test dict-5.2 {dict remove command} {dict remove {a b c d} c} {a b}
test dict-5.3 {dict remove command} {dict remove {a b c d} a c} {}
test dict-5.4 {dict remove command} {dict remove {a b c d} c a} {}
test dict-5.5 {dict remove command} {
    dict remove {a b c d}
} {a b c d}
test dict-5.6 {dict remove command} {dict remove {a b} c} {a b}
test dict-5.7 {dict remove command} -returnCodes error -body {
    dict remove
} -result {wrong # args: should be "dict remove dictionary ?key ...?"}

test dict-6.1 {dict keys command} {dict keys {a b}} a
test dict-6.2 {dict keys command} {dict keys {c d}} c
232
233
234
235
236
237
238
239
240
241
242
243
244


245
246
247
248
249
250
251


252
253
254
255
256
257
258


259
260
261
262
263


264
265
266
267
268


269
270
271
272
273


274
275
276
277
278
279



280
281


282
283
284
285


286
287
288
289


290
291
292
293
294


295
296
297
298


299
300
301
302


303
304
305
306


307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335


336
337
338
339
340


341
342
343
344


345
346
347
348


349
350
351
352


353
354
355
356


357
358
359
360


361
362
363
364
365
366
367
368
369
370


371
372
373
374
375
376
377
378
379



380
381
382
383


384
385
386
387
388


389
390
391
392


393
394
395
396


397
398
399
400


401
402
403
404


405
406
407
408


409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426



427
428
429
430
431
432
433
test dict-10.3 {dict info command} -returnCodes error -body {
    dict info {} x
} -result {wrong # args: should be "dict info dictionary"}
test dict-10.4 {dict info command} -returnCodes error -body {
    dict info x
} -result {missing value to go with key}

test dict-11.1 {dict incr command: unshared value} {
    set dictv [dict create \
	    a [string index "=0=" 1] \
	    b [expr {1+2}] \
	    c [expr {wide(0x80000000)+1}]]
    getOrder [dict incr dictv a] a b c


} {a 1 b 3 c 2147483649 3}
test dict-11.2 {dict incr command: unshared value} {
    set dictv [dict create \
	    a [string index "=0=" 1] \
	    b [expr {1+2}] \
	    c [expr {wide(0x80000000)+1}]]
    getOrder [dict incr dictv b] a b c


} {a 0 b 4 c 2147483649 3}
test dict-11.3 {dict incr command: unshared value} {
    set dictv [dict create \
	    a [string index "=0=" 1] \
	    b [expr {1+2}] \
	    c [expr {wide(0x80000000)+1}]]
    getOrder [dict incr dictv c] a b c


} {a 0 b 3 c 2147483650 3}
test dict-11.4 {dict incr command: shared value} {
    set dictv [dict create a 0 b [expr {1+2}] c [expr {wide(0x80000000)+1}]]
    set sharing [dict values $dictv]
    getOrder [dict incr dictv a] a b c


} {a 1 b 3 c 2147483649 3}
test dict-11.5 {dict incr command: shared value} {
    set dictv [dict create a 0 b [expr {1+2}] c [expr {wide(0x80000000)+1}]]
    set sharing [dict values $dictv]
    getOrder [dict incr dictv b] a b c


} {a 0 b 4 c 2147483649 3}
test dict-11.6 {dict incr command: shared value} {
    set dictv [dict create a 0 b [expr {1+2}] c [expr {wide(0x80000000)+1}]]
    set sharing [dict values $dictv]
    getOrder [dict incr dictv c] a b c


} {a 0 b 3 c 2147483650 3}
test dict-11.7 {dict incr command: unknown values} {
    set dictv [dict create a 0 b [expr {1+2}] c [expr {wide(0x80000000)+1}]]
    getOrder [dict incr dictv d] a b c d
} {a 0 b 3 c 2147483649 d 1 4}
test dict-11.8 {dict incr command} {



    set dictv {a 1}
    dict incr dictv a 2


} {a 3}
test dict-11.9 {dict incr command} -returnCodes error -body {
    set dictv {a dummy}
    dict incr dictv a


} -result {expected integer but got "dummy"}
test dict-11.10 {dict incr command} -returnCodes error -body {
    set dictv {a 1}
    dict incr dictv a dummy


} -result {expected integer but got "dummy"}
test dict-11.11 {dict incr command} -setup {
    catch {unset dictv}
} -body {
    dict incr dictv a


} -result {a 1}
test dict-11.12 {dict incr command} -returnCodes error -body {
    set dictv a
    dict incr dictv a


} -result {missing value to go with key}
test dict-11.13 {dict incr command} -returnCodes error -body {
    set dictv a
    dict incr dictv a a a


} -result {wrong # args: should be "dict incr varName key ?increment?"}
test dict-11.14 {dict incr command} -returnCodes error -body {
    set dictv a
    dict incr dictv


} -result {wrong # args: should be "dict incr varName key ?increment?"}
test dict-11.15 {dict incr command: write failure} -setup {
    catch {unset dictVar}
} -body {
    set dictVar(block) {}
    dict incr dictVar a
} -returnCodes error -cleanup {
    catch {unset dictVar}
} -result {can't set "dictVar": variable is array}
test dict-11.16 {dict incr command: compilation} {
    apply {{} {
	set v {a 0 b 0 c 0}
	dict incr v a
	dict incr v b 1
	dict incr v c 2
	dict incr v d 3
	list [dict get $v a] [dict get $v b] [dict get $v c] [dict get $v d]
    }}
} {1 1 2 3}
test dict-11.17 {dict incr command: compilation} {
    apply {{} {
	set dictv {a 1}
	dict incr dictv a 2
    }}
} {a 3}

test dict-12.1 {dict lappend command} {
    set dictv {a a}
    dict lappend dictv a


} {a a}
test dict-12.2 {dict lappend command} {
    set dictv {a a}
    set sharing [dict values $dictv]
    dict lappend dictv a b


} {a {a b}}
test dict-12.3 {dict lappend command} {
    set dictv {a a}
    dict lappend dictv a b c


} {a {a b c}}
test dict-12.2.1 {dict lappend command} {
    set dictv [dict create a [string index =a= 1]]
    dict lappend dictv a b


} {a {a b}}
test dict-12.4 {dict lappend command} {
    set dictv {}
    dict lappend dictv a x y z


} {a {x y z}}
test dict-12.5 {dict lappend command} {
    catch {unset dictv}
    dict lappend dictv a b


} {a b}
test dict-12.6 {dict lappend command} -returnCodes error -body {
    set dictv a
    dict lappend dictv a a


} -result {missing value to go with key}
test dict-12.7 {dict lappend command} -returnCodes error -body {
    dict lappend
} -result {wrong # args: should be "dict lappend varName key ?value ...?"}
test dict-12.8 {dict lappend command} -returnCodes error -body {
    dict lappend dictv
} -result {wrong # args: should be "dict lappend varName key ?value ...?"}
test dict-12.9 {dict lappend command} -returnCodes error -body {
    set dictv [dict create a "\{"]
    dict lappend dictv a a


} -result {unmatched open brace in list}
test dict-12.10 {dict lappend command: write failure} -setup {
    catch {unset dictVar}
} -body {
    set dictVar(block) {}
    dict lappend dictVar a x
} -returnCodes error -cleanup {
    catch {unset dictVar}
} -result {can't set "dictVar": variable is array}




test dict-13.1 {dict append command} {
    set dictv {a a}
    dict append dictv a


} {a a}
test dict-13.2 {dict append command} {
    set dictv {a a}
    set sharing [dict values $dictv]
    dict append dictv a b


} {a ab}
test dict-13.3 {dict append command} {
    set dictv {a a}
    dict append dictv a b c


} {a abc}
test dict-13.2.1 {dict append command} {
    set dictv [dict create a [string index =a= 1]]
    dict append dictv a b


} {a ab}
test dict-13.4 {dict append command} {
    set dictv {}
    dict append dictv a x y z


} {a xyz}
test dict-13.5 {dict append command} {
    catch {unset dictv}
    dict append dictv a b


} {a b}
test dict-13.6 {dict append command} -returnCodes error -body {
    set dictv a
    dict append dictv a a


} -result {missing value to go with key}
test dict-13.7 {dict append command} -returnCodes error -body {
    dict append
} -result {wrong # args: should be "dict append varName key ?value ...?"}
test dict-13.8 {dict append command} -returnCodes error -body {
    dict append dictv
} -result {wrong # args: should be "dict append varName key ?value ...?"}
test dict-13.9 {dict append command: write failure} -setup {
    catch {unset dictVar}
} -body {
    set dictVar(block) {}
    dict append dictVar a x
} -returnCodes error -cleanup {
    catch {unset dictVar}
} -result {can't set "dictVar": variable is array}
test dict-13.10 {compiled dict append: crash case} {
    apply {{} {dict append dictVar a o k}}
} {a ok}




test dict-14.1 {dict for command: syntax} -returnCodes error -body {
    dict for
} -result {wrong # args: should be "dict for {keyVar valueVar} dictionary script"}
test dict-14.2 {dict for command: syntax} -returnCodes error -body {
    dict for x
} -result {wrong # args: should be "dict for {keyVar valueVar} dictionary script"}







|




|
>
>
|
|




|
>
>
|
|




|
>
>
|
|


|
>
>
|
|


|
>
>
|
|


|
>
>
|
|

|
|
<
>
>
>


>
>
|



>
>




>
>


|


>
>




>
>




>
>




>
>


|




|


















|


>
>
|
|



>
>
|
|


>
>
|
|


>
>
|
|


>
>
|
|
|

>
>
|



>
>










>
>


|




|

>
>
>

|


>
>
|
|



>
>
|
|


>
>
|
|


>
>
|
|


>
>
|
|
|

>
>
|



>
>








|




|




>
>
>







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
test dict-10.3 {dict info command} -returnCodes error -body {
    dict info {} x
} -result {wrong # args: should be "dict info dictionary"}
test dict-10.4 {dict info command} -returnCodes error -body {
    dict info x
} -result {missing value to go with key}

test dict-11.1 {dict incr command: unshared value} -body {
    set dictv [dict create \
	    a [string index "=0=" 1] \
	    b [expr {1+2}] \
	    c [expr {wide(0x80000000)+1}]]
    dict incr dictv a
} -cleanup {
    unset dictv
} -result {a 1 b 3 c 2147483649}
test dict-11.2 {dict incr command: unshared value} -body {
    set dictv [dict create \
	    a [string index "=0=" 1] \
	    b [expr {1+2}] \
	    c [expr {wide(0x80000000)+1}]]
    dict incr dictv b
} -cleanup {
    unset dictv
} -result {a 0 b 4 c 2147483649}
test dict-11.3 {dict incr command: unshared value} -body {
    set dictv [dict create \
	    a [string index "=0=" 1] \
	    b [expr {1+2}] \
	    c [expr {wide(0x80000000)+1}]]
    dict incr dictv c
} -cleanup {
    unset dictv
} -result {a 0 b 3 c 2147483650}
test dict-11.4 {dict incr command: shared value} -body {
    set dictv [dict create a 0 b [expr {1+2}] c [expr {wide(0x80000000)+1}]]
    set sharing [dict values $dictv]
    dict incr dictv a
} -cleanup {
    unset dictv sharing
} -result {a 1 b 3 c 2147483649}
test dict-11.5 {dict incr command: shared value} -body {
    set dictv [dict create a 0 b [expr {1+2}] c [expr {wide(0x80000000)+1}]]
    set sharing [dict values $dictv]
    dict incr dictv b
} -cleanup {
    unset dictv sharing
} -result {a 0 b 4 c 2147483649}
test dict-11.6 {dict incr command: shared value} -body {
    set dictv [dict create a 0 b [expr {1+2}] c [expr {wide(0x80000000)+1}]]
    set sharing [dict values $dictv]
    dict incr dictv c
} -cleanup {
    unset dictv sharing
} -result {a 0 b 3 c 2147483650}
test dict-11.7 {dict incr command: unknown values} -body {
    set dictv [dict create a 0 b [expr {1+2}] c [expr {wide(0x80000000)+1}]]
    dict incr dictv d
} -cleanup {

    unset dictv
} -result {a 0 b 3 c 2147483649 d 1}
test dict-11.8 {dict incr command} -body {
    set dictv {a 1}
    dict incr dictv a 2
} -cleanup {
    unset dictv
} -result {a 3}
test dict-11.9 {dict incr command} -returnCodes error -body {
    set dictv {a dummy}
    dict incr dictv a
} -cleanup {
    unset dictv
} -result {expected integer but got "dummy"}
test dict-11.10 {dict incr command} -returnCodes error -body {
    set dictv {a 1}
    dict incr dictv a dummy
} -cleanup {
    unset dictv
} -result {expected integer but got "dummy"}
test dict-11.11 {dict incr command} -setup {
    unset -nocomplain dictv
} -body {
    dict incr dictv a
} -cleanup {
    unset dictv
} -result {a 1}
test dict-11.12 {dict incr command} -returnCodes error -body {
    set dictv a
    dict incr dictv a
} -cleanup {
    unset dictv
} -result {missing value to go with key}
test dict-11.13 {dict incr command} -returnCodes error -body {
    set dictv a
    dict incr dictv a a a
} -cleanup {
    unset dictv
} -result {wrong # args: should be "dict incr varName key ?increment?"}
test dict-11.14 {dict incr command} -returnCodes error -body {
    set dictv a
    dict incr dictv
} -cleanup {
    unset dictv
} -result {wrong # args: should be "dict incr varName key ?increment?"}
test dict-11.15 {dict incr command: write failure} -setup {
    unset -nocomplain dictVar
} -body {
    set dictVar(block) {}
    dict incr dictVar a
} -returnCodes error -cleanup {
    unset dictVar
} -result {can't set "dictVar": variable is array}
test dict-11.16 {dict incr command: compilation} {
    apply {{} {
	set v {a 0 b 0 c 0}
	dict incr v a
	dict incr v b 1
	dict incr v c 2
	dict incr v d 3
	list [dict get $v a] [dict get $v b] [dict get $v c] [dict get $v d]
    }}
} {1 1 2 3}
test dict-11.17 {dict incr command: compilation} {
    apply {{} {
	set dictv {a 1}
	dict incr dictv a 2
    }}
} {a 3}

test dict-12.1 {dict lappend command} -body {
    set dictv {a a}
    dict lappend dictv a
} -cleanup {
    unset dictv
} -result {a a}
test dict-12.2 {dict lappend command} -body {
    set dictv {a a}
    set sharing [dict values $dictv]
    dict lappend dictv a b
} -cleanup {
    unset dictv sharing
} -result {a {a b}}
test dict-12.3 {dict lappend command} -body {
    set dictv {a a}
    dict lappend dictv a b c
} -cleanup {
    unset dictv
} -result {a {a b c}}
test dict-12.2.1 {dict lappend command} -body {
    set dictv [dict create a [string index =a= 1]]
    dict lappend dictv a b
} -cleanup {
    unset dictv
} -result {a {a b}}
test dict-12.4 {dict lappend command} -body {
    set dictv {}
    dict lappend dictv a x y z
} -cleanup {
    unset dictv
} -result {a {x y z}}
test dict-12.5 {dict lappend command} -body {
    unset -nocomplain dictv
    dict lappend dictv a b
} -cleanup {
    unset dictv
} -result {a b}
test dict-12.6 {dict lappend command} -returnCodes error -body {
    set dictv a
    dict lappend dictv a a
} -cleanup {
    unset dictv
} -result {missing value to go with key}
test dict-12.7 {dict lappend command} -returnCodes error -body {
    dict lappend
} -result {wrong # args: should be "dict lappend varName key ?value ...?"}
test dict-12.8 {dict lappend command} -returnCodes error -body {
    dict lappend dictv
} -result {wrong # args: should be "dict lappend varName key ?value ...?"}
test dict-12.9 {dict lappend command} -returnCodes error -body {
    set dictv [dict create a "\{"]
    dict lappend dictv a a
} -cleanup {
    unset dictv
} -result {unmatched open brace in list}
test dict-12.10 {dict lappend command: write failure} -setup {
    unset -nocomplain dictVar
} -body {
    set dictVar(block) {}
    dict lappend dictVar a x
} -returnCodes error -cleanup {
    unset dictVar
} -result {can't set "dictVar": variable is array}
test dict-12.11 {compiled dict append: invalidate string rep - Bug 3079830} {
    apply {{} {set d {a 1 b 2 c 3}; dict lappend d b 22}}
} {a 1 b {2 22} c 3}

test dict-13.1 {dict append command} -body {
    set dictv {a a}
    dict append dictv a
} -cleanup {
    unset dictv
} -result {a a}
test dict-13.2 {dict append command} -body {
    set dictv {a a}
    set sharing [dict values $dictv]
    dict append dictv a b
} -cleanup {
    unset dictv sharing
} -result {a ab}
test dict-13.3 {dict append command} -body {
    set dictv {a a}
    dict append dictv a b c
} -cleanup {
    unset dictv
} -result {a abc}
test dict-13.2.1 {dict append command} -body {
    set dictv [dict create a [string index =a= 1]]
    dict append dictv a b
} -cleanup {
    unset dictv
} -result {a ab}
test dict-13.4 {dict append command} -body {
    set dictv {}
    dict append dictv a x y z
} -cleanup {
    unset dictv
} -result {a xyz}
test dict-13.5 {dict append command} -body {
    unset -nocomplain dictv
    dict append dictv a b
} -cleanup {
    unset dictv
} -result {a b}
test dict-13.6 {dict append command} -returnCodes error -body {
    set dictv a
    dict append dictv a a
} -cleanup {
    unset dictv
} -result {missing value to go with key}
test dict-13.7 {dict append command} -returnCodes error -body {
    dict append
} -result {wrong # args: should be "dict append varName key ?value ...?"}
test dict-13.8 {dict append command} -returnCodes error -body {
    dict append dictv
} -result {wrong # args: should be "dict append varName key ?value ...?"}
test dict-13.9 {dict append command: write failure} -setup {
    unset -nocomplain dictVar
} -body {
    set dictVar(block) {}
    dict append dictVar a x
} -returnCodes error -cleanup {
    unset dictVar
} -result {can't set "dictVar": variable is array}
test dict-13.10 {compiled dict append: crash case} {
    apply {{} {dict append dictVar a o k}}
} {a ok}
test dict-13.11 {compiled dict append: invalidate string rep - Bug 3079830} {
    apply {{} {set d {a 1 b 2 c 3}; dict append d b 22}}
} {a 1 b 222 c 3}

test dict-14.1 {dict for command: syntax} -returnCodes error -body {
    dict for
} -result {wrong # args: should be "dict for {keyVar valueVar} dictionary script"}
test dict-14.2 {dict for command: syntax} -returnCodes error -body {
    dict for x
} -result {wrong # args: should be "dict for {keyVar valueVar} dictionary script"}
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463


464
465
466
467
468
469
470
471
472
473
474
475
476
477


478
479
480
481
482
483
484
485
486


487
488
489
490
491
492
493
494


495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523


524
525
526
527
528


529
530
531
532
533
534
535
536
537
538


539
540
541
542
543
544
545
546
} -result {must have exactly two variable names}
test dict-14.6 {dict for command: syntax} -returnCodes error -body {
    dict for {x x x} x x
} -result {must have exactly two variable names}
test dict-14.7 {dict for command: syntax} -returnCodes error -body {
    dict for "\{x" x x
} -result {unmatched open brace in list}
test dict-14.8 {dict for command} {
    # This test confirms that [dict keys], [dict values] and [dict for]
    # all traverse a dictionary in the same order.
    set dictv {a A b B c C}
    set keys {}
    set values {}
    dict for {k v} $dictv {
	lappend keys $k
	lappend values $v
    }
    set result [expr {
	$keys eq [dict keys $dictv] && $values eq [dict values $dictv]
    }]
    expr {$result ? "YES" : [list "NO" $dictv $keys $values]}
} YES


test dict-14.9 {dict for command} {
    dict for {k v} {} {
	error "unexpected execution of 'dict for' body"
    }
} {}
test dict-14.10 {dict for command: script results} {
    set times 0
    dict for {k v} {a a b b} {
	incr times
	continue
	error "shouldn't get here"
    }
    return $times
} 2


test dict-14.11 {dict for command: script results} {
    set times 0
    dict for {k v} {a a b b} {
	incr times
	break
	error "shouldn't get here"
    }
    return $times
} 1


test dict-14.12 {dict for command: script results} {
    set times 0
    list [catch {
	dict for {k v} {a a b b} {
	    incr times
	    error test
	}
    } msg] $msg $times $::errorInfo


} {1 test 1 {test
    while executing
"error test"
    ("dict for" body line 3)
    invoked from within
"dict for {k v} {a a b b} {
	    incr times
	    error test
	}"}}
test dict-14.13 {dict for command: script results} {
    apply {{} {
	dict for {k v} {a b} {
	    return ok,$k,$v
	    error "skipped return completely"
	}
	error "return didn't go far enough"
    }}
} ok,a,b
test dict-14.14 {dict for command: handle representation loss} {
    set dictVar {a b c d e f g h}
    set keys {}
    set values {}
    dict for {k v} $dictVar {
	if {[llength $dictVar]} {
	    lappend keys $k
	    lappend values $v
	}
    }
    list [lsort $keys] [lsort $values]


} {{a c e g} {b d f h}}
test dict-14.15 {dict for command: keys are unique and iterated over once only} {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    catch {unset accum}
    array set accum {}


    dict for {k v} $dictVar {
	append accum($k) $v,
    }
    set result [lsort [array names accum]]
    lappend result :
    foreach k $result {
	catch {lappend result $accum($k)}
    }
    catch {unset accum}
    set result


} {a1 a2 b1 b2 bar foo : a, b, c, d, foo, bar,}
test dict-14.16 {dict for command in compilation context} {
    apply {{} {
	set res {x x x x x x}
	dict for {k v} {a 0 b 1 c 2 d 3 e 4 f 5} {
	    lset res $v $k
	    continue
	}







|













|
>
>





|







|
>
>
|







|
>
>
|







>
>
|

















|










>
>
|
|
<
|

>
>








<
|
>
>
|







511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604

605
606
607
608
609
610
611
612
613
614
615
616

617
618
619
620
621
622
623
624
625
626
627
} -result {must have exactly two variable names}
test dict-14.6 {dict for command: syntax} -returnCodes error -body {
    dict for {x x x} x x
} -result {must have exactly two variable names}
test dict-14.7 {dict for command: syntax} -returnCodes error -body {
    dict for "\{x" x x
} -result {unmatched open brace in list}
test dict-14.8 {dict for command} -body {
    # This test confirms that [dict keys], [dict values] and [dict for]
    # all traverse a dictionary in the same order.
    set dictv {a A b B c C}
    set keys {}
    set values {}
    dict for {k v} $dictv {
	lappend keys $k
	lappend values $v
    }
    set result [expr {
	$keys eq [dict keys $dictv] && $values eq [dict values $dictv]
    }]
    expr {$result ? "YES" : [list "NO" $dictv $keys $values]}
} -cleanup {
    unset result keys values k v dictv
} -result YES
test dict-14.9 {dict for command} {
    dict for {k v} {} {
	error "unexpected execution of 'dict for' body"
    }
} {}
test dict-14.10 {dict for command: script results} -body {
    set times 0
    dict for {k v} {a a b b} {
	incr times
	continue
	error "shouldn't get here"
    }
    return $times
} -cleanup {
    unset times k v
} -result 2
test dict-14.11 {dict for command: script results} -body {
    set times 0
    dict for {k v} {a a b b} {
	incr times
	break
	error "shouldn't get here"
    }
    return $times
} -cleanup {
    unset times k v
} -result 1
test dict-14.12 {dict for command: script results} -body {
    set times 0
    list [catch {
	dict for {k v} {a a b b} {
	    incr times
	    error test
	}
    } msg] $msg $times $::errorInfo
} -cleanup {
    unset times k v msg
} -result {1 test 1 {test
    while executing
"error test"
    ("dict for" body line 3)
    invoked from within
"dict for {k v} {a a b b} {
	    incr times
	    error test
	}"}}
test dict-14.13 {dict for command: script results} {
    apply {{} {
	dict for {k v} {a b} {
	    return ok,$k,$v
	    error "skipped return completely"
	}
	error "return didn't go far enough"
    }}
} ok,a,b
test dict-14.14 {dict for command: handle representation loss} -body {
    set dictVar {a b c d e f g h}
    set keys {}
    set values {}
    dict for {k v} $dictVar {
	if {[llength $dictVar]} {
	    lappend keys $k
	    lappend values $v
	}
    }
    list [lsort $keys] [lsort $values]
} -cleanup {
    unset dictVar keys values k v
} -result {{a c e g} {b d f h}}
test dict-14.15 {dict for command: keys are unique and iterated over once only} -setup {

    unset -nocomplain accum
    array set accum {}
} -body {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict for {k v} $dictVar {
	append accum($k) $v,
    }
    set result [lsort [array names accum]]
    lappend result :
    foreach k $result {
	catch {lappend result $accum($k)}
    }

    return $result
} -cleanup {
    unset dictVar k v result accum
} -result {a1 a2 b1 b2 bar foo : a, b, c, d, foo, bar,}
test dict-14.16 {dict for command in compilation context} {
    apply {{} {
	set res {x x x x x x}
	dict for {k v} {a 0 b 1 c 2 d 3 e 4 f 5} {
	    lset res $v $k
	    continue
	}
572
573
574
575
576
577
578
579
580
581


582
583
584
585


586
587
588
589


590
591
592
593


594
595
596
597


598
599
600
601


602
603
604
605


606
607
608

609


610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631


632
633
634
635
636


637
638
639
640


641
642
643
644


645
646
647
648


649
650
651
652


653
654
655
656


657
658
659
660
661


662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677


678
679
680
681
682


683
684
685


686
687
688
689
690
691
692
693
694
695
696
697
698


699
700
701
702
703


704
705
706


707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723


724
725
726
727
728


729
730
731
732


733
734
735
736
737
738
739
740

741
742
743
744
745


746
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
791
792


793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808

809



810








811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
	dict for {a b} $x {}
	concat "c=$y,$args"
    }} {} 1 2 3
} {c=1,2 3}
# There's probably a lot more tests to add here. Really ought to use a
# coverage tool for this job...

test dict-15.1 {dict set command} {
    set dictVar {}
    dict set dictVar a x


} {a x}
test dict-15.2 {dict set command} {
    set dictvar {a {}}
    dict set dictvar a b x


} {a {b x}}
test dict-15.3 {dict set command} {
    set dictvar {a {b {}}}
    dict set dictvar a b c x


} {a {b {c x}}}
test dict-15.4 {dict set command} {
    set dictVar {a y}
    dict set dictVar a x


} {a x}
test dict-15.5 {dict set command} {
    set dictVar {a {b y}}
    dict set dictVar a b x


} {a {b x}}
test dict-15.6 {dict set command} {
    set dictVar {a {b {c y}}}
    dict set dictVar a b c x


} {a {b {c x}}}
test dict-15.7 {dict set command: path creation} {
    set dictVar {}
    dict set dictVar a b x


} {a {b x}}
test dict-15.8 {dict set command: creates variables} {
    catch {unset dictVar}

    dict set dictVar a x


    set dictVar
} {a x}
test dict-15.9 {dict set command: write failure} -setup {
    catch {unset dictVar}
} -body {
    set dictVar(block) {}
    dict set dictVar a x
} -returnCodes error -cleanup {
    catch {unset dictVar}
} -result {can't set "dictVar": variable is array}
test dict-15.10 {dict set command: syntax} -returnCodes error -body {
    dict set
} -result {wrong # args: should be "dict set varName key ?key ...? value"}
test dict-15.11 {dict set command: syntax} -returnCodes error -body {
    dict set a
} -result {wrong # args: should be "dict set varName key ?key ...? value"}
test dict-15.12 {dict set command: syntax} -returnCodes error -body {
    dict set a a
} -result {wrong # args: should be "dict set varName key ?key ...? value"}
test dict-15.13 {dict set command} -returnCodes error -body {
    set dictVar a
    dict set dictVar b c


} -result {missing value to go with key}

test dict-16.1 {dict unset command} {
    set dictVar {a b c d}
    dict unset dictVar a


} {c d}
test dict-16.2 {dict unset command} {
    set dictVar {a b c d}
    dict unset dictVar c


} {a b}
test dict-16.3 {dict unset command} {
    set dictVar {a b}
    dict unset dictVar c


} {a b}
test dict-16.4 {dict unset command} {
    set dictVar {a {b c d e}}
    dict unset dictVar a b


} {a {d e}}
test dict-16.5 {dict unset command} -returnCodes error -body {
    set dictVar a
    dict unset dictVar a


} -result {missing value to go with key}
test dict-16.6 {dict unset command} -returnCodes error -body {
    set dictVar {a b}
    dict unset dictVar c d


} -result {key "c" not known in dictionary}
test dict-16.7 {dict unset command} -setup {
    catch {unset dictVar}
} -body {
    list [info exists dictVar] [dict unset dictVar a] [info exists dictVar]


} -result {0 {} 1}
test dict-16.8 {dict unset command} -returnCodes error -body {
    dict unset dictVar
} -result {wrong # args: should be "dict unset varName key ?key ...?"}
test dict-16.9 {dict unset command: write failure} -setup {
    catch {unset dictVar}
} -body {
    set dictVar(block) {}
    dict unset dictVar a
} -returnCodes error -cleanup {
    catch {unset dictVar}
} -result {can't set "dictVar": variable is array}

test dict-17.1 {dict filter command: key} {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict filter $dictVar key a2


} {a2 b}
test dict-17.2 {dict filter command: key} {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict size [dict filter $dictVar key *]
} 6


test dict-17.3 {dict filter command: key} {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    getOrder [dict filter $dictVar key ???] bar foo


} {bar foo foo bar 2}
test dict-17.4 {dict filter command: key - no patterns} {
    dict filter {a b c d} key
} {}
test dict-17.4.1 {dict filter command: key - many patterns} {
    dict filter {a1 a a2 b b1 c b2 d foo bar bar foo} key a? b?
} {a1 a a2 b b1 c b2 d}
test dict-17.5 {dict filter command: key - bad dict} -returnCodes error -body {
    dict filter {a b c} key
} -result {missing value to go with key}
test dict-17.6 {dict filter command: value} {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict filter $dictVar value c


} {b1 c}
test dict-17.7 {dict filter command: value} {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict size [dict filter $dictVar value *]
} 6


test dict-17.8 {dict filter command: value} {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    getOrder [dict filter $dictVar value ???] bar foo


} {bar foo foo bar 2}
test dict-17.9 {dict filter command: value - no patterns} {
    dict filter {a b c d} value
} {}
test dict-17.9.1 {dict filter command: value - many patterns} {
    dict filter {a a1 b a2 c b1 foo bar bar foo d b2} value a? b?
} {a a1 b a2 c b1 d b2}
test dict-17.10 {dict filter command: value - bad dict} -body {
    dict filter {a b c} value a
} -returnCodes error -result {missing value to go with key}
test dict-17.11 {dict filter command: script} {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    set n 0
    list [getOrder [dict filter $dictVar script {k v} {
	incr n
	expr {[string length $k] == [string length $v]}
    }] bar foo] $n


} {{bar foo foo bar 2} 6}
test dict-17.12 {dict filter command: script} -returnCodes error -body {
    dict filter {a b} script {k v} {
	concat $k $v
    }


} -result {expected boolean value but got "a b"}
test dict-17.13 {dict filter command: script} {
    list [catch {dict filter {a b} script {k v} {error x}} msg] $msg \
	    $::errorInfo


} {1 x {x
    while executing
"error x"
    ("dict filter" script line 1)
    invoked from within
"dict filter {a b} script {k v} {error x}"}}
test dict-17.14 {dict filter command: script} {
    set n 0

    list [dict filter {a b c d} script {k v} {
	incr n
	break
	error boom!
    }] $n


} {{} 1}
test dict-17.15 {dict filter command: script} {
    set n 0

    list [dict filter {a b c d} script {k v} {
	incr n
	continue
	error boom!
    }] $n


} {{} 2}
test dict-17.16 {dict filter command: script} {
    apply {{} {
	dict filter {a b} script {k v} {
	    return ok,$k,$v
	    error "skipped return completely"
	}
	error "return didn't go far enough"
    }}
} ok,a,b
test dict-17.17 {dict filter command: script} {
    dict filter {a b} script {k k} {continue}


    set k
} b
test dict-17.18 {dict filter command: script} -returnCodes error -body {
    dict filter {a b} script {k k}
} -result {wrong # args: should be "dict filter dictionary script {keyVar valueVar} filterScript"}
test dict-17.19 {dict filter command: script} -returnCodes error -body {
    dict filter {a b} script k {continue}
} -result {must have exactly two variable names}
test dict-17.20 {dict filter command: script} -returnCodes error -body {
    dict filter {a b} script "\{k v" {continue}
} -result {unmatched open brace in list}
test dict-17.21 {dict filter command} -returnCodes error -body {
    dict filter {a b}
} -result {wrong # args: should be "dict filter dictionary filterType ?arg ...?"}
test dict-17.22 {dict filter command} -returnCodes error -body {
    dict filter {a b} JUNK
} -result {bad filterType "JUNK": must be key, script, or value}
test dict-17.23 {dict filter command} -returnCodes error -body {
    dict filter a key *
} -result {missing value to go with key}

test dict-18.1 {dict-list relationship} {
    -body {
        # Test that any internal conversion between list and dict
        # does not change the object
        set l [list 1 2 3 4 5 6 7 8 9 0 q w e r t y]
        dict values $l


        set l
    }
    -result {1 2 3 4 5 6 7 8 9 0 q w e r t y}
}
test dict-18.2 {dict-list relationship} {
    -body {
        # Test that the dictionary is a valid list
        set d [dict create "abc def" 0 "a\{b" 1 "c\}d" 2]
        for {set t 0} {$t < 5} {incr t} {
            llength $d
            dict lappend d "abc def" "\}\{"
            dict append  d "a\{b" "\}"
            dict incr    d "c\}d" 1
        }
        llength $d
    }

    -result 6



}









# This is a test for a specific bug.
# It shows a bad ref counter when running with memdebug on.
test dict-19.1 {memory bug} {
    apply {{} {
        set successors [dict create x {c d}]
        dict set successors x a b
        dict get $successors x
    }}
} [dict create c d a b]
test dict-19.2 {dict: testing for leaks} -setup {
    proc getbytes {} {
        set lines [split [memory info] "\n"]
        lindex [lindex $lines 3] 3
    }
} -constraints memory -body {
    # This test is made to stress object reference management
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {
	apply {{} {
	    # A shared invalid dictinary
	    set apa {a {}b c d}
	    set bepa $apa
	    catch {dict replace $apa e f}
	    catch {dict remove  $apa c d}
	    catch {dict incr    apa  a 5}







|


>
>
|
|


>
>
|
|


>
>
|
|


>
>
|
|


>
>
|
|


>
>
|
|


>
>
|
|
|
>

>
>
|
|

|




|













>
>


|


>
>
|
|


>
>
|
|


>
>
|
|


>
>
|



>
>




>
>


|


>
>





|




|


|


>
>
|
|


|
>
>
|

|
>
>
|









|


>
>
|
|


|
>
>
|

|
>
>
|









|


|


|
>
>
|




>
>

|


>
>
|





|

>





>
>
|
|

>





>
>
|









|

>
>
|
|



















|
<
|
|
|
|
>
>
|
<
|
<
|
<
|
|
|
|
|
|
|
|
|
|
>
|
>
>
>
|
>
>
>
>
>
>
>
>










|
<
<
<
<
<

|
<







653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
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
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927

928
929
930
931
932
933
934

935

936

937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971





972
973

974
975
976
977
978
979
980
	dict for {a b} $x {}
	concat "c=$y,$args"
    }} {} 1 2 3
} {c=1,2 3}
# There's probably a lot more tests to add here. Really ought to use a
# coverage tool for this job...

test dict-15.1 {dict set command} -body {
    set dictVar {}
    dict set dictVar a x
} -cleanup {
    unset dictVar
} -result {a x}
test dict-15.2 {dict set command} -body {
    set dictvar {a {}}
    dict set dictvar a b x
} -cleanup {
    unset dictvar
} -result {a {b x}}
test dict-15.3 {dict set command} -body {
    set dictvar {a {b {}}}
    dict set dictvar a b c x
} -cleanup {
    unset dictvar
} -result {a {b {c x}}}
test dict-15.4 {dict set command} -body {
    set dictVar {a y}
    dict set dictVar a x
} -cleanup {
    unset dictVar
} -result {a x}
test dict-15.5 {dict set command} -body {
    set dictVar {a {b y}}
    dict set dictVar a b x
} -cleanup {
    unset dictVar
} -result {a {b x}}
test dict-15.6 {dict set command} -body {
    set dictVar {a {b {c y}}}
    dict set dictVar a b c x
} -cleanup {
    unset dictVar
} -result {a {b {c x}}}
test dict-15.7 {dict set command: path creation} -body {
    set dictVar {}
    dict set dictVar a b x
} -cleanup {
    unset dictVar
} -result {a {b x}}
test dict-15.8 {dict set command: creates variables} -setup {
    unset -nocomplain dictVar
} -body {
    dict set dictVar a x
    return $dictVar
} -cleanup {
    unset dictVar
} -result {a x}
test dict-15.9 {dict set command: write failure} -setup {
    unset -nocomplain dictVar
} -body {
    set dictVar(block) {}
    dict set dictVar a x
} -returnCodes error -cleanup {
    unset dictVar
} -result {can't set "dictVar": variable is array}
test dict-15.10 {dict set command: syntax} -returnCodes error -body {
    dict set
} -result {wrong # args: should be "dict set varName key ?key ...? value"}
test dict-15.11 {dict set command: syntax} -returnCodes error -body {
    dict set a
} -result {wrong # args: should be "dict set varName key ?key ...? value"}
test dict-15.12 {dict set command: syntax} -returnCodes error -body {
    dict set a a
} -result {wrong # args: should be "dict set varName key ?key ...? value"}
test dict-15.13 {dict set command} -returnCodes error -body {
    set dictVar a
    dict set dictVar b c
} -cleanup {
    unset dictVar
} -result {missing value to go with key}

test dict-16.1 {dict unset command} -body {
    set dictVar {a b c d}
    dict unset dictVar a
} -cleanup {
    unset dictVar
} -result {c d}
test dict-16.2 {dict unset command} -body {
    set dictVar {a b c d}
    dict unset dictVar c
} -cleanup {
    unset dictVar
} -result {a b}
test dict-16.3 {dict unset command} -body {
    set dictVar {a b}
    dict unset dictVar c
} -cleanup {
    unset dictVar
} -result {a b}
test dict-16.4 {dict unset command} -body {
    set dictVar {a {b c d e}}
    dict unset dictVar a b
} -cleanup {
    unset dictVar
} -result {a {d e}}
test dict-16.5 {dict unset command} -returnCodes error -body {
    set dictVar a
    dict unset dictVar a
} -cleanup {
    unset dictVar
} -result {missing value to go with key}
test dict-16.6 {dict unset command} -returnCodes error -body {
    set dictVar {a b}
    dict unset dictVar c d
} -cleanup {
    unset dictVar
} -result {key "c" not known in dictionary}
test dict-16.7 {dict unset command} -setup {
    unset -nocomplain dictVar
} -body {
    list [info exists dictVar] [dict unset dictVar a] [info exists dictVar]
} -cleanup {
    unset dictVar
} -result {0 {} 1}
test dict-16.8 {dict unset command} -returnCodes error -body {
    dict unset dictVar
} -result {wrong # args: should be "dict unset varName key ?key ...?"}
test dict-16.9 {dict unset command: write failure} -setup {
    unset -nocomplain dictVar
} -body {
    set dictVar(block) {}
    dict unset dictVar a
} -returnCodes error -cleanup {
    unset dictVar
} -result {can't set "dictVar": variable is array}

test dict-17.1 {dict filter command: key} -body {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict filter $dictVar key a2
} -cleanup {
    unset dictVar
} -result {a2 b}
test dict-17.2 {dict filter command: key} -body {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict size [dict filter $dictVar key *]
} -cleanup {
    unset dictVar
} -result 6
test dict-17.3 {dict filter command: key} -body {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict filter $dictVar key ???
} -cleanup {
    unset dictVar
} -result {foo bar bar foo}
test dict-17.4 {dict filter command: key - no patterns} {
    dict filter {a b c d} key
} {}
test dict-17.4.1 {dict filter command: key - many patterns} {
    dict filter {a1 a a2 b b1 c b2 d foo bar bar foo} key a? b?
} {a1 a a2 b b1 c b2 d}
test dict-17.5 {dict filter command: key - bad dict} -returnCodes error -body {
    dict filter {a b c} key
} -result {missing value to go with key}
test dict-17.6 {dict filter command: value} -body {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict filter $dictVar value c
} -cleanup {
    unset dictVar
} -result {b1 c}
test dict-17.7 {dict filter command: value} -body {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict size [dict filter $dictVar value *]
} -cleanup {
    unset dictVar
} -result 6
test dict-17.8 {dict filter command: value} -body {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    dict filter $dictVar value ???
} -cleanup {
    unset dictVar
} -result {foo bar bar foo}
test dict-17.9 {dict filter command: value - no patterns} {
    dict filter {a b c d} value
} {}
test dict-17.9.1 {dict filter command: value - many patterns} {
    dict filter {a a1 b a2 c b1 foo bar bar foo d b2} value a? b?
} {a a1 b a2 c b1 d b2}
test dict-17.10 {dict filter command: value - bad dict} -body {
    dict filter {a b c} value a
} -returnCodes error -result {missing value to go with key}
test dict-17.11 {dict filter command: script} -body {
    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
    set n 0
    list [dict filter $dictVar script {k v} {
	incr n
	expr {[string length $k] == [string length $v]}
    }] $n
} -cleanup {
    unset dictVar n k v
} -result {{foo bar bar foo} 6}
test dict-17.12 {dict filter command: script} -returnCodes error -body {
    dict filter {a b} script {k v} {
	concat $k $v
    }
} -cleanup {
    unset k v
} -result {expected boolean value but got "a b"}
test dict-17.13 {dict filter command: script} -body {
    list [catch {dict filter {a b} script {k v} {error x}} msg] $msg \
	    $::errorInfo
} -cleanup {
    unset k v msg
} -result {1 x {x
    while executing
"error x"
    ("dict filter" script line 1)
    invoked from within
"dict filter {a b} script {k v} {error x}"}}
test dict-17.14 {dict filter command: script} -setup {
    set n 0
} -body {
    list [dict filter {a b c d} script {k v} {
	incr n
	break
	error boom!
    }] $n
} -cleanup {
    unset n k v
} -result {{} 1}
test dict-17.15 {dict filter command: script} -setup {
    set n 0
} -body {
    list [dict filter {a b c d} script {k v} {
	incr n
	continue
	error boom!
    }] $n
} -cleanup {
    unset n k v
} -result {{} 2}
test dict-17.16 {dict filter command: script} {
    apply {{} {
	dict filter {a b} script {k v} {
	    return ok,$k,$v
	    error "skipped return completely"
	}
	error "return didn't go far enough"
    }}
} ok,a,b
test dict-17.17 {dict filter command: script} -body {
    dict filter {a b} script {k k} {continue}
    return $k
} -cleanup {
    unset k
} -result b
test dict-17.18 {dict filter command: script} -returnCodes error -body {
    dict filter {a b} script {k k}
} -result {wrong # args: should be "dict filter dictionary script {keyVar valueVar} filterScript"}
test dict-17.19 {dict filter command: script} -returnCodes error -body {
    dict filter {a b} script k {continue}
} -result {must have exactly two variable names}
test dict-17.20 {dict filter command: script} -returnCodes error -body {
    dict filter {a b} script "\{k v" {continue}
} -result {unmatched open brace in list}
test dict-17.21 {dict filter command} -returnCodes error -body {
    dict filter {a b}
} -result {wrong # args: should be "dict filter dictionary filterType ?arg ...?"}
test dict-17.22 {dict filter command} -returnCodes error -body {
    dict filter {a b} JUNK
} -result {bad filterType "JUNK": must be key, script, or value}
test dict-17.23 {dict filter command} -returnCodes error -body {
    dict filter a key *
} -result {missing value to go with key}

test dict-18.1 {dict-list relationship} -body {

    # Test that any internal conversion between list and dict does not change
    # the object
    set l [list 1 2 3 4 5 6 7 8 9 0 q w e r t y]
    dict values $l
    return $l
} -cleanup {
    unset l

} -result {1 2 3 4 5 6 7 8 9 0 q w e r t y}

test dict-18.2 {dict-list relationship} -body {

    # Test that the dictionary is a valid list
    set d [dict create "abc def" 0 "a\{b" 1 "c\}d" 2]
    for {set t 0} {$t < 5} {incr t} {
	llength $d
	dict lappend d "abc def" "\}\{"
	dict append  d "a\{b" "\}"
	dict incr    d "c\}d" 1
    }
    llength $d
} -cleanup {
    unset d t
} -result 6
test dict-18.3 {dict-list relationship} -body {
    set ld [list a b c d c e f g]
    list [string length $ld] [dict size $ld] [llength $ld]
} -cleanup {
    unset ld
} -result {15 3 8}
test dict-18.4 {dict-list relationship} -body {
    set ld [list a b c d c e f g]
    list [llength $ld] [dict size $ld] [llength $ld]
} -cleanup {
    unset ld
} -result {8 3 8}

# This is a test for a specific bug.
# It shows a bad ref counter when running with memdebug on.
test dict-19.1 {memory bug} {
    apply {{} {
        set successors [dict create x {c d}]
        dict set successors x a b
        dict get $successors x
    }}
} [dict create c d a b]
test dict-19.2 {dict: testing for leaks} -constraints memory -body {





    # This test is made to stress object reference management
    memtest {

	apply {{} {
	    # A shared invalid dictinary
	    set apa {a {}b c d}
	    set bepa $apa
	    catch {dict replace $apa e f}
	    catch {dict remove  $apa c d}
	    catch {dict incr    apa  a 5}
925
926
927
928
929
930
931




932

933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992


993
994
995
996
997
998
999
1000
1001


1002
1003
1004
1005
1006
1007
1008
1009
1010


1011
1012
1013
1014
1015
1016
1017


1018
1019
1020
1021
1022
1023


1024
1025
1026
1027
1028
1029
1030


1031
1032
1033
1034
1035
1036
1037
1038


1039
1040
1041
1042
1043
1044
1045


1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085


1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099

1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118


1119
1120
1121
1122
1123
1124
1125


1126
1127
1128
1129
1130
1131
1132
1133
1134


1135
1136
1137
1138
1139
1140
1141


1142
1143
1144
1145
1146
1147
1148


1149
1150
1151
1152
1153
1154
1155


1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168


1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182


1183
1184
1185
1186
1187
1188
1189
1190
	    set apa {a 1 b 2}
	    set bepa $apa
	    trace add variable bepa write {error hej}
	    catch {dict unset bepa a}
	    trace remove variable bepa write {error hej}
	    unset bepa
	}}




        set tmp $end

        set end [getbytes]
    }
    expr {$end - $tmp}
} -cleanup {
    unset -nocomplain end i tmp
    rename getbytes {}
#    rename stress {}
} -result 0

test dict-20.1 {dict merge command} {
    dict merge
} {}
test dict-20.2 {dict merge command} {
    getOrder [dict merge {a b c d e f}] a c e
} {a b c d e f 3}
test dict-20.3 {dict merge command} -body {
    dict merge {a b c d e}
} -result {missing value to go with key} -returnCodes error
test dict-20.4 {dict merge command} {
    getOrder [dict merge {a b c d} {e f g h}] a c e g
} {a b c d e f g h 4}
test dict-20.5 {dict merge command} -body {
    dict merge {a b c d e} {e f g h}
} -result {missing value to go with key} -returnCodes error
test dict-20.6 {dict merge command} -body {
    dict merge {a b c d} {e f g h i}
} -result {missing value to go with key} -returnCodes error
test dict-20.7 {dict merge command} {
    getOrder [dict merge {a b c d e f} {e x g h}] a c e g
} {a b c d e x g h 4}
test dict-20.8 {dict merge command} {
    getOrder [dict merge {a b c d} {a x c y}] a c
} {a x c y 2}
test dict-20.9 {dict merge command} {
    getOrder [dict merge {a b c d} {a x c y}] a c
} {a x c y 2}
test dict-20.10 {dict merge command} {
    getOrder [dict merge {a b c d e f} {a x 1 2 3 4} {a - 1 -}] a c e 1 3
} {a - c d e f 1 - 3 4 5}

test dict-21.1 {dict update command} -returnCodes 1 -body {
    dict update
} -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"}
test dict-21.2 {dict update command} -returnCodes 1 -body {
    dict update v
} -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"}
test dict-21.3 {dict update command} -returnCodes 1 -body {
    dict update v k
} -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"}
test dict-21.4 {dict update command} -returnCodes 1 -body {
    dict update v k v
} -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"}
test dict-21.5 {dict update command} {
    set a {b c}
    set result {}
    set bb {}
    dict update a b bb {
	lappend result $a $bb
    }
    lappend result $a


} {{b c} c {b c}}
test dict-21.6 {dict update command} {
    set a {b c}
    set result {}
    set bb {}
    dict update a b bb {
	lappend result $a $bb [set bb d]
    }
    lappend result $a


} {{b c} c d {b d}}
test dict-21.7 {dict update command} {
    set a {b c}
    set result {}
    set bb {}
    dict update a b bb {
	lappend result $a $bb [unset bb]
    }
    lappend result $a


} {{b c} c {} {}}
test dict-21.8 {dict update command} {
    set a {b c d e}
    dict update a b v1 d v2 {
	lassign "$v1 $v2" v2 v1
    }
    getOrder $a b d


} {b e d c 2}
test dict-21.9 {dict update command} {
    set a {b c d e}
    dict update a b v1 d v2 {unset a}
    info exist a
} 0


test dict-21.10 {dict update command} {
    set a {b {c d}}
    dict update a b v1 {
	dict update v1 c v2 {
	    set v2 foo
	}
    }


    set a
} {b {c foo}}
test dict-21.11 {dict update command} {
    set a {b c d e}
    dict update a b v1 d v2 {
	dict set a f g
    }
    getOrder $a b d f


} {b c d e f g 3}
test dict-21.12 {dict update command} {
    set a {b c d e}
    dict update a b v1 d v2 f v3 {
	set v3 g
    }
    getOrder $a b d f


} {b c d e f g 3}
test dict-21.13 {dict update command: compilation} {
    apply {d {
	while 1 {
	    dict update d a alpha b beta {
		set beta $alpha
		unset alpha
		break
	    }
	}
	return [getOrder $d b c]
    }} {a 1 c 2}
} {b 1 c 2 2}
test dict-21.14 {dict update command: compilation} {
    apply {x {
	set indices {2 3}
	trace add variable aa write "string length \$indices ;#"
	dict update x k aa l bb {}
    }} {k 1 l 2}
} {}
test dict-21.15 {dict update command: compilation} {
    apply {x {
	set indices {2 3}
	trace add variable aa read "string length \$indices ;#"
	dict update x k aa l bb {}
    }} {k 1 l 2}
} {}
test dict-21.16 {dict update command: no recursive structures [Bug 1786481]} {
    set foo {a {b {c {d {e 1}}}}}
    dict update foo a t {
	dict update t b t {
	    dict update t c t {
		dict update t d t {
		    dict incr t e
		}
	    }
	}
    }
    string range [append foo OK] end-1 end
} OK


test dict-21.17 {dict update command: no recursive structures [Bug 1786481]} {
    apply {{} {
	set foo {a {b {c {d {e 1}}}}}
	dict update foo a t {
	    dict update t b t {
		dict update t c t {
		    dict update t d t {
			dict incr t e
		    }
		}
	    }
	}
    }}
    string range [append foo OK] end-1 end

} OK

test dict-22.1 {dict with command} -body {
    dict with
} -returnCodes 1 -result {wrong # args: should be "dict with dictVar ?key ...? script"}
test dict-22.2 {dict with command} -body {
    dict with v
} -returnCodes 1 -result {wrong # args: should be "dict with dictVar ?key ...? script"}
test dict-22.3 {dict with command} -body {
    unset -nocomplain v
    dict with v {error "in body"}
} -returnCodes 1 -result {can't read "v": no such variable}
test dict-22.4 {dict with command} {
    set a {b c d e}
    unset -nocomplain b d
    set result [list [info exist b] [info exist d]]
    dict with a {
	lappend result [info exist b] [info exist d] $b $d
    }


    set result
} {0 0 1 1 c e}
test dict-22.5 {dict with command} {
    set a {b c d e}
    dict with a {
	lassign "$b $d" d b
    }


    getOrder $a b d
} {b e d c 2}
test dict-22.6 {dict with command} {
    set a {b c d e}
    dict with a {
	unset b
	# This *won't* go into the dict...
	set f g
    }


    set a
} {d e}
test dict-22.7 {dict with command} {
    set a {b c d e}
    dict with a {
	dict unset a b
    }


    getOrder $a b d
} {b c d e 2}
test dict-22.8 {dict with command} {
    set a [dict create b c]
    dict with a {
	set b $a
    }


    set a
} {b {b c}}
test dict-22.9 {dict with command} {
    set a {b {c d}}
    dict with a b {
	set c $c$c
    }


    set a
} {b {c dd}}
test dict-22.10 {dict with command: result handling tricky case} {
    set a {b {c d}}
    foreach i {0 1} {
	if {$i} break
	dict with a b {
	    set a {}
	    # We're checking to see if we lose this break
	    break
	}
    }
    list $i $a


} {0 {}}
test dict-22.11 {dict with command: no recursive structures [Bug 1786481]} {
    set foo {t {t {t {inner 1}}}}
    dict with foo {
	dict with t {
	    dict with t {
		dict with t {
		    incr inner
		}
	    }
	}
    }
    string range [append foo OK] end-1 end
} OK



# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







>
>
>
>
|
>
|

<

|
<
<






|
|




|
|







|
|

|
|

|
|

|
|













|







>
>
|
|







>
>
|
|







>
>
|
|




|
>
>
|
|



|
>
>
|






>
>
|
|
|




|
>
>
|
|




|
>
>
|









|

|














|











|
>
>












<
|
>












|






>
>
|
|
|




>
>
|
|
|






>
>
|
|
|




>
>
|
|
|




>
>
|
|
|




>
>
|
|
|










>
>
|
|











|
>
>
|







1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083

1084
1085


1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261

1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
	    set apa {a 1 b 2}
	    set bepa $apa
	    trace add variable bepa write {error hej}
	    catch {dict unset bepa a}
	    trace remove variable bepa write {error hej}
	    unset bepa
	}}
    }
} -result 0
test dict-19.3 {testing for leaks - Bug 2874678} -constraints memory -body {
    set d aDictVar; # Force interpreted [dict incr]
    memtest {
	dict incr $d aKey 0
	unset $d
    }

} -cleanup {
    unset d


} -result 0

test dict-20.1 {dict merge command} {
    dict merge
} {}
test dict-20.2 {dict merge command} {
    dict merge {a b c d e f}
} {a b c d e f}
test dict-20.3 {dict merge command} -body {
    dict merge {a b c d e}
} -result {missing value to go with key} -returnCodes error
test dict-20.4 {dict merge command} {
    dict merge {a b c d} {e f g h}
} {a b c d e f g h}
test dict-20.5 {dict merge command} -body {
    dict merge {a b c d e} {e f g h}
} -result {missing value to go with key} -returnCodes error
test dict-20.6 {dict merge command} -body {
    dict merge {a b c d} {e f g h i}
} -result {missing value to go with key} -returnCodes error
test dict-20.7 {dict merge command} {
    dict merge {a b c d e f} {e x g h}
} {a b c d e x g h}
test dict-20.8 {dict merge command} {
    dict merge {a b c d} {a x c y}
} {a x c y}
test dict-20.9 {dict merge command} {
    dict merge {a b c d} {c y a x}
} {a x c y}
test dict-20.10 {dict merge command} {
    dict merge {a b c d e f} {a x 1 2 3 4} {a - 1 -}
} {a - c d e f 1 - 3 4}

test dict-21.1 {dict update command} -returnCodes 1 -body {
    dict update
} -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"}
test dict-21.2 {dict update command} -returnCodes 1 -body {
    dict update v
} -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"}
test dict-21.3 {dict update command} -returnCodes 1 -body {
    dict update v k
} -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"}
test dict-21.4 {dict update command} -returnCodes 1 -body {
    dict update v k v
} -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"}
test dict-21.5 {dict update command} -body {
    set a {b c}
    set result {}
    set bb {}
    dict update a b bb {
	lappend result $a $bb
    }
    lappend result $a
} -cleanup {
    unset a result bb
} -result {{b c} c {b c}}
test dict-21.6 {dict update command} -body {
    set a {b c}
    set result {}
    set bb {}
    dict update a b bb {
	lappend result $a $bb [set bb d]
    }
    lappend result $a
} -cleanup {
    unset a result bb
} -result {{b c} c d {b d}}
test dict-21.7 {dict update command} -body {
    set a {b c}
    set result {}
    set bb {}
    dict update a b bb {
	lappend result $a $bb [unset bb]
    }
    lappend result $a
} -cleanup {
    unset a result
} -result {{b c} c {} {}}
test dict-21.8 {dict update command} -body {
    set a {b c d e}
    dict update a b v1 d v2 {
	lassign "$v1 $v2" v2 v1
    }
    return $a
} -cleanup {
    unset a v1 v2
} -result {b e d c}
test dict-21.9 {dict update command} -body {
    set a {b c d e}
    dict update a b v1 d v2 {unset a}
    info exist a
} -cleanup {
    unset v1 v2
} -result 0
test dict-21.10 {dict update command} -body {
    set a {b {c d}}
    dict update a b v1 {
	dict update v1 c v2 {
	    set v2 foo
	}
    }
    return $a
} -cleanup {
    unset a v1 v2
} -result {b {c foo}}
test dict-21.11 {dict update command} -body {
    set a {b c d e}
    dict update a b v1 d v2 {
	dict set a f g
    }
    return $a
} -cleanup {
    unset a v1 v2
} -result {b c d e f g}
test dict-21.12 {dict update command} -body {
    set a {b c d e}
    dict update a b v1 d v2 f v3 {
	set v3 g
    }
    return $a
} -cleanup {
    unset a v1 v2 v3
} -result {b c d e f g}
test dict-21.13 {dict update command: compilation} {
    apply {d {
	while 1 {
	    dict update d a alpha b beta {
		set beta $alpha
		unset alpha
		break
	    }
	}
	return $d
    }} {a 1 c 2}
} {c 2 b 1}
test dict-21.14 {dict update command: compilation} {
    apply {x {
	set indices {2 3}
	trace add variable aa write "string length \$indices ;#"
	dict update x k aa l bb {}
    }} {k 1 l 2}
} {}
test dict-21.15 {dict update command: compilation} {
    apply {x {
	set indices {2 3}
	trace add variable aa read "string length \$indices ;#"
	dict update x k aa l bb {}
    }} {k 1 l 2}
} {}
test dict-21.16 {dict update command: no recursive structures [Bug 1786481]} -body {
    set foo {a {b {c {d {e 1}}}}}
    dict update foo a t {
	dict update t b t {
	    dict update t c t {
		dict update t d t {
		    dict incr t e
		}
	    }
	}
    }
    string range [append foo OK] end-1 end
} -cleanup {
    unset foo t
} -result OK
test dict-21.17 {dict update command: no recursive structures [Bug 1786481]} {
    apply {{} {
	set foo {a {b {c {d {e 1}}}}}
	dict update foo a t {
	    dict update t b t {
		dict update t c t {
		    dict update t d t {
			dict incr t e
		    }
		}
	    }
	}

	string range [append foo OK] end-1 end
    }}
} OK

test dict-22.1 {dict with command} -body {
    dict with
} -returnCodes 1 -result {wrong # args: should be "dict with dictVar ?key ...? script"}
test dict-22.2 {dict with command} -body {
    dict with v
} -returnCodes 1 -result {wrong # args: should be "dict with dictVar ?key ...? script"}
test dict-22.3 {dict with command} -body {
    unset -nocomplain v
    dict with v {error "in body"}
} -returnCodes 1 -result {can't read "v": no such variable}
test dict-22.4 {dict with command} -body {
    set a {b c d e}
    unset -nocomplain b d
    set result [list [info exist b] [info exist d]]
    dict with a {
	lappend result [info exist b] [info exist d] $b $d
    }
    return $result
} -cleanup {
    unset a b d result
} -result {0 0 1 1 c e}
test dict-22.5 {dict with command} -body {
    set a {b c d e}
    dict with a {
	lassign "$b $d" d b
    }
    return $a
} -cleanup {
    unset a b d
} -result {b e d c}
test dict-22.6 {dict with command} -body {
    set a {b c d e}
    dict with a {
	unset b
	# This *won't* go into the dict...
	set f g
    }
    return $a
} -cleanup {
    unset a d f
} -result {d e}
test dict-22.7 {dict with command} -body {
    set a {b c d e}
    dict with a {
	dict unset a b
    }
    return $a
} -cleanup {
    unset a
} -result {d e b c}
test dict-22.8 {dict with command} -body {
    set a [dict create b c]
    dict with a {
	set b $a
    }
    return $a
} -cleanup {
    unset a b
} -result {b {b c}}
test dict-22.9 {dict with command} -body {
    set a {b {c d}}
    dict with a b {
	set c $c$c
    }
    return $a
} -cleanup {
    unset a c
} -result {b {c dd}}
test dict-22.10 {dict with command: result handling tricky case} -body {
    set a {b {c d}}
    foreach i {0 1} {
	if {$i} break
	dict with a b {
	    set a {}
	    # We're checking to see if we lose this break
	    break
	}
    }
    list $i $a
} -cleanup {
    unset a i c
} -result {0 {}}
test dict-22.11 {dict with command: no recursive structures [Bug 1786481]} -body {
    set foo {t {t {t {inner 1}}}}
    dict with foo {
	dict with t {
	    dict with t {
		dict with t {
		    incr inner
		}
	    }
	}
    }
    string range [append foo OK] end-1 end
} -cleanup {
    unset foo t inner
} -result OK

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/error.test.
14
15
16
17
18
19
20

21















22
23
24
25
26
27
28
# RCS: @(#) $Id: error.test,v 1.16 2006/10/09 19:15:44 msofer Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}


namespace eval ::tcl::test::error {
















proc foo {} {
    global errorInfo
    set a [catch {format [error glorp2]} b]
    error {Human-generated}
}








>

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







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# RCS: @(#) $Id: error.test,v 1.16 2006/10/09 19:15:44 msofer Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

testConstraint memory [llength [info commands memory]]
namespace eval ::tcl::test::error {
if {[testConstraint memory]} {
    proc getbytes {} {
	set lines [split [memory info] \n]
	return [lindex $lines 3 3]
    }
    proc leaktest {script {iterations 3}} {
	set end [getbytes]
	for {set i 0} {$i < $iterations} {incr i} {
	    uplevel 1 $script
	    set tmp $end
	    set end [getbytes]
	}
	return [expr {$end - $tmp}]
    }
}

proc foo {} {
    global errorInfo
    set a [catch {format [error glorp2]} b]
    error {Human-generated}
}

149
150
151
152
153
154
155













156
157
158
159
160
161
162
    while executing
"error msg1"} NONE}
test error-4.5 {errorInfo and errorCode variables} {
    set ::errorCode bogus
    list [catch {error msg1 msg2 {}} msg] $msg $::errorInfo $::errorCode
} {1 msg1 msg2 {}}














# Errors in error command itself

test error-5.1 {errors in error command} {
    list [catch {error} msg] $msg
} {1 {wrong # args: should be "error message ?errorInfo? ?errorCode?"}}
test error-5.2 {errors in error command} {
    list [catch {error a b c d} msg] $msg







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







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
    while executing
"error msg1"} NONE}
test error-4.5 {errorInfo and errorCode variables} {
    set ::errorCode bogus
    list [catch {error msg1 msg2 {}} msg] $msg $::errorInfo $::errorCode
} {1 msg1 msg2 {}}

test error-4.6 {errorstack via info } -body {
    proc f x {g $x$x}
    proc g x {error G:$x}
    catch {f 12}
    info errorstack
} -match glob -result {INNER * CALL {g 1212} CALL {f 12} UP 1}
test error-4.7 {errorstack via options dict } -body {
    proc f x {g $x$x}
    proc g x {error G:$x}
    catch {f 12} m d
    dict get $d -errorstack
} -match glob -result {INNER * CALL {g 1212} CALL {f 12} UP 1}

# Errors in error command itself

test error-5.1 {errors in error command} {
    list [catch {error} msg] $msg
} {1 {wrong # args: should be "error message ?errorInfo? ?errorCode?"}}
test error-5.2 {errors in error command} {
    list [catch {error a b c d} msg] $msg
203
204
205
206
207
208
209









210
211
212
213
214
215
216
test error-6.9 {catch must reset error state} {
    proc foo {} {
	return -code error [catch {error foo bar baz}]
    }
    catch foo
    list $::errorCode
} {NONE}










test error-7.1 {Bug 1397843} -body {
    variable cmds
    proc EIWrite args {
	variable cmds
	lappend cmds [lindex [info level -2] 0]
    }







>
>
>
>
>
>
>
>
>







232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
test error-6.9 {catch must reset error state} {
    proc foo {} {
	return -code error [catch {error foo bar baz}]
    }
    catch foo
    list $::errorCode
} {NONE}
test error-6.10 {catch must reset errorstack} -body {
	proc f x {g $x$x}
	proc g x {error G:$x}
	catch {f 12}
	set e1 [info errorstack]
	catch {f 13}
	set e2 [info errorstack]
	list $e1 $e2
} -match glob -result {{INNER * CALL {g 1212} CALL {f 12} UP 1} {INNER * CALL {g 1313} CALL {f 13} UP 1}}

test error-7.1 {Bug 1397843} -body {
    variable cmds
    proc EIWrite args {
	variable cmds
	lappend cmds [lindex [info level -2] 0]
    }
486
487
488
489
490
491
492








































493
494
495
496
497
498
499
} -returnCodes 2 -result {bar}
test error-15.6 {try with no matching handler (break result propagates)} -body {
    try { if {1} break } on error {} { list a b c }
} -returnCodes 3 -result {}
test error-15.7 {try with no matching handler (unknown integer result propagates)} -body {
    try { return -level 0 -code 123456 } trap {} {} { list a b c }
} -returnCodes 123456 -result {}









































# try tests - propagation (exceptions in handlers, exception chaining)

test error-16.1 {try with successfully executed handler} {
    try { throw FOO bar } trap FOO {} { list a b c }
} {a b c}
test error-16.2 {try with exception (error) in handler} -body {







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







524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
} -returnCodes 2 -result {bar}
test error-15.6 {try with no matching handler (break result propagates)} -body {
    try { if {1} break } on error {} { list a b c }
} -returnCodes 3 -result {}
test error-15.7 {try with no matching handler (unknown integer result propagates)} -body {
    try { return -level 0 -code 123456 } trap {} {} { list a b c }
} -returnCodes 123456 -result {}

foreach level {0 1 2 3} {
    foreach code {0 1 2 3 4 5} {

	# Following cases have different -errorinfo; avoid false alarms
	# TODO: examine whether these difference are as they ought to be.
	if {$level == 0 && $code == 1} continue

	foreach extras {{} {-bar soom}} {

test error-15.8.$level.$code.[llength $extras] {[try] coverage} {
    set script {return -level $level -code $code {*}$extras foo}
    catch $script m1 o1
    catch {try $script} m2 o2
    set o1 [lsort -stride 2 $o1]
    set o2 [lsort -stride 2 $o2]
    expr {$o1 eq $o2 ? "ok" : "$o1\n\tis not equal to\n$o2"}
} ok

test error-15.9.$level.$code.[llength $extras] {[try] coverage} {
    set script {return -level $level -code $code {*}$extras foo}
    catch $script m1 o1
    catch {try $script finally {}} m2 o2
    set o1 [lsort -stride 2 $o1]
    set o2 [lsort -stride 2 $o2]
    expr {$o1 eq $o2 ? "ok" : "$o1\n\tis not equal to\n$o2"}
} ok

test error-15.10.$level.$code.[llength $extras] {[try] coverage} {
    set script {return -level $level -code $code {*}$extras foo}
    catch $script m1 o1
    catch {try $script on $code {x y} {return -options $y $x}} m2 o2
    set o1 [lsort -stride 2 $o1]
    set o2 [lsort -stride 2 $o2]
    expr {$o1 eq $o2 ? "ok" : "$o1\n\tis not equal to\n$o2"}
} ok

	}
    }
}

# try tests - propagation (exceptions in handlers, exception chaining)

test error-16.1 {try with successfully executed handler} {
    try { throw FOO bar } trap FOO {} { list a b c }
} {a b c}
test error-16.2 {try with exception (error) in handler} -body {
743
744
745
746
747
748
749


























































































































































750
751
752
753
754
755
756
757
758
759
760
761
762

















































763
764
765
766
767
768
769
    } trap FOO {} - trap BAR {} { 
	set RES foo
    } trap {} {} - on error {} {
	set RES err
    } 
    set RES
} {err}



























































































































































# FIXME test what vars get set on fallthough ... what is the correct behavior?
# It would seem appropriate to set at least those for the matching handler and
# the executed body; possibly for each handler we fall through as well?

# negative case try tests - bad "on" handler

test error-20.1 {bad code name in on handler} -body {
    try { list a b c } on foo {} {}
} -returnCodes error -match glob -result {bad code *}
test error-20.2 {bad code value in on handler} -body {
    try { list a b c } on 34985723094872345 {} {}
} -returnCodes error -match glob -result {bad code *}


















































# negative case try tests - bad "trap" handler
# what is the effect if we attempt to trap an errorcode that is not a list?
# nested try
# catch inside try
# no tests for bad varslist?
# -errorcode but code!=1 doesn't trap







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








|
|


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







821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
    } trap FOO {} - trap BAR {} { 
	set RES foo
    } trap {} {} - on error {} {
	set RES err
    } 
    set RES
} {err}
proc addmsg msg {
    variable RES
    lappend RES $msg
}
test error-19.6 {compiled try executes all clauses} -setup {
    set RES {}
} -body {
    apply {{} {
	try {
	    addmsg a
	    throw bar hello
	} trap bar {res opt} {
	    addmsg b
	} finally {
	    addmsg c
	}
	addmsg d
    } ::tcl::test::error}
} -cleanup {
    unset RES
} -result {a b c d}
test error-19.7 {compiled try executes all clauses} -setup {
    set RES {}
} -body {
    apply {{} {
	try {
	    addmsg a
	} on error {res opt} {
	    addmsg b
	} on ok {} {
	    addmsg c
	} finally {
	    addmsg d
	}
	addmsg e
    } ::tcl::test::error}
} -cleanup {
    unset RES
} -result {a c d e}
test error-19.8 {compiled try executes all clauses} -setup {
    set RES {}
} -body {
    apply {{} {
	try {
	    addmsg a
	    throw bar hello
	} trap bar {res opt} {
	    addmsg b
	}
	addmsg c
    } ::tcl::test::error}
} -cleanup {
    unset RES
} -result {a b c}
test error-19.9 {compiled try executes all clauses} -setup {
    set RES {}
} -body {
    apply {{} {
	try {
	    addmsg a
	} on error {res opt} {
	    addmsg b
	} on ok {} {
	    addmsg c
	}
	addmsg d
    } ::tcl::test::error}
} -cleanup {
    unset RES
} -result {a c d}
test error-19.10 {compiled try with chained clauses} -setup {
    set RES {}
} -body {
    list [apply {{} {
	try {
	    return good
	} on return {res} - on ok {res} {
	    addmsg ok
	    addmsg $res
	    return handler
	} finally {
	    addmsg finally
	}
    } ::tcl::test::error}] $RES
} -cleanup {
    unset RES
} -result {handler {ok good finally}}
test error-19.11 {compiled try and errors on variable write} -setup {
    set RES {}
} -body {
    apply {{} {
	array set foo {bar boo}
	set bar unset
	catch {
	    try {
		addmsg body
		return a
	    } on return {bar foo} {
		addmsg handler
		return b
	    } finally {
		addmsg finally,$bar
	    }
	} msg
	addmsg $msg
    } ::tcl::test::error}
} -cleanup {
    unset RES
} -result {body finally,a {can't set "foo": variable is array}}
test error-19.12 {interpreted try and errors on variable write} -setup {
    set RES {}
} -body {
    apply {try {
	array set foo {bar boo}
	set bar unset
	catch {
	    $try {
		addmsg body
		return a
	    } on return {bar foo} {
		addmsg handler
		return b
	    } finally {
		addmsg finally,$bar
	    }
	} msg
	addmsg $msg
    } ::tcl::test::error} try
} -cleanup {
    unset RES
} -result {body finally,a {can't set "foo": variable is array}}
test error-19.13 {compiled try and errors on variable write} -setup {
    set RES {}
} -body {
    apply {{} {
	array set foo {bar boo}
	set bar unset
	catch {
	    try {
		addmsg body
		return a
	    } on return {bar foo} - on error {bar foo} {
		addmsg handler
		return b
	    } finally {
		addmsg finally,$bar
	    }
	} msg
	addmsg $msg
    } ::tcl::test::error}
} -cleanup {
    unset RES
} -result {body finally,a {can't set "foo": variable is array}}
rename addmsg {}

# FIXME test what vars get set on fallthough ... what is the correct behavior?
# It would seem appropriate to set at least those for the matching handler and
# the executed body; possibly for each handler we fall through as well?

# negative case try tests - bad "on" handler

test error-20.1 {bad code name in on handler} -body {
    try { list a b c } on err {} {}
} -returnCodes error -match glob -result {bad completion code "err": must be ok, error, return, break, continue*, or an integer}
test error-20.2 {bad code value in on handler} -body {
    try { list a b c } on 34985723094872345 {} {}
} -returnCodes error -match glob -result {bad completion code "34985723094872345": must be ok, error, return, break, continue*, or an integer}

test error-21.1 {memory leaks in try: Bug 2910044} memory {
    leaktest {
	try {string repeat x 10} on ok {} {}
    }
} 0
test error-21.2 {memory leaks in try: Bug 2910044} memory {
    leaktest {
	try {error [string repeat x 10]} on error {} {}
    }
} 0
test error-21.3 {memory leaks in try: Bug 2910044} memory {
    leaktest {
	try {throw FOO [string repeat x 10]} trap FOO {} {}
    }
} 0
test error-21.4 {memory leaks in try: Bug 2910044} memory {
    leaktest {
	try {string repeat x 10}
    }
} 0
test error-21.5 {memory leaks in try: Bug 2910044} memory {
    leaktest {
	try {string repeat x 10} on ok {} {} finally {string repeat y 10}
    }
} 0
test error-21.6 {memory leaks in try: Bug 2910044} memory {
    leaktest {
	try {
	    error [string repeat x 10]
	} on error {} {} finally {
	    string repeat y 10
	}
    }
} 0
test error-21.7 {memory leaks in try: Bug 2910044} memory {
    leaktest {
	try {
	    throw FOO [string repeat x 10]
	} trap FOO {} {} finally {
	    string repeat y 10
	}
    }
} 0
test error-21.8 {memory leaks in try: Bug 2910044} memory {
    leaktest {
	try {string repeat x 10} finally {string repeat y 10}
    }
} 0

# negative case try tests - bad "trap" handler
# what is the effect if we attempt to trap an errorcode that is not a list?
# nested try
# catch inside try
# no tests for bad varslist?
# -errorcode but code!=1 doesn't trap
Changes to tests/expr.test.
6681
6682
6683
6684
6685
6686
6687


















6688
6689
6690
6691
6692
6693
6694
} 0
test expr-38.6 {abs and -0 [Bug 1893815]} {
    ::tcl::mathfunc::abs -0.0
} 0.0
test expr-38.7 {abs and -0 [Bug 1893815]} {
    ::tcl::mathfunc::abs -1e-324
} 0.0



















testConstraint testexprlongobj   [llength [info commands testexprlongobj]]
testConstraint testexprdoubleobj [llength [info commands testexprdoubleobj]]

test expr-39.1 {Check that Tcl_ExprLongObj doesn't modify interpreter result if no error} testexprlongobj {
    testexprlongobj 4+1
} {This is a result: 5}







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







6681
6682
6683
6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702
6703
6704
6705
6706
6707
6708
6709
6710
6711
6712
} 0
test expr-38.6 {abs and -0 [Bug 1893815]} {
    ::tcl::mathfunc::abs -0.0
} 0.0
test expr-38.7 {abs and -0 [Bug 1893815]} {
    ::tcl::mathfunc::abs -1e-324
} 0.0
test expr-38.8 {abs and 0.0 [Bug 2954959]} {
    ::tcl::mathfunc::abs 0.0
} 0.0
test expr-38.9 {abs and 0.0 [Bug 2954959]} {
    expr {abs(0.0)}
} 0.0
test expr-38.10 {abs and -0x0 [Bug 2954959]} {
    expr {abs(-0x0)}
} 0
test expr-38.11 {abs and 0x0 [Bug 2954959]} {
    ::tcl::mathfunc::abs { 	0x0}
} { 	0x0}
test expr-38.12 {abs and -0x0 [Bug 2954959]} {
    ::tcl::mathfunc::abs { 	-0x0}
} 0
test expr-38.13 {abs and 0.0 [Bug 2954959]} {
    ::tcl::mathfunc::abs 1e-324
} 1e-324

testConstraint testexprlongobj   [llength [info commands testexprlongobj]]
testConstraint testexprdoubleobj [llength [info commands testexprdoubleobj]]

test expr-39.1 {Check that Tcl_ExprLongObj doesn't modify interpreter result if no error} testexprlongobj {
    testexprlongobj 4+1
} {This is a result: 5}
Changes to tests/fCmd.test.
16
17
18
19
20
21
22



23
24
25
26
27











28
29
30
31
32
33
34
35
36
37
38














39
40
41
42
43
44
45
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

testConstraint testsetplatform [llength [info commands testsetplatform]]
testConstraint testchmod [llength [info commands testchmod]]



# Don't know how to determine this constraint correctly
testConstraint notNetworkFilesystem 0
testConstraint 95or98 [expr {[testConstraint 95] || [testConstraint 98]}]
testConstraint 2000orNewer [expr {![testConstraint 95or98]}]
testConstraint registryPackage [expr {![catch {package require registry}]}]












# Find a group that exists on this Unix system, or else skip tests that
# require Unix groups.
testConstraint foundGroup [expr {![testConstraint unix]}]
if {[testConstraint unix]} {
    catch {
	set groupList [exec groups]
	set group [lindex $groupList 0]
	testConstraint foundGroup 1
    }
}















testConstraint darwin9 [expr {[testConstraint unix] &&
	$tcl_platform(os) eq "Darwin" &&
	int([string range $tcl_platform(osVersion) 0 \
	[string first . $tcl_platform(osVersion)]]) >= 9}]
testConstraint notDarwin9 [expr {![testConstraint darwin9]}]








>
>
>



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











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







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

testConstraint testsetplatform [llength [info commands testsetplatform]]
testConstraint testchmod [llength [info commands testchmod]]
testConstraint winVista 0
testConstraint win2000orXP 0
testConstraint winOlderThan2000 0
# Don't know how to determine this constraint correctly
testConstraint notNetworkFilesystem 0
testConstraint 95or98 [expr {[testConstraint 95] || [testConstraint 98]}]
testConstraint 2000orNewer [expr {[testConstraint win] && ![testConstraint 95or98]}]
testConstraint reg 0
if {[testConstraint win]} {
    catch {
	# Is the registry extension already static to this shell?
	if [catch {load {} Registry; set ::reglib {}}] {
	    # try the location given to use on the commandline to tcltest
	    ::tcltest::loadTestedCommands
	    load $::reglib Registry
	}
	testConstraint reg 1
    }
}

# Find a group that exists on this Unix system, or else skip tests that
# require Unix groups.
testConstraint foundGroup [expr {![testConstraint unix]}]
if {[testConstraint unix]} {
    catch {
	set groupList [exec groups]
	set group [lindex $groupList 0]
	testConstraint foundGroup 1
    }
}

# Also used in winFCmd...
if {[testConstraint winOnly]} {
    set major [string index $tcl_platform(osVersion) 0]
    if {[testConstraint nt] && $major > 4} {
        if {$major > 5} {
            testConstraint winVista 1
        } elseif {$major == 5} {
            testConstraint win2000orXP 1
        }
    } else {
        testConstraint winOlderThan2000 1
    }
}

testConstraint darwin9 [expr {[testConstraint unix] &&
	$tcl_platform(os) eq "Darwin" &&
	int([string range $tcl_platform(osVersion) 0 \
	[string first . $tcl_platform(osVersion)]]) >= 9}]
testConstraint notDarwin9 [expr {![testConstraint darwin9]}]

380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
} -body {
    createfile tf1
    createfile tf2
    file mkdir td1
    set x [list [file exists tf1] [file exists tf2] [file exists td1]]
    file delete tf1 td1 tf2
    lappend x [file exists tf1] [file exists tf2] [file exists tf3]
} -result {1 1 1 0 0 0}
test fCmd-5.5 {TclFileDeleteCmd: stop at first error} -setup {
    cleanup
} -constraints {notRoot unixOrPc} -body {
    createfile tf1
    createfile tf2
    file mkdir td1
    catch {file delete tf1 td1 $root tf2}
    list [file exists tf1] [file exists tf2] [file exists td1]
} -result {0 1 0}
test fCmd-5.6 {TclFileDeleteCmd: Tcl_TranslateFileName fails} -constraints {notRoot} -body {
    file delete ~_totally_bogus_user
} -returnCodes error -result {user "_totally_bogus_user" doesn't exist}
test fCmd-5.7 {TclFileDeleteCmd: Tcl_TranslateFileName succeeds} -setup {
    catch {file delete ~/tf1}
} -constraints {notRoot} -body {
    createfile ~/tf1







|








|







408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
} -body {
    createfile tf1
    createfile tf2
    file mkdir td1
    set x [list [file exists tf1] [file exists tf2] [file exists td1]]
    file delete tf1 td1 tf2
    lappend x [file exists tf1] [file exists tf2] [file exists tf3]
} -cleanup {cleanup} -result {1 1 1 0 0 0}
test fCmd-5.5 {TclFileDeleteCmd: stop at first error} -setup {
    cleanup
} -constraints {notRoot unixOrPc} -body {
    createfile tf1
    createfile tf2
    file mkdir td1
    catch {file delete tf1 td1 $root tf2}
    list [file exists tf1] [file exists tf2] [file exists td1]
} -cleanup {cleanup} -result {0 1 0}
test fCmd-5.6 {TclFileDeleteCmd: Tcl_TranslateFileName fails} -constraints {notRoot} -body {
    file delete ~_totally_bogus_user
} -returnCodes error -result {user "_totally_bogus_user" doesn't exist}
test fCmd-5.7 {TclFileDeleteCmd: Tcl_TranslateFileName succeeds} -setup {
    catch {file delete ~/tf1}
} -constraints {notRoot} -body {
    createfile ~/tf1
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
    testchmod 444 tf2
    file rename tf1 tf3
    file rename tf2 tf4
    list [lsort [glob tf*]] [file writable tf3] [file writable tf4]
} -result {{tf3 tf4} 1 0}
test fCmd-9.4 {file rename: comprehensive: dir to new name} -setup {
    cleanup
} -constraints {unixOrPc notRoot testchmod notDarwin9} -body {
    file mkdir td1 td2
    testchmod 555 td2
    file rename td1 td3
    file rename td2 td4
    list [lsort [glob td*]] [file writable td3] [file writable td4]
} -cleanup {
    cleanup
} -result {{td3 td4} 1 0}
test fCmd-9.5 {file rename: comprehensive: file to self} -setup {
    cleanup
} -constraints {notRoot testchmod} -body {
    createfile tf1 tf1
    createfile tf2 tf2
    testchmod 444 tf2
    file rename -force tf1 tf1
    file rename -force tf2 tf2
    list [contents tf1] [contents tf2] [file writable tf1] [file writable tf2]
} -result {tf1 tf2 1 0}
test fCmd-9.6 {file rename: comprehensive: dir to self} -setup {
    cleanup
} -constraints {notRoot unixOrPc testchmod} -body {
    file mkdir td1
    file mkdir td2
    testchmod 555 td2
    file rename -force td1 .
    file rename -force td2 .
    list [lsort [glob td*]] [file writable td1] [file writable td2]
} -result {{td1 td2} 1 0}







|




















|







789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
    testchmod 444 tf2
    file rename tf1 tf3
    file rename tf2 tf4
    list [lsort [glob tf*]] [file writable tf3] [file writable tf4]
} -result {{tf3 tf4} 1 0}
test fCmd-9.4 {file rename: comprehensive: dir to new name} -setup {
    cleanup
} -constraints {unixOrPc notRoot testchmod notDarwin9 win2000orXP} -body {
    file mkdir td1 td2
    testchmod 555 td2
    file rename td1 td3
    file rename td2 td4
    list [lsort [glob td*]] [file writable td3] [file writable td4]
} -cleanup {
    cleanup
} -result {{td3 td4} 1 0}
test fCmd-9.5 {file rename: comprehensive: file to self} -setup {
    cleanup
} -constraints {notRoot testchmod} -body {
    createfile tf1 tf1
    createfile tf2 tf2
    testchmod 444 tf2
    file rename -force tf1 tf1
    file rename -force tf2 tf2
    list [contents tf1] [contents tf2] [file writable tf1] [file writable tf2]
} -result {tf1 tf2 1 0}
test fCmd-9.6 {file rename: comprehensive: dir to self} -setup {
    cleanup
} -constraints {notRoot unixOrPc testchmod win2000orXP} -body {
    file mkdir td1
    file mkdir td2
    testchmod 555 td2
    file rename -force td1 .
    file rename -force td2 .
    list [lsort [glob td*]] [file writable td1] [file writable td2]
} -result {{td1 td2} 1 0}
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
test fCmd-9.9 {file rename: comprehensive: dir to non-empty dir} -setup {
    cleanup
} -constraints {notRoot testchmod} -body {
    file mkdir tds1
    file mkdir tds2
    file mkdir [file join tdd1 tds1 xxx]
    file mkdir [file join tdd2 tds2 xxx]
    if {![testConstraint unix]} {
	testchmod 555 tds2
    }
    set a1 [list [catch {file rename -force tds1 tdd1} msg] $msg]
    set a2 [list [catch {file rename -force tds2 tdd2} msg] $msg]
    if {[testConstraint unix]} {
	set w2 0
    } else {
	set w2 [file writable tds2]
    }
    list [lsort [glob td*]] $a1 $a2 [file writable tds1] $w2
} -match glob -result \
    [subst {{tdd1 tdd2 tds1 tds2} {1 {error renaming "tds1" to "[file join tdd1 tds1]": file *}} {1 {error renaming "tds2" to "[file join tdd2 tds2]": file *}} 1 0}]







|




|







886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
test fCmd-9.9 {file rename: comprehensive: dir to non-empty dir} -setup {
    cleanup
} -constraints {notRoot testchmod} -body {
    file mkdir tds1
    file mkdir tds2
    file mkdir [file join tdd1 tds1 xxx]
    file mkdir [file join tdd2 tds2 xxx]
    if {!([testConstraint unix] || [testConstraint winVista])} {
	testchmod 555 tds2
    }
    set a1 [list [catch {file rename -force tds1 tdd1} msg] $msg]
    set a2 [list [catch {file rename -force tds2 tdd2} msg] $msg]
    if {[testConstraint unix] || [testConstraint winVista]} {
	set w2 0
    } else {
	set w2 [file writable tds2]
    }
    list [lsort [glob td*]] $a1 $a2 [file writable tds1] $w2
} -match glob -result \
    [subst {{tdd1 tdd2 tds1 tds2} {1 {error renaming "tds1" to "[file join tdd1 tds1]": file *}} {1 {error renaming "tds2" to "[file join tdd2 tds2]": file *}} 1 0}]
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
} -result [subst {1 {[file join td1 tf3] [file join td1 tf4]} 1 0}]
test fCmd-9.11 {file rename: comprehensive: dir to new name and dir} -setup {
    cleanup
} -constraints {notRoot testchmod} -body {
    file mkdir td1
    file mkdir td2
    file mkdir td3
    if {![testConstraint unix]} {
	testchmod 555 td2
    }
    file rename td1 [file join td3 td3]
    file rename td2 [file join td3 td4]
    if {[testConstraint unix]} {
        set w4 0
    } else {
	set w4 [file writable [file join td3 td4]]
    }
    list [lsort [glob td*]] [lsort [glob -directory td3 t*]] \
    [file writable [file join td3 td3]] $w4
} -result [subst {td3 {[file join td3 td3] [file join td3 td4]} 1 0}]







|




|







917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
} -result [subst {1 {[file join td1 tf3] [file join td1 tf4]} 1 0}]
test fCmd-9.11 {file rename: comprehensive: dir to new name and dir} -setup {
    cleanup
} -constraints {notRoot testchmod} -body {
    file mkdir td1
    file mkdir td2
    file mkdir td3
    if {!([testConstraint unix] || [testConstraint winVista])} {
	testchmod 555 td2
    }
    file rename td1 [file join td3 td3]
    file rename td2 [file join td3 td4]
    if {[testConstraint unix] || [testConstraint winVista]} {
        set w4 0
    } else {
	set w4 [file writable [file join td3 td4]]
    }
    list [lsort [glob td*]] [lsort [glob -directory td3 t*]] \
    [file writable [file join td3 td3]] $w4
} -result [subst {td3 {[file join td3 td3] [file join td3 td4]} 1 0}]
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
	    [glob -directory td4 t*] [file writable td3] [file writable td4]
} -cleanup {
    testchmod 755 td2
    testchmod 755 td4
} -result [list {td1 td2 td3 td4} [file join td3 tdx] [file join td4 tdy] 1 0]
test fCmd-10.3.1 {file copy: comprehensive: dir to new name} -setup {
    cleanup
} -constraints {notRoot win 2000orNewer testchmod} -body {
    # On Windows with ACLs, copying a directory is defined like this
    file mkdir [file join td1 tdx]
    file mkdir [file join td2 tdy]
    testchmod 555 td2
    file copy td1 td3
    file copy td2 td4
    list [lsort [glob td*]] [glob -directory td3 t*] \







|







1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
	    [glob -directory td4 t*] [file writable td3] [file writable td4]
} -cleanup {
    testchmod 755 td2
    testchmod 755 td4
} -result [list {td1 td2 td3 td4} [file join td3 tdx] [file join td4 tdy] 1 0]
test fCmd-10.3.1 {file copy: comprehensive: dir to new name} -setup {
    cleanup
} -constraints {notRoot 2000orNewer testchmod} -body {
    # On Windows with ACLs, copying a directory is defined like this
    file mkdir [file join td1 tdx]
    file mkdir [file join td2 tdy]
    testchmod 555 td2
    file copy td1 td3
    file copy td2 td4
    list [lsort [glob td*]] [glob -directory td3 t*] \
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
    file copy td1 [file join td3 td3]
    file copy td2 [file join td3 td4]
    list [lsort [glob td*]] [lsort [glob -directory td3 t*]] \
    [file writable [file join td3 td3]] [file writable [file join td3 td4]]
} -result [subst {{td1 td2 td3} {[file join td3 td3] [file join td3 td4]} 1 0}]
test fCmd-10.8.1 {file rename: comprehensive: dir to new name and dir} -setup {
    cleanup
} -constraints {notRoot win 2000orNewer testchmod} -body {
    # On Windows with ACLs, copying a directory is defined like this
    file mkdir td1
    file mkdir td2
    file mkdir td3
    testchmod 555 td2
    file copy td1 [file join td3 td3]
    file copy td2 [file join td3 td4]







|







1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
    file copy td1 [file join td3 td3]
    file copy td2 [file join td3 td4]
    list [lsort [glob td*]] [lsort [glob -directory td3 t*]] \
    [file writable [file join td3 td3]] [file writable [file join td3 td4]]
} -result [subst {{td1 td2 td3} {[file join td3 td3] [file join td3 td4]} 1 0}]
test fCmd-10.8.1 {file rename: comprehensive: dir to new name and dir} -setup {
    cleanup
} -constraints {notRoot 2000orNewer testchmod} -body {
    # On Windows with ACLs, copying a directory is defined like this
    file mkdir td1
    file mkdir td2
    file mkdir td3
    testchmod 555 td2
    file copy td1 [file join td3 td3]
    file copy td2 [file join td3 td4]
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532




2533
2534

2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
removeFile abc2.file
removeFile abc.file
removeDirectory abc2.dir
removeDirectory abc.dir

test fCmd-30.1 {file writable on 'My Documents'} -setup {
    # Get the localized version of the folder name by looking in the registry.
    set mydocsname [registry get {HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\DocFolderPaths} $tcl_platform(user)]
} -constraints {win 2000orNewer registryPackage} -body {
    file writable $mydocsname
} -result 1
test fCmd-30.2 {file readable on 'NTUSER.DAT'} -constraints {win 2000orNewer knownBug} -body {
    # Apparently the OS has this file open with exclusive permissions Windows
    # doesn't provide any way to determine that fact without actually trying
    # to open the file (open NTUSER.dat r), which fails. Hence this isn't
    # really a knownBug in Tcl, but an OS limitation. But, perhaps in the
    # future that limitation will be lifted.




    if {[file exists "~/NTUSER.DAT"]} {
	return [file readable "~/NTUSER.DAT"]

    }
    return 0
} -result {0}

# cleanup
cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







|
|


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

|
|









2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
removeFile abc2.file
removeFile abc.file
removeDirectory abc2.dir
removeDirectory abc.dir

test fCmd-30.1 {file writable on 'My Documents'} -setup {
    # Get the localized version of the folder name by looking in the registry.
    set mydocsname [registry get {HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders} Personal]
} -constraints {2000orNewer reg} -body {
    file writable $mydocsname
} -result 1
test fCmd-30.2 {file readable on 'NTUSER.DAT'} -constraints {2000orNewer} -body {
    expr {[info exists env(USERPROFILE)]
          && [file exists $env(USERPROFILE)/NTUSER.DAT]
          && [file readable $env(USERPROFILE)/NTUSER.DAT]}

} -result {1}
test fCmd-30.3 {file readable on 'pagefile.sys'} -constraints {2000orNewer} -body {
    set r {}
    if {[info exists env(SystemDrive)]} {
        set path $env(SystemDrive)/pagefile.sys
        lappend r exists [file exists $path]
        lappend r readable [file readable $path]
        lappend r stat [catch {file stat $path a} e] $e
    }
    return $r
} -result {exists 1 readable 0 stat 0 {}}

# cleanup
cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/fileName.test.
1285
1286
1287
1288
1289
1290
1291















1292
1293
1294
1295
1296
1297
1298
} globTest
test filename-14.29 {Bug 2710920} {unixOrPc} {
    file extension [lindex [lsort [glob globTest/*/]] 0]
} {}
test filename-14.30 {Bug 2710920} {unixOrPc} {
    file rootname [lindex [lsort [glob globTest/*/]] 0]
} globTest/a1/
















unset globname

# The following tests are only valid for Unix systems. On some systems, like
# AFS, "000" protection doesn't prevent access by owner, so the following test
# is not portable.








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







1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
} globTest
test filename-14.29 {Bug 2710920} {unixOrPc} {
    file extension [lindex [lsort [glob globTest/*/]] 0]
} {}
test filename-14.30 {Bug 2710920} {unixOrPc} {
    file rootname [lindex [lsort [glob globTest/*/]] 0]
} globTest/a1/

test filename-14.31 {Bug 2918610} -setup {
    set d [makeDirectory foo]
    makeFile {} bar.soom $d
} -body {
    foreach fn [glob $d/bar.soom] {
        set root [file rootname $fn]
        close [open $root {WRONLY CREAT}]
    }
    llength [glob -directory $d *]
} -cleanup {
    file delete -force $d/bar
    removeFile bar.soom $d
    removeDirectory foo
} -result 2

unset globname

# The following tests are only valid for Unix systems. On some systems, like
# AFS, "000" protection doesn't prevent access by owner, so the following test
# is not portable.

1431
1432
1433
1434
1435
1436
1437





1438
1439
1440
1441
1442
1443
1444
test filename-16.17 {windows specific globbing} -constraints {win} -body {
    cd C:/
    # Ensure correct trimming of tails with absolute and volume relative
    # globbing.
    list [glob -nocomplain -tails -dir C:/ *] \
	[glob -nocomplain -tails -dir C: *]
} -match compareWords -result equal






test filename-17.1 {windows specific special files} {testsetplatform} {
    testsetplatform win
    list [file pathtype com1] [file pathtype con] [file pathtype lpt3] \
	[file pathtype prn] [file pathtype nul] [file pathtype aux] \
	[file pathtype foo]
} {absolute absolute absolute absolute absolute absolute relative}







>
>
>
>
>







1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
test filename-16.17 {windows specific globbing} -constraints {win} -body {
    cd C:/
    # Ensure correct trimming of tails with absolute and volume relative
    # globbing.
    list [glob -nocomplain -tails -dir C:/ *] \
	[glob -nocomplain -tails -dir C: *]
} -match compareWords -result equal

# Put the working directory back now that we're done with globbing in C:/
if {[testConstraint win]} {
    cd $oldDir
}

test filename-17.1 {windows specific special files} {testsetplatform} {
    testsetplatform win
    list [file pathtype com1] [file pathtype con] [file pathtype lpt3] \
	[file pathtype prn] [file pathtype nul] [file pathtype aux] \
	[file pathtype foo]
} {absolute absolute absolute absolute absolute absolute relative}
1505
1506
1507
1508
1509
1510
1511






















































































1512
1513
1514
1515
1516
1517
1518
    makeFile {} TAGS $d
} -body {
    llength [glob -nocomplain -directory $d -types {} -- URGENT Urkle]
} -cleanup {
    removeFile TAGS $d
    removeDirectory foo
} -result 0























































































# cleanup
catch {file delete -force C:/globTest}
cd [temporaryDirectory]
file delete -force globTest
cd $oldpwd
set env(HOME) $oldhome







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







1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
    makeFile {} TAGS $d
} -body {
    llength [glob -nocomplain -directory $d -types {} -- URGENT Urkle]
} -cleanup {
    removeFile TAGS $d
    removeDirectory foo
} -result 0

test fileName-20.5 {Bug 2837800} -setup {
    set dd [makeDirectory isolate]
    set d [makeDirectory ./~foo $dd]
    makeFile {} test $d
    set savewd [pwd]
    cd $dd
} -body {
    glob -nocomplain */test
} -cleanup {
    cd $savewd
    removeFile test $d
    removeDirectory ./~foo $dd
    removeDirectory isolate
} -result ~foo/test

test fileName-20.6 {Bug 2837800} -setup {
    # Recall that we have $env(HOME) set so that references
    # to ~ point to [temporaryDirectory]
    makeFile {} test ~
    set dd [makeDirectory isolate]
    set d [makeDirectory ./~ $dd]
    set savewd [pwd]
    cd $dd
} -body {
    glob -nocomplain */test
} -cleanup {
    cd $savewd
    removeDirectory ./~ $dd
    removeDirectory isolate
    removeFile test ~
} -result {}

test fileName-20.7 {Bug 2806250} -setup {
    set savewd [pwd]
    cd [temporaryDirectory]
    set d [makeDirectory isolate]
    makeFile {} ./~test $d
} -body {
    file exists [lindex [glob -nocomplain isolate/*] 0]
} -cleanup {
    removeFile ./~test $d
    removeDirectory isolate
    cd $savewd
} -result 1

test fileName-20.8 {Bug 2806250} -setup {
    set savewd [pwd]
    cd [temporaryDirectory]
    set d [makeDirectory isolate]
    makeFile {} ./~test $d
} -body {
    file tail [lindex [glob -nocomplain isolate/*] 0]
} -cleanup {
    removeFile ./~test $d
    removeDirectory isolate
    cd $savewd
} -result ./~test

test fileName-20.9 {} -setup {
    makeFile {} test ~
    set d [makeDirectory isolate]
    set savewd [pwd]
    cd $d
} -body {
   glob -nocomplain -directory ~ test
} -cleanup {
    cd $savewd
    removeDirectory isolate
    removeFile test ~
} -result ~/test

test fileName-20.10 {} -setup {
    set s [makeDirectory sub ~]
    makeFile {} fileName-20.10 $s
    set d [makeDirectory isolate]
    set savewd [pwd]
    cd $d
} -body {
   glob -nocomplain -directory ~ -join * fileName-20.10
} -cleanup {
    cd $savewd
    removeDirectory isolate
    removeFile fileName-20.10 $s
    removeDirectory sub ~
} -result ~/sub/fileName-20.10

# cleanup
catch {file delete -force C:/globTest}
cd [temporaryDirectory]
file delete -force globTest
cd $oldpwd
set env(HOME) $oldhome
Changes to tests/fileSystem.test.
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
    set testdir ~
    set res1 "Parent of ~ (/foo/bar/blah) is [file dirname $testdir]"
    set ::env(HOME) /a/b/c
    set res2 "Parent of ~ (/a/b/c) is [file dirname $testdir]"
    list $res1 $res2
} -cleanup {
    set ::env(HOME) $orig
} -match regexp -result {{Parent of ~ \(/foo/bar/blah\) is ([a-zA-Z]:)?(/foo/bar|foo:bar)} {Parent of ~ \(/a/b/c\) is ([a-zA-Z]:)?(/a/b|a:b)}}

test filesystem-6.1 {empty file name} -returnCodes error -body {
    open ""
} -result {couldn't open "": no such file or directory}
test filesystem-6.2 {empty file name} -returnCodes error -body {
    file stat "" arr
} -result {could not read "": no such file or directory}







|







542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
    set testdir ~
    set res1 "Parent of ~ (/foo/bar/blah) is [file dirname $testdir]"
    set ::env(HOME) /a/b/c
    set res2 "Parent of ~ (/a/b/c) is [file dirname $testdir]"
    list $res1 $res2
} -cleanup {
    set ::env(HOME) $orig
} -match regexp -result {{Parent of ~ \(/foo/bar/blah\) is ([a-zA-Z]:)?(/cygwin)?(/foo/bar|foo:bar)} {Parent of ~ \(/a/b/c\) is ([a-zA-Z]:)?(/cygwin)?(/a/b|a:b)}}

test filesystem-6.1 {empty file name} -returnCodes error -body {
    open ""
} -result {couldn't open "": no such file or directory}
test filesystem-6.2 {empty file name} -returnCodes error -body {
    file stat "" arr
} -result {could not read "": no such file or directory}
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
















632
633
634
635
636
637
638
test filesystem-6.33 {empty file name} {file writable ""} 0

# Make sure the testfilesystem hasn't been registered.
if {[testConstraint testfilesystem]} {
    while {![catch {testfilesystem 0}]} {}
}

test filesystem-7.1 {load from vfs} -setup {
    set dir [pwd]
} -constraints {win testsimplefilesystem} -body {
    # This may cause a crash on exit
    cd [file dirname [info nameof]]
    set dde [lindex [glob *dde*[info sharedlib]] 0]
    testsimplefilesystem 1
    # This loads dde via a complex copy-to-temp operation
    load simplefs:/$dde dde
    testsimplefilesystem 0
















    return ok
    # The real result of this test is what happens when Tcl exits.
} -cleanup {
    cd $dir
} -result ok
test filesystem-7.2 {cross-filesystem copy from vfs maintains mtime} -setup {
    set dir [pwd]







|









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







615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
test filesystem-6.33 {empty file name} {file writable ""} 0

# Make sure the testfilesystem hasn't been registered.
if {[testConstraint testfilesystem]} {
    while {![catch {testfilesystem 0}]} {}
}

test filesystem-7.1.1 {load from vfs} -setup {
    set dir [pwd]
} -constraints {win testsimplefilesystem} -body {
    # This may cause a crash on exit
    cd [file dirname [info nameof]]
    set dde [lindex [glob *dde*[info sharedlib]] 0]
    testsimplefilesystem 1
    # This loads dde via a complex copy-to-temp operation
    load simplefs:/$dde dde
    testsimplefilesystem 0
    return ok
    # The real result of this test is what happens when Tcl exits.
} -cleanup {
    cd $dir
} -result ok
test filesystem-7.1.2 {load from vfs, and then unload again} -setup {
    set dir [pwd]
} -constraints {win testsimplefilesystem} -body {
    # This may cause a crash on exit
    cd [file dirname [info nameof]]
    set reg [lindex [glob tclreg*[info sharedlib]] 0]
    testsimplefilesystem 1
    # This loads reg via a complex copy-to-temp operation
    load simplefs:/$reg Registry
    unload simplefs:/$reg
    testsimplefilesystem 0
    return ok
    # The real result of this test is what happens when Tcl exits.
} -cleanup {
    cd $dir
} -result ok
test filesystem-7.2 {cross-filesystem copy from vfs maintains mtime} -setup {
    set dir [pwd]
Changes to tests/format.test.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# %u output depends on word length, so this test is not portable.
testConstraint longIs32bit [expr {int(0x80000000) < 0}]
testConstraint longIs64bit [expr {int(0x8000000000000000) < 0}]
testConstraint wideIs64bit \
	[expr {(wide(0x80000000) > 0) && (wide(0x8000000000000000) < 0)}]
testConstraint wideBiggerThanInt [expr {wide(0x80000000) != int(0x80000000)}]

test format-1.1 {integer formatting} {
    format "%*d %d %d %d" 6 34 16923 -12 -1
} {    34 16923 -12 -1}
test format-1.2 {integer formatting} {
    format "%4d %4d %4d %4d %d %#x %#X" 6 34 16923 -12 -1 14 12
} {   6   34 16923  -12 -1 0xe 0XC}
test format-1.3 {integer formatting} longIs32bit {







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# %u output depends on word length, so this test is not portable.
testConstraint longIs32bit [expr {int(0x80000000) < 0}]
testConstraint longIs64bit [expr {int(0x8000000000000000) < 0}]
testConstraint wideIs64bit \
	[expr {(wide(0x80000000) > 0) && (wide(0x8000000000000000) < 0)}]
testConstraint wideBiggerThanInt [expr {wide(0x80000000) != int(0x80000000)}]

test format-1.1 {integer formatting} {
    format "%*d %d %d %d" 6 34 16923 -12 -1
} {    34 16923 -12 -1}
test format-1.2 {integer formatting} {
    format "%4d %4d %4d %4d %d %#x %#X" 6 34 16923 -12 -1 14 12
} {   6   34 16923  -12 -1 0xe 0XC}
test format-1.3 {integer formatting} longIs32bit {
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567



568








569
570
571
572
573
574
575
576
577
578
579
} 1.000000

test format-18.1 {do not demote existing numeric values} {
    set a 0xaaaaaaaa
    # Ensure $a and $b are separate objects
    set b 0xaaaa
    append b aaaa

    set result [expr {$a == $b}]
    format %08lx $b
    lappend result [expr {$a == $b}]

    set b 0xaaaa
    append b aaaa

    lappend result [expr {$a == $b}]
    format %08x $b
    lappend result [expr {$a == $b}]
} {1 1 1 1}
test format-18.2 {do not demote existing numeric values} {wideBiggerThanInt} {
    set a [expr {0xaaaaaaaaaa + 1}]
    set b 0xaaaaaaaaab
    list [format %08x $a] [expr {$a == $b}]
} {aaaaaaab 1}

test format-19.1 {
    regression test - tcl-core message by Brian Griffin on
    26 0ctober 2004
} -body {
    set x 0x8fedc654
    list [expr { ~ $x }] [format %08x [expr { ~$x }]]
} -match regexp -result {-2414724693 f*701239ab}

test format-19.2 {Bug 1867855} {
    format %llx 0
} 0












# cleanup
catch {unset a}
catch {unset b}
catch {unset c}
catch {unset d}
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







<



<


<

















<



>
>
>

>
>
>
>
>
>
>
>











532
533
534
535
536
537
538

539
540
541

542
543

544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560

561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
} 1.000000

test format-18.1 {do not demote existing numeric values} {
    set a 0xaaaaaaaa
    # Ensure $a and $b are separate objects
    set b 0xaaaa
    append b aaaa

    set result [expr {$a == $b}]
    format %08lx $b
    lappend result [expr {$a == $b}]

    set b 0xaaaa
    append b aaaa

    lappend result [expr {$a == $b}]
    format %08x $b
    lappend result [expr {$a == $b}]
} {1 1 1 1}
test format-18.2 {do not demote existing numeric values} {wideBiggerThanInt} {
    set a [expr {0xaaaaaaaaaa + 1}]
    set b 0xaaaaaaaaab
    list [format %08x $a] [expr {$a == $b}]
} {aaaaaaab 1}

test format-19.1 {
    regression test - tcl-core message by Brian Griffin on
    26 0ctober 2004
} -body {
    set x 0x8fedc654
    list [expr { ~ $x }] [format %08x [expr { ~$x }]]
} -match regexp -result {-2414724693 f*701239ab}

test format-19.2 {Bug 1867855} {
    format %llx 0
} 0
test format-19.3 {Bug 2830354} {
    string length [format %340f 0]
} 340

# Note that this test may fail in future versions
test format-20.1 {Bug 2932421: plain %s caused intrep change of args} -body {
    set x [dict create a b c d]
    format %s $x
    # After this, obj in $x should be a dict with a non-NULL bytes field
    tcl::unsupported::representation $x
} -match glob -result {value is a dict with *, string representation "*".}

# cleanup
catch {unset a}
catch {unset b}
catch {unset c}
catch {unset d}
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/history.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Commands covered:  history
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: history.test,v 1.6 2004/05/19 12:43:03 dkf Exp $
  
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}


|
|
|





|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Commands covered:  history
#
# This file contains a collection of tests for one or more of the Tcl built-in
# commands.  Sourcing this file into Tcl runs the tests and generates output
# for errors.  No output means no errors were found.
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: history.test,v 1.6 2004/05/19 12:43:03 dkf Exp $
  
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    history add {set a 12345}
    history add {set b [format {A test %s} string]}
    history add {Another test}
} else {
    # Dummy value, must be numeric
    set num 0
}

# "history event"

test history-1.1 {event option} history {history event -1} \
	{set b [format {A test %s} string]}
test history-1.2 {event option} history {history event $num} \
	{set a 12345}
test history-1.3 {event option} history {history event [expr $num+2]} \







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    history add {set a 12345}
    history add {set b [format {A test %s} string]}
    history add {Another test}
} else {
    # Dummy value, must be numeric
    set num 0
}

# "history event"

test history-1.1 {event option} history {history event -1} \
	{set b [format {A test %s} string]}
test history-1.2 {event option} history {history event $num} \
	{set a 12345}
test history-1.3 {event option} history {history event [expr $num+2]} \
241
242
243
244
245
246
247
248
249
250
251
252

# miscellaneous

test history-9.1 {miscellaneous} history {catch {history gorp} msg} 1
test history-9.2 {miscellaneous} history {
    catch {history gorp} msg
    set msg
} {bad option "gorp": must be add, change, clear, event, info, keep, nextid, or redo}

# cleanup
::tcltest::cleanupTests
return







|
|



241
242
243
244
245
246
247
248
249
250
251
252

# miscellaneous

test history-9.1 {miscellaneous} history {catch {history gorp} msg} 1
test history-9.2 {miscellaneous} history {
    catch {history gorp} msg
    set msg
} {unknown or ambiguous subcommand "gorp": must be add, change, clear, event, info, keep, nextid, or redo}

# cleanup
::tcltest::cleanupTests
return
Changes to tests/init.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# Functionality covered: this file contains a collection of tests for the
# auto loading and namespaces.
#
# Sourcing this file into Tcl runs the tests and generates output for
# errors. No output means no errors were found.
#
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: init.test,v 1.18 2007/12/13 15:26:06 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Clear out any namespaces called test_ns_*
catch {namespace delete {*}[namespace children :: test_ns_*]}

# Six cases - white box testing

test init-1.1 {auto_qualify - absolute cmd - namespace} {
    auto_qualify ::foo::bar ::blue
} ::foo::bar

test init-1.2 {auto_qualify - absolute cmd - global} {
    auto_qualify ::global ::sub
} global

test init-1.3 {auto_qualify - no colons cmd - global} {
    auto_qualify nocolons ::
} nocolons 

test init-1.4 {auto_qualify - no colons cmd - namespace} {
    auto_qualify nocolons ::sub
} {::sub::nocolons nocolons}

test init-1.5 {auto_qualify - colons in cmd - global} {
    auto_qualify foo::bar ::
} ::foo::bar

test init-1.6 {auto_qualify - colons in cmd - namespace} {
    auto_qualify foo::bar ::sub
} {::sub::foo::bar ::foo::bar}

# Some additional tests

test init-1.7 {auto_qualify - multiples colons 1} {
    auto_qualify :::foo::::bar ::blue
} ::foo::bar

test init-1.8 {auto_qualify - multiple colons 2} {
    auto_qualify :::foo ::bar
} foo


# we use a sub interp and auto_reset and double the tests because there is 2
# places where auto_loading occur (before loading the indexes files and after)

set testInterp [interp create]
interp eval $testInterp [list set argv $argv]
interp eval $testInterp [list package require tcltest]
interp eval $testInterp [list namespace import -force ::tcltest::*]

interp eval $testInterp {

auto_reset
catch {rename parray {}}

test init-2.0 {load parray - stage 1} {
    set ret [catch {parray} error]
    rename parray {} ; # remove it, for the next test - that should not fail.
    list $ret $error
} {1 {wrong # args: should be "parray a ?pattern?"}}


test init-2.1 {load parray - stage 2} {
    set ret [catch {parray} error]
    list $ret $error
} {1 {wrong # args: should be "parray a ?pattern?"}}


auto_reset
catch {rename ::safe::setLogCmd {}}
#unset auto_index(::safe::setLogCmd)
#unset auto_oldpath

test init-2.2 {load ::safe::setLogCmd - stage 1} {
    ::safe::setLogCmd
    rename ::safe::setLogCmd {} ; # should not fail
} {}

test init-2.3 {load ::safe::setLogCmd - stage 2} {
    ::safe::setLogCmd
    rename ::safe::setLogCmd {} ; # should not fail
} {}

auto_reset
catch {rename ::safe::setLogCmd {}}

test init-2.4 {load safe:::setLogCmd - stage 1} {
    safe:::setLogCmd ; # intentionally 3 :
    rename ::safe::setLogCmd {} ; # should not fail
} {}

test init-2.5 {load safe:::setLogCmd - stage 2} {
    safe:::setLogCmd ; # intentionally 3 :
    rename ::safe::setLogCmd {} ; # should not fail
} {}

auto_reset
catch {rename ::safe::setLogCmd {}}

test init-2.6 {load setLogCmd from safe:: - stage 1} {
    namespace eval safe setLogCmd 
    rename ::safe::setLogCmd {} ; # should not fail
} {}

test init-2.7 {oad setLogCmd from safe::  - stage 2} {
    namespace eval safe setLogCmd 
    rename ::safe::setLogCmd {} ; # should not fail
} {}



test init-2.8 {load tcl::HistAdd} -setup {
    auto_reset
    catch {rename ::tcl::HistAdd {}}
} -body {
    # 3 ':' on purpose
    list [catch {tcl:::HistAdd} error] $error
} -cleanup {
    rename ::tcl::HistAdd {} ; 
} -result {1 {wrong # args: should be "tcl:::HistAdd command ?exec?"}}


test init-3.0 {random stuff in the auto_index, should still work} {
    set auto_index(foo:::bar::blah) {
        namespace eval foo {namespace eval bar {proc blah {} {return 1}}}
    }
    foo:::bar::blah
} 1

# Tests that compare the error stack trace generated when autoloading
# with that generated when no autoloading is necessary.  Ideally they
# should be the same.

set count 0
foreach arg [subst -nocommands -novariables {
		c
                {argument
                which spans
                multiple lines}
|
|

|
|




|
|










|





<



<



<



<



<



<

<



<



|
<
|











|


|


<
<




<
<




<


|

<


|

<


<

|
|

<

|
|

<


<


|

<


|

<
<
<







|
|
|
<






|
|
|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

28
29
30

31
32
33

34
35
36

37
38
39

40
41
42

43

44
45
46

47
48
49
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72


73
74
75
76

77
78
79
80

81
82
83
84

85
86

87
88
89
90

91
92
93
94

95
96

97
98
99
100

101
102
103
104



105
106
107
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# Functionality covered: this file contains a collection of tests for the auto
# loading and namespaces.
#
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: init.test,v 1.18 2007/12/13 15:26:06 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Clear out any namespaces called test_ns_*
catch {namespace delete {*}[namespace children :: test_ns_*]}

# Six cases - white box testing

test init-1.1 {auto_qualify - absolute cmd - namespace} {
    auto_qualify ::foo::bar ::blue
} ::foo::bar

test init-1.2 {auto_qualify - absolute cmd - global} {
    auto_qualify ::global ::sub
} global

test init-1.3 {auto_qualify - no colons cmd - global} {
    auto_qualify nocolons ::
} nocolons 

test init-1.4 {auto_qualify - no colons cmd - namespace} {
    auto_qualify nocolons ::sub
} {::sub::nocolons nocolons}

test init-1.5 {auto_qualify - colons in cmd - global} {
    auto_qualify foo::bar ::
} ::foo::bar

test init-1.6 {auto_qualify - colons in cmd - namespace} {
    auto_qualify foo::bar ::sub
} {::sub::foo::bar ::foo::bar}

# Some additional tests

test init-1.7 {auto_qualify - multiples colons 1} {
    auto_qualify :::foo::::bar ::blue
} ::foo::bar

test init-1.8 {auto_qualify - multiple colons 2} {
    auto_qualify :::foo ::bar
} foo


# We use a sub-interp and auto_reset and double the tests because there is 2
# places where auto_loading occur (before loading the indexes files and after)

set testInterp [interp create]
interp eval $testInterp [list set argv $argv]
interp eval $testInterp [list package require tcltest]
interp eval $testInterp [list namespace import -force ::tcltest::*]

interp eval $testInterp {

auto_reset
catch {rename parray {}}

test init-2.0 {load parray - stage 1} {
    set ret [catch {parray} error]
    rename parray {}  ;# remove it, for the next test - that should not fail.
    list $ret $error
} {1 {wrong # args: should be "parray a ?pattern?"}}


test init-2.1 {load parray - stage 2} {
    set ret [catch {parray} error]
    list $ret $error
} {1 {wrong # args: should be "parray a ?pattern?"}}


auto_reset
catch {rename ::safe::setLogCmd {}}
#unset auto_index(::safe::setLogCmd)
#unset auto_oldpath

test init-2.2 {load ::safe::setLogCmd - stage 1} {
    ::safe::setLogCmd
    rename ::safe::setLogCmd {}  ;# should not fail
} {}

test init-2.3 {load ::safe::setLogCmd - stage 2} {
    ::safe::setLogCmd
    rename ::safe::setLogCmd {}  ;# should not fail
} {}

auto_reset
catch {rename ::safe::setLogCmd {}}

test init-2.4 {load safe:::setLogCmd - stage 1} {
    safe:::setLogCmd  ;# intentionally 3 :
    rename ::safe::setLogCmd {}  ;# should not fail
} {}

test init-2.5 {load safe:::setLogCmd - stage 2} {
    safe:::setLogCmd  ;# intentionally 3 :
    rename ::safe::setLogCmd {}  ;# should not fail
} {}

auto_reset
catch {rename ::safe::setLogCmd {}}

test init-2.6 {load setLogCmd from safe:: - stage 1} {
    namespace eval safe setLogCmd 
    rename ::safe::setLogCmd {}  ;# should not fail
} {}

test init-2.7 {oad setLogCmd from safe::  - stage 2} {
    namespace eval safe setLogCmd 
    rename ::safe::setLogCmd {}  ;# should not fail
} {}



test init-2.8 {load tcl::HistAdd} -setup {
    auto_reset
    catch {rename ::tcl::HistAdd {}}
} -body {
    # 3 ':' on purpose
    list [catch {tcl:::HistAdd} error] $error
} -cleanup {
    rename ::tcl::HistAdd {}
} -result {1 {wrong # args: should be "tcl:::HistAdd event ?exec?"}}


test init-3.0 {random stuff in the auto_index, should still work} {
    set auto_index(foo:::bar::blah) {
        namespace eval foo {namespace eval bar {proc blah {} {return 1}}}
    }
    foo:::bar::blah
} 1

# Tests that compare the error stack trace generated when autoloading with
# that generated when no autoloading is necessary.  Ideally they should be the
# same.

set count 0
foreach arg [subst -nocommands -novariables {
		c
                {argument
                which spans
                multiple lines}
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219




	auto_reset
	catch {parray a b $arg}
	set first $::errorInfo
	catch {parray a b $arg}
	set second $::errorInfo
	string equal $first $second
    } 1

    test init-4.$count.1 {::errorInfo produced by [unknown]} {
	auto_reset
	namespace eval junk [list array set $arg [list 1 2 3 4]]
	trace variable ::junk::$arg r \
		"[list error [subst {Variable \"$arg\" is write-only}]] ;# "
	catch {parray ::junk::$arg}
	set first $::errorInfo
	catch {parray ::junk::$arg}
	set second $::errorInfo
	string equal $first $second
    } 1

    incr count
}

test init-5.0 {return options passed through ::unknown} -setup {
    catch {rename xxx {}}
    set ::auto_index(::xxx) {proc ::xxx {} {
	return -code error -level 2 xxx
    }}
} -body {
    set code [catch {::xxx} foo bar]
    set code2 [catch {::xxx} foo2 bar2]
    list $code $foo $bar $code2 $foo2 $bar2
} -cleanup {
    unset ::auto_index(::xxx)
} -result {2 xxx {-errorcode NONE -code 1 -level 1} 2 xxx {-code 1 -level 1 -errorcode NONE}}

cleanupTests
}	;#  End of [interp eval $testInterp]

# cleanup
interp delete $testInterp
::tcltest::cleanupTests
return












<














|











|
|








>
>
>
>
151
152
153
154
155
156
157

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
	auto_reset
	catch {parray a b $arg}
	set first $::errorInfo
	catch {parray a b $arg}
	set second $::errorInfo
	string equal $first $second
    } 1

    test init-4.$count.1 {::errorInfo produced by [unknown]} {
	auto_reset
	namespace eval junk [list array set $arg [list 1 2 3 4]]
	trace variable ::junk::$arg r \
		"[list error [subst {Variable \"$arg\" is write-only}]] ;# "
	catch {parray ::junk::$arg}
	set first $::errorInfo
	catch {parray ::junk::$arg}
	set second $::errorInfo
	string equal $first $second
    } 1

    incr count
}

test init-5.0 {return options passed through ::unknown} -setup {
    catch {rename xxx {}}
    set ::auto_index(::xxx) {proc ::xxx {} {
	return -code error -level 2 xxx
    }}
} -body {
    set code [catch {::xxx} foo bar]
    set code2 [catch {::xxx} foo2 bar2]
    list $code $foo $bar $code2 $foo2 $bar2
} -cleanup {
    unset ::auto_index(::xxx)
} -match glob -result {2 xxx {-errorcode NONE -code 1 -level 1} 2 xxx {-code 1 -level 1 -errorcode NONE}}

cleanupTests
}	;#  End of [interp eval $testInterp]

# cleanup
interp delete $testInterp
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# fill-column: 78
# End:
Changes to tests/io.test.
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
    close $f
    close $f2
    set result
} {{
out
} {err
}}
# This test relies on the fact that the smallest available fd is used first.
test io-14.4 {Tcl_SetStdChannel & Tcl_GetStdChannel} {exec unix} {
    set f [open $path(test1) w]
    puts -nonewline $f { close stdin
	close stdout
	close stderr
	set f  [}
    puts $f [list open $path(test1) r]]
    puts $f "set f2 \[[list open $path(test2) w]]"







|
|







1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
    close $f
    close $f2
    set result
} {{
out
} {err
}}
# This test relies on the fact that stdout is used before stderr
test io-14.4 {Tcl_SetStdChannel & Tcl_GetStdChannel} {exec} {
    set f [open $path(test1) w]
    puts -nonewline $f { close stdin
	close stdout
	close stderr
	set f  [}
    puts $f [list open $path(test1) r]]
    puts $f "set f2 \[[list open $path(test2) w]]"
1692
1693
1694
1695
1696
1697
1698
1699

1700
1701
1702
1703
1704
1705
1706
1707
    set f  [open $path(test2) r]
    set f2 [open $path(test3) r]
    lappend result [read $f] [read $f2]
    close $f
    close $f2
    set result
} {{ close stdin
file1

} {file2
}}
catch {interp delete z}
test io-14.5 {Tcl_GetChannel: stdio name translation} {
    interp create z
    eof stdin
    catch {z eval flush stdin} msg1
    catch {z eval close stdin} msg2







<
>
|







1692
1693
1694
1695
1696
1697
1698

1699
1700
1701
1702
1703
1704
1705
1706
1707
    set f  [open $path(test2) r]
    set f2 [open $path(test3) r]
    lappend result [read $f] [read $f2]
    close $f
    close $f2
    set result
} {{ close stdin

stdout
} {stderr
}}
catch {interp delete z}
test io-14.5 {Tcl_GetChannel: stdio name translation} {
    interp create z
    eof stdin
    catch {z eval flush stdin} msg1
    catch {z eval close stdin} msg2
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
	close stdin
	puts [testchannel open]
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    set l [gets $f]
    close $f
    set l
} {file1 file2}

test io-29.1 {Tcl_WriteChars, channel not writable} {
    list [catch {puts stdin hello} msg] $msg
} {1 {channel "stdin" wasn't opened for writing}}
test io-29.2 {Tcl_WriteChars, empty string} {
    file delete $path(test1)







|







2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
	close stdin
	puts [testchannel open]
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    set l [gets $f]
    close $f
    lsort $l
} {file1 file2}

test io-29.1 {Tcl_WriteChars, channel not writable} {
    list [catch {puts stdin hello} msg] $msg
} {1 {channel "stdin" wasn't opened for writing}}
test io-29.2 {Tcl_WriteChars, empty string} {
    file delete $path(test1)
7122
7123
7124
7125
7126
7127
7128































7129
7130
7131
7132
7133
7134
7135
    catch {close $b}
    close $pipe
    rename ::done {}
    after 1000 ;# Give Windows time to kill the process
    removeFile err
    catch {unset ::forever}
} -result {AB BA}
































test io-54.1 {Recursive channel events} {socket fileevent} {
    # This test checks to see if file events are delivered during recursive
    # event loops when there is buffered data on the channel.

    proc accept {s a p} {
	variable as







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







7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
7149
7150
7151
7152
7153
7154
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164
7165
7166
    catch {close $b}
    close $pipe
    rename ::done {}
    after 1000 ;# Give Windows time to kill the process
    removeFile err
    catch {unset ::forever}
} -result {AB BA}
test io-53.11 {Bug 2895565} -setup {
    set in [makeFile {} in]
    set f [open $in w]
    fconfigure $f -encoding utf-8 -translation binary
    puts -nonewline $f [string repeat "Ho hum\n" 11]
    close $f
    set inChan [open $in r]
    fconfigure $inChan -translation binary
    set out [makeFile {} out]
    set outChan [open $out w]
    fconfigure $outChan -encoding cp1252 -translation crlf
    proc CopyDone {bytes args} {
	variable done
	if {[llength $args]} {
	    set done "Error: '[lindex $args 0]' after $bytes bytes copied"
	} else {
	    set done "$bytes bytes copied"
	}
    }
} -body {
    variable done
    after 2000 [list set [namespace which -variable done] timeout]
    fcopy $inChan $outChan -size 40 -command [namespace which CopyDone]
    vwait [namespace which -variable done]
    set done
} -cleanup {
    close $outChan
    close $inChan
    removeFile out
    removeFile in
} -result {40 bytes copied}

test io-54.1 {Recursive channel events} {socket fileevent} {
    # This test checks to see if file events are delivered during recursive
    # event loops when there is buffered data on the channel.

    proc accept {s a p} {
	variable as
Changes to tests/ioCmd.test.
391
392
393
394
395
396
397



398
399
400
401
402
403
404
} {1 {can't write input to command: standard input was redirected} NONE}
test iocmd-11.2 {I/O to command pipelines} {unixOrPc unixExecs} {
    list [catch {open "| echo > \"$path(test5)\"" r} msg] $msg $::errorCode
} {1 {can't read output from command: standard output was redirected} NONE}
test iocmd-11.3 {I/O to command pipelines} {unixOrPc unixExecs} {
    list [catch {open "| echo > \"$path(test5)\"" r+} msg] $msg $::errorCode
} {1 {can't read output from command: standard output was redirected} NONE}




test iocmd-12.1 {POSIX open access modes: RDONLY} {
    file delete $path(test1)
    set f [open $path(test1) w]
    puts $f "Two lines: this one"
    puts $f "and this one"
    close $f







>
>
>







391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
} {1 {can't write input to command: standard input was redirected} NONE}
test iocmd-11.2 {I/O to command pipelines} {unixOrPc unixExecs} {
    list [catch {open "| echo > \"$path(test5)\"" r} msg] $msg $::errorCode
} {1 {can't read output from command: standard output was redirected} NONE}
test iocmd-11.3 {I/O to command pipelines} {unixOrPc unixExecs} {
    list [catch {open "| echo > \"$path(test5)\"" r+} msg] $msg $::errorCode
} {1 {can't read output from command: standard output was redirected} NONE}
test iocmd-11.4 {I/O to command pipelines} unixOrPc {
    list [catch {open "| no_such_command_exists" rb} msg] $msg $::errorCode
} {1 {couldn't execute "no_such_command_exists": no such file or directory} {POSIX ENOENT {no such file or directory}}}

test iocmd-12.1 {POSIX open access modes: RDONLY} {
    file delete $path(test1)
    set f [open $path(test1) w]
    puts $f "Two lines: this one"
    puts $f "and this one"
    close $f
1011
1012
1013
1014
1015
1016
1017
































1018
1019
1020
1021
1022
1023
1024
    }
    set c [chan create {r w} foo]
    note [catch {read $c 2} msg opt]; note $msg; noteOpts $opt
    close $c
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}}

































# --- === *** ###########################
# method write

test iocmd-24.1 {chan write, regular write} -match glob -body {
    set res {}
    proc foo {args} {







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







1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
    }
    set c [chan create {r w} foo]
    note [catch {read $c 2} msg opt]; note $msg; noteOpts $opt
    close $c
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}}
test iocmd-23.9 {chan read, no data means eof} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return ""
    }
    set c [chan create {r w} foo]
} -body {
    note [read $c 2]
    note [eof $c]
    set res
} -cleanup {
    close $c
    rename foo {}
    unset res
} -result {{read rc* 4096} {} 1}
test iocmd-23.10 {chan read, EAGAIN means no data, yet no eof either} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	error EAGAIN
    }
    set c [chan create {r w} foo]
} -body {
    note [read $c 2]
    note [eof $c]
    set res
} -cleanup {
    close $c
    rename foo {}
    unset res
} -result {{read rc* 4096} {} 0}

# --- === *** ###########################
# method write

test iocmd-24.1 {chan write, regular write} -match glob -body {
    set res {}
    proc foo {args} {
1151
1152
1153
1154
1155
1156
1157


































1158
1159
1160
1161
1162
1163
1164
    note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg opt]
    note $msg
    noteOpts $opt
    close $c
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "write"*}}



































# --- === *** ###########################
# method cgetall

test iocmd-25.1 {chan configure, cgetall, standard options} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}







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







1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
    note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg opt]
    note $msg
    noteOpts $opt
    close $c
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "write"*}}
test iocmd-24.14 {chan write, no EAGAIN means that writing is allowed at this time, bug 2936225} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return 3
    }
    set c [chan create {r w} foo]
} -body {
    note [puts -nonewline $c ABC ; flush $c]
    set res
} -cleanup {
    close $c
    rename foo {}
    unset res
} -result {{write rc* ABC} {}}
test iocmd-24.15 {chan write, EAGAIN means that writing is not allowed at this time, bug 2936225} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	# Note: The EAGAIN signals that the channel cannot accept
	# write requests right now, this in turn causes the IO core to
	# request the generation of writable events (see expected
	# result below, and compare to case 24.14 above).
	error EAGAIN
    }
    set c [chan create {r w} foo]
} -body {
    note [puts -nonewline $c ABC ; flush $c]
    set res
} -cleanup {
    close $c
    rename foo {}
    unset res
} -result {{write rc* ABC} {watch rc* write} {}}

# --- === *** ###########################
# method cgetall

test iocmd-25.1 {chan configure, cgetall, standard options} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
1931
1932
1933
1934
1935
1936
1937













1938
1939
1940
1941
1942
1943
1944
	after 2000
	catch { puts $chan shoo } res
	set res
    }]
    set res
} -constraints {testchannel impossible} \
    -result {Owner lost}














# ### ### ### ######### ######### #########
## Same tests as above, but exercising the code forwarding and
## receiving driver operations to the originator thread.

# -*- tcl -*-
# ### ### ### ######### ######### #########







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







2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
	after 2000
	catch { puts $chan shoo } res
	set res
    }]
    set res
} -constraints {testchannel impossible} \
    -result {Owner lost}

test iocmd-32.2 {delete interp of reflected chan} {
    # Bug 3034840
    # Run this test in an interp with memory debugging to panic
    # on the double free
    interp create slave
    slave eval {
        proc no-op args {}
        proc driver {sub args} {return {initialize finalize watch read}}
        chan event [chan create read driver] readable no-op
    }
    interp delete slave
} {}

# ### ### ### ######### ######### #########
## Same tests as above, but exercising the code forwarding and
## receiving driver operations to the originator thread.

# -*- tcl -*-
# ### ### ### ######### ######### #########
2242
2243
2244
2245
2246
2247
2248








































2249
2250
2251
2252
2253
2254
2255
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}} \
    -constraints {testchannel testthread}









































# --- === *** ###########################
# method write

test iocmd.tf-24.1 {chan write, regular write} -match glob -body {
    set res {}
    proc foo {args} {







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







2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}} \
    -constraints {testchannel testthread}
test iocmd.tf-23.9 {chan read, no data means eof} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return ""
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [read $c 2]
	note [eof $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    rename foo {}
    unset res
} -result {{read rc* 4096} {} 1} \
    -constraints {testchannel testthread}
test iocmd.tf-23.10 {chan read, EAGAIN means no data, yet no eof either} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	error EAGAIN
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [read $c 2]
	note [eof $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    rename foo {}
    unset res
} -result {{read rc* 4096} {} 0} \
    -constraints {testchannel testthread}

# --- === *** ###########################
# method write

test iocmd.tf-24.1 {chan write, regular write} -match glob -body {
    set res {}
    proc foo {args} {
2427
2428
2429
2430
2431
2432
2433










































2434
2435
2436
2437
2438
2439
2440
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "write"*}} \










































    -constraints {testchannel testthread}

# --- === *** ###########################
# method cgetall

test iocmd.tf-25.1 {chan configure, cgetall, standard options} -match glob -body {
    set res {}







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







2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
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
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "write"*}} \
    -constraints {testchannel testthread}
test iocmd.tf-24.14 {chan write, no EAGAIN means that writing is allowed at this time, bug 2936225} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return 3
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [puts -nonewline $c ABC ; flush $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    rename foo {}
    unset res
} -result {{write rc* ABC} {}} \
    -constraints {testchannel testthread}
test iocmd.tf-24.15 {chan write, EAGAIN means that writing is not allowed at this time, bug 2936225} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	# Note: The EAGAIN signals that the channel cannot accept
	# write requests right now, this in turn causes the IO core to
	# request the generation of writable events (see expected
	# result below, and compare to case 24.14 above).
	error EAGAIN
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [puts -nonewline $c ABC ; flush $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    rename foo {}
    unset res
} -result {{write rc* ABC} {watch rc* write} {}} \
    -constraints {testchannel testthread}

# --- === *** ###########################
# method cgetall

test iocmd.tf-25.1 {chan configure, cgetall, standard options} -match glob -body {
    set res {}
Changes to tests/ioTrans.test.
37
38
39
40
41
42
43

44
45
46
47
48
49
50
set helperscript {
    if {[lsearch [namespace children] ::tcltest] == -1} {
	package require tcltest 2
	namespace import -force ::tcltest::*
    }

    proc note  {item}  {global res; lappend res $item; return}

    proc track {}      {upvar args item; note $item; return}
    proc notes {items} {foreach i $items {note $i}}

    # Use to prevent *'s in pattern to match beyond the expected end
    # of the recording.
    proc endnote {} {note |}








>







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
set helperscript {
    if {[lsearch [namespace children] ::tcltest] == -1} {
	package require tcltest 2
	namespace import -force ::tcltest::*
    }

    proc note  {item}  {global res; lappend res $item; return}
    #proc note  {item}  {global res; lappend res $item; puts $item ; flush stdout ; return}
    proc track {}      {upvar args item; note $item; return}
    proc notes {items} {foreach i $items {note $i}}

    # Use to prevent *'s in pattern to match beyond the expected end
    # of the recording.
    proc endnote {} {note |}

448
449
450
451
452
453
454







455



























456
457
458
459
460
461
462
    set c [chan push [tempchan] foo]
    note [catch {read $c 2} msg opt]; note $msg; noteOpts $opt
    tempdone
    rename foo {}
    set res
} -result {{read rt* {test data
}} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}}




































# --- === *** ###########################
# method write (via puts)

test iortrans-5.1 {chan write, regular write} -match glob -body {
    set res {}
    proc foo {args} { oninit; onfinal; track ; return transformresult }







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







449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
    set c [chan push [tempchan] foo]
    note [catch {read $c 2} msg opt]; note $msg; noteOpts $opt
    tempdone
    rename foo {}
    set res
} -result {{read rt* {test data
}} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}}
test iortrans-4.8 {chan read, read, bug 2921116} -match glob -setup {
    set res {}
    proc foo {fd args} {
	oninit; onfinal; track
	# Kill and recreate transform while it is operating
	chan pop  $fd
	chan push $fd [list foo $fd]
    }
    set c [chan push [set c [tempchan]] [list foo $c]]
} -body {
    note [read $c]
    #note [gets $c]
    set res
} -cleanup {
    tempdone
    rename foo {}
} -result {{read rt* {test data
}} file*}
test iortrans-4.9 {chan read, gets, bug 2921116} -match glob -setup {
    set res {}
    proc foo {fd args} {
	oninit; onfinal; track
	# Kill and recreate transform while it is operating
	chan pop  $fd
	chan push $fd [list foo $fd]
    }
    set c [chan push [set c [tempchan]] [list foo $c]]
} -body {
    note [gets $c]
    set res
} -cleanup {
    tempdone
    rename foo {}
} -result {{read rt* {test data
}} file*}

# --- === *** ###########################
# method write (via puts)

test iortrans-5.1 {chan write, regular write} -match glob -body {
    set res {}
    proc foo {args} { oninit; onfinal; track ; return transformresult }
556
557
558
559
560
561
562






















563
564
565
566
567
568
569
    note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg opt]
    note $msg
    noteOpts $opt
    tempdone
    rename foo {}
    set res
} -result {{write rt* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "write"*}}























# --- === *** ###########################
# method limit?, drain (via read)

test iortrans-6.1 {chan read, read limits} -match glob -body {
    set res {}
    proc foo {args} {







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







591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
    note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg opt]
    note $msg
    noteOpts $opt
    tempdone
    rename foo {}
    set res
} -result {{write rt* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "write"*}}
test iortrans-5.11 {chan write, bug 2921116} -match glob -setup {
    set res {}
    set level 0
    proc foo {fd args} {
	oninit; onfinal; track
	# pop - invokes flush - invokes 'foo write' - infinite recursion - stop it
	global level
	if {$level} { return "" }
	incr level
	# Kill and recreate transform while it is operating
	chan pop  $fd
	chan push $fd [list foo $fd]
    }
    set c [chan push [set c [tempchan]] [list foo $c]]
} -body {
    note [puts -nonewline $c abcdef]
    note [flush $c]
    set res
} -cleanup {
    tempdone
    rename foo {}
} -result {{} {write rt* abcdef} {write rt* abcdef} {}}

# --- === *** ###########################
# method limit?, drain (via read)

test iortrans-6.1 {chan read, read limits} -match glob -body {
    set res {}
    proc foo {args} {
627
628
629
630
631
632
633
















634
635
636
637
638
639
640
    }
    set c [chan push [tempchan] foo]
    seek $c 2
    tempdone
    rename foo {}
    set res
} -result {{clear rt*}}

















# --- === *** ###########################
# method flush (via seek, close)

test iortrans-8.1 {seek flushes write buffers, ignores data} -match glob -body {
    set res {}
    proc foo {args} {







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







684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
    }
    set c [chan push [tempchan] foo]
    seek $c 2
    tempdone
    rename foo {}
    set res
} -result {{clear rt*}}
test iortrans-7.4 {chan clear, bug 2921116} -match glob -setup {
    set res {}
    proc foo {fd args} {
	oninit clear; onfinal; track
	# Kill and recreate transform while it is operating
	chan pop  $fd
	chan push $fd [list foo $fd]
    }
    set c [chan push [set c [tempchan]] [list foo $c]]
} -body {
    seek $c 2
    set res
} -cleanup {
    tempdone
    rename foo {}
} -result {{clear rt*}}

# --- === *** ###########################
# method flush (via seek, close)

test iortrans-8.1 {seek flushes write buffers, ignores data} -match glob -body {
    set res {}
    proc foo {args} {
662
663
664
665
666
667
668
















669
670
671
672
673
674
675
    close $c
    note [tempview]
    tempdone
    rename foo {}
    set res
} -result {{flush rt*} {finalize rt*} .flushed.}


















# --- === *** ###########################
# method watch - removed from TIP (rev 1.12+)

# --- === *** ###########################
# method event - removed from TIP (rev 1.12+)








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







735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
    close $c
    note [tempview]
    tempdone
    rename foo {}
    set res
} -result {{flush rt*} {finalize rt*} .flushed.}

test iortrans-8.3 {chan flush, bug 2921116} -match glob -setup {
    set res {}
    proc foo {fd args} {
	oninit flush; onfinal; track
	# Kill and recreate transform while it is operating
	chan pop  $fd
	chan push $fd [list foo $fd]
    }
    set c [chan push [set c [tempchan]] [list foo $c]]
} -body {
    seek $c 2
    set res
} -cleanup {
    tempdone
    rename foo {}
} -result {{flush rt*}}

# --- === *** ###########################
# method watch - removed from TIP (rev 1.12+)

# --- === *** ###########################
# method event - removed from TIP (rev 1.12+)

761
762
763
764
765
766
767






















768
769
770
771
772
773
774
	set res
    }]
    tempdone
    set res
} -constraints {testchannel impossible} \
    -result {Owner lost}























# ### ### ### ######### ######### #########
## Same tests as above, but exercising the code forwarding and
## receiving driver operations to the originator thread.

# -*- tcl -*-
# ### ### ### ######### ######### #########
## Testing the reflected channel (Thread forwarding).







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







850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
	set res
    }]
    tempdone
    set res
} -constraints {testchannel impossible} \
    -result {Owner lost}


test iortrans-11.2 {delete interp of reflected transform} -body {
    interp create slave

    # Magic to get the test* commands into the slave
    load {} Tcltest slave

    # Get base channel into the slave
    set c [tempchan]
    testchannel cut $c
    interp eval slave [list testchannel splice $c]
    interp eval slave [list set c $c]

    slave eval {
        proc no-op args {}
        proc driver {c sub args} {return {initialize finalize read write}}
	set t [chan push $c [list driver $c]]
        chan event $c readable no-op
    }
    interp delete slave
} -result {} -constraints {testchannel}

# ### ### ### ######### ######### #########
## Same tests as above, but exercising the code forwarding and
## receiving driver operations to the originator thread.

# -*- tcl -*-
# ### ### ### ######### ######### #########
## Testing the reflected channel (Thread forwarding).
Changes to tests/load.test.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

testConstraint teststaticpkg [llength [info commands teststaticpkg]]

# Test load-10.1 requires the 'testsimplefilesystem' command from tcltest

testConstraint testsimplefilesystem \
	[llength [info commands testsimplefilesystem]]

test load-1.1 {basic errors} {} {
    list [catch {load} msg] $msg
} "1 {wrong \# args: should be \"load fileName ?packageName? ?interp?\"}"
test load-1.2 {basic errors} {} {
    list [catch {load a b c d} msg] $msg
} "1 {wrong \# args: should be \"load fileName ?packageName? ?interp?\"}"
test load-1.3 {basic errors} {} {







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

testConstraint teststaticpkg [llength [info commands teststaticpkg]]

# Test load-10.1 requires the 'testsimplefilesystem' command from tcltest

testConstraint testsimplefilesystem \
	[llength [info commands testsimplefilesystem]]

test load-1.1 {basic errors} {} {
    list [catch {load} msg] $msg
} "1 {wrong \# args: should be \"load fileName ?packageName? ?interp?\"}"
test load-1.2 {basic errors} {} {
    list [catch {load a b c d} msg] $msg
} "1 {wrong \# args: should be \"load fileName ?packageName? ?interp?\"}"
test load-1.3 {basic errors} {} {
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81


82
83
84
85
86
87
88
test load-1.6 {basic errors} {} {
    list [catch {load {} Unknown} msg] $msg
} {1 {package "Unknown" isn't loaded statically}}

test load-2.1 {basic loading, with guess for package name} \
	[list $dll $loaded] {
    load [file join $testDir pkga$ext]
    list [pkga_eq abc def] [info commands pkga_*]
} {0 {pkga_eq pkga_quote}}
interp create -safe child
test load-2.2 {loading into a safe interpreter, with package name conversion} \
	[list $dll $loaded] {
    load [file join $testDir pkgb$ext] pKgB child
    list [child eval pkgb_sub 44 13] [catch {child eval pkgb_unsafe} msg] $msg \
	    [catch {pkgb_sub 12 10} msg2] $msg2
} {31 1 {invalid command name "pkgb_unsafe"} 1 {invalid command name "pkgb_sub"}}
test load-2.3 {loading with no _Init procedure} -constraints [list $dll $loaded] \
-body {
    list [catch {load [file join $testDir pkgc$ext] foo} msg] $msg
} -match glob -result {1 {*couldn't find procedure Foo_Init}}


test load-2.4 {loading with no _SafeInit procedure} [list $dll $loaded] {
    list [catch {load [file join $testDir pkga$ext] {} child} msg] $msg
} {1 {can't use package in a safe interpreter: no Pkga_SafeInit procedure}}

test load-3.1 {error in _Init procedure, same interpreter} \
	[list $dll $loaded] {
    list [catch {load [file join $testDir pkge$ext] pkge} msg] \







|










|
|
>
>







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
test load-1.6 {basic errors} {} {
    list [catch {load {} Unknown} msg] $msg
} {1 {package "Unknown" isn't loaded statically}}

test load-2.1 {basic loading, with guess for package name} \
	[list $dll $loaded] {
    load [file join $testDir pkga$ext]
    list [pkga_eq abc def] [lsort [info commands pkga_*]]
} {0 {pkga_eq pkga_quote}}
interp create -safe child
test load-2.2 {loading into a safe interpreter, with package name conversion} \
	[list $dll $loaded] {
    load [file join $testDir pkgb$ext] pKgB child
    list [child eval pkgb_sub 44 13] [catch {child eval pkgb_unsafe} msg] $msg \
	    [catch {pkgb_sub 12 10} msg2] $msg2
} {31 1 {invalid command name "pkgb_unsafe"} 1 {invalid command name "pkgb_sub"}}
test load-2.3 {loading with no _Init procedure} -constraints [list $dll $loaded] \
-body {
    list [catch {load [file join $testDir pkgc$ext] foo} msg] $msg $errorCode
} -match glob \
    -result [list 1 {cannot find symbol "Foo_Init"*} \
		 {TCL LOOKUP LOAD_SYMBOL *Foo_Init}]
test load-2.4 {loading with no _SafeInit procedure} [list $dll $loaded] {
    list [catch {load [file join $testDir pkga$ext] {} child} msg] $msg
} {1 {can't use package in a safe interpreter: no Pkga_SafeInit procedure}}

test load-3.1 {error in _Init procedure, same interpreter} \
	[list $dll $loaded] {
    list [catch {load [file join $testDir pkge$ext] pkge} msg] \
202
203
204
205
206
207
208
209
210
211
212
213





test load-10.1 {load from vfs} \
    -constraints [list $dll $loaded testsimplefilesystem] \
    -setup {set dir [pwd]; cd $testDir; testsimplefilesystem 1} \
    -body {list [catch {load simplefs:/pkgd$ext pkgd} msg] $msg} \
    -result {0 {}} \
    -cleanup {testsimplefilesystem 0; cd $dir; unset dir}

# cleanup
unset ext
::tcltest::cleanupTests
return











|




>
>
>
>
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

test load-10.1 {load from vfs} \
    -constraints [list $dll $loaded testsimplefilesystem] \
    -setup {set dir [pwd]; cd $testDir; testsimplefilesystem 1} \
    -body {list [catch {load simplefs:/pkgd$ext pkgd} msg] $msg} \
    -result {0 {}} \
    -cleanup {testsimplefilesystem 0; cd $dir; unset dir}

# cleanup
unset ext
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/namespace.test.
14
15
16
17
18
19
20


21
22
23
24
25
26
27
# RCS: @(#) $Id: namespace.test,v 1.72 2008/06/20 20:48:49 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}



#
# REMARK: the tests for 'namespace upvar' are not done here. They are to be
# found in the file 'upvar.test'.
#

# Clear out any namespaces called test_ns_*
catch {namespace delete {*}[namespace children :: test_ns_*]}







>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# RCS: @(#) $Id: namespace.test,v 1.72 2008/06/20 20:48:49 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

testConstraint memory [llength [info commands memory]]

#
# REMARK: the tests for 'namespace upvar' are not done here. They are to be
# found in the file 'upvar.test'.
#

# Clear out any namespaces called test_ns_*
catch {namespace delete {*}[namespace children :: test_ns_*]}
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
    }
} -result {2 {} 2} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
    catch {namespace delete ::test_ns_4}
}

test namespace-51.13 {name resolution path control} -body {
    set ::result {}
    namespace eval ::test_ns_1 {
	proc foo {} {lappend ::result 1}
    }
    namespace eval ::test_ns_2 {
	proc foo {} {lappend ::result 2}
	trace add command foo delete {namespace eval ::test_ns_3 foo;#}
    }
    namespace eval ::test_ns_3 {
	proc foo {} {
	    lappend ::result 3
	    namespace delete [namespace current]
	    ::test_ns_4::bar
	}







<







|







2394
2395
2396
2397
2398
2399
2400

2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
    }
} -result {2 {} 2} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
    catch {namespace delete ::test_ns_4}
}

test namespace-51.13 {name resolution path control} -body {
    set ::result {}
    namespace eval ::test_ns_1 {
	proc foo {} {lappend ::result 1}
    }
    namespace eval ::test_ns_2 {
	proc foo {} {lappend ::result 2}
	trace add command foo delete "namespace eval ::test_ns_3 foo;#"
    }
    namespace eval ::test_ns_3 {
	proc foo {} {
	    lappend ::result 3
	    namespace delete [namespace current]
	    ::test_ns_4::bar
	}
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438

2439

2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
    # Should the result be "2 {} {2 3 2 1}" instead?
} -result {2 {} {2 3 1 1}} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
    catch {namespace delete ::test_ns_4}
}
test namespace-51.14 {name resolution path control} -body {
    foreach cmd [info commands foo*] {
	rename $cmd {}
    }
    proc foo0 {} {}
    namespace eval ::test_ns_1 {
	proc foo1 {} {}
    }
    namespace eval ::test_ns_2 {

	proc foo2 {} {}

    }
    namespace eval ::test_ns_3 {
	variable result {}
	lappend result [info commands foo*]
	namespace path {::test_ns_1 ::test_ns_2}
	lappend result [info commands foo*]
	proc foo2 {} {}
	lappend result [info commands foo*]
	rename foo2 {}
	lappend result [info commands foo*]
	namespace delete ::test_ns_1
	lappend result [info commands foo*]
    }
} -result {foo0 {foo1 foo2 foo0} {foo2 foo1 foo0} {foo1 foo2 foo0} {foo2 foo0}} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
}
test namespace-51.15 {namespace resolution path control} -body {
    namespace eval ::test_ns_2 {
	proc foo {} {return 2}
    }
    namespace eval ::test_ns_1 {
	namespace eval test_ns_2 {
	    proc foo {} {return 1_2}







|



<
|
|
<
|
>
|
>
|












|



|







2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434

2435
2436

2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
    # Should the result be "2 {} {2 3 2 1}" instead?
} -result {2 {} {2 3 1 1}} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
    catch {namespace delete ::test_ns_4}
}
test namespace-51.14 {name resolution path control} -setup {
    foreach cmd [info commands foo*] {
	rename $cmd {}
    }

    namespace eval ::test_ns_1 {}
    namespace eval ::test_ns_2 {}

    namespace eval ::test_ns_3 {}
} -body {
    proc foo0 {} {}
    proc ::test_ns_1::foo1 {} {}
    proc ::test_ns_2::foo2 {} {}
    namespace eval ::test_ns_3 {
	variable result {}
	lappend result [info commands foo*]
	namespace path {::test_ns_1 ::test_ns_2}
	lappend result [info commands foo*]
	proc foo2 {} {}
	lappend result [info commands foo*]
	rename foo2 {}
	lappend result [info commands foo*]
	namespace delete ::test_ns_1
	lappend result [info commands foo*]
    }
} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
} -result {foo0 {foo1 foo2 foo0} {foo2 foo1 foo0} {foo1 foo2 foo0} {foo2 foo0}}
test namespace-51.15 {namespace resolution path control} -body {
    namespace eval ::test_ns_2 {
	proc foo {} {return 2}
    }
    namespace eval ::test_ns_1 {
	namespace eval test_ns_2 {
	    proc foo {} {return 1_2}
2473
2474
2475
2476
2477
2478
2479








































2480
2481
2482
2483
2484
2485
2486
    namespace delete ::test_ns_2
}
test namespace-51.16 {Bug 1566526} {
    interp create slave
    slave eval namespace eval demo namespace path ::
    interp delete slave
} {}









































# TIP 181 - namespace unknown tests
test namespace-52.1 {unknown: default handler ::unknown} {
    set result [list [namespace eval foobar { namespace unknown }]]
    lappend result [namespace eval :: { namespace unknown }]
    namespace delete foobar
    set result







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







2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
    namespace delete ::test_ns_2
}
test namespace-51.16 {Bug 1566526} {
    interp create slave
    slave eval namespace eval demo namespace path ::
    interp delete slave
} {}
test namespace-51.17 {resolution epoch handling: Bug 2898722} -setup {
    set result {}
    catch {namespace delete ::a}
} -constraints knownBug -body {
    namespace eval ::a {
	proc c {} {lappend ::result A}
	c
	namespace eval b {
	    variable d c
	    lappend ::result [catch { $d }]
	}
	lappend ::result .
	namespace eval b {
	    namespace path [namespace parent]
	    $d;[format %c 99]
	}
	lappend ::result .
	namespace eval b {
	    proc c {} {lappend ::result B}
	    $d;[format %c 99]
	}
	lappend ::result .
    }
    namespace eval ::a::b {
	$d;[format %c 99]
	lappend ::result .
	proc ::c {} {lappend ::result G}
	$d;[format %c 99]
	lappend ::result .
	rename ::a::c {}
	$d;[format %c 99]
	lappend ::result .
	rename ::a::b::c {}
	$d;[format %c 99]
    }
} -cleanup {
    namespace delete ::a
    catch {rename ::c {}}
    unset result
} -result {A 1 . A A . B B . B B . B B . B B . G G}

# TIP 181 - namespace unknown tests
test namespace-52.1 {unknown: default handler ::unknown} {
    set result [list [namespace eval foobar { namespace unknown }]]
    lappend result [namespace eval :: { namespace unknown }]
    namespace delete foobar
    set result
2848
2849
2850
2851
2852
2853
2854





















2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
    1 {wrong # args: should be "ns z1 x a1"}\
    1 {wrong # args: should be "ns z2 x a1 a2"}\
    1 {wrong # args: should be "ns z2 x a1 a2"}\
    1 {wrong # args: should be "::ns::x::z0"}\
    0 {1 v}\
    1 {wrong # args: should be "ns v x z2 a2"}\
    0 {2 v v2}}






















# cleanup
catch {rename cmd1 {}}
catch {unset l}
catch {unset msg}
catch {unset trigger}
namespace delete {*}[namespace children :: test_ns_*]
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







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













2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
    1 {wrong # args: should be "ns z1 x a1"}\
    1 {wrong # args: should be "ns z2 x a1 a2"}\
    1 {wrong # args: should be "ns z2 x a1 a2"}\
    1 {wrong # args: should be "::ns::x::z0"}\
    0 {1 v}\
    1 {wrong # args: should be "ns v x z2 a2"}\
    0 {2 v v2}}

test namespace-54.1 {leak on namespace deletion} -constraints {memory} \
-setup {
    proc getbytes {} {
	set lines [split [memory info] "\n"]
	lindex $lines 3 3
    }
} -body {
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {
	set ns ::y$i
	namespace eval $ns {}
	namespace delete $ns
	set start $end
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $start}]
} -cleanup {
    rename getbytes {}
    unset i ns start end
} -result 0

# cleanup
catch {rename cmd1 {}}
catch {unset l}
catch {unset msg}
catch {unset trigger}
namespace delete {*}[namespace children :: test_ns_*]
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/oo.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# This file contains a collection of tests for Tcl's built-in object system.
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright (c) 2006-2008 Donal K. Fellows
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: oo.test,v 1.7 2008/06/19 21:29:04 dkf Exp $

package require TclOO 0.6.1 ;# Must match value in generic/tclOO.h
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

testConstraint memory [llength [info commands memory]]
if {[testConstraint memory]} {











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# This file contains a collection of tests for Tcl's built-in object system.
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright (c) 2006-2008 Donal K. Fellows
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: oo.test,v 1.7 2008/06/19 21:29:04 dkf Exp $

package require -exact TclOO 0.6.2 ;# Must match value in generic/tclOO.h
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

testConstraint memory [llength [info commands memory]]
if {[testConstraint memory]} {
68
69
70
71
72
73
74




































75
76
77
78
79
80
81
test oo-0.5 {testing literal leak on interp delete} memory {
    leaktest {
	interp create foo
	foo eval {oo::object new}
	interp delete foo
    }
} 0





































test oo-1.1 {basic test of OO functionality: no classes} {
    set result {}
    lappend result [oo::object create foo]
    lappend result [oo::objdefine foo {
	method bar args {
	    global result







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







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
test oo-0.5 {testing literal leak on interp delete} memory {
    leaktest {
	interp create foo
	foo eval {oo::object new}
	interp delete foo
    }
} 0
test oo-0.6 {cleaning the core class pair; way #1} -setup {
    interp create t
    initInterpreter t
} -body {
    t eval {
	package require TclOO
	namespace path oo
	list [catch {class destroy} m] $m [catch {object destroy} m] $m
    }
} -cleanup {
    interp delete t
} -result {0 {} 1 {invalid command name "object"}}
test oo-0.7 {cleaning the core class pair; way #2} -setup {
    interp create t
    initInterpreter t
} -body {
    t eval {
	package require TclOO
	namespace path oo
	list [catch {object destroy} m] $m [catch {class destroy} m] $m
    }
} -cleanup {
    interp delete t
} -result {0 {} 1 {invalid command name "class"}}
test oo-0.8 {leak in variable management} -setup {
    oo::class create foo
} -constraints memory -body {
    oo::define foo {
	constructor {} {
	    variable v 0
	}
    }
    leaktest {[foo new] destroy}
} -cleanup {
    foo destroy
} -result 0

test oo-1.1 {basic test of OO functionality: no classes} {
    set result {}
    lappend result [oo::object create foo]
    lappend result [oo::objdefine foo {
	method bar args {
	    global result
217
218
219
220
221
222
223












224
225
226
227
228
229
230
} -body {
    oo::define B constructor {} {A create test-oo-1.18}
    B create C
} -cleanup {
    rename test-oo-1.18 {}
    A destroy
} -result ::C













test oo-2.1 {basic test of OO functionality: constructor} -setup {
    # This is a bit complex because it needs to run in a sub-interp as
    # we're modifying the root object class's constructor
    interp create subinterp
    initInterpreter subinterp
    subinterp eval {







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







253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
} -body {
    oo::define B constructor {} {A create test-oo-1.18}
    B create C
} -cleanup {
    rename test-oo-1.18 {}
    A destroy
} -result ::C
test oo-1.19 {basic test of OO functionality: teardown order} -body {
    oo::object create o
    namespace delete [info object namespace o]
    o destroy
    # Crashes on error
} -returnCodes error -result {invalid command name "o"}
test oo-1.20 {basic test of OO functionality: my teardown post rename} -body {
    oo::object create obj
    rename [info object namespace obj]::my ::AGlobalName
    obj destroy
    info commands ::AGlobalName
} -result {}

test oo-2.1 {basic test of OO functionality: constructor} -setup {
    # This is a bit complex because it needs to run in a sub-interp as
    # we're modifying the root object class's constructor
    interp create subinterp
    initInterpreter subinterp
    subinterp eval {
315
316
317
318
319
320
321






























































































































































322
323
324
325
326
327
328
	}
	lappend result 1 [oo::object create foo]
	lappend result 2 [rename foo {}]
    }
} -cleanup {
    interp delete subinterp
} -result {1 ::foo died 2 {}}































































































































































test oo-4.1 {basic test of OO functionality: export} {
    set o [oo::object new]
    set result {}
    oo::objdefine $o method Foo {} {lappend ::result Foo; return}
    lappend result [catch {$o Foo} msg] $msg
    oo::objdefine $o export Foo







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







363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
	}
	lappend result 1 [oo::object create foo]
	lappend result 2 [rename foo {}]
    }
} -cleanup {
    interp delete subinterp
} -result {1 ::foo died 2 {}}
test oo-3.3 {basic test of OO functionality: destructor} -setup {
    oo::class create foo
    set result {}
} -cleanup {
    foo destroy
} -body {
    oo::define foo {
	constructor {} {lappend ::result made}
	destructor {lappend ::result died}
    }
    namespace delete [info object namespace [foo new]]
    return $result
} -result {made died}
test oo-3.4 {basic test of OO functionality: my exists in destructor} -setup {
    oo::class create cls
    set result {}
} -cleanup {
    cls destroy
} -body {
    oo::define cls {
	variable state
	constructor {} {
	    proc localcmdexists {} {}
	    set state ok
	}
	forward Report lappend ::result
	destructor {
	    objmy Report [catch {set state} msg] $msg
	    objmy Report [namespace which -var state]
	    objmy Report [info commands localcmdexists]
	}
    }
    cls create obj
    rename [info object namespace obj]::my ::objmy
    obj destroy
    lappend result [info commands ::objmy]
} -match glob -result {0 ok *::state localcmdexists {}}
test oo-3.4a {basic test of OO functionality: my exists in destructor} -setup {
    oo::class create cls
    set result {}
} -cleanup {
    cls destroy
} -body {
    oo::define cls {
	variable state
	constructor {} {
	    proc localcmdexists {} {}
	    set state ok
	}
	forward Report lappend ::result
	destructor {
	    objmy Report [catch {set state} msg] $msg
	    objmy Report [namespace which -var state]
	    objmy Report [info commands localcmdexists]
	}
    }
    cls create obj
    rename [info object namespace obj]::my ::objmy
    rename obj {}
    lappend result [info commands ::objmy]
} -match glob -result {0 ok *::state localcmdexists {}}
test oo-3.5 {basic test of OO functionality: destructor: evil case for Itcl} -setup {
    oo::class create cls
    set result {}
} -cleanup {
    cls destroy
} -body {
    oo::define cls {
	variable state
	constructor {} {
	    proc localcmdexists {} {}
	    set state ok
	}
	forward Report lappend ::result
	destructor {
	    objmy Report [catch {set state} msg] $msg
	    objmy Report [namespace which -var state]
	    objmy Report [info commands localcmdexists]
	}
    }
    cls create obj
    rename [info object namespace obj]::my ::objmy
    namespace delete [info object namespace obj]
    lappend result [info commands ::objmy]
} -match glob -result {0 ok *::state localcmdexists {}}
test oo-3.5a {basic test of OO functionality: destructor: evil case for Itcl} -setup {
    oo::class create cls
    set result {}
} -cleanup {
    cls destroy
} -body {
    oo::define cls {
	variable state result
	constructor {} {
	    proc localcmdexists {} {}
	    set state ok
	    my eval {upvar 0 ::result result}
	}
	method nuke {} {
	    namespace delete [namespace current]
	    return $result
	}
	destructor {
	    lappend result [self] $state [info commands localcmdexists]
	}
    }
    cls create obj
    namespace delete [info object namespace obj]
    [cls create obj2] nuke
} -match glob -result {::obj ok localcmdexists ::obj2 ok localcmdexists}
test oo-3.6 {basic test of OO functionality: errors in destructor} -setup {
    oo::class create cls
} -cleanup {
    cls destroy
} -body {
    oo::define cls destructor {error foo}
    list [catch {[cls create obj] destroy} msg] $msg [info commands obj]
} -result {1 foo {}}
test oo-3.7 {basic test of OO functionality: errors in destructor} -setup {
    oo::class create cls
    set result {}
    proc bgerror msg {lappend ::result $msg}
} -cleanup {
    cls destroy
    rename bgerror {}
} -body {
    oo::define cls destructor {error foo}
    list [rename [cls create obj] {}] \
	[update idletasks] $result [info commands obj]
} -result {{} {} foo {}}
test oo-3.8 {basic test of OO functionality: errors in destructor} -setup {
    oo::class create cls
    set result {}
    proc bgerror msg {lappend ::result $msg}
} -cleanup {
    cls destroy
    rename bgerror {}
} -body {
    oo::define cls destructor {error foo}
    list [namespace delete [info object namespace [cls create obj]]] \
	[update idletasks] $result [info commands obj]
} -result {{} {} foo {}}
test oo-3.9 {Bug 2944404: deleting the object in the destructor} -setup {
    oo::class create cls
    set result {}
} -body {
    oo::define cls {
	destructor {
	    lappend ::result in destructor
	    [self] destroy
	}
    }
    # This used to crash
    [cls new] destroy
    return $result
} -cleanup {
    cls destroy
} -result {in destructor}

test oo-4.1 {basic test of OO functionality: export} {
    set o [oo::object new]
    set result {}
    oo::objdefine $o method Foo {} {lappend ::result Foo; return}
    lappend result [catch {$o Foo} msg] $msg
    oo::objdefine $o export Foo
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
    info object
} -returnCodes 1 -result "wrong \# args: should be \"info object subcommand ?arg ...?\""
test oo-16.2 {OO: object introspection} -body {
    info object class NOTANOBJECT
} -returnCodes 1 -result {NOTANOBJECT does not refer to an object}
test oo-16.3 {OO: object introspection} -body {
    info object gorp oo::object
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be class, definition, filters, forward, isa, methods, mixins, namespace, variables, or vars}
test oo-16.4 {OO: object introspection} -setup {
    oo::class create meta { superclass oo::class }
    [meta create instance1] create instance2
} -body {
    list [list [info object class oo::object] \
	      [info object class oo::class] \
	      [info object class meta] \







|







1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
    info object
} -returnCodes 1 -result "wrong \# args: should be \"info object subcommand ?arg ...?\""
test oo-16.2 {OO: object introspection} -body {
    info object class NOTANOBJECT
} -returnCodes 1 -result {NOTANOBJECT does not refer to an object}
test oo-16.3 {OO: object introspection} -body {
    info object gorp oo::object
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be class, definition, filters, forward, isa, methods, methodtype, mixins, namespace, variables, or vars}
test oo-16.4 {OO: object introspection} -setup {
    oo::class create meta { superclass oo::class }
    [meta create instance1] create instance2
} -body {
    list [list [info object class oo::object] \
	      [info object class oo::class] \
	      [info object class meta] \
1346
1347
1348
1349
1350
1351
1352
1353

1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
    lappend result [info object methods foo] [foo destroy]
} {{} bar {}}
test oo-16.7 {OO: object introspection} -setup {
    oo::object create foo
} -body {
    oo::objdefine foo method bar {a {b c} args} {the body}
    set result [info object methods foo]
    lappend result [info object definition foo bar]

} -cleanup {
    foo destroy
} -result {bar {{a {b c} args} {the body}}}
test oo-16.8 {OO: object introspection} {
    oo::object create foo
    oo::class create bar
    oo::objdefine foo mixin bar
    set result [list [info object mixins foo] \
		    [info object isa mixin foo bar] \
		    [info object isa mixin foo oo::class]]







|
>


|







1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
    lappend result [info object methods foo] [foo destroy]
} {{} bar {}}
test oo-16.7 {OO: object introspection} -setup {
    oo::object create foo
} -body {
    oo::objdefine foo method bar {a {b c} args} {the body}
    set result [info object methods foo]
    lappend result [info object methodtype foo bar] \
	[info object definition foo bar]
} -cleanup {
    foo destroy
} -result {bar method {{a {b c} args} {the body}}}
test oo-16.8 {OO: object introspection} {
    oo::object create foo
    oo::class create bar
    oo::objdefine foo mixin bar
    set result [list [info object mixins foo] \
		    [info object isa mixin foo bar] \
		    [info object isa mixin foo oo::class]]
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449

1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
} -body {
    info class superclass foo
} -returnCodes 1 -cleanup {
    foo destroy
} -result {"foo" is not a class}
test oo-17.4 {OO: class introspection} -body {
    info class gorp oo::object
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be constructor, definition, destructor, filters, forward, instances, methods, mixins, subclasses, superclasses, or variables}
test oo-17.5 {OO: class introspection} -setup {
    oo::class create testClass
} -body {
    testClass create foo
    testClass create bar
    testClass create spong
    lsort [info class instances testClass]
} -cleanup {
    testClass destroy
} -result {::bar ::foo ::spong}
test oo-17.6 {OO: class introspection} -setup {
    oo::class create foo
} -body {
    oo::define foo method bar {a {b c} args} {the body}
    set result [info class methods foo]
    lappend result [info class definition foo bar]

} -cleanup {
    foo destroy
} -result {bar {{a {b c} args} {the body}}}
test oo-17.7 {OO: class introspection} {
    info class superclasses oo::class
} ::oo::object
test oo-17.8 {OO: class introspection} -setup {
    oo::class create testClass
    oo::class create superClass1
    oo::class create superClass2







|















|
>


|







1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
} -body {
    info class superclass foo
} -returnCodes 1 -cleanup {
    foo destroy
} -result {"foo" is not a class}
test oo-17.4 {OO: class introspection} -body {
    info class gorp oo::object
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be constructor, definition, destructor, filters, forward, instances, methods, methodtype, mixins, subclasses, superclasses, or variables}
test oo-17.5 {OO: class introspection} -setup {
    oo::class create testClass
} -body {
    testClass create foo
    testClass create bar
    testClass create spong
    lsort [info class instances testClass]
} -cleanup {
    testClass destroy
} -result {::bar ::foo ::spong}
test oo-17.6 {OO: class introspection} -setup {
    oo::class create foo
} -body {
    oo::define foo method bar {a {b c} args} {the body}
    set result [info class methods foo]
    lappend result [info class methodtype foo bar] \
	[info class definition foo bar]
} -cleanup {
    foo destroy
} -result {bar method {{a {b c} args} {the body}}}
test oo-17.7 {OO: class introspection} {
    info class superclasses oo::class
} ::oo::object
test oo-17.8 {OO: class introspection} -setup {
    oo::class create testClass
    oo::class create superClass1
    oo::class create superClass2
1611
1612
1613
1614
1615
1616
1617











1618
1619
1620
1621
1622
1623
1624
	}]
    }
    lappend result [inst eval set x 0]
} -cleanup {
    inst destroy
    rename foo {}
} -result {{x {} write} ok ok 0}












test oo-20.1 {OO: variable method} -body {
    oo::class create testClass {
	constructor {} {
	    my variable ok
	    set ok {}
	}







>
>
>
>
>
>
>
>
>
>
>







1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
	}]
    }
    lappend result [inst eval set x 0]
} -cleanup {
    inst destroy
    rename foo {}
} -result {{x {} write} ok ok 0}
test oo-19.2 {OO: varname method: Bug 2883857} -setup {
    oo::class create SpecialClass
    oo::objdefine SpecialClass export createWithNamespace
    SpecialClass createWithNamespace inst ::oo_test
    oo::objdefine inst export varname eval
} -body {
    inst eval { variable x; array set x {y z} }
    inst varname x(y)
} -cleanup {
    SpecialClass destroy
} -result ::oo_test::x(y)

test oo-20.1 {OO: variable method} -body {
    oo::class create testClass {
	constructor {} {
	    my variable ok
	    set ok {}
	}
1789
1790
1791
1792
1793
1794
1795













































1796
1797
1798
1799
1800
1801
1802
    foo destroy
} -body {
    oo::objdefine foo method demo {} {
	my variable
    }
    foo demo
} -result {}














































test oo-21.1 {OO: inheritance ordering} -setup {
    oo::class create A
} -body {
    oo::define A method m {} {lappend ::result A}
    oo::class create B {
	superclass A







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







2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
    foo destroy
} -body {
    oo::objdefine foo method demo {} {
	my variable
    }
    foo demo
} -result {}
test oo-20.13 {OO: variable method use in non-methods [Bug 2903811]} -setup {
    oo::object create fooObj
    oo::objdefine fooObj export variable
} -cleanup {
    fooObj destroy
} -body {
    apply {{} {fooObj variable x; set x ok; return}}
    apply {{} {fooObj variable x; return $x}}
} -result ok
test oo-20.14 {OO: variable method use in non-methods [Bug 2903811]} -setup {
    oo::object create fooObj
    oo::objdefine fooObj export variable
    namespace eval ns1 {}
    namespace eval ns2 {}
    set x bad
} -cleanup {
    fooObj destroy
    namespace delete ns1 ns2
    unset x
} -body {
    namespace eval ns1 {fooObj variable x; set x ok; subst ""}
    set x bad
    namespace eval ns2 {fooObj variable x; return $x}
} -result ok
test oo-20.15 {OO: variable method use in non-methods [Bug 2903811]} -setup {
    oo::object create fooObj
    oo::objdefine fooObj export variable varname
} -cleanup {
    fooObj destroy
} -body {
    apply {{} {fooObj variable x; set x ok; return}}
    return [set [fooObj varname x]]
} -result ok
test oo-20.16 {variable method: leak per instance} -setup {
    oo::class create foo
} -constraints memory -body {
    oo::define foo {
	constructor {} {
	    set [my variable v] 0
	}
    }
    leaktest {[foo new] destroy}
} -cleanup {
    foo destroy
} -result 0

test oo-21.1 {OO: inheritance ordering} -setup {
    oo::class create A
} -body {
    oo::define A method m {} {lappend ::result A}
    oo::class create B {
	superclass A
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
	method level {} {
	    expr {[next] - [info frame]}
	}
    }
    list [i level] [i frames] [dict get [c frame] object]
} -cleanup {
    c destroy
} -result {1 {{* cmd {info frame 0} method frames class ::c level 0} {* cmd {info frame 0} method frames object ::i level 0}} ::c}

# Prove that the issue in [Bug 1865054] isn't an issue any more
test oo-23.1 {Self-like derivation; complex case!} -setup {
    oo::class create SELF {
	superclass oo::class
	unexport create new
	# Next is just a convenience







|







2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
	method level {} {
	    expr {[next] - [info frame]}
	}
    }
    list [i level] [i frames] [dict get [c frame] object]
} -cleanup {
    c destroy
} -result {1 {{type source line * file * cmd {info frame 0} method frames class ::c level 0} {type source line * file * cmd {info frame 0} method frames object ::i level 0}} ::c}

# Prove that the issue in [Bug 1865054] isn't an issue any more
test oo-23.1 {Self-like derivation; complex case!} -setup {
    oo::class create SELF {
	superclass oo::class
	unexport create new
	# Next is just a convenience
2276
2277
2278
2279
2280
2281
2282













2283
2284
2285
2286
2287
2288
2289
    inst1 step
    inst2 step
    inst1 step
    inst2 step
    inst1 step
    list [inst1 value] [inst2 value]
} -result {3 2}














# 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 {







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







2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
    inst1 step
    inst2 step
    inst1 step
    inst2 step
    inst1 step
    list [inst1 value] [inst2 value]
} -result {3 2}
test oo-27.12 {variables declaration: leak per instance} -setup {
    oo::class create foo
} -constraints memory -body {
    oo::define foo {
	variable v
	constructor {} {
	    set v 0
	}
    }
    leaktest {[foo new] destroy}
} -cleanup {
    foo destroy
} -result 0

# 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 {
2306
2307
2308
2309
2310
2311
2312

















2313
2314
2315
2316
2317
2318
2319
    oo::objdefine obj method demo {} {
	self class
    }
    obj demo
} -returnCodes error -cleanup {
    obj destroy
} -result {method not defined by a class}


















cleanupTests
return

# Local Variables:
# mode: tcl
# End:







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







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
    oo::objdefine obj method demo {} {
	self class
    }
    obj demo
} -returnCodes error -cleanup {
    obj destroy
} -result {method not defined by a class}

test oo-30.1 {Bug 2903011: deleting an object in a constructor} -setup {
    oo::class create cls
} -body {
    oo::define cls {constructor {} {[self] destroy}}
    cls new
} -returnCodes error -cleanup {
    cls destroy
} -result {object deleted in constructor}
test oo-30.2 {Bug 2903011: deleting an object in a constructor} -setup {
    oo::class create cls
} -body {
    oo::define cls {constructor {} {my destroy}}
    cls new
} -returnCodes error -cleanup {
    cls destroy
} -result {object deleted in constructor}

cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/regexp.test.
15
16
17
18
19
20
21



22
23
24
25
26
27
28

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

catch {unset foo}



test regexp-1.1 {basic regexp operation} {
    regexp ab*c abbbc
} 1
test regexp-1.2 {basic regexp operation} {
    regexp ab*c ac
} 1
test regexp-1.3 {basic regexp operation} {







>
>
>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

catch {unset foo}

testConstraint exec [llength [info commands exec]]

test regexp-1.1 {basic regexp operation} {
    regexp ab*c abbbc
} 1
test regexp-1.2 {basic regexp operation} {
    regexp ab*c ac
} 1
test regexp-1.3 {basic regexp operation} {
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
} {0 1}
test regexp-1.7 {regexp utf compliance} {
    # if not UTF-8 aware, result is "0 1"
    set foo "\u4e4eb q"
    regexp "\u4e4eb q" "a\u4e4eb qw\u5e4e\x4e wq" bar
    list [string compare $foo $bar] [regexp 4 $bar]
} {0 0}

test regexp-1.8 {regexp ***= metasyntax} {
    regexp -- "***=o" "aeiou"
} 1
test regexp-1.9 {regexp ***= metasyntax} {
    set string "aeiou"
    regexp -- "***=o" $string
} 1







<







42
43
44
45
46
47
48

49
50
51
52
53
54
55
} {0 1}
test regexp-1.7 {regexp utf compliance} {
    # if not UTF-8 aware, result is "0 1"
    set foo "\u4e4eb q"
    regexp "\u4e4eb q" "a\u4e4eb qw\u5e4e\x4e wq" bar
    list [string compare $foo $bar] [regexp 4 $bar]
} {0 0}

test regexp-1.8 {regexp ***= metasyntax} {
    regexp -- "***=o" "aeiou"
} 1
test regexp-1.9 {regexp ***= metasyntax} {
    set string "aeiou"
    regexp -- "***=o" $string
} 1
115
116
117
118
119
120
121






















122
123
124
125
126
127
128
    list [regexp f\352te(b*)c f\352tebbbbc foo f2] $foo $f2
} [list 1 f\352tebbbbc bbbb]
test regexp-2.10 {getting substrings back from regexp} {
    set foo {}
    set f2 {}
    list [regexp f\352te(b*)c eff\352tebbbbc foo f2] $foo $f2
} [list 1 f\352tebbbbc bbbb]























test regexp-3.1 {-indices option to regexp} {
    set foo {}
    list [regexp -indices ab*c abbbbc foo] $foo
} {1 {0 5}}
test regexp-3.2 {-indices option to regexp} {
    set foo {}







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







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
    list [regexp f\352te(b*)c f\352tebbbbc foo f2] $foo $f2
} [list 1 f\352tebbbbc bbbb]
test regexp-2.10 {getting substrings back from regexp} {
    set foo {}
    set f2 {}
    list [regexp f\352te(b*)c eff\352tebbbbc foo f2] $foo $f2
} [list 1 f\352tebbbbc bbbb]
test regexp-2.11 {non-capturing subgroup} {
    set foo {}
    set f2 {}
    list [regexp {str(?:a+)} straa foo f2] $foo $f2
} [list 1 straa {}]
test regexp-2.12 {non-capturing subgroup with -inline} {
    regexp -inline {str(?:a+)} straa
} {straa}
test regexp-2.13 {non-capturing and capturing subgroups} {
    set foo {}
    set f2 {}
    set f3 {}
    list [regexp {str(?:a+)(c+)} straacc foo f2 f3] $foo $f2 $f3
} [list 1 straacc cc {}]
test regexp-2.14 {non-capturing and capturing subgroups} {
    regexp -inline {str(?:a+)(c+)} straacc
} {straacc cc}
test regexp-2.15 {getting substrings back from regexp} {
    set foo NA
    set f2 NA
    list [regexp {str(?:a+)} straa foo f2] $foo $f2
} [list 1 straa {}]

test regexp-3.1 {-indices option to regexp} {
    set foo {}
    list [regexp -indices ab*c abbbbc foo] $foo
} {1 {0 5}}
test regexp-3.2 {-indices option to regexp} {
    set foo {}
242
243
244
245
246
247
248



249
250
251
252
253
254
255
    catch {unset f1}
    set f1 44
    list [catch {regexp abc abc f1(f2)} msg] $msg
} {1 {couldn't set variable "f1(f2)"}}
test regexp-6.9 {regexp errors, -start bad int check} {
    list [catch {regexp -start bogus {^$} {}} msg] $msg
} {1 {bad index "bogus": must be integer?[+-]integer? or end?[+-]integer?}}




test regexp-7.1 {basic regsub operation} {
    list [regsub aa+ xaxaaaxaa 111&222 foo] $foo
} {1 xax111aaa222xaa}
test regexp-7.2 {basic regsub operation} {
    list [regsub aa+ aaaxaa &111 foo] $foo
} {1 aaa111xaa}







>
>
>







266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
    catch {unset f1}
    set f1 44
    list [catch {regexp abc abc f1(f2)} msg] $msg
} {1 {couldn't set variable "f1(f2)"}}
test regexp-6.9 {regexp errors, -start bad int check} {
    list [catch {regexp -start bogus {^$} {}} msg] $msg
} {1 {bad index "bogus": must be integer?[+-]integer? or end?[+-]integer?}}
test regexp-6.10 {regexp errors} {
    list [catch {regexp {a[} b} msg] $msg
} {1 {couldn't compile regular expression pattern: brackets [] not balanced}}

test regexp-7.1 {basic regsub operation} {
    list [regsub aa+ xaxaaaxaa 111&222 foo] $foo
} {1 xax111aaa222xaa}
test regexp-7.2 {basic regsub operation} {
    list [regsub aa+ aaaxaa &111 foo] $foo
} {1 aaa111xaa}
301
302
303
304
305
306
307




































308
309
310
311
312
313
314
} {0 {}}
test regexp-7.17 {regsub utf compliance} {
    # if not UTF-8 aware, result is "0 1"
    set foo "xyz555ijka\u4e4ebpqr"
    regsub a\u4e4eb xyza\u4e4ebijka\u4e4ebpqr 555 bar
    list [string compare $foo $bar] [regexp 4 $bar]
} {0 0}





































test regexp-8.1 {case conversion in regsub} {
    list [regsub -nocase a(a+) xaAAaAAay & foo] $foo
} {1 xaAAaAAay}
test regexp-8.2 {case conversion in regsub} {
    list [regsub -nocase a(a+) xaAAaAAay & foo] $foo
} {1 xaAAaAAay}







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







328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
} {0 {}}
test regexp-7.17 {regsub utf compliance} {
    # if not UTF-8 aware, result is "0 1"
    set foo "xyz555ijka\u4e4ebpqr"
    regsub a\u4e4eb xyza\u4e4ebijka\u4e4ebpqr 555 bar
    list [string compare $foo $bar] [regexp 4 $bar]
} {0 0}
test regexp-7.18 {basic regsub replacement} {
    list [regsub a+ aaa {&} foo] $foo
} {1 aaa}
test regexp-7.19 {basic regsub replacement} {
    list [regsub a+ aaa {\&} foo] $foo
} {1 &}
test regexp-7.20 {basic regsub replacement} {
    list [regsub a+ aaa {\\&} foo] $foo
} {1 {\aaa}}
test regexp-7.21 {basic regsub replacement} {
    list [regsub a+ aaa {\\\&} foo] $foo
} {1 {\&}}
test regexp-7.22 {basic regsub replacement} {
    list [regsub a+ aaa {\0} foo] $foo
} {1 aaa}
test regexp-7.23 {basic regsub replacement} {
    list [regsub a+ aaa {\\0} foo] $foo
} {1 {\0}}
test regexp-7.24 {basic regsub replacement} {
    list [regsub a+ aaa {\\\0} foo] $foo
} {1 {\aaa}}
test regexp-7.25 {basic regsub replacement} {
    list [regsub a+ aaa {\\\\0} foo] $foo
} {1 {\\0}}
test regexp-7.26 {dollar zero is not a backslash replacement} {
    list [regsub a+ aaa {$0} foo] $foo
} {1 {$0}}
test regexp-7.27 {dollar zero is not a backslash replacement} {
    list [regsub a+ aaa {\0$0} foo] $foo
} {1 {aaa$0}}
test regexp-7.28 {dollar zero is not a backslash replacement} {
    list [regsub a+ aaa {\$0} foo] $foo
} {1 {\$0}}
test regexp-7.29 {dollar zero is not a backslash replacement} {
    list [regsub a+ aaa {\\} foo] $foo
} {1 \\}

test regexp-8.1 {case conversion in regsub} {
    list [regsub -nocase a(a+) xaAAaAAay & foo] $foo
} {1 xaAAaAAay}
test regexp-8.2 {case conversion in regsub} {
    list [regsub -nocase a(a+) xaAAaAAay & foo] $foo
} {1 xaAAaAAay}
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# 8.2.3 regexp reduced stack space requirements, but this should be
# tested again
test regexp-12.1 {Tcl_RegExpExec: large number of subexpressions} {macCrash} {
    list [regexp (.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.) abcdefghijklmnopqrstuvwxyz all a b c d e f g h i j k l m n o p q r s t u v w x y z] $all $a $b $c $d $e $f $g $h $i $j $k $l $m $n $o $p $q $r $s $t $u $v $w $x $y $z
} {1 abcdefghijklmnopqrstuvwxyz a b c d e f g h i j k l m n o p q r s t u v w x y z}

test regexp-13.1 {regsub of a very large string} {
    # This test is designed to stress the memory subsystem in order
    # to catch Bug #933.  It only fails if the Tcl memory allocator
    # is in use.

    set line {BEGIN_TABLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; END_TABLE}
    set filedata [string repeat $line 200]
    for {set i 1} {$i<10} {incr i} {
	regsub -all "BEGIN_TABLE " $filedata "" newfiledata
    }
    set x done
} {done}







|
|
<
<







484
485
486
487
488
489
490
491
492


493
494
495
496
497
498
499
# 8.2.3 regexp reduced stack space requirements, but this should be
# tested again
test regexp-12.1 {Tcl_RegExpExec: large number of subexpressions} {macCrash} {
    list [regexp (.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.) abcdefghijklmnopqrstuvwxyz all a b c d e f g h i j k l m n o p q r s t u v w x y z] $all $a $b $c $d $e $f $g $h $i $j $k $l $m $n $o $p $q $r $s $t $u $v $w $x $y $z
} {1 abcdefghijklmnopqrstuvwxyz a b c d e f g h i j k l m n o p q r s t u v w x y z}

test regexp-13.1 {regsub of a very large string} {
    # This test is designed to stress the memory subsystem in order to catch
    # Bug #933.  It only fails if the Tcl memory allocator is in use.


    set line {BEGIN_TABLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; END_TABLE}
    set filedata [string repeat $line 200]
    for {set i 1} {$i<10} {incr i} {
	regsub -all "BEGIN_TABLE " $filedata "" newfiledata
    }
    set x done
} {done}
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
    regexp .*c d
    regexp .*d e
    regexp .*e f
    set x .
    append x *a
    regexp -nocase $x bbba
} 1

testConstraint exec [llength [info commands exec]]
test regexp-14.3 {CompileRegexp: regexp cache, empty regexp and empty cache} -constraints {
	exec
} -setup {
    set junk [makeFile {puts [regexp {} foo]} junk.tcl]
} -body {
    exec [interpreter] $junk
} -cleanup {
    removeFile junk.tcl
} -result 1







<
<

|







514
515
516
517
518
519
520


521
522
523
524
525
526
527
528
529
    regexp .*c d
    regexp .*d e
    regexp .*e f
    set x .
    append x *a
    regexp -nocase $x bbba
} 1


test regexp-14.3 {CompileRegexp: regexp cache, empty regexp and empty cache} -constraints {
    exec
} -setup {
    set junk [makeFile {puts [regexp {} foo]} junk.tcl]
} -body {
    exec [interpreter] $junk
} -cleanup {
    removeFile junk.tcl
} -result 1
502
503
504
505
506
507
508




509
510
511
512
513
514
515
    catch {unset x}
    list [regexp -start end {\d} 1abc2de3 x] [info exists x]
} {0 0}
test regexp-15.10 {regexp -start, end relative index} {
    catch {unset x}
    list [regexp -start end-1 {\d} 1abc2de3 x] [info exists x] $x
} {1 1 3}





test regexp-16.1 {regsub -start} {
    catch {unset x}
    list [regsub -all -start 2 {\d} a1b2c3d4e5 {/&} x] $x
} {4 a1b/2c/3d/4e/5}
test regexp-16.2 {regsub -start} {
    catch {unset x}







>
>
>
>







561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
    catch {unset x}
    list [regexp -start end {\d} 1abc2de3 x] [info exists x]
} {0 0}
test regexp-15.10 {regexp -start, end relative index} {
    catch {unset x}
    list [regexp -start end-1 {\d} 1abc2de3 x] [info exists x] $x
} {1 1 3}
test regexp-15.11 {regexp -start, over end of string} {
    set x NA
    list [regexp -start 2 {.*} ab x] $x
} {1 {}}

test regexp-16.1 {regsub -start} {
    catch {unset x}
    list [regsub -all -start 2 {\d} a1b2c3d4e5 {/&} x] $x
} {4 a1b/2c/3d/4e/5}
test regexp-16.2 {regsub -start} {
    catch {unset x}
532
533
534
535
536
537
538
























































539
540
541
542
543
544
545
} {0 abc}
test regexp-16.7 {regexp -start, end relative index} {
    list [regsub -start end a aaa b x] $x
} {0 aaa}
test regexp-16.8 {regexp -start, end relative index} {
    list [regsub -start end-1 a aaa b x] $x
} {1 aab}

























































test regexp-17.1 {regexp -inline} {
    regexp -inline b ababa
} {b}
test regexp-17.2 {regexp -inline} {
    regexp -inline (b) ababa
} {b b}







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







595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
} {0 abc}
test regexp-16.7 {regexp -start, end relative index} {
    list [regsub -start end a aaa b x] $x
} {0 aaa}
test regexp-16.8 {regexp -start, end relative index} {
    list [regsub -start end-1 a aaa b x] $x
} {1 aab}
test regexp-16.9 {regsub -start and -all} {
    set foo {}
    list [regsub -start 0 -all x+ axxxbxx |&| foo] $foo
} {2 a|xxx|b|xx|}
test regexp-16.10 {regsub -start and -all} {
    set foo {}
    list [regsub -start 1 -all x+ axxxbxx |&| foo] $foo
} {2 a|xxx|b|xx|}
test regexp-16.11 {regsub -start and -all} {
    set foo {}
    list [regsub -start 4 -all x+ axxxbxx |&| foo] $foo
} {1 axxxb|xx|}
test regexp-16.12 {regsub -start} {
    set foo {}
    list [regsub -start 4 x+ axxxbxx |&| foo] $foo
} {1 axxxb|xx|}
test regexp-16.13 {regsub -start and -all} {
    set foo {}
    list [regsub -start 1 -all a+ "" & foo] $foo
} {0 {}}
test regexp-16.14 {regsub -start} {
    set foo {}
    list [regsub -start 1 a+ "" & foo] $foo
} {0 {}}
test regexp-16.15 {regsub -start and -all} {
    set foo {}
    list [regsub -start 2 -all a+ "xy" & foo] $foo
} {0 xy}
test regexp-16.16 {regsub -start} {
    set foo {}
    list [regsub -start 2 a+ "xy" & foo] $foo
} {0 xy}
test regexp-16.17 {regsub -start and -all} {
    set foo {}
    list [regsub -start 1 -all y+ "xy" & foo] $foo
} {1 xy}
test regexp-16.18 {regsub -start} {
    set foo {}
    list [regsub -start 1 y+ "xy" & foo] $foo
} {1 xy}
test regexp-16.19 {regsub -start} {
    set foo {}
    list [regsub -start -1 a+ "" & foo] $foo
} {0 {}}
test regexp-16.20 {regsub -start, loss of ^$ behavior} {
    set foo NA
    list [regsub -start 1 {^$} {} & foo] $foo
} {0 {}}
test regexp-16.21 {regsub -start, loss of ^$ behavior} {
    set foo NA
    list [regsub -start 1 {^.*$} abc & foo] $foo
} {0 abc}
test regexp-16.22 {regsub -start, loss of ^$ behavior} {
    set foo NA
    list [regsub -all -start 1 {^.*$} abc & foo] $foo
} {0 abc}

test regexp-17.1 {regexp -inline} {
    regexp -inline b ababa
} {b}
test regexp-17.2 {regexp -inline} {
    regexp -inline (b) ababa
} {b b}
610
611
612
613
614
615
616






617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681




















682
683
684
685
686
687
688
689
690



















































































































































































































































691
692
693

    regexp -all -inline -indices a(b(c)d|e(f)g)h abcdhaefgh
} {{0 4} {1 3} {2 2} {-1 -1} {5 9} {6 8} {-1 -1} {7 7}}

test regexp-19.1 {regsub null replacement} {
    regsub -all {@} {@hel@lo@} "\0a\0" result
    list $result [string length $result]
} "\0a\0hel\0a\0lo\0a\0 14"







test regexp-20.1 {regsub shared object shimmering} {
    # Bug #461322
    set a abcdefghijklmnopqurstuvwxyz 
    set b $a 
    set c abcdefghijklmnopqurstuvwxyz0123456789 
    regsub $a $c $b d 
    list $d [string length $d] [string bytelength $d]
} [list abcdefghijklmnopqurstuvwxyz0123456789 37 37]
test regexp-20.2 {regsub shared object shimmering with -about} {
    eval regexp -about abc
} {0 {}}

test regexp-21.1 {regsub works with empty string} {
    regsub -- ^ {} foo
} {foo}

test regexp-21.2 {regsub works with empty string} {
    regsub -- \$ {} foo
} {foo}

test regexp-21.3 {regsub works with empty string offset} {
    regsub -start 0 -- ^ {} foo
} {foo}

test regexp-21.4 {regsub works with empty string offset} {
    regsub -start 0 -- \$ {} foo
} {foo}

test regexp-21.5 {regsub works with empty string offset} {
    regsub -start 3 -- \$ {123} foo
} {123foo}

test regexp-21.6 {regexp works with empty string} {
    regexp -- ^ {}
} {1}

test regexp-21.7 {regexp works with empty string} {
    regexp -start 0 -- ^ {}
} {1}

test regexp-21.8 {regexp works with empty string offset} {
    regexp -start 3 -- ^ {123}
} {0}

test regexp-21.9 {regexp works with empty string offset} {
    regexp -start 3 -- \$ {123}
} {1}

test regexp-21.10 {multiple matches handle newlines} {
    regsub -all -lineanchor -- {^#[^\n]*\n} "#one\n#two\n#three\n" foo\n
} "foo\nfoo\nfoo\n"

test regexp-21.11 {multiple matches handle newlines} {
    regsub -all -line -- ^ "a\nb\nc" \#
} "\#a\n\#b\n\#c"

test regexp-21.12 {multiple matches handle newlines} {
    regsub -all -line -- ^ "\n\n" \#
} "\#\n\#\n\#"

test regexp-21.13 {multiple matches handle newlines} {
    regexp -all -inline -indices -line -- ^ "a\nb\nc"
} {{0 -1} {2 1} {4 3}}






















test regexp-22.1 {Bug 1810038} {
    regexp ($|^X)* {}
} 1

test regexp-22.2 {regexp compile and backrefs, Bug 1857126} {
    regexp -- {([bc])\1} bb
} 1




















































































































































































































































# cleanup
::tcltest::cleanupTests
return








>
>
>
>
>
>
















<



<



<



<



<



<



<



<



<



<



<



<



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




<




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



>
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
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

791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818

819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
    regexp -all -inline -indices a(b(c)d|e(f)g)h abcdhaefgh
} {{0 4} {1 3} {2 2} {-1 -1} {5 9} {6 8} {-1 -1} {7 7}}

test regexp-19.1 {regsub null replacement} {
    regsub -all {@} {@hel@lo@} "\0a\0" result
    list $result [string length $result]
} "\0a\0hel\0a\0lo\0a\0 14"

test regexp-19.2 {regsub null replacement} {
    regsub -all {@} {@hel@lo@} "\0a\0" result
    set expected "\0a\0hel\0a\0lo\0a\0"
    string equal $result $expected
} 1

test regexp-20.1 {regsub shared object shimmering} {
    # Bug #461322
    set a abcdefghijklmnopqurstuvwxyz 
    set b $a 
    set c abcdefghijklmnopqurstuvwxyz0123456789 
    regsub $a $c $b d 
    list $d [string length $d] [string bytelength $d]
} [list abcdefghijklmnopqurstuvwxyz0123456789 37 37]
test regexp-20.2 {regsub shared object shimmering with -about} {
    eval regexp -about abc
} {0 {}}

test regexp-21.1 {regsub works with empty string} {
    regsub -- ^ {} foo
} {foo}

test regexp-21.2 {regsub works with empty string} {
    regsub -- \$ {} foo
} {foo}

test regexp-21.3 {regsub works with empty string offset} {
    regsub -start 0 -- ^ {} foo
} {foo}

test regexp-21.4 {regsub works with empty string offset} {
    regsub -start 0 -- \$ {} foo
} {foo}

test regexp-21.5 {regsub works with empty string offset} {
    regsub -start 3 -- \$ {123} foo
} {123foo}

test regexp-21.6 {regexp works with empty string} {
    regexp -- ^ {}
} {1}

test regexp-21.7 {regexp works with empty string} {
    regexp -start 0 -- ^ {}
} {1}

test regexp-21.8 {regexp works with empty string offset} {
    regexp -start 3 -- ^ {123}
} {0}

test regexp-21.9 {regexp works with empty string offset} {
    regexp -start 3 -- \$ {123}
} {1}

test regexp-21.10 {multiple matches handle newlines} {
    regsub -all -lineanchor -- {^#[^\n]*\n} "#one\n#two\n#three\n" foo\n
} "foo\nfoo\nfoo\n"

test regexp-21.11 {multiple matches handle newlines} {
    regsub -all -line -- ^ "a\nb\nc" \#
} "\#a\n\#b\n\#c"

test regexp-21.12 {multiple matches handle newlines} {
    regsub -all -line -- ^ "\n\n" \#
} "\#\n\#\n\#"

test regexp-21.13 {multiple matches handle newlines} {
    regexp -all -inline -indices -line -- ^ "a\nb\nc"
} {{0 -1} {2 1} {4 3}}
test regexp-21.14 {regsub works with empty string} {
    regsub -- ^ {} &
} {}
test regexp-21.15 {regsub works with empty string} {
    regsub -- ^ {} foo&
} {foo}
test regexp-21.16 {regsub works with empty string} {
    regsub -all -- ^ {} foo&
} {foo}
test regexp-21.17 {regsub works with empty string} {
    regsub -- ^ {} {foo\0}
} {foo}
test regexp-21.18 {regsub works with empty string} {
    regsub -- ^.* {} {foo$0}
} {foo$0}
test regexp-21.19 {regsub works with empty string} {
    regsub -- ^ {input} {}
} {input}
test regexp-21.20 {regsub works with empty string} {
    regsub -- x {} {foo}
} {}

test regexp-22.1 {Bug 1810038} {
    regexp ($|^X)* {}
} 1

test regexp-22.2 {regexp compile and backrefs, Bug 1857126} {
    regexp -- {([bc])\1} bb
} 1

test regexp-23.1 {regexp -all and -line} {
    set string ""
    list \
	[regexp -all -inline -indices -line -- {^} $string] \
	[regexp -all -inline -indices -line -- {^$} $string] \
	[regexp -all -inline -indices -line -- {$} $string]
} {{{0 -1}} {{0 -1}} {{0 -1}}}
test regexp-23.2 {regexp -all and -line} {
    set string "\n"
    list \
	[regexp -all -inline -indices -line -- {^} $string] \
	[regexp -all -inline -indices -line -- {^$} $string] \
	[regexp -all -inline -indices -line -- {$} $string]
} {{{0 -1}} {{0 -1}} {{0 -1}}}
test regexp-23.3 {regexp -all and -line} {
    set string "\n\n"
    list \
	[regexp -all -inline -indices -line -- {^} $string] \
	[regexp -all -inline -indices -line -- {^$} $string] \
	[regexp -all -inline -indices -line -- {$} $string]
} {{{0 -1} {1 0}} {{0 -1} {1 0}} {{0 -1} {1 0}}}
test regexp-23.4 {regexp -all and -line} {
    set string "a"
    list \
	[regexp -all -inline -indices -line -- {^} $string] \
	[regexp -all -inline -indices -line -- {^.*$} $string] \
	[regexp -all -inline -indices -line -- {$} $string]
} {{{0 -1}} {{0 0}} {{1 0}}}
test regexp-23.5 {regexp -all and -line} {knownBug} {
    set string "a\n"
    list \
	[regexp -all -inline -indices -line -- {^} $string] \
	[regexp -all -inline -indices -line -- {^.*$} $string] \
	[regexp -all -inline -indices -line -- {$} $string]
} {{{0 -1} {2 1}} {{0 0} {2 1}} {{1 0} {2 1}}}
test regexp-23.6 {regexp -all and -line} {
    set string "\na"
    list \
	[regexp -all -inline -indices -line -- {^} $string] \
	[regexp -all -inline -indices -line -- {^.*$} $string] \
	[regexp -all -inline -indices -line -- {$} $string]
} {{{0 -1} {1 0}} {{0 -1} {1 1}} {{0 -1} {2 1}}}
test regexp-23.7 {regexp -all and -line} {knownBug} {
    set string "ab\n"
    list \
	[regexp -all -inline -indices -line -- {^} $string] \
	[regexp -all -inline -indices -line -- {^.*$} $string] \
	[regexp -all -inline -indices -line -- {$} $string]
} {{{0 -1} {3 2}} {{0 1} {3 2}} {{2 1} {3 2}}}
test regexp-23.8 {regexp -all and -line} {
    set string "a\nb"
    list \
	[regexp -all -inline -indices -line -- {^} $string] \
	[regexp -all -inline -indices -line -- {^.*$} $string] \
	[regexp -all -inline -indices -line -- {$} $string]
} {{{0 -1} {2 1}} {{0 0} {2 2}} {{1 0} {3 2}}}
test regexp-23.9 {regexp -all and -line} {knownBug} {
    set string "a\nb\n"
    list \
	[regexp -all -inline -indices -line -- {^} $string] \
	[regexp -all -inline -indices -line -- {^.*$} $string] \
	[regexp -all -inline -indices -line -- {$} $string]
} {{{0 -1} {2 1} {4 3}} {{0 0} {2 2} {4 3}} {{1 0} {3 2} {4 3}}}
test regexp-23.10 {regexp -all and -line} {
    set string "a\nb\nc"
    list \
	[regexp -all -inline -indices -line -- {^} $string] \
	[regexp -all -inline -indices -line -- {^.*$} $string] \
	[regexp -all -inline -indices -line -- {$} $string]
} {{{0 -1} {2 1} {4 3}} {{0 0} {2 2} {4 4}} {{1 0} {3 2} {5 4}}}
test regexp-23.11 {regexp -all and -line} {
    regexp -all -inline -indices -line -- {b} "abb\nb"
} {{1 1} {2 2} {4 4}}

test regexp-24.1 {regsub -all and -line} {
    foreach {v1 v2 v3} {{} {} {}} {}
    set string ""
    list \
	[regsub -line -all {^} $string {<&>} v1] $v1 \
	[regsub -line -all {^$} $string {<&>} v2] $v2 \
	[regsub -line -all {$} $string {<&>} v3] $v3
} {1 <> 1 <> 1 <>}
test regexp-24.2 {regsub -all and -line} {
    foreach {v1 v2 v3} {{} {} {}} {}
    set string "\n"
    list \
	[regsub -line -all {^} $string {<&>} v1] $v1 \
	[regsub -line -all {^$} $string {<&>} v2] $v2 \
	[regsub -line -all {$} $string {<&>} v3] $v3
} [list 2 "<>\n<>" 2 "<>\n<>" 2 "<>\n<>"]
test regexp-24.3 {regsub -all and -line} {
    foreach {v1 v2 v3} {{} {} {}} {}
    set string "\n\n"
    list \
	[regsub -line -all {^} $string {<&>} v1] $v1 \
	[regsub -line -all {^$} $string {<&>} v2] $v2 \
	[regsub -line -all {$} $string {<&>} v3] $v3
} [list 3 "<>\n<>\n<>" 3 "<>\n<>\n<>" 3 "<>\n<>\n<>"]
test regexp-24.4 {regsub -all and -line} {
    foreach {v1 v2 v3} {{} {} {}} {}
    set string "a"
    list \
	[regsub -line -all {^} $string {<&>} v1] $v1 \
	[regsub -line -all {^.*$} $string {<&>} v2] $v2 \
	[regsub -line -all {$} $string {<&>} v3] $v3
} [list 1 "<>a" 1 "<a>" 1 "a<>"]
test regexp-24.5 {regsub -all and -line} {
    foreach {v1 v2 v3} {{} {} {}} {}
    set string "a\n"
    list \
	[regsub -line -all {^} $string {<&>} v1] $v1 \
	[regsub -line -all {^.*$} $string {<&>} v2] $v2 \
	[regsub -line -all {$} $string {<&>} v3] $v3
} [list 2 "<>a\n<>" 2 "<a>\n<>" 2 "a<>\n<>"]
test regexp-24.6 {regsub -all and -line} {
    foreach {v1 v2 v3} {{} {} {}} {}
    set string "\na"
    list \
	[regsub -line -all {^} $string {<&>} v1] $v1 \
	[regsub -line -all {^.*$} $string {<&>} v2] $v2 \
	[regsub -line -all {$} $string {<&>} v3] $v3
} [list 2 "<>\n<>a" 2 "<>\n<a>" 2 "<>\na<>"]
test regexp-24.7 {regsub -all and -line} {
    foreach {v1 v2 v3} {{} {} {}} {}
    set string "ab\n"
    list \
	[regsub -line -all {^} $string {<&>} v1] $v1 \
	[regsub -line -all {^.*$} $string {<&>} v2] $v2 \
	[regsub -line -all {$} $string {<&>} v3] $v3
} [list 2 "<>ab\n<>" 2 "<ab>\n<>" 2 "ab<>\n<>"]
test regexp-24.8 {regsub -all and -line} {
    foreach {v1 v2 v3} {{} {} {}} {}
    set string "a\nb"
    list \
	[regsub -line -all {^} $string {<&>} v1] $v1 \
	[regsub -line -all {^.*$} $string {<&>} v2] $v2 \
	[regsub -line -all {$} $string {<&>} v3] $v3
} [list 2 "<>a\n<>b" 2 "<a>\n<b>" 2 "a<>\nb<>"]
test regexp-24.9 {regsub -all and -line} {
    foreach {v1 v2 v3} {{} {} {}} {}
    set string "a\nb\n"
    list \
	[regsub -line -all {^} $string {<&>} v1] $v1 \
	[regsub -line -all {^.*$} $string {<&>} v2] $v2 \
	[regsub -line -all {$} $string {<&>} v3] $v3
} [list 3 "<>a\n<>b\n<>" 3 "<a>\n<b>\n<>" 3 "a<>\nb<>\n<>"]
test regexp-24.10 {regsub -all and -line} {
    foreach {v1 v2 v3} {{} {} {}} {}
    set string "a\nb\nc"
    list \
	[regsub -line -all {^} $string {<&>} v1] $v1 \
	[regsub -line -all {^.*$} $string {<&>} v2] $v2 \
	[regsub -line -all {$} $string {<&>} v3] $v3
} [list 3 "<>a\n<>b\n<>c" 3 "<a>\n<b>\n<c>" 3 "a<>\nb<>\nc<>"]
test regexp-24.11 {regsub -all and -line} {
    regsub -line -all {b} "abb\nb" {<&>}
} "a<b><b>\n<b>"

test regexp-25.1 {regexp without -line option} {
    set foo ""
    list [regexp {a.*b} "dabc\naxyb\n" foo] $foo
} [list 1 abc\naxyb]
test regexp-25.2 {regexp without -line option} {
    set foo ""
    list [regexp {^a.*b$} "dabc\naxyb\n" foo] $foo
} {0 {}}
test regexp-25.3 {regexp with -line option} {
    set foo ""
    list [regexp -line {^a.*b$} "dabc\naxyb\n" foo] $foo
} {1 axyb}
test regexp-25.4 {regexp with -line option} {
    set foo ""
    list [regexp -line {^a.*b$} "dabc\naxyb\nxb" foo] $foo
} {1 axyb}
test regexp-25.5 {regexp without -line option} {
    set foo ""
    list [regexp {^a.*b$} "dabc\naxyb\nxb" foo] $foo
} {0 {}}
test regexp-25.6 {regexp without -line option} {
    set foo ""
    list [regexp {a.*b$} "dabc\naxyb\nxb" foo] $foo
} "1 {abc\naxyb\nxb}"
test regexp-25.7 {regexp with -lineanchor option} {
    set foo ""
    list [regexp -lineanchor {^a.*b$} "dabc\naxyb\nxb" foo] $foo
} "1 {axyb\nxb}"
test regexp-25.8 {regexp with -lineanchor and -linestop option} {
    set foo ""
    list [regexp -lineanchor -linestop {^a.*b$} "dabc\naxyb\nxb" foo] $foo
} {1 axyb}
test regexp-25.9 {regexp with -linestop option} {
    set foo ""
    list [regexp -linestop {a.*b} "ab\naxyb\nxb" foo] $foo
} {1 ab}

test regexp-26.1 {matches start of line 1 time} {
    regexp -all -inline -- {^a+} "aab\naaa"
} {aa}
test regexp-26.2 {matches start of line(s) 2 times} {
    regexp -all -inline -line -- {^a+} "aab\naaa"
} {aa aaa}
test regexp-26.3 {effect of -line -all and -start} {
    list \
	[regexp -all -inline -line -start 0 -- {^a+} "aab\naaa"] \
	[regexp -all -inline -line -start 1 -- {^a+} "aab\naaa"] \
	[regexp -all -inline -line -start 3 -- {^a+} "aab\naaa"] \
	[regexp -all -inline -line -start 4 -- {^a+} "aab\naaa"] \
} {{aa aaa} aaa aaa aaa}
# No regexp-26.4
test regexp-26.5 {match length 0, match length 1} {
    regexp -all -inline -line -- {^b*} "a\nb"
} {{} b}
test regexp-26.6 {non reporting capture group} {
    regexp -all -inline -line -- {^(?:a+|b)} "aab\naaa"
} {aa aaa}
test regexp-26.7 {Tcl bug 2826551: -line sensitive regexp and -start} {
    set match1 {}
    set match2 {}
    list \
	[regexp -start 0 -indices -line {^a} "\nab" match1] $match1 \
	[regexp -start 1 -indices -line {^a} "\nab" match2] $match2
} {1 {1 1} 1 {1 1}}
test regexp-26.8 {Tcl bug 2826551: diff regexp with -line option} {
    set data "@1\n2\n+3\n@4\n-5\n+6\n7\n@8\n9\n"
    regexp -all -inline -line {^@.*\n(?:[^@].*\n?)*} $data
} [list "@1\n2\n+3\n" "@4\n-5\n+6\n7\n" "@8\n9\n"]
test regexp-26.9 {Tcl bug 2826551: diff regexp with embedded -line option} {
    set data "@1\n2\n+3\n@4\n-5\n+6\n7\n@8\n9\n"
    regexp -all -inline {(?n)^@.*\n(?:[^@].*\n?)*} $data
} [list "@1\n2\n+3\n" "@4\n-5\n+6\n7\n" "@8\n9\n"]
test regexp-26.10 {regexp with -line option} {
    regexp -all -inline -line -- {a*} "a\n"
} {a {}}
test regexp-26.11 {regexp without -line option} {
    regexp -all -inline -- {a*} "a\n"
} {a {}}
test regexp-26.12 {regexp with -line option} {
    regexp -all -inline -line -- {a*} "b\n"
} {{} {}}
test regexp-26.13 {regexp without -line option} {
    regexp -all -inline -- {a*} "b\n"
} {{} {}}

# cleanup
::tcltest::cleanupTests
return

Changes to tests/registry.test.
31
32
33
34
35
36
37
38
39
40
41






42
43
44



45
46
47
48






49
50
51
52
53
54
55
56
57
58






59
60
61
62
63
64
65
66
67
68
69
70
71






72
73
74
75
76
77
78
79
80
81






82
83
84
85
86
87
88
89
90
91
92
93
94






95
96
97
98
99
100
101
102
103
104
105
106
107






108
109
110
111
112
113
114
}

# determine the current locale
testConstraint english [expr {
    [llength [info commands testlocale]]
    && [string match "English*" [testlocale all ""]]
}]

test registry-1.1 {argument parsing for registry command} {win reg} {
    list [catch {registry} msg] $msg
} {1 {wrong # args: should be "registry option ?arg ...?"}}






test registry-1.2 {argument parsing for registry command} {win reg} {
    list [catch {registry foo} msg] $msg
} {1 {bad option "foo": must be broadcast, delete, get, keys, set, type, or values}}




test registry-1.3 {argument parsing for registry command} {win reg} {
    list [catch {registry d} msg] $msg
} {1 {wrong # args: should be "registry delete keyName ?valueName?"}}






test registry-1.4 {argument parsing for registry command} {win reg} {
    list [catch {registry delete} msg] $msg
} {1 {wrong # args: should be "registry delete keyName ?valueName?"}}
test registry-1.5 {argument parsing for registry command} {win reg} {
    list [catch {registry delete foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry delete keyName ?valueName?"}}

test registry-1.6 {argument parsing for registry command} {win reg} {
    list [catch {registry g} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}






test registry-1.7 {argument parsing for registry command} {win reg} {
    list [catch {registry get} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}
test registry-1.8 {argument parsing for registry command} {win reg} {
    list [catch {registry get foo} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}
test registry-1.9 {argument parsing for registry command} {win reg} {
    list [catch {registry get foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}

test registry-1.10 {argument parsing for registry command} {win reg} {
    list [catch {registry k} msg] $msg
} {1 {wrong # args: should be "registry keys keyName ?pattern?"}}






test registry-1.11 {argument parsing for registry command} {win reg} {
    list [catch {registry keys} msg] $msg
} {1 {wrong # args: should be "registry keys keyName ?pattern?"}}
test registry-1.12 {argument parsing for registry command} {win reg} {
    list [catch {registry keys foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry keys keyName ?pattern?"}}

test registry-1.13 {argument parsing for registry command} {win reg} {
    list [catch {registry s} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}






test registry-1.14 {argument parsing for registry command} {win reg} {
    list [catch {registry set} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}
test registry-1.15 {argument parsing for registry command} {win reg} {
    list [catch {registry set foo bar} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}
test registry-1.16 {argument parsing for registry command} {win reg} {
    list [catch {registry set foo bar baz blat gorp} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}

test registry-1.17 {argument parsing for registry command} {win reg} {
    list [catch {registry t} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}






test registry-1.18 {argument parsing for registry command} {win reg} {
    list [catch {registry type} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}
test registry-1.19 {argument parsing for registry command} {win reg} {
    list [catch {registry type foo} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}
test registry-1.20 {argument parsing for registry command} {win reg} {
    list [catch {registry type foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}

test registry-1.21 {argument parsing for registry command} {win reg} {
    list [catch {registry v} msg] $msg
} {1 {wrong # args: should be "registry values keyName ?pattern?"}}






test registry-1.22 {argument parsing for registry command} {win reg} {
    list [catch {registry values} msg] $msg
} {1 {wrong # args: should be "registry values keyName ?pattern?"}}
test registry-1.23 {argument parsing for registry command} {win reg} {
    list [catch {registry values foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry values keyName ?pattern?"}}








|


|
>
>
>
>
>
>



>
>
>




>
>
>
>
>
>










>
>
>
>
>
>













>
>
>
>
>
>










>
>
>
>
>
>













>
>
>
>
>
>













>
>
>
>
>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
}

# determine the current locale
testConstraint english [expr {
    [llength [info commands testlocale]]
    && [string match "English*" [testlocale all ""]]
}]

test registry-1.1 {argument parsing for registry command} {win reg} {
    list [catch {registry} msg] $msg
} {1 {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}}
test registry-1.1a {argument parsing for registry command} {win reg} {
    list [catch {registry -32bit} msg] $msg
} {1 {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}}
test registry-1.1b {argument parsing for registry command} {win reg} {
    list [catch {registry -64bit} msg] $msg
} {1 {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}}
test registry-1.2 {argument parsing for registry command} {win reg} {
    list [catch {registry foo} msg] $msg
} {1 {bad option "foo": must be broadcast, delete, get, keys, set, type, or values}}
test registry-1.2a {argument parsing for registry command} {win reg} {
    list [catch {registry -33bit foo} msg] $msg
} {1 {bad mode "-33bit": must be -32bit or -64bit}}

test registry-1.3 {argument parsing for registry command} {win reg} {
    list [catch {registry d} msg] $msg
} {1 {wrong # args: should be "registry delete keyName ?valueName?"}}
test registry-1.3a {argument parsing for registry command} {win reg} {
    list [catch {registry -32bit d} msg] $msg
} {1 {wrong # args: should be "registry -32bit delete keyName ?valueName?"}}
test registry-1.3b {argument parsing for registry command} {win reg} {
    list [catch {registry -64bit d} msg] $msg
} {1 {wrong # args: should be "registry -64bit delete keyName ?valueName?"}}
test registry-1.4 {argument parsing for registry command} {win reg} {
    list [catch {registry delete} msg] $msg
} {1 {wrong # args: should be "registry delete keyName ?valueName?"}}
test registry-1.5 {argument parsing for registry command} {win reg} {
    list [catch {registry delete foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry delete keyName ?valueName?"}}

test registry-1.6 {argument parsing for registry command} {win reg} {
    list [catch {registry g} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}
test registry-1.6a {argument parsing for registry command} {win reg} {
    list [catch {registry -32bit g} msg] $msg
} {1 {wrong # args: should be "registry -32bit get keyName valueName"}}
test registry-1.6b {argument parsing for registry command} {win reg} {
    list [catch {registry -64bit g} msg] $msg
} {1 {wrong # args: should be "registry -64bit get keyName valueName"}}
test registry-1.7 {argument parsing for registry command} {win reg} {
    list [catch {registry get} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}
test registry-1.8 {argument parsing for registry command} {win reg} {
    list [catch {registry get foo} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}
test registry-1.9 {argument parsing for registry command} {win reg} {
    list [catch {registry get foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}

test registry-1.10 {argument parsing for registry command} {win reg} {
    list [catch {registry k} msg] $msg
} {1 {wrong # args: should be "registry keys keyName ?pattern?"}}
test registry-1.10a {argument parsing for registry command} {win reg} {
    list [catch {registry -32bit k} msg] $msg
} {1 {wrong # args: should be "registry -32bit keys keyName ?pattern?"}}
test registry-1.10b {argument parsing for registry command} {win reg} {
    list [catch {registry -64bit k} msg] $msg
} {1 {wrong # args: should be "registry -64bit keys keyName ?pattern?"}}
test registry-1.11 {argument parsing for registry command} {win reg} {
    list [catch {registry keys} msg] $msg
} {1 {wrong # args: should be "registry keys keyName ?pattern?"}}
test registry-1.12 {argument parsing for registry command} {win reg} {
    list [catch {registry keys foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry keys keyName ?pattern?"}}

test registry-1.13 {argument parsing for registry command} {win reg} {
    list [catch {registry s} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}
test registry-1.13a {argument parsing for registry command} {win reg} {
    list [catch {registry -32bit s} msg] $msg
} {1 {wrong # args: should be "registry -32bit set keyName ?valueName data ?type??"}}
test registry-1.13b {argument parsing for registry command} {win reg} {
    list [catch {registry -64bit s} msg] $msg
} {1 {wrong # args: should be "registry -64bit set keyName ?valueName data ?type??"}}
test registry-1.14 {argument parsing for registry command} {win reg} {
    list [catch {registry set} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}
test registry-1.15 {argument parsing for registry command} {win reg} {
    list [catch {registry set foo bar} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}
test registry-1.16 {argument parsing for registry command} {win reg} {
    list [catch {registry set foo bar baz blat gorp} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}

test registry-1.17 {argument parsing for registry command} {win reg} {
    list [catch {registry t} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}
test registry-1.17a {argument parsing for registry command} {win reg} {
    list [catch {registry -32bit t} msg] $msg
} {1 {wrong # args: should be "registry -32bit type keyName valueName"}}
test registry-1.17b {argument parsing for registry command} {win reg} {
    list [catch {registry -64bit t} msg] $msg
} {1 {wrong # args: should be "registry -64bit type keyName valueName"}}
test registry-1.18 {argument parsing for registry command} {win reg} {
    list [catch {registry type} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}
test registry-1.19 {argument parsing for registry command} {win reg} {
    list [catch {registry type foo} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}
test registry-1.20 {argument parsing for registry command} {win reg} {
    list [catch {registry type foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}

test registry-1.21 {argument parsing for registry command} {win reg} {
    list [catch {registry v} msg] $msg
} {1 {wrong # args: should be "registry values keyName ?pattern?"}}
test registry-1.21a {argument parsing for registry command} {win reg} {
    list [catch {registry -32bit v} msg] $msg
} {1 {wrong # args: should be "registry -32bit values keyName ?pattern?"}}
test registry-1.21b {argument parsing for registry command} {win reg} {
    list [catch {registry -64bit v} msg] $msg
} {1 {wrong # args: should be "registry -64bit values keyName ?pattern?"}}
test registry-1.22 {argument parsing for registry command} {win reg} {
    list [catch {registry values} msg] $msg
} {1 {wrong # args: should be "registry values keyName ?pattern?"}}
test registry-1.23 {argument parsing for registry command} {win reg} {
    list [catch {registry values foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry values keyName ?pattern?"}}

613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
        # This test will only succeed if the current user does not have
        # registry access on the specified machine.
        registry set {\\mom\HKEY_CURRENT_USER\TclFoobar} bar foobar
    } -returnCodes error -result {unable to open key: Access is denied.}

test registry-12.1 {BroadcastValue} -constraints {win reg} -body {
    registry broadcast
} -returnCodes error -result "wrong # args: should be \"registry broadcast keyName ?-timeout millisecs?\""
test registry-12.2 {BroadcastValue} -constraints {win reg} -body {
    registry broadcast "" -time
} -returnCodes error -result "wrong # args: should be \"registry broadcast keyName ?-timeout millisecs?\""
test registry-12.3 {BroadcastValue} -constraints {win reg} -body {
    registry broadcast "" - 500
} -returnCodes error -result "wrong # args: should be \"registry broadcast keyName ?-timeout millisecs?\""
test registry-12.4 {BroadcastValue} -constraints {win reg} -body {
    registry broadcast {Environment}
} -result {1 0}
test registry-12.5 {BroadcastValue} -constraints {win reg} -body {
    registry b {}
} -result {1 0}

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# tcl-indent-level: 4
# fill-column: 78
# End:







|


|


|






|









658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
        # This test will only succeed if the current user does not have
        # registry access on the specified machine.
        registry set {\\mom\HKEY_CURRENT_USER\TclFoobar} bar foobar
    } -returnCodes error -result {unable to open key: Access is denied.}

test registry-12.1 {BroadcastValue} -constraints {win reg} -body {
    registry broadcast
} -returnCodes error -result "wrong # args: should be \"registry broadcast keyName ?-timeout milliseconds?\""
test registry-12.2 {BroadcastValue} -constraints {win reg} -body {
    registry broadcast "" -time
} -returnCodes error -result "wrong # args: should be \"registry broadcast keyName ?-timeout milliseconds?\""
test registry-12.3 {BroadcastValue} -constraints {win reg} -body {
    registry broadcast "" - 500
} -returnCodes error -result "wrong # args: should be \"registry broadcast keyName ?-timeout milliseconds?\""
test registry-12.4 {BroadcastValue} -constraints {win reg} -body {
    registry broadcast {Environment}
} -result {1 0}
test registry-12.5 {BroadcastValue} -constraints {win reg} -body {
    registry b {}
} -result {1 0}

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# tcl-indent-level: 4
# fill-column: 78
# End:
Changes to tests/remote.tcl.
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73

74
75
76
77
78
79
80
81
82
83

84
85
86
87
88
89
90

    if {$VERBOSE} {
	puts "--- Server executing the following for socket $s:"
	puts $l
	puts "---"
    }
    set callerSocket $s

    if {[catch {uplevel #0 $l} msg]} {
	list error $msg
    } else {
	list success $msg
    }
}

proc __readAndExecute__ {s} {
    global command VERBOSE

    set l [gets $s]
    if {[string compare $l "--Marker--Marker--Marker--"] == 0} {
	if {[info exists command($s)]} {
	    puts $s [list error incomplete_command]
	}
	puts $s "--Marker--Marker--Marker--"

	return
    }
    if {[string compare $l ""] == 0} {
	if {[eof $s]} {
	    if {$VERBOSE} {
		puts "Server closing $s, eof from client"
	    }
	    close $s
	}
	return
    }
    append command($s) $l "\n"
    if {[info complete $command($s)]} {
	set cmds $command($s)
	unset command($s)
	puts $s [__doCommands__ $cmds $s]
    }
    if {[eof $s]} {
	if {$VERBOSE} {
	    puts "Server closing $s, eof from client"
	}
	close $s


    }

}

proc __accept__ {s a p} {
    global VERBOSE

    if {$VERBOSE} {
	puts "Server accepts new connection from $a:$p on $s"
    }
    fileevent $s readable [list __readAndExecute__ $s]
    fconfigure $s -buffering line -translation crlf

}

set serverIsSilent 0
for {set i 0} {$i < $argc} {incr i} {
    if {[string compare -serverIsSilent [lindex $argv $i]] == 0} {
	set serverIsSilent 1
	break







>
|
|
<
<
<







|
<
<

>











<
<
<
<
<
<





>
>

>



|




|

>







28
29
30
31
32
33
34
35
36
37



38
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58






59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

    if {$VERBOSE} {
	puts "--- Server executing the following for socket $s:"
	puts $l
	puts "---"
    }
    set callerSocket $s
    set ::errorInfo ""
    set code [catch {uplevel "#0" $l} msg]
    return [list $code $::errorInfo $msg]



}

proc __readAndExecute__ {s} {
    global command VERBOSE

    set l [gets $s]
    if {[string compare $l "--Marker--Marker--Marker--"] == 0} {
        puts $s [__doCommands__ $command($s) $s]


	puts $s "--Marker--Marker--Marker--"
        set command($s) ""
	return
    }
    if {[string compare $l ""] == 0} {
	if {[eof $s]} {
	    if {$VERBOSE} {
		puts "Server closing $s, eof from client"
	    }
	    close $s
	}
	return
    }






    if {[eof $s]} {
	if {$VERBOSE} {
	    puts "Server closing $s, eof from client"
	}
	close $s
        unset command($s)
        return
    }
    append command($s) $l "\n"
}

proc __accept__ {s a p} {
    global command VERBOSE

    if {$VERBOSE} {
	puts "Server accepts new connection from $a:$p on $s"
    }
    set command($s) ""
    fconfigure $s -buffering line -translation crlf
    fileevent $s readable [list __readAndExecute__ $s]
}

set serverIsSilent 0
for {set i 0} {$i < $argc} {incr i} {
    if {[string compare -serverIsSilent [lindex $argv $i]] == 0} {
	set serverIsSilent 1
	break
148
149
150
151
152
153
154




155
156
157
158
159

160
161
162
163
164
165
166
167
168
169
170
171
172
    puts "[info hostname]. You can set these as environment variables"
    puts "from the shell. The tests will not work properly if you set"
    puts "remoteServerIP to \"localhost\" or 127.0.0.1."
    puts ""
    puts -nonewline "Type Ctrl-C to terminate--> "
    flush stdout
}





if {[catch {set serverSocket \
	[socket -myaddr $serverAddress -server __accept__ $serverPort]} msg]} {
    puts "Server on $serverAddress:$serverPort cannot start: $msg"
} else {

    vwait __server_wait_variable__
}


















>
>
>
>





>


<
<
<
<
<
<
<
<
<
<
<
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161











    puts "[info hostname]. You can set these as environment variables"
    puts "from the shell. The tests will not work properly if you set"
    puts "remoteServerIP to \"localhost\" or 127.0.0.1."
    puts ""
    puts -nonewline "Type Ctrl-C to terminate--> "
    flush stdout
}

proc getPort sock {
    lindex [fconfigure $sock -sockname] 2
}

if {[catch {set serverSocket \
	[socket -myaddr $serverAddress -server __accept__ $serverPort]} msg]} {
    puts "Server on $serverAddress:$serverPort cannot start: $msg"
} else {
    puts ready
    vwait __server_wait_variable__
}











Changes to tests/result.test.
127
128
129
130
131
132
133
134











135
136
137
    set ::errorInfo {}
    set ::errorCode {}
} -body {
    foo
} -cleanup {
    rename foo {}
} -result {foo {} {}}












# cleanup
cleanupTests
return







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



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
    set ::errorInfo {}
    set ::errorCode {}
} -body {
    foo
} -cleanup {
    rename foo {}
} -result {foo {} {}}
test result-6.3 {Bug 2383005} {
     catch {return -code error -errorcode {{}a} eek} m
     set m
} {bad -errorcode value: expected a list but got "{}a"}
test result-6.4 {non-list -errorstack} -body {
     catch {return -code error -errorstack {{}a} eek} m o
     list $m [dict get $o -errorcode] [dict get $o -errorstack]
} -match glob -result {{bad -errorstack value: expected a list but got "{}a"} {TCL RESULT NONLIST_ERRORSTACK} {INNER * UP 1}}
test result-6.5 {odd-sized-list -errorstack} -body {
     catch {return -code error -errorstack a eek} m o
     list $m [dict get $o -errorcode] [dict get $o -errorstack]
} -match glob -result {{forbidden odd-sized list for -errorstack: "a"} {TCL RESULT ODDSIZEDLIST_ERRORSTACK} {INNER * UP 1}}
# cleanup
cleanupTests
return
Changes to tests/set-old.test.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

proc ignore args {}

# Simple variable operations.

catch {unset a}
test set-old-1.1 {basic variable setting and unsetting} {
    set a 22
} 22
test set-old-1.2 {basic variable setting and unsetting} {







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

proc ignore args {}

# Simple variable operations.

catch {unset a}
test set-old-1.1 {basic variable setting and unsetting} {
    set a 22
} 22
test set-old-1.2 {basic variable setting and unsetting} {
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
    list [info exists -nocomp] [catch {unset -nocomp}]
} {0 1}

# Array command.

test set-old-8.1 {array command} {
    list [catch {array} msg] $msg
} {1 {wrong # args: should be "array option arrayName ?arg ...?"}}
test set-old-8.2 {array command} {
    list [catch {array a} msg] $msg
} {1 {wrong # args: should be "array option arrayName ?arg ...?"}}
test set-old-8.3 {array command} {
    catch {unset a}
    list [catch {array anymore a b} msg] $msg
} {1 {"a" isn't an array}}
test set-old-8.4 {array command} {
    catch {unset a}
    set a 44







|


|







308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
    list [info exists -nocomp] [catch {unset -nocomp}]
} {0 1}

# Array command.

test set-old-8.1 {array command} {
    list [catch {array} msg] $msg
} {1 {wrong # args: should be "array subcommand ?arg ...?"}}
test set-old-8.2 {array command} {
    list [catch {array a} msg] $msg
} {1 {wrong # args: should be "array anymore arrayName searchId"}}
test set-old-8.3 {array command} {
    catch {unset a}
    list [catch {array anymore a b} msg] $msg
} {1 {"a" isn't an array}}
test set-old-8.4 {array command} {
    catch {unset a}
    set a 44
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
    }
    foo
} {1 {"x" isn't an array}}
test set-old-8.6 {array command} {
    catch {unset a}
    set a(22) 3
    list [catch {array gorp a} msg] $msg
} {1 {bad option "gorp": must be anymore, donesearch, exists, get, names, nextelement, set, size, startsearch, statistics, or unset}}
test set-old-8.7 {array command, anymore option} {
    catch {unset a}
    list [catch {array anymore a x} msg] $msg
} {1 {"a" isn't an array}}
test set-old-8.8 {array command, anymore option, array doesn't exist yet but has compiler-allocated procedure slot} {
    proc foo {x} {
        if {$x==1} {







|







333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
    }
    foo
} {1 {"x" isn't an array}}
test set-old-8.6 {array command} {
    catch {unset a}
    set a(22) 3
    list [catch {array gorp a} msg] $msg
} {1 {unknown or ambiguous subcommand "gorp": must be anymore, donesearch, exists, get, names, nextelement, set, size, startsearch, statistics, or unset}}
test set-old-8.7 {array command, anymore option} {
    catch {unset a}
    list [catch {array anymore a x} msg] $msg
} {1 {"a" isn't an array}}
test set-old-8.8 {array command, anymore option, array doesn't exist yet but has compiler-allocated procedure slot} {
    proc foo {x} {
        if {$x==1} {
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
        }
        set a(x) 123
    }
    list [catch {foo 1} msg] $msg
} {0 0}
test set-old-8.15 {array command, get option} {
    list [catch {array get} msg] $msg
} {1 {wrong # args: should be "array option arrayName ?arg ...?"}}
test set-old-8.16 {array command, get option} {
    list [catch {array get a b c} msg] $msg
} {1 {wrong # args: should be "array get arrayName ?pattern?"}}
test set-old-8.17 {array command, get option} {
    catch {unset a}
    array get a
} {}







|







383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
        }
        set a(x) 123
    }
    list [catch {foo 1} msg] $msg
} {0 0}
test set-old-8.15 {array command, get option} {
    list [catch {array get} msg] $msg
} {1 {wrong # args: should be "array get arrayName ?pattern?"}}
test set-old-8.16 {array command, get option} {
    list [catch {array get a b c} msg] $msg
} {1 {wrong # args: should be "array get arrayName ?pattern?"}}
test set-old-8.17 {array command, get option} {
    catch {unset a}
    array get a
} {}
667
668
669
670
671
672
673
674
675
676






677
678
679
680
681
682
683
    catch {unset a}
    set a(-glob) 1
    set a(-regexp) 1
    set a(-exact) 1
    list [catch {array names a -glob} msg] $msg
} {0 -glob}
test set-old-8.56 {array command, array statistics on a non-array} {
	catch {unset a}
	list [catch {array statistics a} msg] $msg
} [list 1 "\"a\" isn't an array"]







test set-old-9.1 {ids for array enumeration} {
    catch {unset a}
    set a(a) 1
    list [array star a] [array star a] [array done a s-1-a; array star a] \
	    [array done a s-2-a; array d a s-3-a; array start a]
} {s-1-a s-2-a s-3-a s-1-a}







|
|

>
>
>
>
>
>







667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
    catch {unset a}
    set a(-glob) 1
    set a(-regexp) 1
    set a(-exact) 1
    list [catch {array names a -glob} msg] $msg
} {0 -glob}
test set-old-8.56 {array command, array statistics on a non-array} {
    catch {unset a}
    list [catch {array statistics a} msg] $msg
} [list 1 "\"a\" isn't an array"]
test set-old-8.57 {array command, array get with trivial pattern} {
    catch {unset a}
    set a(x) 1
    set a(y) 2
    array get a x
} {x 1}

test set-old-9.1 {ids for array enumeration} {
    catch {unset a}
    set a(a) 1
    list [array star a] [array star a] [array done a s-1-a; array star a] \
	    [array done a s-2-a; array d a s-3-a; array start a]
} {s-1-a s-2-a s-3-a s-1-a}
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
    trace var a(b) r {}
    set x [array startsearch a]
    lsort [list [array next a $x] [array next a $x]]
} {{} a}

test set-old-10.1 {array enumeration errors} {
    list [catch {array start} msg] $msg
} {1 {wrong # args: should be "array option arrayName ?arg ...?"}}
test set-old-10.2 {array enumeration errors} {
    list [catch {array start a b} msg] $msg
} {1 {wrong # args: should be "array startsearch arrayName"}}
test set-old-10.3 {array enumeration errors} {
    catch {unset a}
    list [catch {array start a} msg] $msg
} {1 {"a" isn't an array}}







|







790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
    trace var a(b) r {}
    set x [array startsearch a]
    lsort [list [array next a $x] [array next a $x]]
} {{} a}

test set-old-10.1 {array enumeration errors} {
    list [catch {array start} msg] $msg
} {1 {wrong # args: should be "array startsearch arrayName"}}
test set-old-10.2 {array enumeration errors} {
    list [catch {array start a b} msg] $msg
} {1 {wrong # args: should be "array startsearch arrayName"}}
test set-old-10.3 {array enumeration errors} {
    catch {unset a}
    list [catch {array start a} msg] $msg
} {1 {"a" isn't an array}}
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920




} 12345
test set-old-12.2 {cleanup on procedure return} {
    proc foo {} {
	set x(1) 23456
    }
    foo
} 23456

# Must delete variables when done, since these arrays get used as
# scalars by other tests.
catch {unset a}
catch {unset b}
catch {unset c}
catch {unset aVaRnAmE}
catch {rename foo {}}

# cleanup
::tcltest::cleanupTests
return 











|











>
>
>
>
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
} 12345
test set-old-12.2 {cleanup on procedure return} {
    proc foo {} {
	set x(1) 23456
    }
    foo
} 23456

# Must delete variables when done, since these arrays get used as
# scalars by other tests.
catch {unset a}
catch {unset b}
catch {unset c}
catch {unset aVaRnAmE}
catch {rename foo {}}

# cleanup
::tcltest::cleanupTests
return 

# Local Variables:
# mode: tcl
# End:
Changes to tests/socket.test.
64
65
66
67
68
69
70




71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90


















91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

package require tcltest 2
namespace import -force ::tcltest::*

# Some tests require the testthread and exec commands
testConstraint testthread [llength [info commands testthread]]
testConstraint exec [llength [info commands exec]]





# If remoteServerIP or remoteServerPort are not set, check in the environment
# variables for externally set values.
#

if {![info exists remoteServerIP]} {
    if {[info exists env(remoteServerIP)]} {
	set remoteServerIP $env(remoteServerIP)
    }
}
if {![info exists remoteServerPort]} {
    if {[info exists env(remoteServerIP)]} {
	set remoteServerPort $env(remoteServerPort)
    } else {
        if {[info exists remoteServerIP]} {
	    set remoteServerPort 2048
        }
    }
}



















#
# Check if we're supposed to do tests against the remote server
#

set doTestsWithRemoteServer 1
if {![info exists remoteServerIP]} {
    set remoteServerIP 127.0.0.1
}
if {($doTestsWithRemoteServer == 1) && (![info exists remoteServerPort])} {
    set remoteServerPort 2048
}

# Attempt to connect to a remote server if one is already running. If it is
# not running or for some other reason the connect fails, attempt to start the
# remote server on the local host listening on port 2048. This is only done on
# platforms that support exec (i.e. not on the Mac). On platforms that do not
# support exec, the remote server must be started by the user before running







>
>
>
>











|








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






|


|







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

package require tcltest 2
namespace import -force ::tcltest::*

# Some tests require the testthread and exec commands
testConstraint testthread [llength [info commands testthread]]
testConstraint exec [llength [info commands exec]]

# Produce a random port number in the Dynamic/Private range
# from 49152 through 65535.
proc randport {} { expr {int(rand()*16383+49152)} }

# If remoteServerIP or remoteServerPort are not set, check in the environment
# variables for externally set values.
#

if {![info exists remoteServerIP]} {
    if {[info exists env(remoteServerIP)]} {
	set remoteServerIP $env(remoteServerIP)
    }
}
if {![info exists remoteServerPort]} {
    if {[info exists env(remoteServerPort)]} {
	set remoteServerPort $env(remoteServerPort)
    } else {
        if {[info exists remoteServerIP]} {
	    set remoteServerPort 2048
        }
    }
}

if 0 {
    # activate this to time the tests
    proc test {args} {
        set name [lindex $args 0]
        puts "[lindex [time {uplevel [linsert $args 0 tcltest::test]}] 0] @@@ $name"
    }
}

foreach {af localhost} {
    any 127.0.0.1
    inet 127.0.0.1
    inet6 ::1
} {
    set ::tcl::unsupported::socketAF $af
    # Check if the family is supported and set the constraint accordingly
    testConstraint supported_$af [expr {![catch {socket -server foo 0} sock]}]
    catch {close $sock}
    
#
# Check if we're supposed to do tests against the remote server
#

set doTestsWithRemoteServer 1
if {![info exists remoteServerIP]} {
    set remoteServerIP $localhost
}
if {($doTestsWithRemoteServer == 1) && (![info exists remoteServerPort])} {
    set remoteServerPort [randport]
}

# Attempt to connect to a remote server if one is already running. If it is
# not running or for some other reason the connect fails, attempt to start the
# remote server on the local host listening on port 2048. This is only done on
# platforms that support exec (i.e. not on the Mac). On platforms that do not
# support exec, the remote server must be started by the user before running
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
	set commandSocket [socket $remoteServerIP $remoteServerPort]
    }]} then {
	fconfigure $commandSocket -translation crlf -buffering line
    } elseif {![testConstraint exec]} {
	set noRemoteTestReason "can't exec"
	set doTestsWithRemoteServer 0
    } else {
	set remoteServerIP 127.0.0.1
	# Be *extra* careful in case this file is sourced from
	# a directory other than the current one...
	set remoteFile [file join [pwd] [file dirname [info script]] \
		remote.tcl]
	if {![catch {
	    set remoteProcChan [open "|[list \
		    [interpreter] $remoteFile -serverIsSilent \
		    -port $remoteServerPort -address $remoteServerIP]" w+]
	} msg]} then {
	    after 1000
	    if {[catch {
		set commandSocket [socket $remoteServerIP $remoteServerPort]
	    } msg] == 0} then {
		fconfigure $commandSocket -translation crlf -buffering line
	    } else {
		set noRemoteTestReason $msg
		set doTestsWithRemoteServer 0







|









|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
	set commandSocket [socket $remoteServerIP $remoteServerPort]
    }]} then {
	fconfigure $commandSocket -translation crlf -buffering line
    } elseif {![testConstraint exec]} {
	set noRemoteTestReason "can't exec"
	set doTestsWithRemoteServer 0
    } else {
	set remoteServerIP $localhost
	# Be *extra* careful in case this file is sourced from
	# a directory other than the current one...
	set remoteFile [file join [pwd] [file dirname [info script]] \
		remote.tcl]
	if {![catch {
	    set remoteProcChan [open "|[list \
		    [interpreter] $remoteFile -serverIsSilent \
		    -port $remoteServerPort -address $remoteServerIP]" w+]
	} msg]} then {
	    gets $remoteProcChan
	    if {[catch {
		set commandSocket [socket $remoteServerIP $remoteServerPort]
	    } msg] == 0} then {
		fconfigure $commandSocket -translation crlf -buffering line
	    } else {
		set noRemoteTestReason $msg
		set doTestsWithRemoteServer 0
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193


194


195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
	if {[catch {puts $commandSocket $c} msg]} {
	    error "remote server disappaered: $msg"
	}
	if {[catch {puts $commandSocket "--Marker--Marker--Marker--"} msg]} {
	    error "remote server disappeared: $msg"
	}

	set resp ""
	while {1} {
	    set line [gets $commandSocket]
	    if {[eof $commandSocket]} {
		error "remote server disappaered"
	    }
	    if {[string compare $line "--Marker--Marker--Marker--"] == 0} {
		if {[string compare [lindex $resp 0] error] == 0} {
		    error [lindex $resp 1]
		} else {
		    return [lindex $resp 1]
		}
	    } else {
		append resp $line "\n"
	    }
	}
    }
}





# ----------------------------------------------------------------------

test socket-1.1 {arg parsing for socket command} -constraints socket -body {
    socket -server
} -returnCodes error -result {no argument given for -server option}
test socket-1.2 {arg parsing for socket command} -constraints socket -body {
    socket -server foo
} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
test socket-1.3 {arg parsing for socket command} -constraints socket -body {
    socket -myaddr
} -returnCodes error -result {no argument given for -myaddr option}
test socket-1.4 {arg parsing for socket command} -constraints socket -body {
    socket -myaddr 127.0.0.1
} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
test socket-1.5 {arg parsing for socket command} -constraints socket -body {
    socket -myport
} -returnCodes error -result {no argument given for -myport option}
test socket-1.6 {arg parsing for socket command} -constraints socket -body {
    socket -myport xxxx
} -returnCodes error -result {expected integer but got "xxxx"}
test socket-1.7 {arg parsing for socket command} -constraints socket -body {
    socket -myport 2522
} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
test socket-1.8 {arg parsing for socket command} -constraints socket -body {
    socket -froboz
} -returnCodes error -result {bad option "-froboz": must be -async, -myaddr, -myport, or -server}
test socket-1.9 {arg parsing for socket command} -constraints socket -body {
    socket -server foo -myport 2521 3333
} -returnCodes error -result {option -myport is not valid for servers}
test socket-1.10 {arg parsing for socket command} -constraints socket -body {
    socket host 2528 -junk
} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
test socket-1.11 {arg parsing for socket command} -constraints socket -body {
    socket -server callback 2520 --
} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
test socket-1.12 {arg parsing for socket command} -constraints socket -body {
    socket foo badport
} -returnCodes error -result {expected integer but got "badport"}
test socket-1.13 {arg parsing for socket command} -constraints socket -body {
    socket -async -server
} -returnCodes error -result {cannot set -async option for server sockets}
test socket-1.14 {arg parsing for socket command} -constraints socket -body {
    socket -server foo -async
} -returnCodes error -result {cannot set -async option for server sockets}

set path(script) [makeFile {} script]

test socket-2.1 {tcp connection} -constraints {socket stdio} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set timer [after 10000 "set x timed_out"]
	set f [socket -server accept 0]
	proc accept {file addr port} {
	    global x







<





|
<
|
<
|
|
<
|
|
|
|
|
>
>
|
>
>


|


|


|


|
|

|


|


|


|


|


|


|


|


|


|





|







191
192
193
194
195
196
197

198
199
200
201
202
203

204

205
206

207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
	if {[catch {puts $commandSocket $c} msg]} {
	    error "remote server disappaered: $msg"
	}
	if {[catch {puts $commandSocket "--Marker--Marker--Marker--"} msg]} {
	    error "remote server disappeared: $msg"
	}


	while {1} {
	    set line [gets $commandSocket]
	    if {[eof $commandSocket]} {
		error "remote server disappaered"
	    }
	    if {$line eq "--Marker--Marker--Marker--"} {

		lassign $result code info value

                return -code $code -errorinfo $info $value
	    }

            append result $line "\n"
	}
    }
}

proc getPort sock {
    lindex [fconfigure $sock -sockname] 2
}


# ----------------------------------------------------------------------

test socket_$af-1.1 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -server
} -returnCodes error -result {no argument given for -server option}
test socket_$af-1.2 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -server foo
} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
test socket_$af-1.3 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -myaddr
} -returnCodes error -result {no argument given for -myaddr option}
test socket_$af-1.4 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -myaddr $localhost
} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
test socket_$af-1.5 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -myport
} -returnCodes error -result {no argument given for -myport option}
test socket_$af-1.6 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -myport xxxx
} -returnCodes error -result {expected integer but got "xxxx"}
test socket_$af-1.7 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -myport 2522
} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
test socket_$af-1.8 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -froboz
} -returnCodes error -result {bad option "-froboz": must be -async, -myaddr, -myport, or -server}
test socket_$af-1.9 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -server foo -myport 2521 3333
} -returnCodes error -result {option -myport is not valid for servers}
test socket_$af-1.10 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket host 2528 -junk
} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
test socket_$af-1.11 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -server callback 2520 --
} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
test socket_$af-1.12 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket foo badport
} -returnCodes error -result {expected integer but got "badport"}
test socket_$af-1.13 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -async -server
} -returnCodes error -result {cannot set -async option for server sockets}
test socket_$af-1.14 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
    socket -server foo -async
} -returnCodes error -result {cannot set -async option for server sockets}

set path(script) [makeFile {} script]

test socket_$af-2.1 {tcp connection} -constraints [list socket supported_$af stdio] -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set timer [after 10000 "set x timed_out"]
	set f [socket -server accept 0]
	proc accept {file addr port} {
	    global x
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278

279
280
281
282
283
284
285
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f x
    gets $f listen
} -body {
    # $x == "ready" at this point
    set sock [socket 127.0.0.1 $listen]
    lappend x [gets $f]
    close $sock
    lappend x [gets $f]
} -cleanup {
    close $f
} -result {ready done {}}
if {[info exists port]} {
    incr port
} else {
    set port [expr {2048 + [pid]%1024}]
}
test socket-2.2 {tcp connection with client port specified} -setup {

    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set timer [after 10000 "set x timeout"]
        set f [socket -server accept 0]
	proc accept {file addr port} {
            global x







|






<
<
<
<
<
|
>







281
282
283
284
285
286
287
288
289
290
291
292
293
294





295
296
297
298
299
300
301
302
303
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f x
    gets $f listen
} -body {
    # $x == "ready" at this point
    set sock [socket $localhost $listen]
    lappend x [gets $f]
    close $sock
    lappend x [gets $f]
} -cleanup {
    close $f
} -result {ready done {}}





test socket_$af-2.2 {tcp connection with client port specified} -setup {
    set port [randport]
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set timer [after 10000 "set x timeout"]
        set f [socket -server accept 0]
	proc accept {file addr port} {
            global x
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324

325
326
327
328
329
330
331

332
333
334
335
336
337
338
339
340
341
342
343
344
345
346

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
	after cancel $timer
	close $f
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f x
    gets $f listen
} -constraints {socket stdio} -body {
    # $x == "ready" at this point
    global port
    set sock [socket -myport $port 127.0.0.1 $listen]
    puts $sock hello
    flush $sock
    lappend x [gets $f]
    close $sock
    return $x
} -cleanup {
    catch {close [socket 127.0.0.1 $listen]}
    close $f
} -result [list ready "hello $port"]
test socket-2.3 {tcp connection with client interface specified} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set timer [after 2000 "set x done"]
        set f [socket  -server accept 2830]
	proc accept {file addr port} {
            global x
            puts "[gets $file] $addr"
            close $file
            set x done
	}

	puts ready
	vwait x
	after cancel $timer
	close $f
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]

    gets $f x
} -constraints {socket stdio} -body {
    # $x == "ready" at this point
    set sock [socket -myaddr 127.0.0.1 127.0.0.1 2830]
    puts $sock hello
    flush $sock
    lappend x [gets $f]
    close $sock
    return $x
} -cleanup {
    close $f
} -result {ready {hello 127.0.0.1}}
test socket-2.4 {tcp connection with server interface specified} -setup {
    file delete $path(script)
    set f [open $path(script) w]

    puts $f {
	set timer [after 2000 "set x done"]
        set f [socket -server accept -myaddr 127.0.0.1 0]
	proc accept {file addr port} {
            global x
            puts "[gets $file]"
            close $file
            set x done
	}
	puts ready
	puts [lindex [fconfigure $f -sockname] 2]
	vwait x
	after cancel $timer
	close $f
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f x
    gets $f listen
} -constraints {socket stdio} -body {
    # $x == "ready" at this point
    set sock [socket 127.0.0.1 $listen]
    puts $sock hello
    flush $sock
    lappend x [gets $f]
    close $sock
    return $x
} -cleanup {
    close $f
} -result {ready hello}
test socket-2.5 {tcp connection with redundant server port} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set timer [after 10000 "set x timeout"]
        set f [socket -server accept 0]
	proc accept {file addr port} {
            global x







|

<
|


|



|

|
|




|






>







>

|

|







|
|


>


|
















|

|








|







311
312
313
314
315
316
317
318
319

320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
	after cancel $timer
	close $f
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f x
    gets $f listen
} -constraints [list socket supported_$af stdio] -body {
    # $x == "ready" at this point

    set sock [socket -myport $port $localhost $listen]
    puts $sock hello
    flush $sock
    lappend x [expr {[gets $f] eq "hello $port"}]
    close $sock
    return $x
} -cleanup {
    catch {close [socket $localhost $listen]}
    close $f
} -result {ready 1}
test socket_$af-2.3 {tcp connection with client interface specified} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set timer [after 2000 "set x done"]
        set f [socket  -server accept 0]
	proc accept {file addr port} {
            global x
            puts "[gets $file] $addr"
            close $file
            set x done
	}
	puts [lindex [fconfigure $f -sockname] 2]
	puts ready
	vwait x
	after cancel $timer
	close $f
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f listen
    gets $f x
} -constraints [list socket supported_$af stdio] -body {
    # $x == "ready" at this point
    set sock [socket -myaddr $localhost $localhost $listen]
    puts $sock hello
    flush $sock
    lappend x [gets $f]
    close $sock
    return $x
} -cleanup {
    close $f
} -result [list ready [list hello $localhost]]
test socket_$af-2.4 {tcp connection with server interface specified} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f [list set localhost $localhost]
    puts $f {
	set timer [after 2000 "set x done"]
        set f [socket -server accept -myaddr $localhost 0]
	proc accept {file addr port} {
            global x
            puts "[gets $file]"
            close $file
            set x done
	}
	puts ready
	puts [lindex [fconfigure $f -sockname] 2]
	vwait x
	after cancel $timer
	close $f
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f x
    gets $f listen
} -constraints [list socket supported_$af stdio] -body {
    # $x == "ready" at this point
    set sock [socket $localhost $listen]
    puts $sock hello
    flush $sock
    lappend x [gets $f]
    close $sock
    return $x
} -cleanup {
    close $f
} -result {ready hello}
test socket_$af-2.5 {tcp connection with redundant server port} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set timer [after 10000 "set x timeout"]
        set f [socket -server accept 0]
	proc accept {file addr port} {
            global x
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
	after cancel $timer
	close $f
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f x
    gets $f listen
} -constraints {socket stdio} -body {
    # $x == "ready" at this point
    set sock [socket 127.0.0.1 $listen]
    puts $sock hello
    flush $sock
    lappend x [gets $f]
    close $sock
    return $x
} -cleanup {
    close $f
} -result {ready hello}
test socket-2.6 {tcp connection} -constraints socket -body {
    set status ok
    if {![catch {set sock [socket 127.0.0.1 2833]}]} {
	if {![catch {gets $sock}]} {
	    set status broken
	}
	close $sock
    }
    set status
} -result ok
test socket-2.7 {echo server, one line} -constraints {socket stdio} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set timer [after 10000 "set x timeout"]
	set f [socket -server accept 0]
	proc accept {s a p} {
            fileevent $s readable [list echo $s]







|

|








|

|







|







412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
	after cancel $timer
	close $f
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f x
    gets $f listen
} -constraints [list socket supported_$af stdio] -body {
    # $x == "ready" at this point
    set sock [socket $localhost $listen]
    puts $sock hello
    flush $sock
    lappend x [gets $f]
    close $sock
    return $x
} -cleanup {
    close $f
} -result {ready hello}
test socket_$af-2.6 {tcp connection} -constraints [list socket supported_$af] -body {
    set status ok
    if {![catch {set sock [socket $localhost [randport]]}]} {
	if {![catch {gets $sock}]} {
	    set status broken
	}
	close $sock
    }
    set status
} -result ok
test socket_$af-2.7 {echo server, one line} -constraints [list socket supported_$af stdio] -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set timer [after 10000 "set x timeout"]
	set f [socket -server accept 0]
	proc accept {s a p} {
            fileevent $s readable [list echo $s]
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
	puts $x
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f
    gets $f listen
} -body {
    set s [socket 127.0.0.1 $listen]
    fconfigure $s -buffering line -translation lf
    puts $s "hello abcdefghijklmnop"
    after 1000
    set x [gets $s]
    close $s
    list $x [gets $f]
} -cleanup {
    close $f
} -result {{hello abcdefghijklmnop} done}
removeFile script
test socket-2.8 {echo server, loop 50 times, single connection} -setup {
    set path(script) [makeFile {
	set f [socket -server accept 0]
	proc accept {s a p} {
            fileevent $s readable [list echo $s]
            fconfigure $s -buffering line
        }
	proc echo {s} {







|


<







|







465
466
467
468
469
470
471
472
473
474

475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
	puts $x
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f
    gets $f listen
} -body {
    set s [socket $localhost $listen]
    fconfigure $s -buffering line -translation lf
    puts $s "hello abcdefghijklmnop"

    set x [gets $s]
    close $s
    list $x [gets $f]
} -cleanup {
    close $f
} -result {{hello abcdefghijklmnop} done}
removeFile script
test socket_$af-2.8 {echo server, loop 50 times, single connection} -setup {
    set path(script) [makeFile {
	set f [socket -server accept 0]
	proc accept {s a p} {
            fileevent $s readable [list echo $s]
            fconfigure $s -buffering line
        }
	proc echo {s} {
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561

562
563
564
565
566
567
568

569
570
571
572
573
574
575
576
577
578
579
580

581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600

601
602
603
604
605
606
607
608
609
610
611
612
613
	after cancel $timer
	close $f
	puts "done $i"
    } script]
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f
    gets $f listen
} -constraints {socket stdio} -body {
    set s [socket 127.0.0.1 $listen]
    fconfigure $s -buffering line
    catch {
	for {set x 0} {$x < 50} {incr x} {
	    puts $s "hello abcdefghijklmnop"
	    gets $s
	}
    }
    close $s
    catch {set x [gets $f]}
    return $x
} -cleanup {
    close $f
    removeFile script
} -result {done 50}
set path(script) [makeFile {} script]
test socket-2.9 {socket conflict} -constraints {socket stdio} -body {
    set s [socket -server accept 0]
    file delete $path(script)
    set f [open $path(script) w]

    puts -nonewline $f "socket -server accept [lindex [fconfigure $s -sockname] 2]"
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f
    after 100
    close $f
} -returnCodes error -cleanup {
    close $s
} -match glob -result {couldn't open socket: address already in use*}
test socket-2.10 {close on accept, accepted socket lives} -setup {
    set done 0
    set timer [after 20000 "set done timed_out"]
} -constraints socket -body {
    set ss [socket -server accept 0]
    proc accept {s a p} {
	global ss
	close $ss
	fileevent $s readable "readit $s"
	fconfigure $s -trans lf
    }
    proc readit {s} {
	global done
	gets $s
	close $s
	set done 1
    }
    set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]]
    puts $cs hello
    close $cs
    vwait done
    return $done
} -cleanup {
    after cancel $timer
} -result 1
test socket-2.11 {detecting new data} -constraints socket -setup {
    proc accept {s a p} {
	global sock
	set sock $s
    }
    set s [socket -server accept 0]
    set sock ""
} -body {
    set s2 [socket 127.0.0.1 [lindex [fconfigure $s -sockname] 2]]
    vwait sock
    puts $s2 one
    flush $s2
    after 500

    fconfigure $sock -blocking 0
    set result a:[gets $sock]
    lappend result b:[gets $sock]
    fconfigure $sock -blocking 1
    puts $s2 two
    flush $s2
    after 500

    fconfigure $sock -blocking 0
    lappend result c:[gets $sock]
} -cleanup {
    fconfigure $sock -blocking 1
    close $s2
    close $s
    close $sock
} -result {a:one b: c:two}

test socket-3.1 {socket conflict} -constraints {socket stdio} -setup {
    file delete $path(script)
    set f [open $path(script) w]

    puts $f {
	set f [socket -server accept -myaddr 127.0.0.1 0]
	puts ready
	puts [lindex [fconfigure $f -sockname] 2]
	gets stdin
	close $f
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r+]
    gets $f
    gets $f listen
} -body {
    socket -server accept -myaddr 127.0.0.1 $listen
} -cleanup {
    puts $f bye
    close $f
} -returnCodes error -result {couldn't open socket: address already in use}
test socket-3.2 {server with several clients} -setup {
    file delete $path(script)
    set f [open $path(script) w]

    puts $f {
	set t1 [after 30000 "set x timed_out"]
	set t2 [after 31000 "set x timed_out"]
	set t3 [after 32000 "set x timed_out"]
	set counter 0
	set s [socket -server accept -myaddr 127.0.0.1 0]
	proc accept {s a p} {
	    fileevent $s readable [list echo $s]
	    fconfigure $s -buffering line
	}
	proc echo {s} {
	     global x
             set l [gets $s]







|
|















|



>
|








|


|













|







|







|



|
>






|
>









|


>

|










|




|


>





|







506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
	after cancel $timer
	close $f
	puts "done $i"
    } script]
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f
    gets $f listen
} -constraints [list socket supported_$af stdio] -body {
    set s [socket $localhost $listen]
    fconfigure $s -buffering line
    catch {
	for {set x 0} {$x < 50} {incr x} {
	    puts $s "hello abcdefghijklmnop"
	    gets $s
	}
    }
    close $s
    catch {set x [gets $f]}
    return $x
} -cleanup {
    close $f
    removeFile script
} -result {done 50}
set path(script) [makeFile {} script]
test socket_$af-2.9 {socket conflict} -constraints [list socket supported_$af stdio] -body {
    set s [socket -server accept 0]
    file delete $path(script)
    set f [open $path(script) w]
    puts $f [list set ::tcl::unsupported::socketAF $::tcl::unsupported::socketAF]
    puts $f "socket -server accept [lindex [fconfigure $s -sockname] 2]"
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f
    after 100
    close $f
} -returnCodes error -cleanup {
    close $s
} -match glob -result {couldn't open socket: address already in use*}
test socket_$af-2.10 {close on accept, accepted socket lives} -setup {
    set done 0
    set timer [after 20000 "set done timed_out"]
} -constraints [list socket supported_$af] -body {
    set ss [socket -server accept 0]
    proc accept {s a p} {
	global ss
	close $ss
	fileevent $s readable "readit $s"
	fconfigure $s -trans lf
    }
    proc readit {s} {
	global done
	gets $s
	close $s
	set done 1
    }
    set cs [socket $localhost [lindex [fconfigure $ss -sockname] 2]]
    puts $cs hello
    close $cs
    vwait done
    return $done
} -cleanup {
    after cancel $timer
} -result 1
test socket_$af-2.11 {detecting new data} -constraints [list socket supported_$af] -setup {
    proc accept {s a p} {
	global sock
	set sock $s
    }
    set s [socket -server accept 0]
    set sock ""
} -body {
    set s2 [socket $localhost [lindex [fconfigure $s -sockname] 2]]
    vwait sock
    puts $s2 one
    flush $s2
    after idle {set x 1}
    vwait x
    fconfigure $sock -blocking 0
    set result a:[gets $sock]
    lappend result b:[gets $sock]
    fconfigure $sock -blocking 1
    puts $s2 two
    flush $s2
    after idle {set x 1}
    vwait x
    fconfigure $sock -blocking 0
    lappend result c:[gets $sock]
} -cleanup {
    fconfigure $sock -blocking 1
    close $s2
    close $s
    close $sock
} -result {a:one b: c:two}

test socket_$af-3.1 {socket conflict} -constraints [list socket supported_$af stdio] -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f [list set localhost $localhost]
    puts $f {
	set f [socket -server accept -myaddr $localhost 0]
	puts ready
	puts [lindex [fconfigure $f -sockname] 2]
	gets stdin
	close $f
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r+]
    gets $f
    gets $f listen
} -body {
    socket -server accept -myaddr $localhost $listen
} -cleanup {
    puts $f bye
    close $f
} -returnCodes error -result {couldn't open socket: address already in use}
test socket_$af-3.2 {server with several clients} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f [list set localhost $localhost]
    puts $f {
	set t1 [after 30000 "set x timed_out"]
	set t2 [after 31000 "set x timed_out"]
	set t3 [after 32000 "set x timed_out"]
	set counter 0
	set s [socket -server accept -myaddr $localhost 0]
	proc accept {s a p} {
	    fileevent $s readable [list echo $s]
	    fconfigure $s -buffering line
	}
	proc echo {s} {
	     global x
             set l [gets $s]
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662

663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
	close $s
	puts $x
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r+]
    set x [gets $f]
    gets $f listen
} -constraints {socket stdio} -body {
    # $x == "ready" here
    set s1 [socket 127.0.0.1 $listen]
    fconfigure $s1 -buffering line
    set s2 [socket 127.0.0.1 $listen]
    fconfigure $s2 -buffering line
    set s3 [socket 127.0.0.1 $listen]
    fconfigure $s3 -buffering line
    for {set i 0} {$i < 100} {incr i} {
	puts $s1 hello,s1
	gets $s1
	puts $s2 hello,s2
	gets $s2
	puts $s3 hello,s3
	gets $s3
    }
    close $s1
    close $s2
    close $s3
    lappend x [gets $f]
} -cleanup {
    close $f
} -result {ready done}

test socket-4.1 {server with several clients} -setup {
    file delete $path(script)
    set f [open $path(script) w]

    puts $f {
	set port [gets stdin]
	set s [socket 127.0.0.1 $port]
	fconfigure $s -buffering line
	for {set i 0} {$i < 100} {incr i} {
	    puts $s hello
	    gets $s
	}
	close $s
	puts bye
	gets stdin
    }
    close $f
    set p1 [open "|[list [interpreter] $path(script)]" r+]
    fconfigure $p1 -buffering line
    set p2 [open "|[list [interpreter] $path(script)]" r+]
    fconfigure $p2 -buffering line
    set p3 [open "|[list [interpreter] $path(script)]" r+]
    fconfigure $p3 -buffering line
} -constraints {socket stdio} -body {
    proc accept {s a p} {
	fconfigure $s -buffering line
	fileevent $s readable [list echo $s]
    }
    proc echo {s} {
	global x
        set l [gets $s]
        if {[eof $s]} {
            close $s
            set x done
        } else {
            puts $s $l
        }
    }
    set t1 [after 30000 "set x timed_out"]
    set t2 [after 31000 "set x timed_out"]
    set t3 [after 32000 "set x timed_out"]
    set s [socket -server accept -myaddr 127.0.0.1 0]
    set listen [lindex [fconfigure $s -sockname] 2]
    puts $p1 $listen
    puts $p2 $listen
    puts $p3 $listen
    vwait x
    vwait x
    vwait x







|

|

|

|

















|


>


|
















|

















|







653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
	close $s
	puts $x
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r+]
    set x [gets $f]
    gets $f listen
} -constraints [list socket supported_$af stdio] -body {
    # $x == "ready" here
    set s1 [socket $localhost $listen]
    fconfigure $s1 -buffering line
    set s2 [socket $localhost $listen]
    fconfigure $s2 -buffering line
    set s3 [socket $localhost $listen]
    fconfigure $s3 -buffering line
    for {set i 0} {$i < 100} {incr i} {
	puts $s1 hello,s1
	gets $s1
	puts $s2 hello,s2
	gets $s2
	puts $s3 hello,s3
	gets $s3
    }
    close $s1
    close $s2
    close $s3
    lappend x [gets $f]
} -cleanup {
    close $f
} -result {ready done}

test socket_$af-4.1 {server with several clients} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f [list set localhost $localhost]
    puts $f {
	set port [gets stdin]
	set s [socket $localhost $port]
	fconfigure $s -buffering line
	for {set i 0} {$i < 100} {incr i} {
	    puts $s hello
	    gets $s
	}
	close $s
	puts bye
	gets stdin
    }
    close $f
    set p1 [open "|[list [interpreter] $path(script)]" r+]
    fconfigure $p1 -buffering line
    set p2 [open "|[list [interpreter] $path(script)]" r+]
    fconfigure $p2 -buffering line
    set p3 [open "|[list [interpreter] $path(script)]" r+]
    fconfigure $p3 -buffering line
} -constraints [list socket supported_$af stdio] -body {
    proc accept {s a p} {
	fconfigure $s -buffering line
	fileevent $s readable [list echo $s]
    }
    proc echo {s} {
	global x
        set l [gets $s]
        if {[eof $s]} {
            close $s
            set x done
        } else {
            puts $s $l
        }
    }
    set t1 [after 30000 "set x timed_out"]
    set t2 [after 31000 "set x timed_out"]
    set t3 [after 32000 "set x timed_out"]
    set s [socket -server accept -myaddr $localhost 0]
    set listen [lindex [fconfigure $s -sockname] 2]
    puts $p1 $listen
    puts $p2 $listen
    puts $p3 $listen
    vwait x
    vwait x
    vwait x
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
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
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
    puts $p1 bye
    puts $p2 bye
    puts $p3 bye
    close $p1
    close $p2
    close $p3
} -result {{p1 bye done} {p2 bye done} {p3 bye done}}
test socket-4.2 {byte order problems, socket numbers, htons} -body {
    close [socket -server dodo -myaddr 127.0.0.1 0x3000]
    return ok
} -constraints socket -result ok

test socket-5.1 {byte order problems, socket numbers, htons} -body {
    if {![catch {socket -server dodo 0x1} msg]} {
	close $msg
        return {htons problem, should be disallowed, are you running as SU?}
    }
    return {couldn't open socket: not owner}
} -constraints {socket unix notRoot} -result {couldn't open socket: not owner}
test socket-5.2 {byte order problems, socket numbers, htons} -body {
    if {![catch {socket -server dodo 0x10000} msg]} {
	close $msg
	return {port resolution problem, should be disallowed}
    }
    return {couldn't open socket: port number too high}
} -constraints socket -result {couldn't open socket: port number too high}
test socket-5.3 {byte order problems, socket numbers, htons} -body {
    if {![catch {socket -server dodo 21} msg]} {
	close $msg
	return {htons problem, should be disallowed, are you running as SU?}
    }
    return {couldn't open socket: not owner}
} -constraints {socket unix notRoot} -result {couldn't open socket: not owner}

test socket-6.1 {accept callback error} -constraints {socket stdio} -setup {
    proc myHandler {msg options} {
	variable x $msg
    }
    set handler [interp bgerror {}]
    interp bgerror {} [namespace which myHandler]
    file delete $path(script)
} -body {
    set f [open $path(script) w]

    puts $f {
	gets stdin port
	socket 127.0.0.1 $port
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r+]
    proc accept {s a p} {expr 10 / 0}
    set s [socket -server accept -myaddr 127.0.0.1 0]
    puts $f [lindex [fconfigure $s -sockname] 2]
    close $f
    set timer [after 10000 "set x timed_out"]
    vwait x
    after cancel $timer
    close $s
    return $x
} -cleanup {
    interp bgerror {} $handler
} -result {divide by zero}

test socket-7.1 {testing socket specific options} -setup {
    file delete $path(script)
    set f [open $path(script) w]































    puts $f {
	set ss [socket -server accept 0]
	proc accept args {
	    global x
	    set x done
	}
	puts ready
	puts [lindex [fconfigure $ss -sockname] 2]
	set timer [after 10000 "set x timed_out"]
	vwait x
	after cancel $timer
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f
    gets $f listen
    set l ""
} -constraints {socket stdio} -body {
    set s [socket 127.0.0.1 $listen]
    set p [fconfigure $s -peername]
    close $s
    lappend l [string compare [lindex $p 0] 127.0.0.1]
    lappend l [string compare [lindex $p 2] $listen]
    lappend l [llength $p]
} -cleanup {
    close $f
} -result {0 0 3}
test socket-7.2 {testing socket specific options} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set ss [socket -server accept 2821]
	proc accept args {
	    global x
	    set x done
	}
	puts ready
	puts [lindex [fconfigure $ss -sockname] 2]
	set timer [after 10000 "set x timed_out"]
	vwait x
	after cancel $timer
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f
    gets $f listen
} -constraints {socket stdio} -body {
    set s [socket 127.0.0.1 $listen]
    set p [fconfigure $s -sockname]
    close $s
    list [llength $p] \
	    [regexp {^(127\.0\.0\.1|0\.0\.0\.0)$} [lindex $p 0]] \
	    [expr {[lindex $p 2] == $listen}]
} -cleanup {
    close $f
} -result {3 1 0}
test socket-7.3 {testing socket specific options} -constraints socket -body {
    set s [socket -server accept -myaddr 127.0.0.1 0]
    set l [fconfigure $s]
    close $s
    update
    llength $l
} -result 14
test socket-7.4 {testing socket specific options} -constraints socket -setup {
    set timer [after 10000 "set x timed_out"]
    set l ""
} -body {
    set s [socket -server accept -myaddr 127.0.0.1 0]
    proc accept {s a p} {
	global x
	set x [fconfigure $s -sockname]
	close $s
    }
    set listen [lindex [fconfigure $s -sockname] 2]
    set s1 [socket 127.0.0.1 $listen]
    vwait x
    lappend l [expr {[lindex $x 2] == $listen}] [llength $x]
} -cleanup {
    after cancel $timer
    close $s
    close $s1
} -result {1 3}
test socket-7.5 {testing socket specific options} -setup {
    set timer [after 10000 "set x timed_out"]
    set l ""
} -constraints {socket unixOrPc} -body {
    set s [socket -server accept 0]
    proc accept {s a p} {
	global x
	set x [fconfigure $s -sockname]
	close $s
    }
    set listen [lindex [fconfigure $s -sockname] 2]
    set s1 [socket 127.0.0.1 $listen]
    vwait x
    lappend l [lindex $x 0] [expr {[lindex $x 2] == $listen}] [llength $x]
} -cleanup {
    after cancel $timer
    close $s
    close $s1
} -result {127.0.0.1 1 3}

test socket-8.1 {testing -async flag on sockets} -constraints socket -body {
    # NOTE: This test may fail on some Solaris 2.4 systems. If it does, check
    # that you have these patches installed (using showrev -p):
    #
    # 101907-05, 101925-02, 101945-14, 101959-03, 101969-05, 101973-03,
    # 101977-03, 101981-02, 101985-01, 102001-03, 102003-01, 102007-01,
    # 102011-02, 102024-01, 102039-01, 102044-01, 102048-01, 102062-03,
    # 102066-04, 102070-01, 102105-01, 102153-03, 102216-01, 102232-01,
    # 101878-03, 101879-01, 101880-03, 101933-01, 101950-01, 102030-01,
    # 102057-08, 102140-01, 101920-02, 101921-09, 101922-07, 101923-03
    #
    # If after installing these patches you are still experiencing a problem,
    # please email [email protected]. We have not observed this failure on
    # Solaris 2.5, so another option (instead of installing these patches) is
    # to upgrade to Solaris 2.5.
    set s [socket -server accept -myaddr 127.0.0.1 0]
    proc accept {s a p} {
	global x
	puts $s bye
	close $s
	set x done
    }
    set s1 [socket -async 127.0.0.1 [lindex [fconfigure $s -sockname] 2]]
    vwait x
    gets $s1
} -cleanup {
    close $s
    close $s1
} -result bye

test socket-9.1 {testing spurious events} -constraints socket -setup {
    set len 0
    set spurious 0
    set done 0
    set timer [after 10000 "set done timed_out"]
} -body {
    proc readlittle {s} {
	global spurious done len







|
|

|

|





|
|





|
|





|

|








>


|




|











|


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
















<
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



|




|
|





|



|






|







|


|







|






|

|














|






|







|







742
743
744
745
746
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
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854

855
856





























857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
    puts $p1 bye
    puts $p2 bye
    puts $p3 bye
    close $p1
    close $p2
    close $p3
} -result {{p1 bye done} {p2 bye done} {p3 bye done}}
test socket_$af-4.2 {byte order problems, socket numbers, htons} -body {
    close [socket -server dodo -myaddr $localhost 0x3000]
    return ok
} -constraints [list socket supported_$af] -result ok

test socket_$af-5.1 {byte order problems, socket numbers, htons} -body {
    if {![catch {socket -server dodo 0x1} msg]} {
	close $msg
        return {htons problem, should be disallowed, are you running as SU?}
    }
    return {couldn't open socket: not owner}
} -constraints [list socket supported_$af unix notRoot] -result {couldn't open socket: not owner}
test socket_$af-5.2 {byte order problems, socket numbers, htons} -body {
    if {![catch {socket -server dodo 0x10000} msg]} {
	close $msg
	return {port resolution problem, should be disallowed}
    }
    return {couldn't open socket: port number too high}
} -constraints [list socket supported_$af] -result {couldn't open socket: port number too high}
test socket_$af-5.3 {byte order problems, socket numbers, htons} -body {
    if {![catch {socket -server dodo 21} msg]} {
	close $msg
	return {htons problem, should be disallowed, are you running as SU?}
    }
    return {couldn't open socket: not owner}
} -constraints [list socket supported_$af unix notRoot] -result {couldn't open socket: not owner}

test socket_$af-6.1 {accept callback error} -constraints [list socket supported_$af stdio] -setup {
    proc myHandler {msg options} {
	variable x $msg
    }
    set handler [interp bgerror {}]
    interp bgerror {} [namespace which myHandler]
    file delete $path(script)
} -body {
    set f [open $path(script) w]
    puts $f [list set localhost $localhost]
    puts $f {
	gets stdin port
	socket $localhost $port
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r+]
    proc accept {s a p} {expr 10 / 0}
    set s [socket -server accept -myaddr $localhost 0]
    puts $f [lindex [fconfigure $s -sockname] 2]
    close $f
    set timer [after 10000 "set x timed_out"]
    vwait x
    after cancel $timer
    close $s
    return $x
} -cleanup {
    interp bgerror {} $handler
} -result {divide by zero}

test socket_$af-7.1 {testing socket specific options} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set ss [socket -server accept 0]
	proc accept args {
	    global x
	    set x done
	}
	puts ready
	puts [lindex [fconfigure $ss -sockname] 2]
	set timer [after 10000 "set x timed_out"]
	vwait x
	after cancel $timer
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f
    gets $f listen
    set l ""
} -constraints [list socket supported_$af stdio] -body {
    set s [socket $localhost $listen]
    set p [fconfigure $s -peername]
    close $s
    lappend l [string compare [lindex $p 0] $localhost]
    lappend l [string compare [lindex $p 2] $listen]
    lappend l [llength $p]
} -cleanup {
    close $f
} -result {0 0 3}
test socket_$af-7.2 {testing socket specific options} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f [list set ::tcl::unsupported::socketAF $::tcl::unsupported::socketAF]
    puts $f {
	set ss [socket -server accept 0]
	proc accept args {
	    global x
	    set x done
	}
	puts ready
	puts [lindex [fconfigure $ss -sockname] 2]
	set timer [after 10000 "set x timed_out"]
	vwait x
	after cancel $timer
    }
    close $f
    set f [open "|[list [interpreter] $path(script)]" r]
    gets $f
    gets $f listen

} -constraints [list socket supported_$af stdio] -body {
    set s [socket $localhost $listen]





























    set p [fconfigure $s -sockname]
    close $s
    list [llength $p] \
	    [regexp {^(127\.0\.0\.1|0\.0\.0\.0|::1)$} [lindex $p 0]] \
	    [expr {[lindex $p 2] == $listen}]
} -cleanup {
    close $f
} -result {3 1 0}
test socket_$af-7.3 {testing socket specific options} -constraints [list socket supported_$af] -body {
    set s [socket -server accept -myaddr $localhost 0]
    set l [fconfigure $s]
    close $s
    update
    llength $l
} -result 14
test socket_$af-7.4 {testing socket specific options} -constraints [list socket supported_$af] -setup {
    set timer [after 10000 "set x timed_out"]
    set l ""
} -body {
    set s [socket -server accept -myaddr $localhost 0]
    proc accept {s a p} {
	global x
	set x [fconfigure $s -sockname]
	close $s
    }
    set listen [lindex [fconfigure $s -sockname] 2]
    set s1 [socket $localhost $listen]
    vwait x
    lappend l [expr {[lindex $x 2] == $listen}] [llength $x]
} -cleanup {
    after cancel $timer
    close $s
    close $s1
} -result {1 3}
test socket_$af-7.5 {testing socket specific options} -setup {
    set timer [after 10000 "set x timed_out"]
    set l ""
} -constraints [list socket supported_$af unixOrPc] -body {
    set s [socket -server accept 0]
    proc accept {s a p} {
	global x
	set x [fconfigure $s -sockname]
	close $s
    }
    set listen [lindex [fconfigure $s -sockname] 2]
    set s1 [socket $localhost $listen]
    vwait x
    lappend l [lindex $x 0] [expr {[lindex $x 2] == $listen}] [llength $x]
} -cleanup {
    after cancel $timer
    close $s
    close $s1
} -result [list $localhost 1 3]

test socket_$af-8.1 {testing -async flag on sockets} -constraints [list socket supported_$af] -body {
    # NOTE: This test may fail on some Solaris 2.4 systems. If it does, check
    # that you have these patches installed (using showrev -p):
    #
    # 101907-05, 101925-02, 101945-14, 101959-03, 101969-05, 101973-03,
    # 101977-03, 101981-02, 101985-01, 102001-03, 102003-01, 102007-01,
    # 102011-02, 102024-01, 102039-01, 102044-01, 102048-01, 102062-03,
    # 102066-04, 102070-01, 102105-01, 102153-03, 102216-01, 102232-01,
    # 101878-03, 101879-01, 101880-03, 101933-01, 101950-01, 102030-01,
    # 102057-08, 102140-01, 101920-02, 101921-09, 101922-07, 101923-03
    #
    # If after installing these patches you are still experiencing a problem,
    # please email [email protected]. We have not observed this failure on
    # Solaris 2.5, so another option (instead of installing these patches) is
    # to upgrade to Solaris 2.5.
    set s [socket -server accept -myaddr $localhost 0]
    proc accept {s a p} {
	global x
	puts $s bye
	close $s
	set x done
    }
    set s1 [socket -async $localhost [lindex [fconfigure $s -sockname] 2]]
    vwait x
    gets $s1
} -cleanup {
    close $s
    close $s1
} -result bye

test socket_$af-9.1 {testing spurious events} -constraints [list socket supported_$af] -setup {
    set len 0
    set spurious 0
    set done 0
    set timer [after 10000 "set done timed_out"]
} -body {
    proc readlittle {s} {
	global spurious done len
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069

1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089

1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109























1110



1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186

1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218

1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247

1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268

1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291

1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327

1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385

1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419

1420
1421
1422
1423
1424
1425
1426
1427
1428

1429
1430
1431
1432
1433
1434
1435

1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463

1464
1465
1466
1467
1468
1469
1470
1471
1472
1473

1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
	    incr len [string length $l]
	}
    }
    proc accept {s a p} {
	fconfigure $s -buffering none -blocking off
	fileevent $s readable [list readlittle $s]
    }
    set s [socket -server accept -myaddr 127.0.0.1 0]
    set c [socket 127.0.0.1 [lindex [fconfigure $s -sockname] 2]]
    puts -nonewline $c 01234567890123456789012345678901234567890123456789
    close $c
    vwait done
    close $s
    list $spurious $len
} -cleanup {
    after cancel $timer
} -result {0 50}
test socket-9.2 {testing async write, fileevents, flush on close} -constraints socket -setup {
    set firstblock ""
    for {set i 0} {$i < 5} {incr i} {set firstblock "a$firstblock$firstblock"}
    set secondblock ""
    for {set i 0} {$i < 16} {incr i} {
	set secondblock "b$secondblock$secondblock"
    }
    set timer [after 10000 "set done timed_out"]
    set l [socket -server accept -myaddr 127.0.0.1 0]
    proc accept {s a p} {
	fconfigure $s -blocking 0 -translation lf -buffersize 16384 \
		-buffering line
	fileevent $s readable "readable $s"
    }
    proc readable {s} {
	set l [gets $s]
	fileevent $s readable {}
	after 1000 respond $s
    }
    proc respond {s} {
	global firstblock
	puts -nonewline $s $firstblock
	after 1000 writedata $s
    }
    proc writedata {s} {
	global secondblock
	puts -nonewline $s $secondblock
	close $s
    }
} -body {
    set s [socket 127.0.0.1 [lindex [fconfigure $l -sockname] 2]]
    fconfigure $s -blocking 0 -trans lf -buffering line
    set count 0
    puts $s hello
    proc readit {s} {
	global count done
	set l [read $s]
	incr count [string length $l]
	if {[eof $s]} {
	    close $s
	    set done 1
	}
    }
    fileevent $s readable "readit $s"
    vwait done
    return $count
} -cleanup {
    close $l
    after cancel $timer
} -result 65566
test socket-9.3 {testing EOF stickyness} -constraints socket -setup {
    set count 0
    set done false
    proc write_then_close {s} {
	puts $s bye
	close $s
    }
    proc accept {s a p} {
	fconfigure $s -buffering line -translation lf
	fileevent $s writable "write_then_close $s"
    }
    set s [socket -server accept -myaddr 127.0.0.1 0]
} -body {
    proc count_to_eof {s} {
	global count done
	set l [gets $s]
	if {[eof $s]} {
	    incr count
	    if {$count > 9} {
		close $s
		set done true
		set count {eof is sticky}
	    }
	}
    }
    proc timerproc {s} {
	global done count
	set done true
	set count {timer went off, eof is not sticky}
	close $s
    }
    set c [socket 127.0.0.1 [lindex [fconfigure $s -sockname] 2]]
    fconfigure $c -blocking off -buffering line -translation lf
    fileevent $c readable "count_to_eof $c"
    set timer [after 1000 timerproc $c]
    vwait done
    return $count
} -cleanup {
    close $s
    after cancel $timer
} -result {eof is sticky}

removeFile script

test socket-10.1 {testing socket accept callback error handling} -constraints {
    socket
} -setup {
    variable goterror 0
    proc myHandler {msg options} {
	variable goterror 1
    }
    set handler [interp bgerror {}]
    interp bgerror {} [namespace which myHandler]
} -body {
    set s [socket -server accept -myaddr 127.0.0.1 0]
    proc accept {s a p} {close $s; error}
    set c [socket 127.0.0.1 [lindex [fconfigure $s -sockname] 2]]
    vwait goterror
    close $s
    close $c
    return $goterror
} -cleanup {
    interp bgerror {} $handler
} -result 1

test socket-11.1 {tcp connection} -setup {
    sendCommand {
	set socket9_1_test_server [socket -server accept 2834]
	proc accept {s a p} {
	    puts $s done
	    close $s
	}

    }
} -constraints {socket doTestsWithRemoteServer} -body {
    set s [socket $remoteServerIP 2834]
    gets $s
} -cleanup {
    close $s
    sendCommand {close $socket9_1_test_server}
} -result done
test socket-11.2 {client specifies its port} -setup {
    if {[info exists port]} {
	incr port
    } else {
	set port [expr 2048 + [pid]%1024]
    }
    sendCommand {
	set socket9_2_test_server [socket -server accept 2835]
	proc accept {s a p} {
	    puts $s $p
	    close $s
	}

    }
} -constraints {socket doTestsWithRemoteServer} -body {
    set s [socket -myport $port $remoteServerIP 2835]
    set r [gets $s]
    expr {$r==$port ? "ok" : "broken: $r != $port"}
} -cleanup {
    close $s
    sendCommand {close $socket9_2_test_server}
} -result ok
test socket-11.3 {trying to connect, no server} -body {
    set status ok
    if {![catch {set s [socket $remoteServerIp 2836]}]} {
	if {![catch {gets $s}]} {
	    set status broken
	}
	close $s
    }
    return $status
} -constraints {socket doTestsWithRemoteServer} -result ok
test socket-11.4 {remote echo, one line} -setup {























    sendCommand {



	set socket10_6_test_server [socket -server accept 2836]
	proc accept {s a p} {
	    fileevent $s readable [list echo $s]
	    fconfigure $s -buffering line -translation crlf
	}
	proc echo {s} {
	    set l [gets $s]
	    if {[eof $s]} {
		close $s
	    } else {
		puts $s $l
	    }
	}
    }
} -constraints {socket doTestsWithRemoteServer} -body {
    set f [socket $remoteServerIP 2836]
    fconfigure $f -translation crlf -buffering line
    puts $f hello
    gets $f
} -cleanup {
    catch {close $f}
    sendCommand {close $socket10_6_test_server}
} -result hello
test socket-11.5 {remote echo, 50 lines} -setup {
    sendCommand {
	set socket10_7_test_server [socket -server accept 2836]
	proc accept {s a p} {
	    fileevent $s readable [list echo $s]
	    fconfigure $s -buffering line -translation crlf
	}
	proc echo {s} {
	    set l [gets $s]
	    if {[eof $s]} {
		close $s
	    } else {
		puts $s $l
	    }
	}
    }
} -constraints {socket doTestsWithRemoteServer} -body {
    set f [socket $remoteServerIP 2836]
    fconfigure $f -translation crlf -buffering line
    for {set cnt 0} {$cnt < 50} {incr cnt} {
	puts $f "hello, $cnt"
	if {[gets $f] != "hello, $cnt"} {
	    break
	}
    }
    return $cnt
} -cleanup {
    close $f
    sendCommand {close $socket10_7_test_server}
} -result 50
test socket-11.6 {socket conflict} -setup {
    set s1 [socket -server accept -myaddr 127.0.0.1 2836]
} -constraints {socket doTestsWithRemoteServer} -body {
    set s2 [socket -server accept -myaddr 127.0.0.1 2836]
    list [lindex [fconfigure $s2 -sockname] 2] [close $s2]
} -cleanup {
    close $s1
} -returnCodes error -result {couldn't open socket: address already in use}
test socket-11.7 {server with several clients} -setup {
    sendCommand {
	set socket10_9_test_server [socket -server accept 2836]
	proc accept {s a p} {
	    fconfigure $s -buffering line
	    fileevent $s readable [list echo $s]
	}
	proc echo {s} {
	    set l [gets $s]
	    if {[eof $s]} {
		close $s
	    } else {
		puts $s $l
	    }
	}

    }
} -constraints {socket doTestsWithRemoteServer} -body {
    set s1 [socket $remoteServerIP 2836]
    fconfigure $s1 -buffering line
    set s2 [socket $remoteServerIP 2836]
    fconfigure $s2 -buffering line
    set s3 [socket $remoteServerIP 2836]
    fconfigure $s3 -buffering line
    for {set i 0} {$i < 100} {incr i} {
	puts $s1 hello,s1
	gets $s1
	puts $s2 hello,s2
	gets $s2
	puts $s3 hello,s3
	gets $s3
    }
    return $i
} -cleanup {
    close $s1
    close $s2
    close $s3
    sendCommand {close $socket10_9_test_server}
} -result 100
test socket-11.8 {client with several servers} -setup {
    sendCommand {
	set s1 [socket -server "accept 4003" 4003]
	set s2 [socket -server "accept 4004" 4004]
	set s3 [socket -server "accept 4005" 4005]
	proc accept {mp s a p} {
	    puts $s $mp
	    close $s
	}

    }
} -constraints {socket doTestsWithRemoteServer} -body {
    set s1 [socket $remoteServerIP 4003]
    set s2 [socket $remoteServerIP 4004]
    set s3 [socket $remoteServerIP 4005]
    list [gets $s1] [gets $s1] [eof $s1] [gets $s2] [gets $s2] [eof $s2] \
	[gets $s3] [gets $s3] [eof $s3]
} -cleanup {
    close $s1
    close $s2
    close $s3
    sendCommand {
	close $s1
	close $s2
	close $s3
    }
} -result {4003 {} 1 4004 {} 1 4005 {} 1}
test socket-11.9 {accept callback error} -constraints {
    socket doTestsWithRemoteServer
} -setup {
    proc myHandler {msg options} {
	variable x $msg
    }
    set handler [interp bgerror {}]
    interp bgerror {} [namespace which myHandler]
    set timer [after 10000 "set x timed_out"]
} -body {
    set s [socket -server accept 2836]
    proc accept {s a p} {expr 10 / 0}

    if {[catch {
	sendCommand {
	    set peername [fconfigure $callerSocket -peername]
	    set s [socket [lindex $peername 0] 2836]
	    close $s
    	 }
    } msg]} then {
	close $s
	error $msg
    }
    vwait x
    return $x
} -cleanup {
    close $s
    after cancel $timer
    interp bgerror {} $handler
} -result {divide by zero}
test socket-11.10 {testing socket specific options} -setup {
    sendCommand {
	set socket10_12_test_server [socket -server accept 2836]
	proc accept {s a p} {close $s}

    }
} -constraints {socket doTestsWithRemoteServer} -body {
    set s [socket $remoteServerIP 2836]
    set p [fconfigure $s -peername]
    set n [fconfigure $s -sockname]
    list [lindex $p 2] [llength $p] [llength $n]
} -cleanup {
    close $s
    sendCommand {close $socket10_12_test_server}
} -result {2836 3 3}
test socket-11.11 {testing spurious events} -setup {
    sendCommand {
	set socket10_13_test_server [socket -server accept 2836]
	proc accept {s a p} {
	    fconfigure $s -translation "auto lf"
	    after 100 writesome $s
	}
	proc writesome {s} {
	    for {set i 0} {$i < 100} {incr i} {
		puts $s "line $i from remote server"
	    }
	    close $s
	}

    }
    set len 0
    set spurious 0
    set done 0
    set timer [after 40000 "set done timed_out"]
} -constraints {socket doTestsWithRemoteServer} -body {
    proc readlittle {s} {
	global spurious done len
	set l [read $s 1]
	if {[string length $l] == 0} {
	    if {![eof $s]} {
		incr spurious
	    } else {
		close $s
		set done 1
	    }
	} else {
	    incr len [string length $l]
	}
    }
    set c [socket $remoteServerIP 2836]
    fileevent $c readable "readlittle $c"
    vwait done
    list $spurious $len $done
} -cleanup {
    after cancel $timer
    sendCommand {close $socket10_13_test_server}
} -result {0 2690 1}
test socket-11.12 {testing EOF stickyness} -constraints {socket doTestsWithRemoteServer} -setup {
    set counter 0
    set done 0
    sendCommand {
	set socket10_14_test_server [socket -server accept 2836]
	proc accept {s a p} {
	    after 100 close $s
	}

    }
    proc timed_out {} {
	global c done
	set done {timed_out, EOF is not sticky}
	close $c
    }
    set after_id [after 1000 timed_out]
} -body {
    proc count_up {s} {
	global counter done
	set l [gets $s]
	if {[eof $s]} {
	    incr counter
	    if {$counter > 9} {
		set done {EOF is sticky}
		close $s
	    }
	}
    }
    set c [socket $remoteServerIP 2836]
    fileevent $c readable [list count_up $c]
    vwait done
    return $done
} -cleanup {
    after cancel $after_id
    sendCommand {close $socket10_14_test_server}
} -result {EOF is sticky}
test socket-11.13 {testing async write, async flush, async close} -setup {
    sendCommand {
	set firstblock ""
	for {set i 0} {$i < 5} {incr i} {
		set firstblock "a$firstblock$firstblock"
	}
	set secondblock ""
	for {set i 0} {$i < 16} {incr i} {
	    set secondblock "b$secondblock$secondblock"
	}
	set l [socket -server accept 2845]
	proc accept {s a p} {
	    fconfigure $s -blocking 0 -translation lf -buffersize 16384 \
		-buffering line
	    fileevent $s readable "readable $s"
	}
	proc readable {s} {
	    set l [gets $s]
	    fileevent $s readable {}
	    after 1000 respond $s
	}
	proc respond {s} {
	    global firstblock
	    puts -nonewline $s $firstblock
	    after 1000 writedata $s
	}
	proc writedata {s} {
	    global secondblock
	    puts -nonewline $s $secondblock
	    close $s
	}

    }
    set timer [after 10000 "set done timed_out"]
} -constraints {socket doTestsWithRemoteServer} -body {
    proc readit {s} {
	global count done
	set l [read $s]
	incr count [string length $l]
	if {[eof $s]} {
	    close $s
	    set done 1
	}
    }
    set s [socket $remoteServerIP 2845]
    fconfigure $s -blocking 0 -trans lf -buffering line
    set count 0
    puts $s hello
    fileevent $s readable "readit $s"
    vwait done
    return $count
} -cleanup {
    after cancel $timer
    sendCommand {close $l}
} -result 65566

set path(script1) [makeFile {} script1]
set path(script2) [makeFile {} script2]

test socket-12.1 {testing inheritance of server sockets} -setup {
    file delete $path(script1)
    file delete $path(script2)
    # Script1 is just a 10 second delay. If the server socket is inherited, it
    # will be held open for 10 seconds
    set f [open $path(script1) w]
    puts $f {

	after 10000 exit
	vwait forever
    }
    close $f
    # Script2 creates the server socket, launches script1, waits a second, and
    # exits. The server socket will now be closed unless script1 inherited it.
    set f [open $path(script2) w]
    puts $f [list set tcltest [interpreter]]
    puts $f [list set delay $path(script1)]

    puts $f {
	set f [socket -server accept -myaddr 127.0.0.1 0]
	puts [lindex [fconfigure $f -sockname] 2]
	proc accept { file addr port } {
	    close $file
	}
	exec $tcltest $delay &

	close $f
	after 1000 exit
	vwait forever
    }
    close $f
} -constraints {socket stdio exec} -body {
    # Launch script2 and wait 5 seconds
    ### exec [interpreter] script2 &
    set p [open "|[list [interpreter] $path(script2)]" r]
    gets $p listen
    after 5000 { set ok_to_proceed 1 }
    vwait ok_to_proceed
    # If we can still connect to the server, the socket got inherited.
    if {[catch {close [socket 127.0.0.1 $listen]}]} {
	return {server socket was not inherited}
    } else {
	return {server socket was inherited}
    }
} -cleanup {
    close $p
} -result {server socket was not inherited}
test socket-12.2 {testing inheritance of client sockets} -setup {
    file delete $path(script1)
    file delete $path(script2)
    # Script1 is just a 20 second delay. If the server socket is inherited, it
    # will be held open for 20 seconds
    set f [open $path(script1) w]
    puts $f {

	after 20000 exit
	vwait forever
    }
    close $f
    # Script2 opens the client socket and writes to it. It then launches
    # script1 and exits. If the child process inherited the client socket, the
    # socket will still be open.
    set f [open $path(script2) w]
    puts $f [list set tcltest [interpreter]]
    puts $f [list set delay $path(script1)]

    puts $f {
        gets stdin port
	set f [socket 127.0.0.1 $port]
        exec $tcltest $delay &
	puts $f testing
	flush $f
	after 1000 exit
	vwait forever
    }
    close $f
    # If the socket doesn't hit end-of-file in 10 seconds, the script1 process
    # must have inherited the client.
    set failed 0
    after 10000 [list set failed 1]
} -constraints {socket stdio exec} -body {
    # Create the server socket
    set server [socket -server accept -myaddr 127.0.0.1 0]
    proc accept { file host port } {
	# When the client connects, establish the read handler
	global server
	close $server
	fileevent $file readable [list getdata $file]
	fconfigure $file -buffering line -blocking 0
    }







|
|








|







|








|




|







|



















|










|



















|












|
<
|







|

|








|
|
|




>
|
|
|



|

|
<
|
<
<
<
|
|




>
|
|
|

|


|

|

|






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












<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
|
|










|

|
|
|
|
|



|
|
|












>
|
|
|

|

|














|

|
|
|
|
|




>
|
|
|
|
|











|
|
<
<







|
|
>



|













|
|
|

>
|
|
|


|


|
|
|
|
|


|







>
|




|














|





|

|


|
|

|

>
|


















|





|

|
|








|








|




|






>
|

|









|














|






>




|
|



>

|
<




>

|
<


|



<
<
<

|





|

|






>










>


|



|
<





|
|

|







958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069

1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105

1106



1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173





1174










1175









1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264


1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463

1464
1465
1466
1467
1468
1469
1470

1471
1472
1473
1474
1475
1476



1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511

1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
	    incr len [string length $l]
	}
    }
    proc accept {s a p} {
	fconfigure $s -buffering none -blocking off
	fileevent $s readable [list readlittle $s]
    }
    set s [socket -server accept -myaddr $localhost 0]
    set c [socket $localhost [lindex [fconfigure $s -sockname] 2]]
    puts -nonewline $c 01234567890123456789012345678901234567890123456789
    close $c
    vwait done
    close $s
    list $spurious $len
} -cleanup {
    after cancel $timer
} -result {0 50}
test socket_$af-9.2 {testing async write, fileevents, flush on close} -constraints [list socket supported_$af] -setup {
    set firstblock ""
    for {set i 0} {$i < 5} {incr i} {set firstblock "a$firstblock$firstblock"}
    set secondblock ""
    for {set i 0} {$i < 16} {incr i} {
	set secondblock "b$secondblock$secondblock"
    }
    set timer [after 10000 "set done timed_out"]
    set l [socket -server accept -myaddr $localhost 0]
    proc accept {s a p} {
	fconfigure $s -blocking 0 -translation lf -buffersize 16384 \
		-buffering line
	fileevent $s readable "readable $s"
    }
    proc readable {s} {
	set l [gets $s]
	fileevent $s readable {}
	after idle respond $s
    }
    proc respond {s} {
	global firstblock
	puts -nonewline $s $firstblock
	after idle writedata $s
    }
    proc writedata {s} {
	global secondblock
	puts -nonewline $s $secondblock
	close $s
    }
} -body {
    set s [socket $localhost [lindex [fconfigure $l -sockname] 2]]
    fconfigure $s -blocking 0 -trans lf -buffering line
    set count 0
    puts $s hello
    proc readit {s} {
	global count done
	set l [read $s]
	incr count [string length $l]
	if {[eof $s]} {
	    close $s
	    set done 1
	}
    }
    fileevent $s readable "readit $s"
    vwait done
    return $count
} -cleanup {
    close $l
    after cancel $timer
} -result 65566
test socket_$af-9.3 {testing EOF stickyness} -constraints [list socket supported_$af] -setup {
    set count 0
    set done false
    proc write_then_close {s} {
	puts $s bye
	close $s
    }
    proc accept {s a p} {
	fconfigure $s -buffering line -translation lf
	fileevent $s writable "write_then_close $s"
    }
    set s [socket -server accept -myaddr $localhost 0]
} -body {
    proc count_to_eof {s} {
	global count done
	set l [gets $s]
	if {[eof $s]} {
	    incr count
	    if {$count > 9} {
		close $s
		set done true
		set count {eof is sticky}
	    }
	}
    }
    proc timerproc {s} {
	global done count
	set done true
	set count {timer went off, eof is not sticky}
	close $s
    }
    set c [socket $localhost [lindex [fconfigure $s -sockname] 2]]
    fconfigure $c -blocking off -buffering line -translation lf
    fileevent $c readable "count_to_eof $c"
    set timer [after 1000 timerproc $c]
    vwait done
    return $count
} -cleanup {
    close $s
    after cancel $timer
} -result {eof is sticky}

removeFile script

test socket_$af-10.1 {testing socket accept callback error handling} \

    -constraints [list socket supported_$af] -setup {
    variable goterror 0
    proc myHandler {msg options} {
	variable goterror 1
    }
    set handler [interp bgerror {}]
    interp bgerror {} [namespace which myHandler]
} -body {
    set s [socket -server accept -myaddr $localhost 0]
    proc accept {s a p} {close $s; error}
    set c [socket $localhost [lindex [fconfigure $s -sockname] 2]]
    vwait goterror
    close $s
    close $c
    return $goterror
} -cleanup {
    interp bgerror {} $handler
} -result 1

test socket_$af-11.1 {tcp connection} -setup {
    set port [sendCommand {
	set server [socket -server accept 0]
	proc accept {s a p} {
	    puts $s done
	    close $s
	}
	getPort $server
    }]
} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
    set s [socket $remoteServerIP $port]
    gets $s
} -cleanup {
    close $s
    sendCommand {close $server}
} -result done
test socket_$af-11.2 {client specifies its port} -setup {

    set lport [randport]



    set rport [sendCommand {
	set server [socket -server accept 0]
	proc accept {s a p} {
	    puts $s $p
	    close $s
	}
	getPort $server
    }]
} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
    set s [socket -myport $lport $remoteServerIP $rport]
    set r [gets $s]
    expr {$r==$lport ? "ok" : "broken: $r != $port"}
} -cleanup {
    close $s
    sendCommand {close $server}
} -result ok
test socket_$af-11.3 {trying to connect, no server} -body {
    set status ok
    if {![catch {set s [socket $remoteServerIp [randport]]}]} {
	if {![catch {gets $s}]} {
	    set status broken
	}
	close $s
    }
    return $status
} -constraints [list socket supported_$af doTestsWithRemoteServer] -result ok
test socket_$af-11.4 {remote echo, one line} -setup {
    set port [sendCommand {
	set server [socket -server accept 0]
	proc accept {s a p} {
	    fileevent $s readable [list echo $s]
	    fconfigure $s -buffering line -translation crlf
	}
	proc echo {s} {
	    set l [gets $s]
	    if {[eof $s]} {
		close $s
	    } else {
		puts $s $l
	    }
	}
	getPort $server
    }]
} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
    set f [socket $remoteServerIP $port]
    fconfigure $f -translation crlf -buffering line
    puts $f hello
    gets $f
} -cleanup {
    catch {close $f}
    sendCommand {close $server}
} -result hello
test socket_$af-11.5 {remote echo, 50 lines} -setup {
    set port [sendCommand {
	set server [socket -server accept 0]
	proc accept {s a p} {
	    fileevent $s readable [list echo $s]
	    fconfigure $s -buffering line -translation crlf
	}
	proc echo {s} {
	    set l [gets $s]
	    if {[eof $s]} {
		close $s
	    } else {
		puts $s $l
	    }
	}





	getPort $server










    }]









} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
    set f [socket $remoteServerIP $port]
    fconfigure $f -translation crlf -buffering line
    for {set cnt 0} {$cnt < 50} {incr cnt} {
	puts $f "hello, $cnt"
	if {[gets $f] != "hello, $cnt"} {
	    break
	}
    }
    return $cnt
} -cleanup {
    close $f
    sendCommand {close $server}
} -result 50
test socket_$af-11.6 {socket conflict} -setup {
    set s1 [socket -server accept -myaddr $localhost 0]
} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
    set s2 [socket -server accept -myaddr $localhost [getPort $s1]]
    list [getPort $s2] [close $s2]
} -cleanup {
    close $s1
} -returnCodes error -result {couldn't open socket: address already in use}
test socket_$af-11.7 {server with several clients} -setup {
    set port [sendCommand {
	set server [socket -server accept 0]
	proc accept {s a p} {
	    fconfigure $s -buffering line
	    fileevent $s readable [list echo $s]
	}
	proc echo {s} {
	    set l [gets $s]
	    if {[eof $s]} {
		close $s
	    } else {
		puts $s $l
	    }
	}
	getPort $server
    }]
} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
    set s1 [socket $remoteServerIP $port]
    fconfigure $s1 -buffering line
    set s2 [socket $remoteServerIP $port]
    fconfigure $s2 -buffering line
    set s3 [socket $remoteServerIP $port]
    fconfigure $s3 -buffering line
    for {set i 0} {$i < 100} {incr i} {
	puts $s1 hello,s1
	gets $s1
	puts $s2 hello,s2
	gets $s2
	puts $s3 hello,s3
	gets $s3
    }
    return $i
} -cleanup {
    close $s1
    close $s2
    close $s3
    sendCommand {close $server}
} -result 100
test socket_$af-11.8 {client with several servers} -setup {
    lassign [sendCommand {
	set s1 [socket -server "accept server1" 0]
	set s2 [socket -server "accept server2" 0]
	set s3 [socket -server "accept server3" 0]
	proc accept {mp s a p} {
	    puts $s $mp
	    close $s
	}
	list [getPort $s1] [getPort $s2] [getPort $s3]
    }] p1 p2 p3
} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
    set s1 [socket $remoteServerIP $p1]
    set s2 [socket $remoteServerIP $p2]
    set s3 [socket $remoteServerIP $p3]
    list [gets $s1] [gets $s1] [eof $s1] [gets $s2] [gets $s2] [eof $s2] \
	[gets $s3] [gets $s3] [eof $s3]
} -cleanup {
    close $s1
    close $s2
    close $s3
    sendCommand {
	close $s1
	close $s2
	close $s3
    }
} -result {server1 {} 1 server2 {} 1 server3 {} 1}
test socket_$af-11.9 {accept callback error} -constraints [list socket supported_$af doTestsWithRemoteServer] -setup {


    proc myHandler {msg options} {
	variable x $msg
    }
    set handler [interp bgerror {}]
    interp bgerror {} [namespace which myHandler]
    set timer [after 10000 "set x timed_out"]
} -body {
    set s [socket -server accept 0]
    proc accept {s a p} {expr {10 / 0}}
    sendCommand "set port [getPort $s]"
    if {[catch {
	sendCommand {
	    set peername [fconfigure $callerSocket -peername]
	    set s [socket [lindex $peername 0] $port]
	    close $s
    	 }
    } msg]} then {
	close $s
	error $msg
    }
    vwait x
    return $x
} -cleanup {
    close $s
    after cancel $timer
    interp bgerror {} $handler
} -result {divide by zero}
test socket_$af-11.10 {testing socket specific options} -setup {
    set port [sendCommand {
	set server [socket -server accept 0]
	proc accept {s a p} {close $s}
	getPort $server
    }]
} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
    set s [socket $remoteServerIP $port]
    set p [fconfigure $s -peername]
    set n [fconfigure $s -sockname]
    list [expr {[lindex $p 2] == $port}] [llength $p] [llength $n]
} -cleanup {
    close $s
    sendCommand {close $server}
} -result {1 3 3}
test socket_$af-11.11 {testing spurious events} -setup {
    set port [sendCommand {
	set server [socket -server accept 0]
	proc accept {s a p} {
	    fconfigure $s -translation "auto lf"
	    after idle writesome $s
	}
	proc writesome {s} {
	    for {set i 0} {$i < 100} {incr i} {
		puts $s "line $i from remote server"
	    }
	    close $s
	}
	getPort $server
    }]
    set len 0
    set spurious 0
    set done 0
    set timer [after 40000 "set done timed_out"]
} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
    proc readlittle {s} {
	global spurious done len
	set l [read $s 1]
	if {[string length $l] == 0} {
	    if {![eof $s]} {
		incr spurious
	    } else {
		close $s
		set done 1
	    }
	} else {
	    incr len [string length $l]
	}
    }
    set c [socket $remoteServerIP $port]
    fileevent $c readable "readlittle $c"
    vwait done
    list $spurious $len $done
} -cleanup {
    after cancel $timer
    sendCommand {close $server}
} -result {0 2690 1}
test socket_$af-11.12 {testing EOF stickyness} -constraints [list socket supported_$af doTestsWithRemoteServer] -setup {
    set counter 0
    set done 0
    set port [sendCommand {
	set server [socket -server accept 0]
	proc accept {s a p} {
	    after idle close $s
	}
	getPort $server
    }]
    proc timed_out {} {
	global c done
	set done {timed_out, EOF is not sticky}
	close $c
    }
    set after_id [after 1000 timed_out]
} -body {
    proc count_up {s} {
	global counter done
	set l [gets $s]
	if {[eof $s]} {
	    incr counter
	    if {$counter > 9} {
		set done {EOF is sticky}
		close $s
	    }
	}
    }
    set c [socket $remoteServerIP $port]
    fileevent $c readable [list count_up $c]
    vwait done
    return $done
} -cleanup {
    after cancel $after_id
    sendCommand {close $server}
} -result {EOF is sticky}
test socket_$af-11.13 {testing async write, async flush, async close} -setup {
    set port [sendCommand {
	set firstblock ""
	for {set i 0} {$i < 5} {incr i} {
		set firstblock "a$firstblock$firstblock"
	}
	set secondblock ""
	for {set i 0} {$i < 16} {incr i} {
	    set secondblock "b$secondblock$secondblock"
	}
	set l [socket -server accept 0]
	proc accept {s a p} {
	    fconfigure $s -blocking 0 -translation lf -buffersize 16384 \
		-buffering line
	    fileevent $s readable "readable $s"
	}
	proc readable {s} {
	    set l [gets $s]
	    fileevent $s readable {}
	    after idle respond $s
	}
	proc respond {s} {
	    global firstblock
	    puts -nonewline $s $firstblock
	    after idle writedata $s
	}
	proc writedata {s} {
	    global secondblock
	    puts -nonewline $s $secondblock
	    close $s
	}
	getPort $l
    }]
    set timer [after 10000 "set done timed_out"]
} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
    proc readit {s} {
	global count done
	set l [read $s]
	incr count [string length $l]
	if {[eof $s]} {
	    close $s
	    set done 1
	}
    }
    set s [socket $remoteServerIP $port]
    fconfigure $s -blocking 0 -trans lf -buffering line
    set count 0
    puts $s hello
    fileevent $s readable "readit $s"
    vwait done
    return $count
} -cleanup {
    after cancel $timer
    sendCommand {close $l}
} -result 65566

set path(script1) [makeFile {} script1]
set path(script2) [makeFile {} script2]

test socket_$af-12.1 {testing inheritance of server sockets} -setup {
    file delete $path(script1)
    file delete $path(script2)
    # Script1 is just a 10 second delay. If the server socket is inherited, it
    # will be held open for 10 seconds
    set f [open $path(script1) w]
    puts $f {
	fileevent stdin readable exit
	after 10000 exit
	vwait forever
    }
    close $f
    # Script2 creates the server socket, launches script1, and exits.
    # The server socket will now be closed unless script1 inherited it.
    set f [open $path(script2) w]
    puts $f [list set tcltest [interpreter]]
    puts $f [list set delay $path(script1)]
    puts $f [list set localhost $localhost]
    puts $f {
	set f [socket -server accept -myaddr $localhost 0]

	proc accept { file addr port } {
	    close $file
	}
	exec $tcltest $delay &
	puts [lindex [fconfigure $f -sockname] 2]
	close $f
        exit

    }
    close $f
} -constraints [list socket supported_$af stdio exec] -body {
    # Launch script2 and wait 5 seconds
    ### exec [interpreter] script2 &
    set p [open "|[list [interpreter] $path(script2)]" r]



    # If we can still connect to the server, the socket got inherited.
    if {[catch {close [socket $localhost $listen]}]} {
	return {server socket was not inherited}
    } else {
	return {server socket was inherited}
    }
} -cleanup {
    catch {close $p}
} -result {server socket was not inherited}
test socket_$af-12.2 {testing inheritance of client sockets} -setup {
    file delete $path(script1)
    file delete $path(script2)
    # Script1 is just a 20 second delay. If the server socket is inherited, it
    # will be held open for 20 seconds
    set f [open $path(script1) w]
    puts $f {
	fileevent stdin readable exit
	after 20000 exit
	vwait forever
    }
    close $f
    # Script2 opens the client socket and writes to it. It then launches
    # script1 and exits. If the child process inherited the client socket, the
    # socket will still be open.
    set f [open $path(script2) w]
    puts $f [list set tcltest [interpreter]]
    puts $f [list set delay $path(script1)]
    puts $f [list set localhost $localhost]
    puts $f {
        gets stdin port
	set f [socket $localhost $port]
        exec $tcltest $delay &
	puts $f testing
	flush $f
        exit

    }
    close $f
    # If the socket doesn't hit end-of-file in 10 seconds, the script1 process
    # must have inherited the client.
    set failed 0
    set after [after 10000 [list set failed 1]]
} -constraints [list socket supported_$af stdio exec] -body {
    # Create the server socket
    set server [socket -server accept -myaddr $localhost 0]
    proc accept { file host port } {
	# When the client connects, establish the read handler
	global server
	close $server
	fileevent $file readable [list getdata $file]
	fconfigure $file -buffering line -blocking 0
    }
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535

1536
1537
1538
1539
1540
1541
1542

1543
1544
1545
1546
1547
1548
1549
1550
1551

1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
    # Launch the script2 process
    ### exec [interpreter] script2 &
    set p [open "|[list [interpreter] $path(script2)]" w]
    puts $p [lindex [fconfigure $server -sockname] 2] ; flush $p
    vwait x
    return $x
} -cleanup {
    if {!$failed} {
	vwait failed
    }
    close $p
} -result {client socket was not inherited}
test socket-12.3 {testing inheritance of accepted sockets} -setup {
    file delete $path(script1)
    file delete $path(script2)
    set f [open $path(script1) w]
    puts $f {

	after 10000 exit
	vwait forever
    }
    close $f
    set f [open $path(script2) w]
    puts $f [list set tcltest [interpreter]]
    puts $f [list set delay $path(script1)]

    puts $f {
	set server [socket -server accept -myaddr 127.0.0.1 0]
	puts stdout [lindex [fconfigure $server -sockname] 2]
	proc accept { file host port } {
	    global tcltest delay
	    puts $file {test data on socket}
	    exec $tcltest $delay &
	    after 1000 exit
	}

	vwait forever
    }
    close $f
} -constraints {socket stdio exec} -body {
    # Launch the script2 process and connect to it. See how long the socket
    # stays open
    ## exec [interpreter] script2 &
    set p [open "|[list [interpreter] $path(script2)]" r]
    gets $p listen
    after 1000 set ok_to_proceed 1
    vwait ok_to_proceed
    set f [socket 127.0.0.1 $listen]
    fconfigure $f -buffering full -blocking 0
    fileevent $f readable [list getdata $f]
    # If the socket is still open after 5 seconds, the script1 process must
    # have inherited the accepted socket.
    set failed 0
    after 5000 set failed 1
    proc getdata { file } {







|
<
<


|




>







>

|
<




|

>



|





<
<
|







1549
1550
1551
1552
1553
1554
1555
1556


1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574

1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590


1591
1592
1593
1594
1595
1596
1597
1598
    # Launch the script2 process
    ### exec [interpreter] script2 &
    set p [open "|[list [interpreter] $path(script2)]" w]
    puts $p [lindex [fconfigure $server -sockname] 2] ; flush $p
    vwait x
    return $x
} -cleanup {
    after cancel $after


    close $p
} -result {client socket was not inherited}
test socket_$af-12.3 {testing inheritance of accepted sockets} -setup {
    file delete $path(script1)
    file delete $path(script2)
    set f [open $path(script1) w]
    puts $f {
	fileevent stdin readable exit
	after 10000 exit
	vwait forever
    }
    close $f
    set f [open $path(script2) w]
    puts $f [list set tcltest [interpreter]]
    puts $f [list set delay $path(script1)]
    puts $f [list set localhost $localhost]
    puts $f {
	set server [socket -server accept -myaddr $localhost 0]

	proc accept { file host port } {
	    global tcltest delay
	    puts $file {test data on socket}
	    exec $tcltest $delay &
            after idle exit
	}
	puts stdout [lindex [fconfigure $server -sockname] 2]
	vwait forever
    }
    close $f
} -constraints [list socket supported_$af stdio exec] -body {
    # Launch the script2 process and connect to it. See how long the socket
    # stays open
    ## exec [interpreter] script2 &
    set p [open "|[list [interpreter] $path(script2)]" r]
    gets $p listen


    set f [socket $localhost $listen]
    fconfigure $f -buffering full -blocking 0
    fileevent $f readable [list getdata $f]
    # If the socket is still open after 5 seconds, the script1 process must
    # have inherited the accepted socket.
    set failed 0
    after 5000 set failed 1
    proc getdata { file } {
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
    }
    vwait x
    return $x
} -cleanup {
    catch {close $p}
} -result {accepted socket was not inherited}

test socket-13.1 {Testing use of shared socket between two threads} -setup {
    threadReap
    set path(script) [makeFile {
        set f [socket -server accept -myaddr 127.0.0.1 0]
        set listen [lindex [fconfigure $f -sockname] 2]
        proc accept {s a p} {
            fileevent $s readable [list echo $s]
            fconfigure $s -buffering line
        }
        proc echo {s} {
             global i







|

|
|







1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
    }
    vwait x
    return $x
} -cleanup {
    catch {close $p}
} -result {accepted socket was not inherited}

test socket_$af-13.1 {Testing use of shared socket between two threads} -setup {
    threadReap
    set path(script) [makeFile [string map [list @localhost@ $localhost] {
        set f [socket -server accept -myaddr @localhost@ 0]
        set listen [lindex [fconfigure $f -sockname] 2]
        proc accept {s a p} {
            fileevent $s readable [list echo $s]
            fconfigure $s -buffering line
        }
        proc echo {s} {
             global i
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658

1659
1660
1661
1662
1663
1664
1665
1666
             }
        }
        set i 0
        vwait x
        close $f
        # thread cleans itself up.
        testthread exit
    } script]
} -constraints {socket testthread} -body {
    # create a thread
    set serverthread [testthread create [list source $path(script) ] ]
    update
    set port [testthread send $serverthread {set listen}]
    update
    after 1000
    set s [socket 127.0.0.1 $port]
    fconfigure $s -buffering line
    catch {
        puts $s "hello"
        gets $s result
    }
    close $s
    update
    after 2000
    append result " " [threadReap]
} -cleanup {
    removeFile script
} -result {hello 1}

# ----------------------------------------------------------------------

removeFile script1
removeFile script2

# cleanup
if {[string match sock* $commandSocket] == 1} {
   puts $commandSocket exit
   flush $commandSocket
}
catch {close $commandSocket}
catch {close $remoteProcChan}

::tcltest::cleanupTests
flush stdout
return

# Local Variables:
# mode: tcl
# fill-column: 78
# End:







|
|





<
|







<











|
<
|



>








1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659

1660
1661
1662
1663
1664
1665
1666
1667

1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679

1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
             }
        }
        set i 0
        vwait x
        close $f
        # thread cleans itself up.
        testthread exit
    }] script]
} -constraints [list socket supported_$af testthread] -body {
    # create a thread
    set serverthread [testthread create [list source $path(script) ] ]
    update
    set port [testthread send $serverthread {set listen}]
    update

    set s [socket $localhost $port]
    fconfigure $s -buffering line
    catch {
        puts $s "hello"
        gets $s result
    }
    close $s
    update

    append result " " [threadReap]
} -cleanup {
    removeFile script
} -result {hello 1}

# ----------------------------------------------------------------------

removeFile script1
removeFile script2

# cleanup
if {$remoteProcChan ne ""} {

    catch {sendCommand exit}
}
catch {close $commandSocket}
catch {close $remoteProcChan}
}
::tcltest::cleanupTests
flush stdout
return

# Local Variables:
# mode: tcl
# fill-column: 78
# End:
Changes to tests/subst.test.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#
# RCS: @(#) $Id: subst.test,v 1.19 2008/04/23 15:44:38 dkf Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2.1
    namespace import -force ::tcltest::*
}

test subst-1.1 {basics} -returnCodes error -body {
    subst
} -result {wrong # args: should be "subst ?-nobackslashes? ?-nocommands? ?-novariables? string"}
test subst-1.2 {basics} -returnCodes error -body {
    subst a b c
} -result {bad switch "a": must be -nobackslashes, -nocommands, or -novariables}








|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#
# RCS: @(#) $Id: subst.test,v 1.19 2008/04/23 15:44:38 dkf Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2.1
    namespace import -force ::tcltest::*
}

test subst-1.1 {basics} -returnCodes error -body {
    subst
} -result {wrong # args: should be "subst ?-nobackslashes? ?-nocommands? ?-novariables? string"}
test subst-1.2 {basics} -returnCodes error -body {
    subst a b c
} -result {bad switch "a": must be -nobackslashes, -nocommands, or -novariables}

257
258
259
260
261
262
263










264
























265
266
267




    set x 0
    for {set i 0} {$i < 10} {incr i} {
	set res [list [catch {subst "\[incr x"} msg] $msg]
	if {$msg ne "missing close-bracket"} break
    }
    lappend res $x
} {1 {missing close-bracket} 0}



































# cleanup
::tcltest::cleanupTests
return











>
>
>
>
>
>
>
>
>
>

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



>
>
>
>
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
    set x 0
    for {set i 0} {$i < 10} {incr i} {
	set res [list [catch {subst "\[incr x"} msg] $msg]
	if {$msg ne "missing close-bracket"} break
    }
    lappend res $x
} {1 {missing close-bracket} 0}
test subst-12.6 {nasty case with compilation} {
    set x unset
    set y unset
    list [eval [list subst {[set x 1;break;incr x][set y $x]}]] $x $y
} {{} 1 unset}
test subst-12.7 {nasty case with compilation} {
    set x unset
    set y unset
    list [eval [list subst {[set x 1;continue;incr x][set y $x]}]] $x $y
} {1 1 1}

test subst-13.1 {Bug 3081065} -setup {
    set script [makeFile {
	proc demo {string} {
	    subst $string
	}
	demo name2
    } subst13.tcl]
} -body {
    interp create slave
    slave eval [list source $script]
    interp delete slave
    interp create slave
    slave eval {
	set count 400
	while {[incr count -1]} {
	    lappend bloat [expr {rand()}]
	}
    }
    slave eval [list source $script]
    interp delete slave
} -cleanup {
    removeFile subst13.tcl
}

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/unknown.test.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

catch {unset x}
catch {rename unknown unknown.old}

test unknown-1.1 {non-existent "unknown" command} {
    list [catch {_non-existent_ foo bar} msg] $msg
} {1 {invalid command name "_non-existent_"}}

proc unknown {args} {
    global x
    set x $args
}

test unknown-2.1 {calling "unknown" command} {
    foobar x y z
    set x
} {foobar x y z}
test unknown-2.2 {calling "unknown" command with lots of args} {
    foobar 1 2 3 4 5 6 7
    set x







|








<







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

catch {unset x}
catch {rename unknown unknown.old}

test unknown-1.1 {non-existent "unknown" command} {
    list [catch {_non-existent_ foo bar} msg] $msg
} {1 {invalid command name "_non-existent_"}}

proc unknown {args} {
    global x
    set x $args
}

test unknown-2.1 {calling "unknown" command} {
    foobar x y z
    set x
} {foobar x y z}
test unknown-2.2 {calling "unknown" command with lots of args} {
    foobar 1 2 3 4 5 6 7
    set x
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67




    foobar \{ \} a\{b \; "\\" \$a a\[b \]
    set x
} "foobar \\{ \\} a\\{b {;} \\\\ {\$a} {a\[b} \\]"

proc unknown args {
    error "unknown failed"
}

test unknown-4.1 {errors in "unknown" procedure} {
    list [catch {non-existent a b} msg] $msg $errorCode
} {1 {unknown failed} NONE}

# cleanup
catch {rename unknown {}}
catch {rename unknown.old unknown}
::tcltest::cleanupTests
return 











<



|





>
>
>
>
50
51
52
53
54
55
56

57
58
59
60
61
62
63
64
65
66
67
68
69
    foobar \{ \} a\{b \; "\\" \$a a\[b \]
    set x
} "foobar \\{ \\} a\\{b {;} \\\\ {\$a} {a\[b} \\]"

proc unknown args {
    error "unknown failed"
}

test unknown-4.1 {errors in "unknown" procedure} {
    list [catch {non-existent a b} msg] $msg $errorCode
} {1 {unknown failed} NONE}

# cleanup
catch {rename unknown {}}
catch {rename unknown.old unknown}
::tcltest::cleanupTests
return 

# Local Variables:
# mode: tcl
# End:
Changes to tests/var.test.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
catch {namespace delete test_ns_var}
catch {unset xx}
catch {unset x}
catch {unset y}
catch {unset i}
catch {unset a}
catch {unset arr}

test var-1.1 {TclLookupVar, Array handling} {
    catch {unset a}
    set x "incr"  ;# force no compilation and runtime call to Tcl_IncrCmd 
    set i 10
    set arr(foo) 37
    list [$x i] $i [$x arr(foo)] $arr(foo)
} {11 11 38 38}







|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
catch {namespace delete test_ns_var}
catch {unset xx}
catch {unset x}
catch {unset y}
catch {unset i}
catch {unset a}
catch {unset arr}

test var-1.1 {TclLookupVar, Array handling} {
    catch {unset a}
    set x "incr"  ;# force no compilation and runtime call to Tcl_IncrCmd 
    set i 10
    set arr(foo) 37
    list [$x i] $i [$x arr(foo)] $arr(foo)
} {11 11 38 38}
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745



























746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763




    #
    namespace eval test A useSomeUnlikelyNameHere
    namespace eval test unset useSomeUnlikelyNameHere
} {}


test var-16.1 {CallVarTraces: save/restore interp error state} {
    trace add variable ::errorCode write { ;#}
    catch {error foo bar baz}
    trace remove variable ::errorCode write { ;#}
    set ::errorInfo
} bar

test var-17.1 {TclArraySet [Bug 1669489]} -setup {
    unset -nocomplain ::a
} -body {
    namespace eval :: {
	set elements {1 2 3 4}
	trace add variable a write {string length $elements ;#}
	array set a $elements
    }
} -cleanup {
    unset -nocomplain ::a ::elements
} -result {}




























catch {namespace delete ns}
catch {unset arr}
catch {unset v}

catch {rename p ""}
catch {namespace delete test_ns_var}
catch {namespace delete test_ns_var2}
catch {unset xx}
catch {unset x}
catch {unset y}
catch {unset i}
catch {unset a}
catch {unset xxxxx}
catch {unset aaaaa}

# cleanup
::tcltest::cleanupTests
return











|

|








|






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


















>
>
>
>
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
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
791
792
793
794
    #
    namespace eval test A useSomeUnlikelyNameHere
    namespace eval test unset useSomeUnlikelyNameHere
} {}


test var-16.1 {CallVarTraces: save/restore interp error state} {
    trace add variable ::errorCode write " ;#"
    catch {error foo bar baz}
    trace remove variable ::errorCode write " ;#"
    set ::errorInfo
} bar

test var-17.1 {TclArraySet [Bug 1669489]} -setup {
    unset -nocomplain ::a
} -body {
    namespace eval :: {
	set elements {1 2 3 4}
	trace add variable a write "string length \$elements ;#"
	array set a $elements
    }
} -cleanup {
    unset -nocomplain ::a ::elements
} -result {}

test var-18.1 {array unset and unset traces: Bug 2939073} -setup {
    set already 0
    unset x
} -body {
    array set x {e 1 i 1}
    trace add variable x unset {apply {args {
	global already x
	if {!$already} {
	    set already 1
	    unset x(i)
	}
    }}}
    # The next command would crash reliably with memory debugging prior to the
    # bug fix.
    array unset x *
    array size x
} -cleanup {
    unset x already
} -result 0


test var-19.1 {crash when freeing locals hashtable: Bug 3037525} {
    proc foo {} { catch {upvar 0 dummy \$index} }
    foo ; # This crashes without the fix for the bug
    rename foo {}
} {}

catch {namespace delete ns}
catch {unset arr}
catch {unset v}

catch {rename p ""}
catch {namespace delete test_ns_var}
catch {namespace delete test_ns_var2}
catch {unset xx}
catch {unset x}
catch {unset y}
catch {unset i}
catch {unset a}
catch {unset xxxxx}
catch {unset aaaaa}

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to unix/tclUnixChan.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * tclUnixChan.c
 *
 *	Common channel driver for Unix channels based on files, command pipes
 *	and TCP sockets.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixChan.c,v 1.93 2008/03/03 14:54:43 rmax Exp $
 */

#include "tclInt.h"	/* Internal definitions for Tcl. */
#include "tclIO.h"	/* To get Channel type declaration. */










|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * tclUnixChan.c
 *
 *	Common channel driver for Unix channels based on files, command pipes
 *	and TCP sockets.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixChan.c,v 1.93 2008/03/03 14:54:43 rmax Exp $
 */

#include "tclInt.h"	/* Internal definitions for Tcl. */
#include "tclIO.h"	/* To get Channel type declaration. */

183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
			    const char *value);
#endif	/* SUPPORTS_TTY */

/*
 * This structure describes the channel type structure for file based IO:
 */

static Tcl_ChannelType fileChannelType = {
    "file",			/* Type name. */
    TCL_CHANNEL_VERSION_5,	/* v5 channel */
    FileCloseProc,		/* Close proc. */
    FileInputProc,		/* Input proc. */
    FileOutputProc,		/* Output proc. */
    FileSeekProc,		/* Seek proc. */
    NULL,			/* Set option proc. */
    NULL,			/* Get option proc. */
    FileWatchProc,		/* Initialize notifier. */
    FileGetHandleProc,		/* Get OS handles out of channel. */
    NULL,			/* close2proc. */
    FileBlockModeProc,		/* Set blocking or non-blocking mode.*/
    NULL,			/* flush proc. */
    NULL,			/* handler proc. */
    FileWideSeekProc,		/* wide seek proc. */
    NULL,
    FileTruncateProc,		/* truncate proc. */
};

#ifdef SUPPORTS_TTY
/*
 * This structure describes the channel type structure for serial IO.
 * Note that this type is a subclass of the "file" type.
 */

static Tcl_ChannelType ttyChannelType = {
    "tty",			/* Type name. */
    TCL_CHANNEL_VERSION_5,	/* v5 channel */
    FileCloseProc,		/* Close proc. */
    FileInputProc,		/* Input proc. */
    FileOutputProc,		/* Output proc. */
    NULL,			/* Seek proc. */
    TtySetOptionProc,		/* Set option proc. */
    TtyGetOptionProc,		/* Get option proc. */
    FileWatchProc,		/* Initialize notifier. */
    FileGetHandleProc,		/* Get OS handles out of channel. */
    NULL,			/* close2proc. */
    FileBlockModeProc,		/* Set blocking or non-blocking mode.*/
    NULL,			/* flush proc. */
    NULL,			/* handler proc. */
    NULL,			/* wide seek proc. */
    NULL,			/* thread action proc. */
    NULL,			/* truncate proc. */
};
#endif	/* SUPPORTS_TTY */


/*
 *----------------------------------------------------------------------
 *
 * FileBlockModeProc --
 *
 *	Helper function to set blocking and nonblocking modes on a file based







|
















|








|
















|


<







183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235

236
237
238
239
240
241
242
			    const char *value);
#endif	/* SUPPORTS_TTY */

/*
 * This structure describes the channel type structure for file based IO:
 */

static const Tcl_ChannelType fileChannelType = {
    "file",			/* Type name. */
    TCL_CHANNEL_VERSION_5,	/* v5 channel */
    FileCloseProc,		/* Close proc. */
    FileInputProc,		/* Input proc. */
    FileOutputProc,		/* Output proc. */
    FileSeekProc,		/* Seek proc. */
    NULL,			/* Set option proc. */
    NULL,			/* Get option proc. */
    FileWatchProc,		/* Initialize notifier. */
    FileGetHandleProc,		/* Get OS handles out of channel. */
    NULL,			/* close2proc. */
    FileBlockModeProc,		/* Set blocking or non-blocking mode.*/
    NULL,			/* flush proc. */
    NULL,			/* handler proc. */
    FileWideSeekProc,		/* wide seek proc. */
    NULL,
    FileTruncateProc		/* truncate proc. */
};

#ifdef SUPPORTS_TTY
/*
 * This structure describes the channel type structure for serial IO.
 * Note that this type is a subclass of the "file" type.
 */

static const Tcl_ChannelType ttyChannelType = {
    "tty",			/* Type name. */
    TCL_CHANNEL_VERSION_5,	/* v5 channel */
    FileCloseProc,		/* Close proc. */
    FileInputProc,		/* Input proc. */
    FileOutputProc,		/* Output proc. */
    NULL,			/* Seek proc. */
    TtySetOptionProc,		/* Set option proc. */
    TtyGetOptionProc,		/* Get option proc. */
    FileWatchProc,		/* Initialize notifier. */
    FileGetHandleProc,		/* Get OS handles out of channel. */
    NULL,			/* close2proc. */
    FileBlockModeProc,		/* Set blocking or non-blocking mode.*/
    NULL,			/* flush proc. */
    NULL,			/* handler proc. */
    NULL,			/* wide seek proc. */
    NULL,			/* thread action proc. */
    NULL			/* truncate proc. */
};
#endif	/* SUPPORTS_TTY */


/*
 *----------------------------------------------------------------------
 *
 * FileBlockModeProc --
 *
 *	Helper function to set blocking and nonblocking modes on a file based
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
 *----------------------------------------------------------------------
 */

	/* ARGSUSED */
static int
FileBlockModeProc(
    ClientData instanceData,	/* File state. */
    int mode)			/* The mode to set. Can be one of
				 * TCL_MODE_BLOCKING or
				 * TCL_MODE_NONBLOCKING. */
{
    FileState *fsPtr = (FileState *) instanceData;

    if (TclUnixSetBlockingMode(fsPtr->fd, mode) < 0) {
	return errno;
    }

    return 0;
}







|
<
|

|







251
252
253
254
255
256
257
258

259
260
261
262
263
264
265
266
267
268
 *----------------------------------------------------------------------
 */

	/* ARGSUSED */
static int
FileBlockModeProc(
    ClientData instanceData,	/* File state. */
    int mode)			/* The mode to set. Can be TCL_MODE_BLOCKING

				 * or TCL_MODE_NONBLOCKING. */
{
    FileState *fsPtr = instanceData;

    if (TclUnixSetBlockingMode(fsPtr->fd, mode) < 0) {
	return errno;
    }

    return 0;
}
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
FileInputProc(
    ClientData instanceData,	/* File state. */
    char *buf,			/* Where to store data read. */
    int toRead,			/* How much space is available in the
				 * buffer? */
    int *errorCodePtr)		/* Where to store error code. */
{
    FileState *fsPtr = (FileState *) instanceData;
    int bytesRead;		/* How many bytes were actually read from the
				 * input device? */

    *errorCodePtr = 0;

    /*
     * Assume there is always enough input available. This will block







|







289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
FileInputProc(
    ClientData instanceData,	/* File state. */
    char *buf,			/* Where to store data read. */
    int toRead,			/* How much space is available in the
				 * buffer? */
    int *errorCodePtr)		/* Where to store error code. */
{
    FileState *fsPtr = instanceData;
    int bytesRead;		/* How many bytes were actually read from the
				 * input device? */

    *errorCodePtr = 0;

    /*
     * Assume there is always enough input available. This will block
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
static int
FileOutputProc(
    ClientData instanceData,	/* File state. */
    const char *buf,		/* The data buffer. */
    int toWrite,		/* How many bytes to write? */
    int *errorCodePtr)		/* Where to store error code. */
{
    FileState *fsPtr = (FileState *) instanceData;
    int written;

    *errorCodePtr = 0;

    if (toWrite == 0) {
	/*
	 * SF Tcl Bug 465765. Do not try to write nothing into a file. STREAM







|







335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
static int
FileOutputProc(
    ClientData instanceData,	/* File state. */
    const char *buf,		/* The data buffer. */
    int toWrite,		/* How many bytes to write? */
    int *errorCodePtr)		/* Where to store error code. */
{
    FileState *fsPtr = instanceData;
    int written;

    *errorCodePtr = 0;

    if (toWrite == 0) {
	/*
	 * SF Tcl Bug 465765. Do not try to write nothing into a file. STREAM
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
 */

static int
FileCloseProc(
    ClientData instanceData,	/* File state. */
    Tcl_Interp *interp)		/* For error reporting - unused. */
{
    FileState *fsPtr = (FileState *) instanceData;
    int errorCode = 0;

    Tcl_DeleteFileHandler(fsPtr->fd);

    /*
     * Do not close standard channels while in thread-exit.
     */







|







379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
 */

static int
FileCloseProc(
    ClientData instanceData,	/* File state. */
    Tcl_Interp *interp)		/* For error reporting - unused. */
{
    FileState *fsPtr = instanceData;
    int errorCode = 0;

    Tcl_DeleteFileHandler(fsPtr->fd);

    /*
     * Do not close standard channels while in thread-exit.
     */
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
FileSeekProc(
    ClientData instanceData,	/* File state. */
    long offset,		/* Offset to seek to. */
    int mode,			/* Relative to where should we seek? Can be
				 * one of SEEK_START, SEEK_SET or SEEK_END. */
    int *errorCodePtr)		/* To store error code. */
{
    FileState *fsPtr = (FileState *) instanceData;
    Tcl_WideInt oldLoc, newLoc;

    /*
     * Save our current place in case we need to roll-back the seek.
     */

    oldLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) 0, SEEK_CUR);







|







425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
FileSeekProc(
    ClientData instanceData,	/* File state. */
    long offset,		/* Offset to seek to. */
    int mode,			/* Relative to where should we seek? Can be
				 * one of SEEK_START, SEEK_SET or SEEK_END. */
    int *errorCodePtr)		/* To store error code. */
{
    FileState *fsPtr = instanceData;
    Tcl_WideInt oldLoc, newLoc;

    /*
     * Save our current place in case we need to roll-back the seek.
     */

    oldLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) 0, SEEK_CUR);
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
FileWideSeekProc(
    ClientData instanceData,	/* File state. */
    Tcl_WideInt offset,		/* Offset to seek to. */
    int mode,			/* Relative to where should we seek? Can be
				 * one of SEEK_START, SEEK_CUR or SEEK_END. */
    int *errorCodePtr)		/* To store error code. */
{
    FileState *fsPtr = (FileState *) instanceData;
    Tcl_WideInt newLoc;

    newLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) offset, mode);

    *errorCodePtr = (newLoc == -1) ? errno : 0;
    return newLoc;
}







|







486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
FileWideSeekProc(
    ClientData instanceData,	/* File state. */
    Tcl_WideInt offset,		/* Offset to seek to. */
    int mode,			/* Relative to where should we seek? Can be
				 * one of SEEK_START, SEEK_CUR or SEEK_END. */
    int *errorCodePtr)		/* To store error code. */
{
    FileState *fsPtr = instanceData;
    Tcl_WideInt newLoc;

    newLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) offset, mode);

    *errorCodePtr = (newLoc == -1) ? errno : 0;
    return newLoc;
}
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
static void
FileWatchProc(
    ClientData instanceData,	/* The file state. */
    int mask)			/* Events of interest; an OR-ed combination of
				 * TCL_READABLE, TCL_WRITABLE and
				 * TCL_EXCEPTION. */
{
    FileState *fsPtr = (FileState *) instanceData;

    /*
     * Make sure we only register for events that are valid on this file. Note
     * that we are passing Tcl_NotifyChannel directly to Tcl_CreateFileHandler
     * with the channel pointer as the client data.
     */

    mask &= fsPtr->validMask;
    if (mask) {
	Tcl_CreateFileHandler(fsPtr->fd, mask,
		(Tcl_FileProc *) Tcl_NotifyChannel,
		(ClientData) fsPtr->channel);
    } else {
	Tcl_DeleteFileHandler(fsPtr->fd);
    }
}

/*
 *----------------------------------------------------------------------







|










|
<







519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537

538
539
540
541
542
543
544
static void
FileWatchProc(
    ClientData instanceData,	/* The file state. */
    int mask)			/* Events of interest; an OR-ed combination of
				 * TCL_READABLE, TCL_WRITABLE and
				 * TCL_EXCEPTION. */
{
    FileState *fsPtr = instanceData;

    /*
     * Make sure we only register for events that are valid on this file. Note
     * that we are passing Tcl_NotifyChannel directly to Tcl_CreateFileHandler
     * with the channel pointer as the client data.
     */

    mask &= fsPtr->validMask;
    if (mask) {
	Tcl_CreateFileHandler(fsPtr->fd, mask,
		(Tcl_FileProc *) Tcl_NotifyChannel, fsPtr->channel);

    } else {
	Tcl_DeleteFileHandler(fsPtr->fd);
    }
}

/*
 *----------------------------------------------------------------------
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580

static int
FileGetHandleProc(
    ClientData instanceData,	/* The file state. */
    int direction,		/* TCL_READABLE or TCL_WRITABLE */
    ClientData *handlePtr)	/* Where to store the handle. */
{
    FileState *fsPtr = (FileState *) instanceData;

    if (direction & fsPtr->validMask) {
	*handlePtr = (ClientData) INT2PTR(fsPtr->fd);
	return TCL_OK;
    }
    return TCL_ERROR;
}

#ifdef SUPPORTS_TTY
#ifdef USE_TERMIOS







|


|







560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577

static int
FileGetHandleProc(
    ClientData instanceData,	/* The file state. */
    int direction,		/* TCL_READABLE or TCL_WRITABLE */
    ClientData *handlePtr)	/* Where to store the handle. */
{
    FileState *fsPtr = instanceData;

    if (direction & fsPtr->validMask) {
	*handlePtr = INT2PTR(fsPtr->fd);
	return TCL_OK;
    }
    return TCL_ERROR;
}

#ifdef SUPPORTS_TTY
#ifdef USE_TERMIOS
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654

655
656
657
658
659
660
661
static int
TtySetOptionProc(
    ClientData instanceData,	/* File state. */
    Tcl_Interp *interp,		/* For error reporting - can be NULL. */
    const char *optionName,	/* Which option to set? */
    const char *value)		/* New value for option. */
{
    FileState *fsPtr = (FileState *) instanceData;
    unsigned int len, vlen;
    TtyAttrs tty;
#ifdef USE_TERMIOS
    int flag, control, argc;
    const char **argv;
    IOSTATE iostate;
#endif /* USE_TERMIOS */

    len = strlen(optionName);
    vlen = strlen(value);

    /*
     * Option -mode baud,parity,databits,stopbits
     */

    if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) {
	if (TtyParseMode(interp, value, &tty.baud, &tty.parity, &tty.data,
		&tty.stop) != TCL_OK) {
	    return TCL_ERROR;
	}

	/*







|














>







630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
static int
TtySetOptionProc(
    ClientData instanceData,	/* File state. */
    Tcl_Interp *interp,		/* For error reporting - can be NULL. */
    const char *optionName,	/* Which option to set? */
    const char *value)		/* New value for option. */
{
    FileState *fsPtr = instanceData;
    unsigned int len, vlen;
    TtyAttrs tty;
#ifdef USE_TERMIOS
    int flag, control, argc;
    const char **argv;
    IOSTATE iostate;
#endif /* USE_TERMIOS */

    len = strlen(optionName);
    vlen = strlen(value);

    /*
     * Option -mode baud,parity,databits,stopbits
     */

    if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) {
	if (TtyParseMode(interp, value, &tty.baud, &tty.parity, &tty.data,
		&tty.stop) != TCL_OK) {
	    return TCL_ERROR;
	}

	/*
679
680
681
682
683
684
685

686

687
688
689
690
691
692
693

	GETIOSTATE(fsPtr->fd, &iostate);
	CLEAR_BITS(iostate.c_iflag, IXON | IXOFF | IXANY);
#ifdef CRTSCTS
	CLEAR_BITS(iostate.c_cflag, CRTSCTS);
#endif /* CRTSCTS */
	if (strncasecmp(value, "NONE", vlen) == 0) {

	    /* leave all handshake options disabled */

	} else if (strncasecmp(value, "XONXOFF", vlen) == 0) {
	    SET_BITS(iostate.c_iflag, IXON | IXOFF | IXANY);
	} else if (strncasecmp(value, "RTSCTS", vlen) == 0) {
#ifdef CRTSCTS
	    SET_BITS(iostate.c_cflag, CRTSCTS);
#else /* !CRTSTS */
	    UNSUPPORTED_OPTION("-handshake RTSCTS");







>
|
>







677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693

	GETIOSTATE(fsPtr->fd, &iostate);
	CLEAR_BITS(iostate.c_iflag, IXON | IXOFF | IXANY);
#ifdef CRTSCTS
	CLEAR_BITS(iostate.c_cflag, CRTSCTS);
#endif /* CRTSCTS */
	if (strncasecmp(value, "NONE", vlen) == 0) {
	    /*
	     * Leave all handshake options disabled.
	     */
	} else if (strncasecmp(value, "XONXOFF", vlen) == 0) {
	    SET_BITS(iostate.c_iflag, IXON | IXOFF | IXANY);
	} else if (strncasecmp(value, "RTSCTS", vlen) == 0) {
#ifdef CRTSCTS
	    SET_BITS(iostate.c_cflag, CRTSCTS);
#else /* !CRTSTS */
	    UNSUPPORTED_OPTION("-handshake RTSCTS");
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738

739








740


741
742
743
744
745
746
747
    }

    /*
     * Option -xchar {\x11 \x13}
     */

    if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) {
	GETIOSTATE(fsPtr->fd, &iostate);
	if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
	    return TCL_ERROR;
	}
	if (argc == 2) {
	    Tcl_DString ds;
	    Tcl_DStringInit(&ds);

	    Tcl_UtfToExternalDString(NULL, argv[0], -1, &ds);
	    iostate.c_cc[VSTART] = *(const cc_t *) Tcl_DStringValue(&ds);
	    Tcl_DStringSetLength(&ds, 0);

	    Tcl_UtfToExternalDString(NULL, argv[1], -1, &ds);
	    iostate.c_cc[VSTOP] = *(const cc_t *) Tcl_DStringValue(&ds);
	    Tcl_DStringFree(&ds);
	} else {
	    if (interp) {
		Tcl_AppendResult(interp, "bad value for -xchar: "
			"should be a list of two elements", NULL);
	    }
	    ckfree((char *) argv);
	    return TCL_ERROR;
	}

	SETIOSTATE(fsPtr->fd, &iostate);








	ckfree((char *) argv);


	return TCL_OK;
    }

    /*
     * Option -timeout msec
     */








<
<
<
<
<
|
<

<
<
<
|
<
<
|
|







>
|
>
>
>
>
>
>
>
>

>
>







709
710
711
712
713
714
715





716

717



718


719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
    }

    /*
     * Option -xchar {\x11 \x13}
     */

    if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) {





	Tcl_DString ds;





	if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {


	    return TCL_ERROR;
	} else if (argc != 2) {
	    if (interp) {
		Tcl_AppendResult(interp, "bad value for -xchar: "
			"should be a list of two elements", NULL);
	    }
	    ckfree((char *) argv);
	    return TCL_ERROR;
	}

	GETIOSTATE(fsPtr->fd, &iostate);

	Tcl_UtfToExternalDString(NULL, argv[0], -1, &ds);
	iostate.c_cc[VSTART] = *(const cc_t *) Tcl_DStringValue(&ds);
	Tcl_DStringSetLength(&ds, 0);

	Tcl_UtfToExternalDString(NULL, argv[1], -1, &ds);
	iostate.c_cc[VSTOP] = *(const cc_t *) Tcl_DStringValue(&ds);
	Tcl_DStringFree(&ds);
	ckfree((char *) argv);

	SETIOSTATE(fsPtr->fd, &iostate);
	return TCL_OK;
    }

    /*
     * Option -timeout msec
     */

864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
static int
TtyGetOptionProc(
    ClientData instanceData,	/* File state. */
    Tcl_Interp *interp,		/* For error reporting - can be NULL. */
    const char *optionName,	/* Option to get. */
    Tcl_DString *dsPtr)		/* Where to store value(s). */
{
    FileState *fsPtr = (FileState *) instanceData;
    unsigned int len;
    char buf[3*TCL_INTEGER_SPACE + 16];
    int valid = 0;		/* Flag if valid option parsed. */

    if (optionName == NULL) {
	len = 0;
    } else {







|







864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
static int
TtyGetOptionProc(
    ClientData instanceData,	/* File state. */
    Tcl_Interp *interp,		/* For error reporting - can be NULL. */
    const char *optionName,	/* Option to get. */
    Tcl_DString *dsPtr)		/* Where to store value(s). */
{
    FileState *fsPtr = instanceData;
    unsigned int len;
    char buf[3*TCL_INTEGER_SPACE + 16];
    int valid = 0;		/* Flag if valid option parsed. */

    if (optionName == NULL) {
	len = 0;
    } else {
898
899
900
901
902
903
904
905
906

907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
    if (len == 0) {
	Tcl_DStringAppendElement(dsPtr, "-xchar");
	Tcl_DStringStartSublist(dsPtr);
    }
    if (len==0 || (len>1 && strncmp(optionName, "-xchar", len)==0)) {
	IOSTATE iostate;
	Tcl_DString ds;
	valid = 1;


	GETIOSTATE(fsPtr->fd, &iostate);
	Tcl_DStringInit(&ds);

	Tcl_ExternalToUtfDString(NULL,  (const char *) &iostate.c_cc[VSTART], 1, &ds);
	Tcl_DStringAppendElement(dsPtr, (const char *) Tcl_DStringValue(&ds));
	Tcl_DStringSetLength(&ds, 0);

	Tcl_ExternalToUtfDString(NULL,  (const char *) &iostate.c_cc[VSTOP], 1, &ds);
	Tcl_DStringAppendElement(dsPtr, (const char *) Tcl_DStringValue(&ds));
	Tcl_DStringFree(&ds);
    }
    if (len == 0) {
	Tcl_DStringEndSublist(dsPtr);
    }

    /*







<

>



|
|


|
|







898
899
900
901
902
903
904

905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
    if (len == 0) {
	Tcl_DStringAppendElement(dsPtr, "-xchar");
	Tcl_DStringStartSublist(dsPtr);
    }
    if (len==0 || (len>1 && strncmp(optionName, "-xchar", len)==0)) {
	IOSTATE iostate;
	Tcl_DString ds;


	valid = 1;
	GETIOSTATE(fsPtr->fd, &iostate);
	Tcl_DStringInit(&ds);

	Tcl_ExternalToUtfDString(NULL, (char *) &iostate.c_cc[VSTART], 1, &ds);
	Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds));
	Tcl_DStringSetLength(&ds, 0);

	Tcl_ExternalToUtfDString(NULL, (char *) &iostate.c_cc[VSTOP], 1, &ds);
	Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds));
	Tcl_DStringFree(&ds);
    }
    if (len == 0) {
	Tcl_DStringEndSublist(dsPtr);
    }

    /*
945
946
947
948
949
950
951

952
953
954
955
956
957
958
    }

    /*
     * Get option -ttystatus
     * Option is readonly and returned by [fconfigure chan -ttystatus] but not
     * returned by unnamed [fconfigure chan].
     */

    if ((len > 4) && (strncmp(optionName, "-ttystatus", len) == 0)) {
	int status;

	valid = 1;
	GETCONTROL(fsPtr->fd, &status);
	TtyModemStatusStr(status, dsPtr);
    }







>







945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
    }

    /*
     * Get option -ttystatus
     * Option is readonly and returned by [fconfigure chan -ttystatus] but not
     * returned by unnamed [fconfigure chan].
     */

    if ((len > 4) && (strncmp(optionName, "-ttystatus", len) == 0)) {
	int status;

	valid = 1;
	GETCONTROL(fsPtr->fd, &status);
	TtyModemStatusStr(status, dsPtr);
    }
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
    case PARENB | PARODD | PAREXT : parity = 'm'; break;
    }
#else /* !PAREXT */
    switch ((int) (iostate.c_cflag & (PARENB | PARODD))) {
    case PARENB		 : parity = 'e'; break;
    case PARENB | PARODD : parity = 'o'; break;
    }
#endif /* !PAREXT */

    data = iostate.c_cflag & CSIZE;
    data = (data == CS5) ? 5 : (data == CS6) ? 6 : (data == CS7) ? 7 : 8;

    stop = (iostate.c_cflag & CSTOPB) ? 2 : 1;
#endif /* USE_TERMIOS */








|







1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
    case PARENB | PARODD | PAREXT : parity = 'm'; break;
    }
#else /* !PAREXT */
    switch ((int) (iostate.c_cflag & (PARENB | PARODD))) {
    case PARENB		 : parity = 'e'; break;
    case PARENB | PARODD : parity = 'o'; break;
    }
#endif /* PAREXT */

    data = iostate.c_cflag & CSIZE;
    data = (data == CS5) ? 5 : (data == CS6) ? 6 : (data == CS7) ? 7 : 8;

    stop = (iostate.c_cflag & CSTOPB) ? 2 : 1;
#endif /* USE_TERMIOS */

1385
1386
1387
1388
1389
1390
1391




1392
1393

1394
1395
1396
1397
1398

1399
1400
1401
1402
1403
1404
1405
	}
	return TCL_ERROR;
    }

    /*
     * Only allow setting mark/space parity on platforms that support it Make
     * sure to allow for the case where strchr is a macro. [Bug: 5089]




     */


#if defined(PAREXT) || defined(USE_TERMIO)
    if (strchr("noems", parity) == NULL) {
#else
    if (strchr("noe", parity) == NULL) {
#endif /* PAREXT|USE_TERMIO */

	if (interp != NULL) {
	    Tcl_AppendResult(interp, bad, " parity: should be ",
#if defined(PAREXT) || defined(USE_TERMIO)
		    "n, o, e, m, or s",
#else
		    "n, o, or e",
#endif /* PAREXT|USE_TERMIO */







>
>
>
>


>

|

|

>







1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
	}
	return TCL_ERROR;
    }

    /*
     * Only allow setting mark/space parity on platforms that support it Make
     * sure to allow for the case where strchr is a macro. [Bug: 5089]
     *
     * We cannot if/else/endif the strchr arguments, it has to be the whole
     * function. On AIX this function is apparently a macro, and macros do
     * not allow pre-processor directives in their arguments.
     */

    if (
#if defined(PAREXT) || defined(USE_TERMIO)
        strchr("noems", parity)
#else
        strchr("noe", parity)
#endif /* PAREXT|USE_TERMIO */
                               == NULL) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, bad, " parity: should be ",
#if defined(PAREXT) || defined(USE_TERMIO)
		    "n, o, e, m, or s",
#else
		    "n, o, or e",
#endif /* PAREXT|USE_TERMIO */
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490

static FileState *
TtyInit(
    int fd,			/* Open file descriptor for serial port to be
				 * initialized. */
    int initialize)
{
    TtyState *ttyPtr;
    int stateUpdated = 0;

    ttyPtr = (TtyState *) ckalloc((unsigned) sizeof(TtyState));
    GETIOSTATE(fd, &ttyPtr->savedState);
    if (initialize) {
	IOSTATE iostate = ttyPtr->savedState;

#if defined(USE_TERMIOS) || defined(USE_TERMIO)
	if (iostate.c_iflag != IGNBRK ||
		iostate.c_oflag != 0 ||
		iostate.c_lflag != 0 ||
		iostate.c_cflag & CREAD ||
		iostate.c_cc[VMIN] != 1 ||
		iostate.c_cc[VTIME] != 0) {
	    stateUpdated = 1;
	}
	iostate.c_iflag = IGNBRK;
	iostate.c_oflag = 0;
	iostate.c_lflag = 0;
	SET_BITS(iostate.c_cflag, CREAD);
	iostate.c_cc[VMIN] = 1;
	iostate.c_cc[VTIME] = 0;
#endif	/* USE_TERMIOS|USE_TERMIO */

#ifdef USE_SGTTY
	if ((iostate.sg_flags & (EVENP | ODDP)) ||
		!(iostate.sg_flags & RAW)) {
	    ttyPtr->stateUpdated = 1;
	}
	iostate.sg_flags &= EVENP | ODDP;
	SET_BITS(iostate.sg_flags, RAW);
#endif	/* USE_SGTTY */

	/*







|


<





|
|
|
|
|
|











|
|







1456
1457
1458
1459
1460
1461
1462
1463
1464
1465

1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496

static FileState *
TtyInit(
    int fd,			/* Open file descriptor for serial port to be
				 * initialized. */
    int initialize)
{
    TtyState *ttyPtr = (TtyState *) ckalloc((unsigned) sizeof(TtyState));
    int stateUpdated = 0;


    GETIOSTATE(fd, &ttyPtr->savedState);
    if (initialize) {
	IOSTATE iostate = ttyPtr->savedState;

#if defined(USE_TERMIOS) || defined(USE_TERMIO)
	if (iostate.c_iflag != IGNBRK
		|| iostate.c_oflag != 0
		|| iostate.c_lflag != 0
		|| iostate.c_cflag & CREAD
		|| iostate.c_cc[VMIN] != 1
		|| iostate.c_cc[VTIME] != 0) {
	    stateUpdated = 1;
	}
	iostate.c_iflag = IGNBRK;
	iostate.c_oflag = 0;
	iostate.c_lflag = 0;
	SET_BITS(iostate.c_cflag, CREAD);
	iostate.c_cc[VMIN] = 1;
	iostate.c_cc[VTIME] = 0;
#endif	/* USE_TERMIOS|USE_TERMIO */

#ifdef USE_SGTTY
	if ((iostate.sg_flags & (EVENP | ODDP))
		|| !(iostate.sg_flags & RAW)) {
	    ttyPtr->stateUpdated = 1;
	}
	iostate.sg_flags &= EVENP | ODDP;
	SET_BITS(iostate.sg_flags, RAW);
#endif	/* USE_SGTTY */

	/*
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
    int permissions)		/* If the open involves creating a file, with
				 * what modes to create it? */
{
    int fd, channelPermissions;
    FileState *fsPtr;
    const char *native, *translation;
    char channelName[16 + TCL_INTEGER_SPACE];
    Tcl_ChannelType *channelTypePtr;

    switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
    case O_RDONLY:
	channelPermissions = TCL_READABLE;
	break;
    case O_WRONLY:
	channelPermissions = TCL_WRITABLE;







|







1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
    int permissions)		/* If the open involves creating a file, with
				 * what modes to create it? */
{
    int fd, channelPermissions;
    FileState *fsPtr;
    const char *native, *translation;
    char channelName[16 + TCL_INTEGER_SPACE];
    const Tcl_ChannelType *channelTypePtr;

    switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
    case O_RDONLY:
	channelPermissions = TCL_READABLE;
	break;
    case O_WRONLY:
	channelPermissions = TCL_WRITABLE;
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
	fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));
    }

    fsPtr->validMask = channelPermissions | TCL_EXCEPTION;
    fsPtr->fd = fd;

    fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName,
	    (ClientData) fsPtr, channelPermissions);

    if (translation != NULL) {
	/*
	 * Gotcha. Most modems need a "\r" at the end of the command sequence.
	 * If you just send "at\n", the modem will not respond with "OK"
	 * because it never got a "\r" to actually invoke the command. So, by
	 * default, newlines are translated to "\r\n" on output to avoid "bug"







|







1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
	fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));
    }

    fsPtr->validMask = channelPermissions | TCL_EXCEPTION;
    fsPtr->fd = fd;

    fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName,
	    fsPtr, channelPermissions);

    if (translation != NULL) {
	/*
	 * Gotcha. Most modems need a "\r" at the end of the command sequence.
	 * If you just send "at\n", the modem will not respond with "OK"
	 * because it never got a "\r" to actually invoke the command. So, by
	 * default, newlines are translated to "\r\n" on output to avoid "bug"
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
    ClientData handle,		/* OS level handle. */
    int mode)			/* ORed combination of TCL_READABLE and
				 * TCL_WRITABLE to indicate file mode. */
{
    FileState *fsPtr;
    char channelName[16 + TCL_INTEGER_SPACE];
    int fd = PTR2INT(handle);
    Tcl_ChannelType *channelTypePtr;
    struct sockaddr sockaddr;
    socklen_t sockaddrLen = sizeof(sockaddr);

    if (mode == 0) {
	return NULL;
    }

    sockaddr.sa_family = AF_UNSPEC;

#ifdef SUPPORTS_TTY
    if (isatty(fd)) {
	fsPtr = TtyInit(fd, 0);
	channelTypePtr = &ttyChannelType;
	sprintf(channelName, "serial%d", fd);
    } else
#endif /* SUPPORTS_TTY */
    if (getsockname(fd, (struct sockaddr *)&sockaddr, &sockaddrLen) == 0
	    && sockaddrLen > 0
	    && sockaddr.sa_family == AF_INET) {
	return TclpMakeTcpClientChannelMode((ClientData) INT2PTR(fd), mode);
    } else {
	channelTypePtr = &fileChannelType;
	fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));
	sprintf(channelName, "file%d", fd);
    }

    fsPtr->fd = fd;
    fsPtr->validMask = mode | TCL_EXCEPTION;
    fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName,
	    (ClientData) fsPtr, mode);

    return fsPtr->channel;
}

/*
 *----------------------------------------------------------------------
 *







|
















|
|
|
|









|







1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
    ClientData handle,		/* OS level handle. */
    int mode)			/* ORed combination of TCL_READABLE and
				 * TCL_WRITABLE to indicate file mode. */
{
    FileState *fsPtr;
    char channelName[16 + TCL_INTEGER_SPACE];
    int fd = PTR2INT(handle);
    const Tcl_ChannelType *channelTypePtr;
    struct sockaddr sockaddr;
    socklen_t sockaddrLen = sizeof(sockaddr);

    if (mode == 0) {
	return NULL;
    }

    sockaddr.sa_family = AF_UNSPEC;

#ifdef SUPPORTS_TTY
    if (isatty(fd)) {
	fsPtr = TtyInit(fd, 0);
	channelTypePtr = &ttyChannelType;
	sprintf(channelName, "serial%d", fd);
    } else
#endif /* SUPPORTS_TTY */
    if ((getsockname(fd, (struct sockaddr *)&sockaddr, &sockaddrLen) == 0)
	&& (sockaddrLen > 0)
	&& (sockaddr.sa_family == AF_INET || sockaddr.sa_family == AF_INET6)) {
	return TclpMakeTcpClientChannelMode(INT2PTR(fd), mode);
    } else {
	channelTypePtr = &fileChannelType;
	fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));
	sprintf(channelName, "file%d", fd);
    }

    fsPtr->fd = fd;
    fsPtr->validMask = mode | TCL_EXCEPTION;
    fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName,
	    fsPtr, mode);

    return fsPtr->channel;
}

/*
 *----------------------------------------------------------------------
 *
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
	Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type");
	break;
    }

#undef ZERO_OFFSET
#undef ERROR_OFFSET

    channel = Tcl_MakeFileChannel((ClientData) INT2PTR(fd), mode);
    if (channel == NULL) {
	return NULL;
    }

    /*
     * Set up the normal channel options for stdio handles.
     */







|







1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
	Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type");
	break;
    }

#undef ZERO_OFFSET
#undef ERROR_OFFSET

    channel = Tcl_MakeFileChannel(INT2PTR(fd), mode);
    if (channel == NULL) {
	return NULL;
    }

    /*
     * Set up the normal channel options for stdio handles.
     */
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
    Tcl_Channel chan;
    int chanMode, fd;
    const Tcl_ChannelType *chanTypePtr;
    ClientData data;
    FILE *f;

    chan = Tcl_GetChannel(interp, chanID, &chanMode);
    if (chan == (Tcl_Channel) NULL) {
	return TCL_ERROR;
    }
    if ((forWriting) && ((chanMode & TCL_WRITABLE) == 0)) {
	Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for writing",
		NULL);
	return TCL_ERROR;
    } else if ((!forWriting) && ((chanMode & TCL_READABLE) == 0)) {







|







1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
    Tcl_Channel chan;
    int chanMode, fd;
    const Tcl_ChannelType *chanTypePtr;
    ClientData data;
    FILE *f;

    chan = Tcl_GetChannel(interp, chanID, &chanMode);
    if (chan == NULL) {
	return TCL_ERROR;
    }
    if ((forWriting) && ((chanMode & TCL_WRITABLE) == 0)) {
	Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for writing",
		NULL);
	return TCL_ERROR;
    } else if ((!forWriting) && ((chanMode & TCL_READABLE) == 0)) {
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
    if ((chanTypePtr == &fileChannelType)
#ifdef SUPPORTS_TTY
	    || (chanTypePtr == &ttyChannelType)
#endif /* SUPPORTS_TTY */
	    || (strcmp(chanTypePtr->typeName, "tcp") == 0)
	    || (strcmp(chanTypePtr->typeName, "pipe") == 0)) {
	if (Tcl_GetChannelHandle(chan,
		(forWriting ? TCL_WRITABLE : TCL_READABLE),
		(ClientData*) &data) == TCL_OK) {
	    fd = PTR2INT(data);

	    /*
	     * The call to fdopen below is probably dangerous, since it will
	     * truncate an existing file if the file is being opened for
	     * writing....
	     */

	    f = fdopen(fd, (forWriting ? "w" : "r"));
	    if (f == NULL) {
		Tcl_AppendResult(interp, "cannot get a FILE * for \"", chanID,
			"\"", NULL);
		return TCL_ERROR;
	    }
	    *filePtr = (ClientData) f;
	    return TCL_OK;
	}
    }

    Tcl_AppendResult(interp, "\"", chanID,
	    "\" cannot be used to get a FILE *", NULL);
    return TCL_ERROR;







|
<














|







1851
1852
1853
1854
1855
1856
1857
1858

1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
    if ((chanTypePtr == &fileChannelType)
#ifdef SUPPORTS_TTY
	    || (chanTypePtr == &ttyChannelType)
#endif /* SUPPORTS_TTY */
	    || (strcmp(chanTypePtr->typeName, "tcp") == 0)
	    || (strcmp(chanTypePtr->typeName, "pipe") == 0)) {
	if (Tcl_GetChannelHandle(chan,
		(forWriting ? TCL_WRITABLE : TCL_READABLE), &data) == TCL_OK) {

	    fd = PTR2INT(data);

	    /*
	     * The call to fdopen below is probably dangerous, since it will
	     * truncate an existing file if the file is being opened for
	     * writing....
	     */

	    f = fdopen(fd, (forWriting ? "w" : "r"));
	    if (f == NULL) {
		Tcl_AppendResult(interp, "cannot get a FILE * for \"", chanID,
			"\"", NULL);
		return TCL_ERROR;
	    }
	    *filePtr = f;
	    return TCL_OK;
	}
    }

    Tcl_AppendResult(interp, "\"", chanID,
	    "\" cannot be used to get a FILE *", NULL);
    return TCL_ERROR;
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
				 * forever. */
{
    Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */
    struct timeval blockTime, *timeoutPtr;
    int numFound, result = 0;
    fd_set readableMask;
    fd_set writableMask;
    fd_set exceptionalMask;

#ifndef _DARWIN_C_SOURCE
    /*
     * Sanity check fd.
     */

    if (fd >= FD_SETSIZE) {







|







1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
				 * forever. */
{
    Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */
    struct timeval blockTime, *timeoutPtr;
    int numFound, result = 0;
    fd_set readableMask;
    fd_set writableMask;
    fd_set exceptionMask;

#ifndef _DARWIN_C_SOURCE
    /*
     * Sanity check fd.
     */

    if (fd >= FD_SETSIZE) {
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968

    /*
     * Initialize the select masks.
     */

    FD_ZERO(&readableMask);
    FD_ZERO(&writableMask);
    FD_ZERO(&exceptionalMask);

    /*
     * Loop in a mini-event loop of our own, waiting for either the file to
     * become ready or a timeout to occur.
     */

    while (1) {







|







1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973

    /*
     * Initialize the select masks.
     */

    FD_ZERO(&readableMask);
    FD_ZERO(&writableMask);
    FD_ZERO(&exceptionMask);

    /*
     * Loop in a mini-event loop of our own, waiting for either the file to
     * become ready or a timeout to occur.
     */

    while (1) {
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
	    }
	}

	/*
	 * Setup the select masks for the fd.
	 */

	if (mask & TCL_READABLE)  {
	    FD_SET(fd, &readableMask);
	}
	if (mask & TCL_WRITABLE)  {
	    FD_SET(fd, &writableMask);
	}
	if (mask & TCL_EXCEPTION) {
	    FD_SET(fd, &exceptionalMask);
	}

	/*
	 * Wait for the event or a timeout.
	 */

	numFound = select(fd + 1, &readableMask, &writableMask,
		&exceptionalMask, timeoutPtr);
	if (numFound == 1) {
	    if (FD_ISSET(fd, &readableMask))   {
		SET_BITS(result, TCL_READABLE);
	    }
	    if (FD_ISSET(fd, &writableMask))  {
		SET_BITS(result, TCL_WRITABLE);
	    }
	    if (FD_ISSET(fd, &exceptionalMask)) { 
		SET_BITS(result, TCL_EXCEPTION);
	    }
	    result &= mask;
	    if (result) {
		break;
	    }
	}







|


|



|







|

|


|


|







1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
	    }
	}

	/*
	 * Setup the select masks for the fd.
	 */

	if (mask & TCL_READABLE) {
	    FD_SET(fd, &readableMask);
	}
	if (mask & TCL_WRITABLE) {
	    FD_SET(fd, &writableMask);
	}
	if (mask & TCL_EXCEPTION) {
	    FD_SET(fd, &exceptionMask);
	}

	/*
	 * Wait for the event or a timeout.
	 */

	numFound = select(fd + 1, &readableMask, &writableMask,
		&exceptionMask, timeoutPtr);
	if (numFound == 1) {
	    if (FD_ISSET(fd, &readableMask)) {
		SET_BITS(result, TCL_READABLE);
	    }
	    if (FD_ISSET(fd, &writableMask)) {
		SET_BITS(result, TCL_WRITABLE);
	    }
	    if (FD_ISSET(fd, &exceptionMask)) { 
		SET_BITS(result, TCL_EXCEPTION);
	    }
	    result &= mask;
	    if (result) {
		break;
	    }
	}
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
 */

static int
FileTruncateProc(
    ClientData instanceData,
    Tcl_WideInt length)
{
    FileState *fsPtr = (FileState *) instanceData;
    int result;

#ifdef HAVE_TYPE_OFF64_T
    /*
     * We assume this goes with the type for now...
     */








|







2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
 */

static int
FileTruncateProc(
    ClientData instanceData,
    Tcl_WideInt length)
{
    FileState *fsPtr = instanceData;
    int result;

#ifdef HAVE_TYPE_OFF64_T
    /*
     * We assume this goes with the type for now...
     */

Changes to unix/tclUnixFCmd.c.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the University of
 *      California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

#include "tclInt.h"
#include <utime.h>
#include <grp.h>
#ifndef HAVE_ST_BLKSIZE
#ifndef NO_FSTATFS
#include <sys/statfs.h>
#endif
#endif
#ifdef HAVE_FTS
#include <fts.h>
#endif







<
<
<
<
|



















|







21
22
23
24
25
26
27




28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.




 * 3. Neither the name of the University nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

#include "tclInt.h"
#include <utime.h>
#include <grp.h>
#ifndef HAVE_STRUCT_STAT_ST_BLKSIZE
#ifndef NO_FSTATFS
#include <sys/statfs.h>
#endif
#endif
#ifdef HAVE_FTS
#include <fts.h>
#endif
452
453
454
455
456
457
458
459
460
461
462

463
464
465
466
467
468
469
470
471
472
473
474
	    return TCL_ERROR;
	}
    }

    switch ((int) (statBufPtr->st_mode & S_IFMT)) {
#ifndef DJGPP
    case S_IFLNK: {
	char link[MAXPATHLEN];
	int length;

	length = readlink(src, link, sizeof(link));	/* INTL: Native. */

	if (length == -1) {
	    return TCL_ERROR;
	}
	link[length] = '\0';
	if (symlink(link, dst) < 0) {			/* INTL: Native. */
	    return TCL_ERROR;
	}
#ifdef MAC_OSX_TCL
	TclMacOSXCopyFileAttributes(src, dst, statBufPtr);
#endif
	break;
    }







|


|
>



|
|







448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
	    return TCL_ERROR;
	}
    }

    switch ((int) (statBufPtr->st_mode & S_IFMT)) {
#ifndef DJGPP
    case S_IFLNK: {
	char linkBuf[MAXPATHLEN];
	int length;

	length = readlink(src, linkBuf, sizeof(linkBuf));
							/* INTL: Native. */
	if (length == -1) {
	    return TCL_ERROR;
	}
	linkBuf[length] = '\0';
	if (symlink(linkBuf, dst) < 0) {		/* INTL: Native. */
	    return TCL_ERROR;
	}
#ifdef MAC_OSX_TCL
	TclMacOSXCopyFileAttributes(src, dst, statBufPtr);
#endif
	break;
    }
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570

571
572
573
574
575
576
577

    /*
     * Try to work out the best size of buffer to use for copying. If we
     * can't, it's no big deal as we can just use a (32-bit) page, since
     * that's likely to be fairly efficient anyway.
     */

#ifdef HAVE_ST_BLKSIZE
    blockSize = statBufPtr->st_blksize;
#elif !defined(NO_FSTATFS)
    {
	struct statfs fs;

	if (fstatfs(srcFd, &fs, sizeof(fs), 0) == 0) {
	    blockSize = fs.f_bsize;
	} else {
	    blockSize = DEFAULT_COPY_BLOCK_SIZE;
	}
    }
#else
    blockSize = DEFAULT_COPY_BLOCK_SIZE;
#endif /* HAVE_ST_BLKSIZE */

    /*
     * [SF Tcl Bug 1586470] Even if we HAVE_ST_BLKSIZE, there are filesystems
     * which report a bogus value for the blocksize. An example is the Andrew
     * Filesystem (afs), reporting a blocksize of 0. When detecting such a
     * situation we now simply fall back to a hardwired default size.

     */

    if (blockSize <= 0) {
	blockSize = DEFAULT_COPY_BLOCK_SIZE;
    }
    buffer = ckalloc(blockSize);
    while (1) {







|





|







|


|
|
|
|
>







540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575

    /*
     * Try to work out the best size of buffer to use for copying. If we
     * can't, it's no big deal as we can just use a (32-bit) page, since
     * that's likely to be fairly efficient anyway.
     */

#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
    blockSize = statBufPtr->st_blksize;
#elif !defined(NO_FSTATFS)
    {
	struct statfs fs;

	if (fstatfs(srcFd, &fs) == 0) {
	    blockSize = fs.f_bsize;
	} else {
	    blockSize = DEFAULT_COPY_BLOCK_SIZE;
	}
    }
#else
    blockSize = DEFAULT_COPY_BLOCK_SIZE;
#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */

    /*
     * [SF Tcl Bug 1586470] Even if we HAVE_STRUCT_STAT_ST_BLKSIZE, there are
     * filesystems which report a bogus value for the blocksize. An example
     * is the Andrew Filesystem (afs), reporting a blocksize of 0. When
     * detecting such a situation we now simply fall back to a hardwired
     * default size.
     */

    if (blockSize <= 0) {
	blockSize = DEFAULT_COPY_BLOCK_SIZE;
    }
    buffer = ckalloc(blockSize);
    while (1) {
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
    Tcl_Obj *pathPtr)
{
    return TclpDeleteFile(Tcl_FSGetNativePath(pathPtr));
}

int
TclpDeleteFile(
    const char *path)		/* Pathname of file to be removed (native). */
{
    if (unlink(path) != 0) {				/* INTL: Native. */
	return TCL_ERROR;
    }
    return TCL_OK;
}

/*
 *---------------------------------------------------------------------------







|

|







628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
    Tcl_Obj *pathPtr)
{
    return TclpDeleteFile(Tcl_FSGetNativePath(pathPtr));
}

int
TclpDeleteFile(
    const void *path)		/* Pathname of file to be removed (native). */
{
    if (unlink((const char *)path) != 0) {
	return TCL_ERROR;
    }
    return TCL_OK;
}

/*
 *---------------------------------------------------------------------------
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
	Tcl_DString ds;
	const char *utf;

	utf = Tcl_ExternalToUtfDString(NULL, groupPtr->gr_name, -1, &ds);
	*attributePtrPtr = Tcl_NewStringObj(utf, -1);
	Tcl_DStringFree(&ds);
    }
    endgrent();
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * GetOwnerAttribute







<







1335
1336
1337
1338
1339
1340
1341

1342
1343
1344
1345
1346
1347
1348
	Tcl_DString ds;
	const char *utf;

	utf = Tcl_ExternalToUtfDString(NULL, groupPtr->gr_name, -1, &ds);
	*attributePtrPtr = Tcl_NewStringObj(utf, -1);
	Tcl_DStringFree(&ds);
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * GetOwnerAttribute
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
	Tcl_DString ds;
	const char *utf;

	utf = Tcl_ExternalToUtfDString(NULL, pwPtr->pw_name, -1, &ds);
	*attributePtrPtr = Tcl_NewStringObj(utf, Tcl_DStringLength(&ds));
	Tcl_DStringFree(&ds);
    }
    endpwent();
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * GetPermissionsAttribute







<







1389
1390
1391
1392
1393
1394
1395

1396
1397
1398
1399
1400
1401
1402
	Tcl_DString ds;
	const char *utf;

	utf = Tcl_ExternalToUtfDString(NULL, pwPtr->pw_name, -1, &ds);
	*attributePtrPtr = Tcl_NewStringObj(utf, Tcl_DStringLength(&ds));
	Tcl_DStringFree(&ds);
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * GetPermissionsAttribute
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
	string = Tcl_GetStringFromObj(attributePtr, &length);

	native = Tcl_UtfToExternalDString(NULL, string, length, &ds);
	groupPtr = TclpGetGrNam(native); /* INTL: Native. */
	Tcl_DStringFree(&ds);

	if (groupPtr == NULL) {
	    endgrent();
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "could not set group for file \"",
			TclGetString(fileName), "\": group \"", string,
			"\" does not exist", NULL);
	    }
	    return TCL_ERROR;
	}
	gid = groupPtr->gr_gid;
    }

    native = Tcl_FSGetNativePath(fileName);
    result = chown(native, (uid_t) -1, (gid_t) gid);	/* INTL: Native. */

    endgrent();
    if (result != 0) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, "could not set group for file \"",
		    TclGetString(fileName), "\": ", Tcl_PosixError(interp),
		    NULL);
	}
	return TCL_ERROR;







<













<







1475
1476
1477
1478
1479
1480
1481

1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494

1495
1496
1497
1498
1499
1500
1501
	string = Tcl_GetStringFromObj(attributePtr, &length);

	native = Tcl_UtfToExternalDString(NULL, string, length, &ds);
	groupPtr = TclpGetGrNam(native); /* INTL: Native. */
	Tcl_DStringFree(&ds);

	if (groupPtr == NULL) {

	    if (interp != NULL) {
		Tcl_AppendResult(interp, "could not set group for file \"",
			TclGetString(fileName), "\": group \"", string,
			"\" does not exist", NULL);
	    }
	    return TCL_ERROR;
	}
	gid = groupPtr->gr_gid;
    }

    native = Tcl_FSGetNativePath(fileName);
    result = chown(native, (uid_t) -1, (gid_t) gid);	/* INTL: Native. */


    if (result != 0) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, "could not set group for file \"",
		    TclGetString(fileName), "\": ", Tcl_PosixError(interp),
		    NULL);
	}
	return TCL_ERROR;
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
	struct passwd *pwPtr = NULL;
	const char *string;
	int length;

	string = Tcl_GetStringFromObj(attributePtr, &length);

	native = Tcl_UtfToExternalDString(NULL, string, length, &ds);
	pwPtr = TclpGetPwNam(native); /* INTL: Native. */
	Tcl_DStringFree(&ds);

	if (pwPtr == NULL) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "could not set owner for file \"",
			TclGetString(fileName), "\": user \"", string,
			"\" does not exist", NULL);







|







1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
	struct passwd *pwPtr = NULL;
	const char *string;
	int length;

	string = Tcl_GetStringFromObj(attributePtr, &length);

	native = Tcl_UtfToExternalDString(NULL, string, length, &ds);
	pwPtr = TclpGetPwNam(native);			/* INTL: Native. */
	Tcl_DStringFree(&ds);

	if (pwPtr == NULL) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "could not set owner for file \"",
			TclGetString(fileName), "\": user \"", string,
			"\" does not exist", NULL);
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916


1917
1918
1919
1920
1921
1922
1923
    Tcl_Obj *pathPtr,
    int nextCheckpoint)
{
    const char *currentPathEndPosition;
    int pathLen;
    char cur;
    const char *path = Tcl_GetStringFromObj(pathPtr, &pathLen);
#ifndef NO_REALPATH
    char normPath[MAXPATHLEN];
    Tcl_DString ds;
    const char *nativePath;


#endif

    /*
     * We add '1' here because if nextCheckpoint is zero we know that '/'
     * exists, and if it isn't zero, it must point at a directory separator
     * which we also know exists.
     */







<
<


>
>







1900
1901
1902
1903
1904
1905
1906


1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
    Tcl_Obj *pathPtr,
    int nextCheckpoint)
{
    const char *currentPathEndPosition;
    int pathLen;
    char cur;
    const char *path = Tcl_GetStringFromObj(pathPtr, &pathLen);


    Tcl_DString ds;
    const char *nativePath;
#ifndef NO_REALPATH
    char normPath[MAXPATHLEN];
#endif

    /*
     * We add '1' here because if nextCheckpoint is zero we know that '/'
     * exists, and if it isn't zero, it must point at a directory separator
     * which we also know exists.
     */
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
    while (1) {
	cur = *currentPathEndPosition;
	if ((cur == '/') && (path != currentPathEndPosition)) {
	    /*
	     * Reached directory separator.
	     */

	    Tcl_DString ds;
	    const char *nativePath;
	    int accessOk;

	    nativePath = Tcl_UtfToExternalDString(NULL, path,
		    currentPathEndPosition - path, &ds);
	    accessOk = access(nativePath, F_OK);
	    Tcl_DStringFree(&ds);








<
<







1955
1956
1957
1958
1959
1960
1961


1962
1963
1964
1965
1966
1967
1968
    while (1) {
	cur = *currentPathEndPosition;
	if ((cur == '/') && (path != currentPathEndPosition)) {
	    /*
	     * Reached directory separator.
	     */



	    int accessOk;

	    nativePath = Tcl_UtfToExternalDString(NULL, path,
		    currentPathEndPosition - path, &ds);
	    accessOk = access(nativePath, F_OK);
	    Tcl_DStringFree(&ds);

2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
	 * normalized pwd, which is not what we want at all!
	 */

	if (nextCheckpoint == 0) {
	    return 0;
	}

	nativePath = Tcl_UtfToExternalDString(NULL, path, nextCheckpoint, &ds);
	if (Realpath(nativePath, normPath) != NULL) {
	    int newNormLen;

	wholeStringOk:
	    newNormLen = strlen(normPath);
	    if ((newNormLen == Tcl_DStringLength(&ds))
		    && (strcmp(normPath, nativePath) == 0)) {







|







2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
	 * normalized pwd, which is not what we want at all!
	 */

	if (nextCheckpoint == 0) {
	    return 0;
	}

	nativePath = Tcl_UtfToExternalDString(NULL, path,nextCheckpoint, &ds);
	if (Realpath(nativePath, normPath) != NULL) {
	    int newNormLen;

	wholeStringOk:
	    newNormLen = strlen(normPath);
	    if ((newNormLen == Tcl_DStringLength(&ds))
		    && (strcmp(normPath, nativePath) == 0)) {
Changes to unix/tclUnixFile.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
 * tclUnixFile.c --
 *
 *	This file contains wrappers around UNIX file handling functions.
 *	These wrappers mask differences between Windows and UNIX.
 *
 * Copyright (c) 1995-1998 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixFile.c,v 1.53 2008/04/27 22:21:34 dkf Exp $
 */

#include "tclInt.h"
#include "tclFileSystem.h"









|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
 * tclUnixFile.c --
 *
 *	This file contains wrappers around UNIX file handling functions.
 *	These wrappers mask differences between Windows and UNIX.
 *
 * Copyright (c) 1995-1998 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixFile.c,v 1.53 2008/04/27 22:21:34 dkf Exp $
 */

#include "tclInt.h"
#include "tclFileSystem.h"

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
	/*
	 * Match a file directly.
	 */

	Tcl_Obj *tailPtr;
	const char *nativeTail;

	native = (const char *) Tcl_FSGetNativePath(pathPtr);
	tailPtr = TclPathPart(interp, pathPtr, TCL_PATH_TAIL);
	nativeTail = (const char *) Tcl_FSGetNativePath(tailPtr);
	matchResult = NativeMatchType(interp, native, nativeTail, types);
	if (matchResult == 1) {
	    Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
	}
	Tcl_DecrRefCount(tailPtr);
	Tcl_DecrRefCount(fileNamePtr);
    } else {







|

|







228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
	/*
	 * Match a file directly.
	 */

	Tcl_Obj *tailPtr;
	const char *nativeTail;

	native = Tcl_FSGetNativePath(pathPtr);
	tailPtr = TclPathPart(interp, pathPtr, TCL_PATH_TAIL);
	nativeTail = Tcl_FSGetNativePath(tailPtr);
	matchResult = NativeMatchType(interp, native, nativeTail, types);
	if (matchResult == 1) {
	    Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
	}
	Tcl_DecrRefCount(tailPtr);
	Tcl_DecrRefCount(fileNamePtr);
    } else {
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

char *
TclpGetUserHome(
    const char *name,		/* User name for desired home directory. */
    Tcl_DString *bufferPtr)	/* Uninitialized or free DString filled with
				 * name of user's home directory. */
{
    struct passwd *pwPtr;
    Tcl_DString ds;
    const char *native = Tcl_UtfToExternalDString(NULL, name, -1, &ds);

    pwPtr = getpwnam(native);				/* INTL: Native. */
    Tcl_DStringFree(&ds);

    if (pwPtr == NULL) {
	endpwent();
	return NULL;
    }
    Tcl_ExternalToUtfDString(NULL, pwPtr->pw_dir, -1, bufferPtr);
    endpwent();
    return Tcl_DStringValue(bufferPtr);
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpObjAccess --







|









|



<



<







564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584

585
586
587

588
589
590
591
592
593
594
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

const char *
TclpGetUserHome(
    const char *name,		/* User name for desired home directory. */
    Tcl_DString *bufferPtr)	/* Uninitialized or free DString filled with
				 * name of user's home directory. */
{
    struct passwd *pwPtr;
    Tcl_DString ds;
    const char *native = Tcl_UtfToExternalDString(NULL, name, -1, &ds);

    pwPtr = TclpGetPwNam(native);			/* INTL: Native. */
    Tcl_DStringFree(&ds);

    if (pwPtr == NULL) {

	return NULL;
    }
    Tcl_ExternalToUtfDString(NULL, pwPtr->pw_dir, -1, bufferPtr);

    return Tcl_DStringValue(bufferPtr);
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpObjAccess --
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
    }
#endif

    if ((clientData == NULL) || strcmp(buffer, (const char*)clientData)) {
	char *newCd = ckalloc((unsigned) strlen(buffer) + 1);

	strcpy(newCd, buffer);
	return (ClientData) newCd;
    }

    /*
     * No change to pwd.
     */

    return clientData;







|







706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
    }
#endif

    if ((clientData == NULL) || strcmp(buffer, (const char*)clientData)) {
	char *newCd = ckalloc((unsigned) strlen(buffer) + 1);

	strcpy(newCd, buffer);
	return newCd;
    }

    /*
     * No change to pwd.
     */

    return clientData;
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
    Tcl_UtfToExternalDString(NULL, str, len, &ds);
    len = Tcl_DStringLength(&ds) + sizeof(char);
    Tcl_DecrRefCount(validPathPtr);
    nativePathPtr = ckalloc((unsigned) len);
    memcpy(nativePathPtr, Tcl_DStringValue(&ds), (size_t) len);

    Tcl_DStringFree(&ds);
    return (ClientData)nativePathPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclNativeDupInternalRep --
 *







|







1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
    Tcl_UtfToExternalDString(NULL, str, len, &ds);
    len = Tcl_DStringLength(&ds) + sizeof(char);
    Tcl_DecrRefCount(validPathPtr);
    nativePathPtr = ckalloc((unsigned) len);
    memcpy(nativePathPtr, Tcl_DStringValue(&ds), (size_t) len);

    Tcl_DStringFree(&ds);
    return nativePathPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclNativeDupInternalRep --
 *
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
     * ASCII representation when running on Unix.
     */

    len = (strlen((const char*) clientData) + 1) * sizeof(char);

    copy = ckalloc(len);
    memcpy(copy, clientData, len);
    return (ClientData) copy;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpUtime --
 *







|







1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
     * ASCII representation when running on Unix.
     */

    len = (strlen((const char*) clientData) + 1) * sizeof(char);

    copy = ckalloc(len);
    memcpy(copy, clientData, len);
    return copy;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpUtime --
 *
Changes to unix/tclUnixPort.h.
100
101
102
103
104
105
106





107
108
109
110
111
112
113
#endif
#ifndef NO_SYS_WAIT_H
#   include <sys/wait.h>
#endif
#if HAVE_INTTYPES_H
#   include <inttypes.h>
#endif





#if HAVE_STDINT_H
#   include <stdint.h>
#endif
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#else
#   include "../compat/unistd.h"







>
>
>
>
>







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#endif
#ifndef NO_SYS_WAIT_H
#   include <sys/wait.h>
#endif
#if HAVE_INTTYPES_H
#   include <inttypes.h>
#endif
#ifdef NO_LIMITS_H
#   include "../compat/limits.h"
#else
#   include <limits.h>
#endif
#if HAVE_STDINT_H
#   include <stdint.h>
#endif
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#else
#   include "../compat/unistd.h"
123
124
125
126
127
128
129
130



131
132
133
134
135
136
137
 */
#include <sys/socket.h>		/* struct sockaddr, SOCK_STREAM, ... */
#ifndef NO_UNAME
#   include <sys/utsname.h>	/* uname system call. */
#endif
#include <netinet/in.h>		/* struct in_addr, struct sockaddr_in */
#include <arpa/inet.h>		/* inet_ntoa() */
#include <netdb.h>		/* gethostbyname() */




/*
 * Some platforms (e.g. SunOS) don't define FLT_MAX and FLT_MIN, so we
 * look for an alternative definition.  If no other alternative is available
 * we use a reasonable guess.
 */








|
>
>
>







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
 */
#include <sys/socket.h>		/* struct sockaddr, SOCK_STREAM, ... */
#ifndef NO_UNAME
#   include <sys/utsname.h>	/* uname system call. */
#endif
#include <netinet/in.h>		/* struct in_addr, struct sockaddr_in */
#include <arpa/inet.h>		/* inet_ntoa() */
#include <netdb.h>		/* getaddrinfo() */
#ifdef NEED_FAKE_RFC2553
# include "../compat/fake-rfc2553.h"
#endif

/*
 * Some platforms (e.g. SunOS) don't define FLT_MAX and FLT_MIN, so we
 * look for an alternative definition.  If no other alternative is available
 * we use a reasonable guess.
 */

247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#else
#   ifdef HAVE_BSDGETTIMEOFDAY
#	define gettimeofday BSDgettimeofday
#   endif
#endif

#ifdef GETTOD_NOT_DECLARED
EXTERN int		gettimeofday(struct timeval *tp, struct timezone *tzp);
#endif

/*
 * Define access mode constants if they aren't already defined.
 */

#ifndef F_OK







|







255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#else
#   ifdef HAVE_BSDGETTIMEOFDAY
#	define gettimeofday BSDgettimeofday
#   endif
#endif

#ifdef GETTOD_NOT_DECLARED
MODULE_SCOPE int		gettimeofday(struct timeval *tp, struct timezone *tzp);
#endif

/*
 * Define access mode constants if they aren't already defined.
 */

#ifndef F_OK
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
#else
#   if defined(_sgi) || defined(__sgi)
#       define environ _environ
#   endif
extern char **environ;
#endif

/*
 * There is no platform-specific panic routine for Unix in the Tcl internals.
 */

#define TclpPanic ((Tcl_PanicProc *) NULL)

/*
 * Darwin specifc configure overrides.
 */

#ifdef __APPLE__
/*
 * Support for fat compiles: configure runs only once for multiple architectures







<
<
<
<
<
<







462
463
464
465
466
467
468






469
470
471
472
473
474
475
#else
#   if defined(_sgi) || defined(__sgi)
#       define environ _environ
#   endif
extern char **environ;
#endif







/*
 * Darwin specifc configure overrides.
 */

#ifdef __APPLE__
/*
 * Support for fat compiles: configure runs only once for multiple architectures
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
	    (__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ > 0))))
#       undef USE_VFORK
#   endif /* __llvm__ */
#endif /* __APPLE__ */

/*
 *---------------------------------------------------------------------------
 * The following macros and declarations represent the interface between 
 * generic and unix-specific parts of Tcl.  Some of the macros may override 
 * functions declared in tclInt.h.
 *---------------------------------------------------------------------------
 */

/*
 * The default platform eol translation on Unix is TCL_TRANSLATE_LF.
 */

#ifdef DJGPP
#define	TCL_PLATFORM_TRANSLATION	TCL_TRANSLATE_CRLF
typedef int socklen_t;
#else
#define	TCL_PLATFORM_TRANSLATION	TCL_TRANSLATE_LF
#endif

/*
 * The following macros have trivial definitions, allowing generic code to 
 * address platform-specific issues.
 */

#define TclpGetPid(pid)		((unsigned long) (pid))
#define TclpReleaseFile(file)	/* Nothing. */

/*







|
|
















|







551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
	    (__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ > 0))))
#       undef USE_VFORK
#   endif /* __llvm__ */
#endif /* __APPLE__ */

/*
 *---------------------------------------------------------------------------
 * The following macros and declarations represent the interface between
 * generic and unix-specific parts of Tcl.  Some of the macros may override
 * functions declared in tclInt.h.
 *---------------------------------------------------------------------------
 */

/*
 * The default platform eol translation on Unix is TCL_TRANSLATE_LF.
 */

#ifdef DJGPP
#define	TCL_PLATFORM_TRANSLATION	TCL_TRANSLATE_CRLF
typedef int socklen_t;
#else
#define	TCL_PLATFORM_TRANSLATION	TCL_TRANSLATE_LF
#endif

/*
 * The following macros have trivial definitions, allowing generic code to
 * address platform-specific issues.
 */

#define TclpGetPid(pid)		((unsigned long) (pid))
#define TclpReleaseFile(file)	/* Nothing. */

/*
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604





605
606
607
608
609
610
611
612
613
614
615
616
617
618
 * The following macros and declaration wrap the C runtime library
 * functions.
 */

#define TclpExit		exit

#ifdef TCL_THREADS
EXTERN struct tm *     	TclpLocaltime(const time_t *);
EXTERN struct tm *     	TclpGmtime(const time_t *);
EXTERN char *          	TclpInetNtoa(struct in_addr);
/* #define localtime(x)	TclpLocaltime(x)
 * #define gmtime(x)	TclpGmtime(x)    */
#   undef inet_ntoa
#   define inet_ntoa(x)	TclpInetNtoa(x)
#endif /* TCL_THREADS */






/*
 * Set of MT-safe implementations of some
 * known-to-be-MT-unsafe library calls.
 * Instead of returning pointers to the
 * static storage, those return pointers
 * to the TSD data. 
 */

#include <pwd.h>
#include <grp.h>

MODULE_SCOPE struct passwd*  TclpGetPwNam(const char *name);
MODULE_SCOPE struct group*   TclpGetGrNam(const char *name);







<
<
<
<
<



>
>
>
>
>






|







592
593
594
595
596
597
598





599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
 * The following macros and declaration wrap the C runtime library
 * functions.
 */

#define TclpExit		exit

#ifdef TCL_THREADS





#   undef inet_ntoa
#   define inet_ntoa(x)	TclpInetNtoa(x)
#endif /* TCL_THREADS */

/* FIXME */
#ifndef AF_INET6
#define AF_INET6 10
#endif

/*
 * Set of MT-safe implementations of some
 * known-to-be-MT-unsafe library calls.
 * Instead of returning pointers to the
 * static storage, those return pointers
 * to the TSD data.
 */

#include <pwd.h>
#include <grp.h>

MODULE_SCOPE struct passwd*  TclpGetPwNam(const char *name);
MODULE_SCOPE struct group*   TclpGetGrNam(const char *name);
Changes to unix/tclUnixSock.c.
18
19
20
21
22
23
24












25
26
27
28
29








30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 * what they say on the tin. :-) They also only ever refer to their arguments
 * once, and so can be used without regard to side effects.
 */

#define SET_BITS(var, bits)	((var) |= (bits))
#define CLEAR_BITS(var, bits)	((var) &= ~(bits))













/*
 * This structure describes per-instance state of a tcp based channel.
 */

typedef struct TcpState {








    Tcl_Channel channel;	/* Channel associated with this file. */
    int fd;			/* The socket itself. */
    int flags;			/* ORed combination of the bitfields defined
				 * below. */
    Tcl_TcpAcceptProc *acceptProc;
				/* Proc to call on accept. */
    ClientData acceptProcData;	/* The data for the accept proc. */
} TcpState;

/*
 * These bits may be ORed together into the "flags" field of a TcpState
 * structure.
 */

#define TCP_ASYNC_SOCKET	(1<<0)	/* Asynchronous socket. */







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




|
>
>
>
>
>
>
>
>

|





|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
 * what they say on the tin. :-) They also only ever refer to their arguments
 * once, and so can be used without regard to side effects.
 */

#define SET_BITS(var, bits)	((var) |= (bits))
#define CLEAR_BITS(var, bits)	((var) &= ~(bits))

/*
 * This is needed to comply with the strict aliasing rules of GCC, but it also
 * simplifies casting between the different sockaddr types.
 */

typedef union {
    struct sockaddr sa;
    struct sockaddr_in sa4;
    struct sockaddr_in6 sa6;
    struct sockaddr_storage sas;
} address;

/*
 * This structure describes per-instance state of a tcp based channel.
 */

typedef struct TcpState TcpState;

typedef struct TcpFdList {
    TcpState *statePtr;
    int fd;
    struct TcpFdList *next;
} TcpFdList;

struct TcpState {
    Tcl_Channel channel;	/* Channel associated with this file. */
    TcpFdList *fds;		/* The file descriptors of the sockets. */
    int flags;			/* ORed combination of the bitfields defined
				 * below. */
    Tcl_TcpAcceptProc *acceptProc;
				/* Proc to call on accept. */
    ClientData acceptProcData;	/* The data for the accept proc. */
};

/*
 * These bits may be ORed together into the "flags" field of a TcpState
 * structure.
 */

#define TCP_ASYNC_SOCKET	(1<<0)	/* Asynchronous socket. */
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

#define SOCKET_BUFSIZE	4096

/*
 * Static routines for this file:
 */

static TcpState *	CreateSocket(Tcl_Interp *interp, int port,
			    const char *host, int server, const char *myaddr,
			    int myport, int async);
static int		CreateSocketAddress(struct sockaddr_in *sockaddrPtr,
			    const char *host, int port, int willBind,
			    const char **errorMsgPtr);
static void		TcpAccept(ClientData data, int mask);
static int		TcpBlockModeProc(ClientData data, int mode);
static int		TcpCloseProc(ClientData instanceData,
			    Tcl_Interp *interp);
static int		TcpClose2Proc(ClientData instanceData,
				      Tcl_Interp *interp,
				      int flags);
static int		TcpGetHandleProc(ClientData instanceData,
			    int direction, ClientData *handlePtr);
static int		TcpGetOptionProc(ClientData instanceData,
			    Tcl_Interp *interp, const char *optionName,
			    Tcl_DString *dsPtr);
static int		TcpInputProc(ClientData instanceData, char *buf,
			    int toRead, int *errorCode);
static int		TcpOutputProc(ClientData instanceData,
			    const char *buf, int toWrite, int *errorCode);
static void		TcpWatchProc(ClientData instanceData, int mask);
static int		WaitForConnect(TcpState *statePtr, int *errorCodePtr);

/*
 * This structure describes the channel type structure for TCP socket
 * based IO:
 */

static Tcl_ChannelType tcpChannelType = {
    "tcp",			/* Type name. */
    TCL_CHANNEL_VERSION_5,	/* v5 channel */
    TcpCloseProc,		/* Close proc. */
    TcpInputProc,		/* Input proc. */
    TcpOutputProc,		/* Output proc. */
    NULL,			/* Seek proc. */
    NULL,			/* Set option proc. */
    TcpGetOptionProc,		/* Get option proc. */
    TcpWatchProc,		/* Initialize notifier. */
    TcpGetHandleProc,		/* Get OS handles out of channel. */
    TcpClose2Proc,		/* Close2 proc. */
    TcpBlockModeProc,		/* Set blocking or non-blocking mode.*/
    NULL,			/* flush proc. */
    NULL,			/* handler proc. */
    NULL,			/* wide seek proc. */
    NULL,			/* thread action proc. */
    NULL,			/* truncate proc. */
};


/*
 * The following variable holds the network name of this host.
 */

static TclInitProcessGlobalValueProc InitializeHostName;
static ProcessGlobalValue hostName =
	{0, 0, NULL, NULL, InitializeHostName, NULL, NULL};


/*
 *----------------------------------------------------------------------
 *
 * InitializeHostName --
 *
 * 	This routine sets the process global value of the name of the local







|
|

<
<
<





|
<











>





|
















|

<








<







87
88
89
90
91
92
93
94
95
96



97
98
99
100
101
102

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

139
140
141
142
143
144
145
146

147
148
149
150
151
152
153

#define SOCKET_BUFSIZE	4096

/*
 * Static routines for this file:
 */

static TcpState *	CreateClientSocket(Tcl_Interp *interp, int port,
			    const char *host, const char *myaddr,
			    int myport, int async);



static void		TcpAccept(ClientData data, int mask);
static int		TcpBlockModeProc(ClientData data, int mode);
static int		TcpCloseProc(ClientData instanceData,
			    Tcl_Interp *interp);
static int		TcpClose2Proc(ClientData instanceData,
			    Tcl_Interp *interp, int flags);

static int		TcpGetHandleProc(ClientData instanceData,
			    int direction, ClientData *handlePtr);
static int		TcpGetOptionProc(ClientData instanceData,
			    Tcl_Interp *interp, const char *optionName,
			    Tcl_DString *dsPtr);
static int		TcpInputProc(ClientData instanceData, char *buf,
			    int toRead, int *errorCode);
static int		TcpOutputProc(ClientData instanceData,
			    const char *buf, int toWrite, int *errorCode);
static void		TcpWatchProc(ClientData instanceData, int mask);
static int		WaitForConnect(TcpState *statePtr, int *errorCodePtr);

/*
 * This structure describes the channel type structure for TCP socket
 * based IO:
 */

static const Tcl_ChannelType tcpChannelType = {
    "tcp",			/* Type name. */
    TCL_CHANNEL_VERSION_5,	/* v5 channel */
    TcpCloseProc,		/* Close proc. */
    TcpInputProc,		/* Input proc. */
    TcpOutputProc,		/* Output proc. */
    NULL,			/* Seek proc. */
    NULL,			/* Set option proc. */
    TcpGetOptionProc,		/* Get option proc. */
    TcpWatchProc,		/* Initialize notifier. */
    TcpGetHandleProc,		/* Get OS handles out of channel. */
    TcpClose2Proc,		/* Close2 proc. */
    TcpBlockModeProc,		/* Set blocking or non-blocking mode.*/
    NULL,			/* flush proc. */
    NULL,			/* handler proc. */
    NULL,			/* wide seek proc. */
    NULL,			/* thread action proc. */
    NULL			/* truncate proc. */
};


/*
 * The following variable holds the network name of this host.
 */

static TclInitProcessGlobalValueProc InitializeHostName;
static ProcessGlobalValue hostName =
	{0, 0, NULL, NULL, InitializeHostName, NULL, NULL};


/*
 *----------------------------------------------------------------------
 *
 * InitializeHostName --
 *
 * 	This routine sets the process global value of the name of the local
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
    TcpState *statePtr = (TcpState *) instanceData;

    if (mode == TCL_MODE_BLOCKING) {
	CLEAR_BITS(statePtr->flags, TCP_ASYNC_SOCKET);
    } else {
	SET_BITS(statePtr->flags, TCP_ASYNC_SOCKET);
    }
    if (TclUnixSetBlockingMode(statePtr->fd, mode) < 0) {
	return errno;
    }
    return 0;
}

/*
 *----------------------------------------------------------------------







|







331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
    TcpState *statePtr = (TcpState *) instanceData;

    if (mode == TCL_MODE_BLOCKING) {
	CLEAR_BITS(statePtr->flags, TCP_ASYNC_SOCKET);
    } else {
	SET_BITS(statePtr->flags, TCP_ASYNC_SOCKET);
    }
    if (TclUnixSetBlockingMode(statePtr->fds->fd, mode) < 0) {
	return errno;
    }
    return 0;
}

/*
 *----------------------------------------------------------------------
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
    if (statePtr->flags & TCP_ASYNC_CONNECT) {
	if (statePtr->flags & TCP_ASYNC_SOCKET) {
	    timeOut = 0;
	} else {
	    timeOut = -1;
	}
	errno = 0;
	state = TclUnixWaitForFile(statePtr->fd,
		TCL_WRITABLE | TCL_EXCEPTION, timeOut);
	if (state & TCL_EXCEPTION) {
	    return -1;
	}
	if (state & TCL_WRITABLE) {
	    CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
	} else if (timeOut == 0) {







|







373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
    if (statePtr->flags & TCP_ASYNC_CONNECT) {
	if (statePtr->flags & TCP_ASYNC_SOCKET) {
	    timeOut = 0;
	} else {
	    timeOut = -1;
	}
	errno = 0;
	state = TclUnixWaitForFile(statePtr->fds->fd,
		TCL_WRITABLE | TCL_EXCEPTION, timeOut);
	if (state & TCL_EXCEPTION) {
	    return -1;
	}
	if (state & TCL_WRITABLE) {
	    CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
	} else if (timeOut == 0) {
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
    TcpState *statePtr = (TcpState *) instanceData;
    int bytesRead;

    *errorCodePtr = 0;
    if (WaitForConnect(statePtr, errorCodePtr) != 0) {
	return -1;
    }
    bytesRead = recv(statePtr->fd, buf, (size_t) bufSize, 0);
    if (bytesRead > -1) {
	return bytesRead;
    }
    if (errno == ECONNRESET) {
	/*
	 * Turn ECONNRESET into a soft EOF condition.
	 */







|







426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
    TcpState *statePtr = (TcpState *) instanceData;
    int bytesRead;

    *errorCodePtr = 0;
    if (WaitForConnect(statePtr, errorCodePtr) != 0) {
	return -1;
    }
    bytesRead = recv(statePtr->fds->fd, buf, (size_t) bufSize, 0);
    if (bytesRead > -1) {
	return bytesRead;
    }
    if (errno == ECONNRESET) {
	/*
	 * Turn ECONNRESET into a soft EOF condition.
	 */
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
    TcpState *statePtr = (TcpState *) instanceData;
    int written;

    *errorCodePtr = 0;
    if (WaitForConnect(statePtr, errorCodePtr) != 0) {
	return -1;
    }
    written = send(statePtr->fd, buf, (size_t) toWrite, 0);
    if (written > -1) {
	return written;
    }
    *errorCodePtr = errno;
    return -1;
}








|







476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
    TcpState *statePtr = (TcpState *) instanceData;
    int written;

    *errorCodePtr = 0;
    if (WaitForConnect(statePtr, errorCodePtr) != 0) {
	return -1;
    }
    written = send(statePtr->fds->fd, buf, (size_t) toWrite, 0);
    if (written > -1) {
	return written;
    }
    *errorCodePtr = errno;
    return -1;
}

495
496
497
498
499
500
501

502
503
504
505
506
507
508
509
510


511
512
513
514
515
516
517

518
519
520
521
522
523
524
static int
TcpCloseProc(
    ClientData instanceData,	/* The socket to close. */
    Tcl_Interp *interp)		/* For error reporting - unused. */
{
    TcpState *statePtr = (TcpState *) instanceData;
    int errorCode = 0;


    /*
     * Delete a file handler that may be active for this socket if this is a
     * server socket - the file handler was created automatically by Tcl as
     * part of the mechanism to accept new client connections. Channel
     * handlers are already deleted in the generic IO channel closing code
     * that called this function, so we do not have to delete them here.
     */



    Tcl_DeleteFileHandler(statePtr->fd);

    if (close(statePtr->fd) < 0) {
	errorCode = errno;
    }
    ckfree((char *) statePtr);


    return errorCode;
}

/*
 *----------------------------------------------------------------------
 *
 * TcpClose2Proc --







>








|
>
>
|
<
|
|
|
|
|
>







510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529

530
531
532
533
534
535
536
537
538
539
540
541
542
static int
TcpCloseProc(
    ClientData instanceData,	/* The socket to close. */
    Tcl_Interp *interp)		/* For error reporting - unused. */
{
    TcpState *statePtr = (TcpState *) instanceData;
    int errorCode = 0;
    TcpFdList *fds;

    /*
     * Delete a file handler that may be active for this socket if this is a
     * server socket - the file handler was created automatically by Tcl as
     * part of the mechanism to accept new client connections. Channel
     * handlers are already deleted in the generic IO channel closing code
     * that called this function, so we do not have to delete them here.
     */
    
    for (fds = statePtr->fds; fds != NULL; fds = statePtr->fds) {
	statePtr->fds = fds->next;
	Tcl_DeleteFileHandler(fds->fd);

	if (close(fds->fd) < 0) {
	    errorCode = errno;
	}
	ckfree((char *) fds);
    }
    ckfree((char *) statePtr);
    return errorCode;
}

/*
 *----------------------------------------------------------------------
 *
 * TcpClose2Proc --
544
545
546
547
548
549
550
551
552

553
554
555
556
557
558
559
560

561
562
563
564
565
566
567
568
569
570
571
572
    TcpState *statePtr = (TcpState *) instanceData;
    int errorCode = 0;
    int sd;

    /*
     * Shutdown the OS socket handle.
     */
    switch(flags)
	{

	case TCL_CLOSE_READ:
	    sd=SHUT_RD;
	    break;
	case TCL_CLOSE_WRITE:
	    sd=SHUT_WR;
	    break;
	default:
	    if (interp) {

		Tcl_AppendResult(interp, "Socket close2proc called bidirectionally", NULL);
	    }
	    return TCL_ERROR;
	}
    if (shutdown(statePtr->fd,sd)<0) {
	errorCode = errno;
    }

    return errorCode;
}

/*







<
|
>
|
|
|
|
|
|
|
|
>
|
|
|
|
|







562
563
564
565
566
567
568

569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
    TcpState *statePtr = (TcpState *) instanceData;
    int errorCode = 0;
    int sd;

    /*
     * Shutdown the OS socket handle.
     */


    switch(flags) {
    case TCL_CLOSE_READ:
        sd = SHUT_RD;
        break;
    case TCL_CLOSE_WRITE:
        sd = SHUT_WR;
        break;
    default:
        if (interp) {
            Tcl_AppendResult(interp,
                    "Socket close2proc called bidirectionally", NULL);
        }
        return TCL_ERROR;
    }
    if (shutdown(statePtr->fds->fd,sd) < 0) {
	errorCode = errno;
    }

    return errorCode;
}

/*
597
598
599
600
601
602
603
604
605
606
607
608
609


610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630




631
632
633


634
635
636
637
638
639
640
641
642
643
644
645
646
647

648
649
650


651
652
653
654
655
656
657
658
659

660
661
662
663
664
665
666
    const char *optionName,	/* Name of the option to retrieve the value
				 * for, or NULL to get all options and their
				 * values. */
    Tcl_DString *dsPtr)		/* Where to store the computed value;
				 * initialized by caller. */
{
    TcpState *statePtr = (TcpState *) instanceData;
    struct sockaddr_in sockname;
    struct sockaddr_in peername;
    struct hostent *hostEntPtr;
    socklen_t size = sizeof(struct sockaddr_in);
    size_t len = 0;
    char buf[TCL_INTEGER_SPACE];



    if (optionName != NULL) {
	len = strlen(optionName);
    }

    if ((len > 1) && (optionName[1] == 'e') &&
	    (strncmp(optionName, "-error", len) == 0)) {
	socklen_t optlen = sizeof(int);
	int err, ret;

	ret = getsockopt(statePtr->fd, SOL_SOCKET, SO_ERROR,
		(char *)&err, &optlen);
	if (ret < 0) {
	    err = errno;
	}
	if (err != 0) {
	    Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(err), -1);
	}
	return TCL_OK;
    }





    if ((len == 0) ||
	    ((len > 1) && (optionName[1] == 'p') &&
		    (strncmp(optionName, "-peername", len) == 0))) {


	if (getpeername(statePtr->fd, (struct sockaddr *) &peername,
		&size) >= 0) {
	    if (len == 0) {
		Tcl_DStringAppendElement(dsPtr, "-peername");
		Tcl_DStringStartSublist(dsPtr);
	    }
	    Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr));
	    hostEntPtr = TclpGetHostByAddr(			/* INTL: Native. */
		    (char *) &peername.sin_addr,
		    sizeof(peername.sin_addr), AF_INET);
	    if (hostEntPtr != NULL) {
		Tcl_DString ds;

		Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds);

		Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds));
		Tcl_DStringFree(&ds);
	    } else {


		Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr));
	    }
	    TclFormatInt(buf, ntohs(peername.sin_port));
	    Tcl_DStringAppendElement(dsPtr, buf);
	    if (len == 0) {
		Tcl_DStringEndSublist(dsPtr);
	    } else {
		return TCL_OK;
	    }

	} else {
	    /*
	     * getpeername failed - but if we were asked for all the options
	     * (len==0), don't flag an error at that point because it could be
	     * an fconfigure request on a server socket (which have no peer).
	     * Same must be done on win&mac.
	     */







<
<
|
<

<
>
>










|










>
>
>
>



>
>
|
|




<
<
<
<
<
<
|
|
>
|
<
<
>
>
|
<
<
|
|
<
<
|
|
>







616
617
618
619
620
621
622


623

624

625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662






663
664
665
666


667
668
669


670
671


672
673
674
675
676
677
678
679
680
681
    const char *optionName,	/* Name of the option to retrieve the value
				 * for, or NULL to get all options and their
				 * values. */
    Tcl_DString *dsPtr)		/* Where to store the computed value;
				 * initialized by caller. */
{
    TcpState *statePtr = (TcpState *) instanceData;


    char host[NI_MAXHOST], port[NI_MAXSERV];

    size_t len = 0;

    int reverseDNS = 0;
#define SUPPRESS_RDNS_VAR "::tcl::unsupported::noReverseDNS"

    if (optionName != NULL) {
	len = strlen(optionName);
    }

    if ((len > 1) && (optionName[1] == 'e') &&
	    (strncmp(optionName, "-error", len) == 0)) {
	socklen_t optlen = sizeof(int);
	int err, ret;

	ret = getsockopt(statePtr->fds->fd, SOL_SOCKET, SO_ERROR,
		(char *)&err, &optlen);
	if (ret < 0) {
	    err = errno;
	}
	if (err != 0) {
	    Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(err), -1);
	}
	return TCL_OK;
    }

    if (interp != NULL && Tcl_GetVar(interp, SUPPRESS_RDNS_VAR, 0) != NULL) {
        reverseDNS = NI_NUMERICHOST;
    }
    
    if ((len == 0) ||
	    ((len > 1) && (optionName[1] == 'p') &&
		    (strncmp(optionName, "-peername", len) == 0))) {
        address peername;
        socklen_t size = sizeof(peername);

	if (getpeername(statePtr->fds->fd, &peername.sa, &size) >= 0) {
	    if (len == 0) {
		Tcl_DStringAppendElement(dsPtr, "-peername");
		Tcl_DStringStartSublist(dsPtr);
	    }






            
	    getnameinfo(&peername.sa, size, host, sizeof(host), NULL, 0,
                    NI_NUMERICHOST);
	    Tcl_DStringAppendElement(dsPtr, host);


	    getnameinfo(&peername.sa, size, host, sizeof(host), port,
                    sizeof(port), reverseDNS | NI_NUMERICSERV);
	    Tcl_DStringAppendElement(dsPtr, host);


	    Tcl_DStringAppendElement(dsPtr, port);
	    if (len) {


                return TCL_OK;
            }
            Tcl_DStringEndSublist(dsPtr);
	} else {
	    /*
	     * getpeername failed - but if we were asked for all the options
	     * (len==0), don't flag an error at that point because it could be
	     * an fconfigure request on a server socket (which have no peer).
	     * Same must be done on win&mac.
	     */
674
675
676
677
678
679
680

681


682
683
684
685
686








687
688




689

690
691
692


693













694

695
696
697
698
699
700
701


702
703
704
705
706

707
708
709
710
711
712
713
714
715
716
717
718
	    }
	}
    }

    if ((len == 0) ||
	    ((len > 1) && (optionName[1] == 's') &&
	    (strncmp(optionName, "-sockname", len) == 0))) {

	if (getsockname(statePtr->fd, (struct sockaddr *) &sockname,


		&size) >= 0) {
	    if (len == 0) {
		Tcl_DStringAppendElement(dsPtr, "-sockname");
		Tcl_DStringStartSublist(dsPtr);
	    }








	    Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr));
	    hostEntPtr = TclpGetHostByAddr(			/* INTL: Native. */




		    (char *) &sockname.sin_addr,

		    sizeof(sockname.sin_addr), AF_INET);
	    if (hostEntPtr != NULL) {
		Tcl_DString ds;
















		Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds);

		Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds));
		Tcl_DStringFree(&ds);
	    } else {
		Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr));
	    }
	    TclFormatInt(buf, ntohs(sockname.sin_port));
	    Tcl_DStringAppendElement(dsPtr, buf);


	    if (len == 0) {
		Tcl_DStringEndSublist(dsPtr);
	    } else {
		return TCL_OK;
	    }

	} else {
	    if (interp) {
		Tcl_AppendResult(interp, "can't get sockname: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
    }

    if (len > 0) {
	return Tcl_BadChannelOption(interp, optionName, "peername sockname");
    }







>
|
>
>
|
|
|
|
|
>
>
>
>
>
>
>
>
|
|
>
>
>
>
|
>
|
<
<
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
<
<
|

<
<
>
>
|
<
<
|
|
>
|
|
|
|
|







689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721


722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740


741
742


743
744
745


746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
	    }
	}
    }

    if ((len == 0) ||
	    ((len > 1) && (optionName[1] == 's') &&
	    (strncmp(optionName, "-sockname", len) == 0))) {
	TcpFdList *fds;
        address sockname;
        socklen_t size;
	int found = 0;

	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-sockname");
	    Tcl_DStringStartSublist(dsPtr);
	}
	for (fds = statePtr->fds; fds != NULL; fds = fds->next) {
	    size = sizeof(sockname);
	    if (getsockname(fds->fd, &(sockname.sa), &size) >= 0) {
                int flags = reverseDNS;

		found = 1;
                getnameinfo(&sockname.sa, size, host, sizeof(host), NULL, 0,
                        NI_NUMERICHOST);
                Tcl_DStringAppendElement(dsPtr, host);

                /*
                 * We don't want to resolve INADDR_ANY and sin6addr_any; they
                 * can sometimes cause problems (and never have a name).
                 */

                flags |= NI_NUMERICSERV;
                if (sockname.sa.sa_family == AF_INET) {


                    if (sockname.sa4.sin_addr.s_addr == INADDR_ANY) {
                        flags |= NI_NUMERICHOST;
                    }
#ifndef NEED_FAKE_RFC2553
                } else if (sockname.sa.sa_family == AF_INET6) {
                    if ((IN6_ARE_ADDR_EQUAL(&sockname.sa6.sin6_addr,
                                &in6addr_any))
                        || (IN6_IS_ADDR_V4MAPPED(&sockname.sa6.sin6_addr) &&
                            sockname.sa6.sin6_addr.s6_addr[12] == 0 &&
                            sockname.sa6.sin6_addr.s6_addr[13] == 0 &&
                            sockname.sa6.sin6_addr.s6_addr[14] == 0 &&
                            sockname.sa6.sin6_addr.s6_addr[15] == 0)) {
                        flags |= NI_NUMERICHOST;
                    }
#endif
                }
		getnameinfo(&sockname.sa, size, host, sizeof(host), port,
                        sizeof(port), flags);
		Tcl_DStringAppendElement(dsPtr, host);


		Tcl_DStringAppendElement(dsPtr, port);
	    }


	}
        if (found) {
            if (len) {


                return TCL_OK;
            }
            Tcl_DStringEndSublist(dsPtr);
        } else {
            if (interp) {
                Tcl_AppendResult(interp, "can't get sockname: ",
                        Tcl_PosixError(interp), NULL);
            }
	    return TCL_ERROR;
	}
    }

    if (len > 0) {
	return Tcl_BadChannelOption(interp, optionName, "peername sockname");
    }
749
750
751
752
753
754
755



756
757
758
759
760
761

762
763
764
765
766
767
768
    /*
     * Make sure we don't mess with server sockets since they will never be
     * readable or writable at the Tcl level. This keeps Tcl scripts from
     * interfering with the -accept behavior.
     */

    if (!statePtr->acceptProc) {



	if (mask) {
	    Tcl_CreateFileHandler(statePtr->fd, mask,
		    (Tcl_FileProc *) Tcl_NotifyChannel,
		    (ClientData) statePtr->channel);
	} else {
	    Tcl_DeleteFileHandler(statePtr->fd);

	}
    }
}

/*
 *----------------------------------------------------------------------
 *







>
>
>
|
|
|
|
|
|
>







791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
    /*
     * Make sure we don't mess with server sockets since they will never be
     * readable or writable at the Tcl level. This keeps Tcl scripts from
     * interfering with the -accept behavior.
     */

    if (!statePtr->acceptProc) {
	TcpFdList *fds;

	for (fds = statePtr->fds; fds != NULL; fds = fds->next) {
	    if (mask) {
		Tcl_CreateFileHandler(fds->fd, mask,
			(Tcl_FileProc *) Tcl_NotifyChannel,
			(ClientData) statePtr->channel);
	    } else {
		Tcl_DeleteFileHandler(fds->fd);
	    }
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
TcpGetHandleProc(
    ClientData instanceData,	/* The socket state. */
    int direction,		/* Not used. */
    ClientData *handlePtr)	/* Where to store the handle. */
{
    TcpState *statePtr = (TcpState *) instanceData;

    *handlePtr = (ClientData) INT2PTR(statePtr->fd);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * CreateSocket --







|







832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
TcpGetHandleProc(
    ClientData instanceData,	/* The socket state. */
    int direction,		/* Not used. */
    ClientData *handlePtr)	/* Where to store the handle. */
{
    TcpState *statePtr = (TcpState *) instanceData;

    *handlePtr = INT2PTR(statePtr->fds->fd);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * CreateSocket --
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829

830

831
832
833
834
835
836
837
838
839
840
841
842






















843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860

861
862
863
864
865
866
867


868
869
870
871
872
873
874

875
876
877
878
879
880
881
882
883
884

885
886
887
888
889
890
891
892
893

894

895
896
897
898
899
900


901
902
903
904
905
906
907
908
909
910
911
912
913
914

915
916
917



918




919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
 * Side effects:
 *	Opens a socket.
 *
 *----------------------------------------------------------------------
 */

static TcpState *
CreateSocket(
    Tcl_Interp *interp,		/* For error reporting; can be NULL. */
    int port,			/* Port number to open. */
    const char *host,		/* Name of host on which to open port. NULL
				 * implies INADDR_ANY */
    int server,			/* 1 if socket should be a server socket, else
				 * 0 for a client socket. */
    const char *myaddr,		/* Optional client-side address */
    int myport,			/* Optional client-side port */
    int async)			/* If nonzero and creating a client socket,
				 * attempt to do an async connect. Otherwise
				 * do a synchronous connect or bind. */
{
    int status = 0, sock = -1;

    struct sockaddr_in sockaddr;	/* socket address */

    struct sockaddr_in mysockaddr;	/* Socket address for client */
    TcpState *statePtr;
    const char *errorMsg = NULL;

    if (!CreateSocketAddress(&sockaddr, host, port, 0, &errorMsg)) {
	goto error;
    }
    if ((myaddr != NULL || myport != 0) &&
	    !CreateSocketAddress(&mysockaddr, myaddr, myport, 1, &errorMsg)) {
	goto error;
    }























    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
	goto error;
    }

    /*
     * Set the close-on-exec flag so that the socket will not get inherited by
     * child processes.
     */

    fcntl(sock, F_SETFD, FD_CLOEXEC);

    /*
     * Set kernel space buffering
     */

    TclSockMinimumBuffers(sock, SOCKET_BUFSIZE);


    status = 0;
    if (server) {
	/*
	 * Set up to reuse server addresses automatically and bind to the
	 * specified port.
	 */



	int reuseaddr = 1;
	(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 
		      (char *) &reuseaddr, sizeof(reuseaddr));
	status = bind(sock, (struct sockaddr *) &sockaddr,
		sizeof(struct sockaddr));
	if (status != -1) {
	    status = listen(sock, SOMAXCONN);

	}
    } else {
	if (myaddr != NULL || myport != 0) {
	    int reuseaddr = 1;
	    (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
		    (char *) &reuseaddr, sizeof(reuseaddr));
	    status = bind(sock, (struct sockaddr *) &mysockaddr,
		    sizeof(struct sockaddr));
	    if (status < 0) {
		goto error;

	    }
	}

	/*
	 * Attempt to connect. The connect may fail at present with an
	 * EINPROGRESS but at a later time it will complete. The caller will
	 * set up a file handler on the socket if she is interested in being
	 * informed when the connect completes.
	 */



	if (async) {
	    status = TclUnixSetBlockingMode(sock, TCL_MODE_NONBLOCKING);
	    if (status < 0) {
		goto error;
	    }
	}



	status = connect(sock, (struct sockaddr *) &sockaddr,
		sizeof(sockaddr));
	if (status < 0) {
	    if (errno == EINPROGRESS) {
		status = 0;
	    } else {
		goto error;
	    }
	} 
	if (async) {
	    /*
	     * Restore blocking mode.
	     */

	    status = TclUnixSetBlockingMode(sock, TCL_MODE_BLOCKING);
	}
    }








    if (status < 0) {
error:
	if (interp != NULL) {
	    Tcl_AppendResult(interp, "couldn't open socket: ",
		    Tcl_PosixError(interp), NULL);
	    if (errorMsg != NULL) {
		Tcl_AppendResult(interp, " (", errorMsg, ")", NULL);
	    }
	}
	if (sock != -1) {
	    close(sock);
	}
	return NULL;
    }

    /*
     * Allocate a new TcpState for this socket.
     */

    statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState));
    statePtr->flags = async ? TCP_ASYNC_CONNECT : 0;
    statePtr->fd = sock;

    return statePtr;
}

/*
 *----------------------------------------------------------------------
 *
 * CreateSocketAddress --
 *
 *	This function initializes a sockaddr structure for a host and port.
 *
 * Results:
 *	1 if the host was valid, 0 if the host could not be converted to an IP
 *	address.
 *
 * Side effects:
 *	Fills in the *sockaddrPtr structure.
 *
 *----------------------------------------------------------------------
 */

static int
CreateSocketAddress(
    struct sockaddr_in *sockaddrPtr,	/* Socket address */
    const char *host,			/* Host. NULL implies INADDR_ANY */
    int port,				/* Port number */
    int willBind,			/* Is this an address to bind() to or
					 * to connect() to? */
    const char **errorMsgPtr)		/* Place to store the error message
					 * detail, if available. */
{
#ifdef HAVE_GETADDRINFO
    struct addrinfo hints, *resPtr = NULL;
    char *native;
    Tcl_DString ds;
    int result;

    if (host == NULL) {
	sockaddrPtr->sin_family = AF_INET;
	sockaddrPtr->sin_addr.s_addr = INADDR_ANY;
    addPort:
	sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF));
	return 1;
    }

    (void) memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    if (willBind) {
	hints.ai_flags |= AI_PASSIVE;
    }

    /*
     * Note that getaddrinfo() *is* thread-safe. If a platform doesn't get
     * that right, it shouldn't use this part of the code.
     */

    native = Tcl_UtfToExternalDString(NULL, host, -1, &ds);
    result = getaddrinfo(native, NULL, &hints, &resPtr);
    Tcl_DStringFree(&ds);
    if (result == 0) {
	memcpy(sockaddrPtr, resPtr->ai_addr, sizeof(struct sockaddr_in));
	freeaddrinfo(resPtr);
	goto addPort;
    }

    /*
     * Ought to use gai_strerror() here...
     */

    switch (result) {
    case EAI_NONAME:
    case EAI_SERVICE:
#if defined(EAI_ADDRFAMILY) && EAI_ADDRFAMILY != EAI_NONAME
    case EAI_ADDRFAMILY:
#endif
#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
    case EAI_NODATA:
#endif
	*errorMsgPtr = gai_strerror(result);
	errno = EHOSTUNREACH;
	return 0;
    case EAI_SYSTEM:
	return 0;
    default:
	*errorMsgPtr = gai_strerror(result);
	errno = ENXIO;
	return 0;
    }
#else /* !HAVE_GETADDRINFO */
    struct in_addr addr;		/* For 64/32 bit madness */

    (void) memset(sockaddrPtr, '\0', sizeof(struct sockaddr_in));
    sockaddrPtr->sin_family = AF_INET;
    sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF));
    if (host == NULL) {
	addr.s_addr = INADDR_ANY;
    } else {
	struct hostent *hostent;	/* Host database entry */
	Tcl_DString ds;
	const char *native;

	if (host == NULL) {
	    native = NULL;
	} else {
	    native = Tcl_UtfToExternalDString(NULL, host, -1, &ds);
	}
	addr.s_addr = inet_addr(native);		/* INTL: Native. */

	/*
	 * This is 0xFFFFFFFF to ensure that it compares as a 32bit -1 on
	 * either 32 or 64 bits systems.
	 */

	if (addr.s_addr == 0xFFFFFFFF) {
	    hostent = TclpGetHostByName(native);	/* INTL: Native. */
	    if (hostent != NULL) {
		memcpy(&addr, hostent->h_addr_list[0],
			(size_t) hostent->h_length);
	    } else {
#ifdef	EHOSTUNREACH
		errno = EHOSTUNREACH;
#else /* !EHOSTUNREACH */
#ifdef ENXIO
		errno = ENXIO;
#endif /* ENXIO */
#endif /* EHOSTUNREACH */
		if (native != NULL) {
		    Tcl_DStringFree(&ds);
		}
		return 0;	/* Error. */
	    }
	}
	if (native != NULL) {
	    Tcl_DStringFree(&ds);
	}
    }

    /*
     * NOTE: On 64 bit machines the assignment below is rumored to not do the
     * right thing. Please report errors related to this if you observe
     * incorrect behavior on 64 bit machines such as DEC Alphas. Should we
     * modify this code to do an explicit memcpy?
     */

    sockaddrPtr->sin_addr.s_addr = addr.s_addr;
    return 1;			/* Success. */
#endif /* HAVE_GETADDRINFO */
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_OpenTcpClient --
 *
 *	Opens a TCP client socket and creates a channel around it.







|




<
<






|
>
|
>
|



|


<
|



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

|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
<
<
|
<
|
>
>
|
|
|
|
<
|
<
>
|
|
<
<
<
<
|
<
|
<
>

<
|
<
<
<
<
|
<
>
|
>
|
|
<
|


>
>
|
|
|
|
<
|
<
<
|
|
|
|
|
|
>
|
|
|
>
>
>
|
>
>
>
>

<



















|
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







855
856
857
858
859
860
861
862
863
864
865
866


867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883

884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930


931

932
933
934
935
936
937
938

939

940
941
942




943

944

945
946

947




948

949
950
951
952
953

954
955
956
957
958
959
960
961
962

963


964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982

983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005







































1006
1007









































































































1008
1009
1010
1011
1012
1013
1014
 * Side effects:
 *	Opens a socket.
 *
 *----------------------------------------------------------------------
 */

static TcpState *
CreateClientSocket(
    Tcl_Interp *interp,		/* For error reporting; can be NULL. */
    int port,			/* Port number to open. */
    const char *host,		/* Name of host on which to open port. NULL
				 * implies INADDR_ANY */


    const char *myaddr,		/* Optional client-side address */
    int myport,			/* Optional client-side port */
    int async)			/* If nonzero and creating a client socket,
				 * attempt to do an async connect. Otherwise
				 * do a synchronous connect or bind. */
{
    int status = -1, connected = 0, sock = -1;
    struct addrinfo *addrlist = NULL, *addrPtr;
                                /* Socket address */
    struct addrinfo *myaddrlist = NULL, *myaddrPtr;
                                /* Socket address for client */
    TcpState *statePtr;
    const char *errorMsg = NULL;

    if (!TclCreateSocketAddress(interp, &addrlist, host, port, 0, &errorMsg)) {
	goto error;
    }

    if (!TclCreateSocketAddress(interp, &myaddrlist, myaddr, myport, 1, &errorMsg)) {
	goto error;
    }

    for (myaddrPtr = myaddrlist; myaddrPtr != NULL;
            myaddrPtr = myaddrPtr->ai_next) {
	for (addrPtr = addrlist; addrPtr != NULL;
                addrPtr = addrPtr->ai_next) {
            int reuseaddr;

	    /*
	     * No need to try combinations of local and remote addresses of
	     * different families.
	     */

	    if (myaddrPtr->ai_family != addrPtr->ai_family) {
		continue;
	    }

	    /*
	     * Attempt to connect. The connect may fail at present with an
	     * EINPROGRESS but at a later time it will complete. The caller
	     * will set up a file handler on the socket if she is interested
	     * in being informed when the connect completes.
	     */
	    
	    sock = socket(myaddrPtr->ai_family, SOCK_STREAM, 0);
	    if (sock < 0) {
		continue;
	    }

	    /*
	     * Set the close-on-exec flag so that the socket will not get
	     * inherited by child processes.
	     */
	    
	    fcntl(sock, F_SETFD, FD_CLOEXEC);
	    
	    /*
	     * Set kernel space buffering
	     */
	    
	    TclSockMinimumBuffers(sock, SOCKET_BUFSIZE);
    
	    if (async) {
		status = TclUnixSetBlockingMode(sock, TCL_MODE_NONBLOCKING);
		if (status < 0) {


		    goto looperror;

		}
	    }

            reuseaddr = 1;
            (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                    (char *) &reuseaddr, sizeof(reuseaddr));
            status = bind(sock, myaddrPtr->ai_addr, myaddrPtr->ai_addrlen);

            if (status < 0) {

                goto looperror;
            }





	    status = connect(sock, addrPtr->ai_addr, addrPtr->ai_addrlen);

	    if (status < 0 && errno == EINPROGRESS) {

		status = 0;
	    }

	    if (status == 0) {




		connected = 1;

		break;
	    }
	looperror:
	    if (sock != -1) {
		close(sock);

		sock = -1;
	    }
	}
	if (connected) {
	    break;
	} 
	status = -1;
	if (sock >= 0) {
	    close(sock);

	    sock = -1;


	}
    }
    if (async) {
	/*
	 * Restore blocking mode.
	 */

	status = TclUnixSetBlockingMode(sock, TCL_MODE_BLOCKING);
    }

error:
    if (addrlist) {
	freeaddrinfo(addrlist);
    }
    if (myaddrlist) {
	freeaddrinfo(myaddrlist);
    }
    
    if (status < 0) {

	if (interp != NULL) {
	    Tcl_AppendResult(interp, "couldn't open socket: ",
		    Tcl_PosixError(interp), NULL);
	    if (errorMsg != NULL) {
		Tcl_AppendResult(interp, " (", errorMsg, ")", NULL);
	    }
	}
	if (sock != -1) {
	    close(sock);
	}
	return NULL;
    }

    /*
     * Allocate a new TcpState for this socket.
     */

    statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState));
    statePtr->flags = async ? TCP_ASYNC_CONNECT : 0;
    statePtr->fds = (TcpFdList *) ckalloc((unsigned) sizeof(TcpFdList));
    memset(statePtr->fds, (int) 0, sizeof(TcpFdList));
    statePtr->fds->fd = sock;








































    return statePtr;
}










































































































/*
 *----------------------------------------------------------------------
 *
 * Tcl_OpenTcpClient --
 *
 *	Opens a TCP client socket and creates a channel around it.
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
    TcpState *statePtr;
    char channelName[16 + TCL_INTEGER_SPACE];

    /*
     * Create a new client socket and wrap it in a channel.
     */

    statePtr = CreateSocket(interp, port, host, 0, myaddr, myport, async);
    if (statePtr == NULL) {
	return NULL;
    }

    statePtr->acceptProc = NULL;
    statePtr->acceptProcData = NULL;

    sprintf(channelName, "sock%d", statePtr->fd);

    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE));
    if (Tcl_SetChannelOption(interp, statePtr->channel, "-translation",
	    "auto crlf") == TCL_ERROR) {
	Tcl_Close(NULL, statePtr->channel);
	return NULL;
    }
    return statePtr->channel;
}







|







|


|







1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
    TcpState *statePtr;
    char channelName[16 + TCL_INTEGER_SPACE];

    /*
     * Create a new client socket and wrap it in a channel.
     */

    statePtr = CreateClientSocket(interp, port, host, myaddr, myport, async);
    if (statePtr == NULL) {
	return NULL;
    }

    statePtr->acceptProc = NULL;
    statePtr->acceptProcData = NULL;

    sprintf(channelName, "sock%d", statePtr->fds->fd);

    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    statePtr, (TCL_READABLE | TCL_WRITABLE));
    if (Tcl_SetChannelOption(interp, statePtr->channel, "-translation",
	    "auto crlf") == TCL_ERROR) {
	Tcl_Close(NULL, statePtr->channel);
	return NULL;
    }
    return statePtr->channel;
}
1189
1190
1191
1192
1193
1194
1195


1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
    int mode)			/* ORed combination of TCL_READABLE and
				 * TCL_WRITABLE to indicate file mode. */
{
    TcpState *statePtr;
    char channelName[16 + TCL_INTEGER_SPACE];

    statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState));


    statePtr->fd = PTR2INT(sock);
    statePtr->flags = 0;
    statePtr->acceptProc = NULL;
    statePtr->acceptProcData = NULL;

    sprintf(channelName, "sock%d", statePtr->fd);

    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    (ClientData) statePtr, mode);
    if (Tcl_SetChannelOption(NULL, statePtr->channel, "-translation",
	    "auto crlf") == TCL_ERROR) {
	Tcl_Close(NULL, statePtr->channel);
	return NULL;
    }
    return statePtr->channel;
}







>
>
|




|


|







1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
    int mode)			/* ORed combination of TCL_READABLE and
				 * TCL_WRITABLE to indicate file mode. */
{
    TcpState *statePtr;
    char channelName[16 + TCL_INTEGER_SPACE];

    statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState));
    statePtr->fds = (TcpFdList *) ckalloc((unsigned) sizeof(TcpFdList));
    memset(statePtr->fds, (int) 0, sizeof(TcpFdList));
    statePtr->fds->fd = PTR2INT(sock);
    statePtr->flags = 0;
    statePtr->acceptProc = NULL;
    statePtr->acceptProcData = NULL;

    sprintf(channelName, "sock%d", statePtr->fds->fd);

    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    statePtr, mode);
    if (Tcl_SetChannelOption(NULL, statePtr->channel, "-translation",
	    "auto crlf") == TCL_ERROR) {
	Tcl_Close(NULL, statePtr->channel);
	return NULL;
    }
    return statePtr->channel;
}
1233
1234
1235
1236
1237
1238
1239


1240
1241


1242










1243



1244




1245
1246

1247
































1248






1249




1250


1251















1252
1253







1254
1255
1256
1257
1258
1259
1260

1261




1262
1263
1264
1265












1266
1267
1268
1269
1270
1271
1272
    int port,			/* Port number to open. */
    const char *myHost,		/* Name of local host. */
    Tcl_TcpAcceptProc *acceptProc,
				/* Callback for accepting connections from new
				 * clients. */
    ClientData acceptProcData)	/* Data for the callback. */
{


    TcpState *statePtr;
    char channelName[16 + TCL_INTEGER_SPACE];













    /*



     * Create a new client socket and wrap it in a channel.




     */


    statePtr = CreateSocket(interp, port, myHost, 1, NULL, 0, 0);
































    if (statePtr == NULL) {






	return NULL;




    }


















    statePtr->acceptProc = acceptProc;
    statePtr->acceptProcData = acceptProcData;








    /*
     * Set up the callback mechanism for accepting connections from new
     * clients.
     */

    Tcl_CreateFileHandler(statePtr->fd, TCL_READABLE, TcpAccept,

	    (ClientData) statePtr);




    sprintf(channelName, "sock%d", statePtr->fd);
    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    (ClientData) statePtr, 0);
    return statePtr->channel;












}

/*
 *----------------------------------------------------------------------
 *
 * TcpAccept --
 *	Accept a TCP socket connection.	 This is called by the event loop.







>
>
|

>
>

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







1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
    int port,			/* Port number to open. */
    const char *myHost,		/* Name of local host. */
    Tcl_TcpAcceptProc *acceptProc,
				/* Callback for accepting connections from new
				 * clients. */
    ClientData acceptProcData)	/* Data for the callback. */
{
    int status = 0, sock = -1, reuseaddr = 1, chosenport = 0;
    struct addrinfo *addrlist = NULL, *addrPtr;	/* socket address */
    TcpState *statePtr = NULL;
    char channelName[16 + TCL_INTEGER_SPACE];
    const char *errorMsg = NULL;
    TcpFdList *fds = NULL, *newfds;

    if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) {
	goto error;
    }

    for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) {
	sock = socket(addrPtr->ai_family, SOCK_STREAM, 0);
	if (sock == -1) {
	    continue;
	}
	
	/*
	 * Set the close-on-exec flag so that the socket will not get
	 * inherited by child processes.
	 */
	
	fcntl(sock, F_SETFD, FD_CLOEXEC);
	
	/*
	 * Set kernel space buffering
	 */
	
	TclSockMinimumBuffers(sock, SOCKET_BUFSIZE);
	
	/*
	 * Set up to reuse server addresses automatically and bind to the
	 * specified port.
	 */
	
	(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 
		(char *) &reuseaddr, sizeof(reuseaddr));
	
        /*
         * Make sure we use the same port when opening two server sockets for
         * IPv4 and IPv6.
         *
         * As sockaddr_in6 uses the same offset and size for the port member
         * as sockaddr_in, we can handle both through the IPv4 API.
         */

	if (port == 0 && chosenport != 0) {
	    ((struct sockaddr_in *) addrPtr->ai_addr)->sin_port =
                    htons(chosenport);
	}

#ifdef IPV6_V6ONLY
	/* Missing on: Solaris 2.8 */
        if (addrPtr->ai_family == AF_INET6) {
            int v6only = 1;

            (void) setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
                    &v6only, sizeof(v6only));
        }
#endif

	status = bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen);
        if (status == -1) {
            close(sock);
            continue;
        }
        if (port == 0 && chosenport == 0) {
            address sockname;
            socklen_t namelen = sizeof(sockname);

            /*
             * Synchronize port numbers when binding to port 0 of multiple
             * addresses.
             */

            if (getsockname(sock, &sockname.sa, &namelen) >= 0) {
                chosenport = ntohs(sockname.sa4.sin_port);
            }
        }
        status = listen(sock, SOMAXCONN);
        if (status < 0) {
            close(sock);
            continue;
        }
        newfds = (TcpFdList *) ckalloc((unsigned) sizeof(TcpFdList));
        memset(newfds, (int) 0, sizeof(TcpFdList));
        if (statePtr == NULL) {
            /*
             * Allocate a new TcpState for this socket.
             */
            
            statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState));
            statePtr->fds = newfds;
            statePtr->acceptProc = acceptProc;
            statePtr->acceptProcData = acceptProcData;
            sprintf(channelName, "sock%d", sock);
        } else {
            fds->next = newfds;
        }
        newfds->fd = sock;
        newfds->statePtr = statePtr;
        fds = newfds;
	
        /*
         * Set up the callback mechanism for accepting connections from new
         * clients.
         */
        
        Tcl_CreateFileHandler(sock, TCL_READABLE, TcpAccept, fds);
    }

  error:
    if (addrlist != NULL) {
	freeaddrinfo(addrlist);
    }
    if (statePtr != NULL) {
	statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
		statePtr, 0);
	return statePtr->channel;
    }
    if (interp != NULL) {
	Tcl_AppendResult(interp, "couldn't open socket: ",
		Tcl_PosixError(interp), NULL);
	if (errorMsg != NULL) {
	    Tcl_AppendResult(interp, " (", errorMsg, ")", NULL);
	}
    }
    if (sock != -1) {
	close(sock);
    }
    return NULL;
}

/*
 *----------------------------------------------------------------------
 *
 * TcpAccept --
 *	Accept a TCP socket connection.	 This is called by the event loop.
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295

1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314


1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326


1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337


1338
1339

	/* ARGSUSED */
static void
TcpAccept(
    ClientData data,		/* Callback token. */
    int mask)			/* Not used. */
{
    TcpState *sockState;	/* Client data of server socket. */
    int newsock;		/* The new client socket */
    TcpState *newSockState;	/* State for new socket. */
    struct sockaddr_in addr;	/* The remote address */
    socklen_t len;		/* For accept interface */
    char channelName[16 + TCL_INTEGER_SPACE];


    sockState = (TcpState *) data;

    len = sizeof(struct sockaddr_in);
    newsock = accept(sockState->fd, (struct sockaddr *) &addr, &len);
    if (newsock < 0) {
	return;
    }

    /*
     * Set close-on-exec flag to prevent the newly accepted socket from being
     * inherited by child processes.
     */

    (void) fcntl(newsock, F_SETFD, FD_CLOEXEC);

    newSockState = (TcpState *) ckalloc((unsigned) sizeof(TcpState));

    newSockState->flags = 0;


    newSockState->fd = newsock;
    newSockState->acceptProc = NULL;
    newSockState->acceptProcData = NULL;

    sprintf(channelName, "sock%d", newsock);
    newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    (ClientData) newSockState, (TCL_READABLE | TCL_WRITABLE));

    Tcl_SetChannelOption(NULL, newSockState->channel, "-translation",
	    "auto crlf");

    if (sockState->acceptProc != NULL) {


	sockState->acceptProc(sockState->acceptProcData,
		newSockState->channel, inet_ntoa(addr.sin_addr),
		ntohs(addr.sin_port));
    }
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78


 * End:
 */







|


|


>
|
|

|
|














>
>
|





|




|
>
>
|
|
<








>
>


1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358

1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370

	/* ARGSUSED */
static void
TcpAccept(
    ClientData data,		/* Callback token. */
    int mask)			/* Not used. */
{
    TcpFdList *fds;		/* Client data of server socket. */
    int newsock;		/* The new client socket */
    TcpState *newSockState;	/* State for new socket. */
    address addr;		/* The remote address */
    socklen_t len;		/* For accept interface */
    char channelName[16 + TCL_INTEGER_SPACE];
    char host[NI_MAXHOST], port[NI_MAXSERV];
    
    fds = (TcpFdList *) data;

    len = sizeof(addr);
    newsock = accept(fds->fd, &(addr.sa), &len);
    if (newsock < 0) {
	return;
    }

    /*
     * Set close-on-exec flag to prevent the newly accepted socket from being
     * inherited by child processes.
     */

    (void) fcntl(newsock, F_SETFD, FD_CLOEXEC);

    newSockState = (TcpState *) ckalloc((unsigned) sizeof(TcpState));

    newSockState->flags = 0;
    newSockState->fds = (TcpFdList *) ckalloc(sizeof(TcpFdList));
    memset(newSockState->fds, (int) 0, sizeof(TcpFdList));
    newSockState->fds->fd = newsock;
    newSockState->acceptProc = NULL;
    newSockState->acceptProcData = NULL;

    sprintf(channelName, "sock%d", newsock);
    newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    newSockState, (TCL_READABLE | TCL_WRITABLE));

    Tcl_SetChannelOption(NULL, newSockState->channel, "-translation",
	    "auto crlf");

    if (fds->statePtr->acceptProc != NULL) {
	getnameinfo(&(addr.sa), len, host, sizeof(host), port, sizeof(port),
                NI_NUMERICHOST|NI_NUMERICSERV);
	fds->statePtr->acceptProc(fds->statePtr->acceptProcData,
                newSockState->channel, host, atoi(port));

    }
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * tab-width: 8
 * indent-tabs-mode: nil
 * End:
 */