Check-in [1555a1857d]
Not logged in

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

Overview
Comment:merge trunk
Timelines: family | ancestors | descendants | both | internal-ensemble-cleanup
Files: files | file ages | folders
SHA3-256: 1555a1857dda0c77900497fb714a41296495a547742a2764a51c8add9f4202ba
User & Date: dkf 2025-09-25 19:07:30.917
Context
2025-10-30
11:55
merge trunk check-in: aae841a4d3 user: dkf tags: internal-ensemble-cleanup
2025-09-26
14:14
modernise how the memory command works (the removal of [memory display] was documented in Tcl 8.4's ... Leaf check-in: 50416ae0d5 user: dkf tags: modernise-memory-command
2025-09-25
19:07
merge trunk check-in: 1555a1857d user: dkf tags: internal-ensemble-cleanup
14:03
merge 9.0 check-in: e360c5a082 user: sebres tags: trunk, main
2025-09-16
08:04
merge trunk check-in: d63cf48838 user: dkf tags: internal-ensemble-cleanup
Changes
Unified Diff Ignore Whitespace Patch
Changes to doc/define.n.
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
method \fIshould not\fR return an error unless it is called from outside a
definition context or with the wrong number of arguments; unresolvable
arguments should be returned as is (as not all slot operations strictly
require that values are resolvable to work).
.RS
.PP
Implementations \fIshould not\fR enforce uniqueness and ordering constraints
in this method; that is the responsibility of the \fBSet\fR method.


.RE
.VE TIP516
.\" METHOD: Resolve
.TP
\fIslot\fR \fBResolve \fIelement\fR
.VS
This converts an element of the slotted collection into its resolved form; for
a simple value, it could just return the value, but for a slot that contains
references to commands or classes it should convert those into their
fully-qualified forms (so they can be compared with \fBstring equals\fR): that
could be done by forwarding to \fBnamespace which\fR or similar.
.VE
.\" METHOD: Set
.TP
\fIslot\fR \fBSet \fIelementList\fR
.
Sets the contents of the slot to the list \fIelementList\fR and returns the
empty string. This method must always be called from a stack frame created by
a call to \fBoo::define\fR or \fBoo::objdefine\fR. This method may return an







|
>
>


<
<
<
<
<
<
<
<
<
<







603
604
605
606
607
608
609
610
611
612
613
614










615
616
617
618
619
620
621
method \fIshould not\fR return an error unless it is called from outside a
definition context or with the wrong number of arguments; unresolvable
arguments should be returned as is (as not all slot operations strictly
require that values are resolvable to work).
.RS
.PP
Implementations \fIshould not\fR enforce uniqueness and ordering constraints
in this method; that is the responsibility of the \fBSet\fR method. A default
implementation of this method (that just returns its \fIslotElement\fR
argument) is provided in the \fBoo::Slot\fR class.
.RE
.VE TIP516










.\" METHOD: Set
.TP
\fIslot\fR \fBSet \fIelementList\fR
.
Sets the contents of the slot to the list \fIelementList\fR and returns the
empty string. This method must always be called from a stack frame created by
a call to \fBoo::define\fR or \fBoo::objdefine\fR. This method may return an
Changes to doc/interp.n.
386
387
388
389
390
391
392










393
394
395
396
397
398
399
The command sets the maximum size of the Tcl call stack only. It cannot
by itself prevent stack overflows on the C stack being used by the
application. If your machine has a limit on the size of the C stack, you
may get stack overflows before reaching the limit set by the command. If
this happens, see if there is a mechanism in your system for increasing
the maximum size of the C stack.
.RE










.\" METHOD: share
.TP
\fBinterp share\fI srcPath channel destPath\fR
.
Causes the IO channel identified by \fIchannel\fR to become shared
between the interpreter identified by \fIsrcPath\fR and the interpreter
identified by \fIdestPath\fR. Both interpreters have the same permissions







>
>
>
>
>
>
>
>
>
>







386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
The command sets the maximum size of the Tcl call stack only. It cannot
by itself prevent stack overflows on the C stack being used by the
application. If your machine has a limit on the size of the C stack, you
may get stack overflows before reaching the limit set by the command. If
this happens, see if there is a mechanism in your system for increasing
the maximum size of the C stack.
.RE
.\" METHOD: set
.TP
\fBinterp set\fI path varName\fR ?\fIvalue\fR?
.VS 9.1
Writes to, or reads from, the variable \fIvarName\fR in the interpreter
specifed by \fIpath\fR. If \fIvalue\fR is given, writes to the variable and
returns its new value; if \fIvalue\fR is omitted, reads from the variable.
As with the \fBset\fR command, traces may affect what the value of the
variable is.
.VE 9.1
.\" METHOD: share
.TP
\fBinterp share\fI srcPath channel destPath\fR
.
Causes the IO channel identified by \fIchannel\fR to become shared
between the interpreter identified by \fIsrcPath\fR and the interpreter
identified by \fIdestPath\fR. Both interpreters have the same permissions
597
598
599
600
601
602
603











604
605
606
607
608
609
610
The command sets the maximum size of the Tcl call stack only. It cannot
by itself prevent stack overflows on the C stack being used by the
application. If your machine has a limit on the size of the C stack, you
may get stack overflows before reaching the limit set by the command. If
this happens, see if there is a mechanism in your system for increasing
the maximum size of the C stack.
.RE











.SH "SAFE INTERPRETERS"
.PP
A safe interpreter is one with restricted functionality, so that
is safe to execute an arbitrary script from your worst enemy without
fear of that script damaging the enclosing application or the rest
of your computing environment.  In order to make an interpreter
safe, certain commands and variables are removed from the interpreter.







>
>
>
>
>
>
>
>
>
>
>







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
The command sets the maximum size of the Tcl call stack only. It cannot
by itself prevent stack overflows on the C stack being used by the
application. If your machine has a limit on the size of the C stack, you
may get stack overflows before reaching the limit set by the command. If
this happens, see if there is a mechanism in your system for increasing
the maximum size of the C stack.
.RE
.RE
.\" METHOD: set
.TP
\fIchild \fBset\fR \fIvarName\fR ?\fIvalue\fR?
.VS 9.1
Writes to, or reads from, the variable \fIvarName\fR in the \fIchild\fR
interpreter. If \fIvalue\fR is given, writes to the variable and
returns its new value; if \fIvalue\fR is omitted, reads from the variable.
As with the \fBset\fR command, traces may affect what the value of the
variable is.
.VE 9.1
.SH "SAFE INTERPRETERS"
.PP
A safe interpreter is one with restricted functionality, so that
is safe to execute an arbitrary script from your worst enemy without
fear of that script damaging the enclosing application or the rest
of your computing environment.  In order to make an interpreter
safe, certain commands and variables are removed from the interpreter.
Changes to doc/library.n.
227
228
229
230
231
232
233

234
235
236
237
238
239
240
their initialization.  They call this procedure to look for their
script library in several standard directories.
The last component of the name of the library directory is
normally \fIbasenameversion\fR
(e.g., tk8.0), but it might be
.QW library
when in the build hierarchies.

The \fIinitScript\fR file will be sourced into the interpreter
once it is found.  The directory in which this file is found is
stored into the global variable \fIvarName\fR.
If this variable is already defined (e.g., by C code during
application initialization) then no searching is done.
Otherwise the search looks in these directories:
the directory named by the environment variable \fIenVarName\fR;







>







227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
their initialization.  They call this procedure to look for their
script library in several standard directories.
The last component of the name of the library directory is
normally \fIbasenameversion\fR
(e.g., tk8.0), but it might be
.QW library
when in the build hierarchies.
The \fIpatch\fR argument is not used.
The \fIinitScript\fR file will be sourced into the interpreter
once it is found.  The directory in which this file is found is
stored into the global variable \fIvarName\fR.
If this variable is already defined (e.g., by C code during
application initialization) then no searching is done.
Otherwise the search looks in these directories:
the directory named by the environment variable \fIenVarName\fR;
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
.\" VARIABLE: tcl_nonwordchars
.TP
\fBtcl_nonwordchars\fR
.
This variable contains a regular expression that is used by routines
like \fBtcl_endOfWord\fR to identify whether a character is part of a
word or not.  If the pattern matches a character, the character is
considered to be a non-word character. The default value is \fB\eW\fR.
.\" VARIABLE: tcl_wordchars
.TP
\fBtcl_wordchars\fR
.
This variable contains a regular expression that is used by routines
like \fBtcl_endOfWord\fR to identify whether a character is part of a
word or not.  If the pattern matches a character, the character is
considered to be a word character. The default value is \fB\ew\fR.
.SH "SEE ALSO"
env(n), info(n), re_syntax(n)
.SH KEYWORDS
auto-exec, auto-load, library, unknown, word, whitespace
'\"Local Variables:
'\"mode: nroff
'\"End:







|







|







470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
.\" VARIABLE: tcl_nonwordchars
.TP
\fBtcl_nonwordchars\fR
.
This variable contains a regular expression that is used by routines
like \fBtcl_endOfWord\fR to identify whether a character is part of a
word or not.  If the pattern matches a character, the character is
considered to be a non-word character.  The default value is \fB\eW\fR.
.\" VARIABLE: tcl_wordchars
.TP
\fBtcl_wordchars\fR
.
This variable contains a regular expression that is used by routines
like \fBtcl_endOfWord\fR to identify whether a character is part of a
word or not.  If the pattern matches a character, the character is
considered to be a word character.  The default value is \fB\ew\fR.
.SH "SEE ALSO"
env(n), info(n), re_syntax(n)
.SH KEYWORDS
auto-exec, auto-load, library, unknown, word, whitespace
'\"Local Variables:
'\"mode: nroff
'\"End:
Changes to doc/switch.n.
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
.TH switch n 8.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
switch \- Evaluate one of several scripts, depending on a given value
.SH SYNOPSIS
\fBswitch \fR?\fIoptions\fR?\fI string pattern body \fR?\fIpattern body \fR...?
.sp
\fBswitch \fR?\fIoptions\fR?\fI string \fR{\fIpattern body \fR?\fIpattern body \fR...?}
.BE
.SH DESCRIPTION
.PP
The \fBswitch\fR command matches its \fIstring\fR argument against each of
the \fIpattern\fR arguments in order.
As soon as it finds a \fIpattern\fR that matches \fIstring\fR it
evaluates the following \fIbody\fR argument by passing it recursively
to the Tcl interpreter and returns the result of that evaluation.
If the last \fIpattern\fR argument is \fBdefault\fR then it matches
anything.
If no \fIpattern\fR argument
matches \fIstring\fR and no default is given, then the \fBswitch\fR
command returns an empty string.
.PP
If the initial arguments to \fBswitch\fR start with \fB\-\fR then
they are treated as options
unless there are exactly two arguments to \fBswitch\fR (in which case the
first must the \fIstring\fR and the second must be the
\fIpattern\fR/\fIbody\fR list).
The following options are currently supported:
.\" OPTION: -exact
.TP 10
\fB\-exact\fR
.
Use exact matching when comparing \fIstring\fR to a pattern.  This
is the default.
.\" OPTION: -glob
.TP 10
\fB\-glob\fR
.
When matching \fIstring\fR to the patterns, use glob-style matching
(i.e. the same as implemented by the \fBstring match\fR command).









.\" OPTION: -regexp
.TP 10
\fB\-regexp\fR
.
When matching \fIstring\fR to the patterns, use regular
expression matching
(as described in the \fBre_syntax\fR reference page).
.\" OPTION: -nocase
.TP 10
\fB\-nocase\fR
.
Causes comparisons to be handled in a case-insensitive manner.

.\" OPTION: -matchvar
.TP 10
\fB\-matchvar\fI varName\fR
.
This option (only legal when \fB\-regexp\fR is also specified)
specifies the name of a variable into which the list of matches
found by the regular expression engine will be written.  The first
element of the list written will be the overall substring of the input
string (i.e. the \fIstring\fR argument to \fBswitch\fR) matched, the
second element of the list will be the substring matched by the first
capturing parenthesis in the regular expression that matched, and so
on.  When a \fBdefault\fR branch is taken, the variable will have the
empty list written to it.  This option may be specified at the same
time as the \fB\-indexvar\fR option.
.\" OPTION: -indexvar
.TP 10
\fB\-indexvar\fI varName\fR
.
This option (only legal when \fB\-regexp\fR is also specified)
specifies the name of a variable into which the list of indices
referring to matching substrings
found by the regular expression engine will be written.  The first
element of the list written will be a two-element list specifying the
index of the start and index of the first character after the end of
the overall substring of the input
string (i.e. the \fIstring\fR argument to \fBswitch\fR) matched, in a
similar way to the \fB\-indices\fR option to the \fBregexp\fR can
obtain.  Similarly, the second element of the list refers to the first
capturing parenthesis in the regular expression that matched, and so
on.  When a \fBdefault\fR branch is taken, the variable will have the
empty list written to it.  This option may be specified at the same
time as the \fB\-matchvar\fR option.
.\" OPTION: --
.TP 10
\fB\-\|\-\fR
.
Marks the end of options.  The argument following this one will
be treated as \fIstring\fR even if it starts with a \fB\-\fR.
This is not required when the matching patterns and bodies are grouped
together in a single argument.
.PP
Two syntaxes are provided for the \fIpattern\fR and \fIbody\fR arguments.
The first uses a separate argument for each of the patterns and commands;
this form is convenient if substitutions are desired on some of the
patterns or commands.







|

|



|

|





|





|






|





|

>
>
>
>
>
>
>
>
>




|







>








|
















|











|







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
.TH switch n 8.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
switch \- Evaluate one of several scripts, depending on a given value
.SH SYNOPSIS
\fBswitch \fR?\fIoptions\fR?\fI value pattern body \fR?\fIpattern body \fR...?
.sp
\fBswitch \fR?\fIoptions\fR?\fI value \fR{\fIpattern body \fR?\fIpattern body \fR...?}
.BE
.SH DESCRIPTION
.PP
The \fBswitch\fR command matches its \fIvalue\fR argument against each of
the \fIpattern\fR arguments in order.
As soon as it finds a \fIpattern\fR that matches \fIvalue\fR it
evaluates the following \fIbody\fR argument by passing it recursively
to the Tcl interpreter and returns the result of that evaluation.
If the last \fIpattern\fR argument is \fBdefault\fR then it matches
anything.
If no \fIpattern\fR argument
matches \fIvalue\fR and no default is given, then the \fBswitch\fR
command returns an empty string.
.PP
If the initial arguments to \fBswitch\fR start with \fB\-\fR then
they are treated as options
unless there are exactly two arguments to \fBswitch\fR (in which case the
first must the \fIvalue\fR and the second must be the
\fIpattern\fR/\fIbody\fR list).
The following options are currently supported:
.\" OPTION: -exact
.TP 10
\fB\-exact\fR
.
Use exact matching when comparing \fIvalue\fR to a pattern.  This
is the default.
.\" OPTION: -glob
.TP 10
\fB\-glob\fR
.
When matching \fIvalue\fR to the patterns, use glob-style matching
(i.e. the same as implemented by the \fBstring match\fR command).
.\" OPTION: -integer
.TP 10
\fB\-integer\fR
.VS 9.1
.\" TIP #730
When matching \fIvalue\fR to the patterns, use integer comparisons. Note
that this makes using a non-integer \fIvalue\fR or \fIpattern\fR (other
than a final \fBdefault\fR) into an error.
.VE 9.1
.\" OPTION: -regexp
.TP 10
\fB\-regexp\fR
.
When matching \fIvalue\fR to the patterns, use regular
expression matching
(as described in the \fBre_syntax\fR reference page).
.\" OPTION: -nocase
.TP 10
\fB\-nocase\fR
.
Causes comparisons to be handled in a case-insensitive manner.
Not supported with the \fB\-integer\fR option.
.\" OPTION: -matchvar
.TP 10
\fB\-matchvar\fI varName\fR
.
This option (only legal when \fB\-regexp\fR is also specified)
specifies the name of a variable into which the list of matches
found by the regular expression engine will be written.  The first
element of the list written will be the overall substring of the input
string (i.e. the \fIvalue\fR argument to \fBswitch\fR) matched, the
second element of the list will be the substring matched by the first
capturing parenthesis in the regular expression that matched, and so
on.  When a \fBdefault\fR branch is taken, the variable will have the
empty list written to it.  This option may be specified at the same
time as the \fB\-indexvar\fR option.
.\" OPTION: -indexvar
.TP 10
\fB\-indexvar\fI varName\fR
.
This option (only legal when \fB\-regexp\fR is also specified)
specifies the name of a variable into which the list of indices
referring to matching substrings
found by the regular expression engine will be written.  The first
element of the list written will be a two-element list specifying the
index of the start and index of the first character after the end of
the overall substring of the input
string (i.e. the \fIvalue\fR argument to \fBswitch\fR) matched, in a
similar way to the \fB\-indices\fR option to the \fBregexp\fR can
obtain.  Similarly, the second element of the list refers to the first
capturing parenthesis in the regular expression that matched, and so
on.  When a \fBdefault\fR branch is taken, the variable will have the
empty list written to it.  This option may be specified at the same
time as the \fB\-matchvar\fR option.
.\" OPTION: --
.TP 10
\fB\-\|\-\fR
.
Marks the end of options.  The argument following this one will
be treated as \fIvalue\fR even if it starts with a \fB\-\fR.
This is not required when the matching patterns and bodies are grouped
together in a single argument.
.PP
Two syntaxes are provided for the \fIpattern\fR and \fIbody\fR arguments.
The first uses a separate argument for each of the patterns and commands;
this form is convenient if substitutions are desired on some of the
patterns or commands.
180
181
182
183
184
185
186




















187
188
189
190
191
192
193
    }
    d(e*)f(g*)h {
        puts "Found [string length [lindex $foo 1]] 'e's and\e
                [string length [lindex $foo 2]] 'g's"
    }
}
.CE




















.SH "SEE ALSO"
for(n), if(n), regexp(n)
.SH KEYWORDS
switch, match, regular expression
.\" Local Variables:
.\" mode: nroff
.\" End:







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







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
    }
    d(e*)f(g*)h {
        puts "Found [string length [lindex $foo 1]] 'e's and\e
                [string length [lindex $foo 2]] 'g's"
    }
}
.CE
.PP
.VS 9.1
Deciding what to do with a procedure based on the number of arguments:
.PP
.CS
proc example args {
    \fBswitch\fR -integer -- [llength $args] {
        0 {
            puts "no arguments"
        }
        1 {
            puts "one argument: [lindex $args 0]"
        }
        default {
            puts "many arguments: $args"
        }
    }
}
.CE
.VE 9.1
.SH "SEE ALSO"
for(n), if(n), regexp(n)
.SH KEYWORDS
switch, match, regular expression
.\" Local Variables:
.\" mode: nroff
.\" End:
Changes to generic/tcl.h.
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
			    Tcl_LibraryInitProc *initProc,
			    Tcl_LibraryInitProc *safeInitProc);
#ifndef TCL_NO_DEPRECATED
#   define Tcl_StaticPackage Tcl_StaticLibrary
#endif
EXTERN Tcl_ExitProc *	Tcl_SetExitProc(Tcl_ExitProc *proc);
#ifdef _WIN32
EXTERN const char *TclZipfs_AppHook(int *argc, wchar_t ***argv);
#else
EXTERN const char *TclZipfs_AppHook(int *argc, char ***argv);
#endif
#if defined(_WIN32) && defined(UNICODE)
#ifndef USE_TCL_STUBS
#   define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg)))
#endif
#   define Tcl_MainEx Tcl_MainExW
    EXTERN TCL_NORETURN void Tcl_MainExW(Tcl_Size argc, wchar_t **argv,
	    Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);
#endif
#if defined(USE_TCL_STUBS)
#define Tcl_SetPanicProc(panicProc) \
    TclInitStubTable(((const char *(*)(Tcl_PanicProc *))TclStubCall((void *)panicProc))(panicProc))
#define Tcl_InitSubsystems() \
    TclInitStubTable(((const char *(*)(void))TclStubCall((void *)1))())







|








|







2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
			    Tcl_LibraryInitProc *initProc,
			    Tcl_LibraryInitProc *safeInitProc);
#ifndef TCL_NO_DEPRECATED
#   define Tcl_StaticPackage Tcl_StaticLibrary
#endif
EXTERN Tcl_ExitProc *	Tcl_SetExitProc(Tcl_ExitProc *proc);
#ifdef _WIN32
EXTERN const char *TclZipfs_AppHook(int *argc, unsigned short ***argv);
#else
EXTERN const char *TclZipfs_AppHook(int *argc, char ***argv);
#endif
#if defined(_WIN32) && defined(UNICODE)
#ifndef USE_TCL_STUBS
#   define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg)))
#endif
#   define Tcl_MainEx Tcl_MainExW
    EXTERN TCL_NORETURN void Tcl_MainExW(Tcl_Size argc, unsigned short **argv,
	    Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);
#endif
#if defined(USE_TCL_STUBS)
#define Tcl_SetPanicProc(panicProc) \
    TclInitStubTable(((const char *(*)(Tcl_PanicProc *))TclStubCall((void *)panicProc))(panicProc))
#define Tcl_InitSubsystems() \
    TclInitStubTable(((const char *(*)(void))TclStubCall((void *)1))())
Changes to generic/tclBasic.c.
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
     * otherwise, we always put it in the global namespace.
     */

    if (strstr(cmdName, "::") != NULL) {
	Namespace *dummy1, *dummy2;

	TclGetNamespaceForQualName(interp, cmdName, NULL,
	    TCL_CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);
	if ((nsPtr == NULL) || (tail == NULL)) {
	    return (Tcl_Command) NULL;
	}
    } else {
	nsPtr = iPtr->globalNsPtr;
	tail = cmdName;
    }







|







2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
     * otherwise, we always put it in the global namespace.
     */

    if (strstr(cmdName, "::") != NULL) {
	Namespace *dummy1, *dummy2;

	TclGetNamespaceForQualName(interp, cmdName, NULL,
		TCL_CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);
	if ((nsPtr == NULL) || (tail == NULL)) {
	    return (Tcl_Command) NULL;
	}
    } else {
	nsPtr = iPtr->globalNsPtr;
	tail = cmdName;
    }
Changes to generic/tclClock.c.
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
			    TclDateFields *, Tcl_Size, Tcl_Obj *const[],
			    Tcl_WideInt *rangesVal);
static int		ConvertUTCToLocalUsingC(Tcl_Interp *,
			    TclDateFields *, int);
static int		ConvertLocalToUTC(ClockClientData *, Tcl_Interp *,
			    TclDateFields *, Tcl_Obj *timezoneObj, int);
static int		ConvertLocalToUTCUsingTable(Tcl_Interp *,
			    TclDateFields *, int, Tcl_Obj *const[],
			    Tcl_WideInt *rangesVal);
static int		ConvertLocalToUTCUsingC(Tcl_Interp *,
			    TclDateFields *, int);
static Tcl_ObjCmdProc	ClockConfigureObjCmd;
static void		GetYearWeekDay(TclDateFields *, int);
static void		GetGregorianEraYearDay(TclDateFields *, int);


static void		GetMonthDay(TclDateFields *);
static Tcl_WideInt	WeekdayOnOrBefore(int, Tcl_WideInt);
static Tcl_ObjCmdProc	ClockClicksObjCmd;
static Tcl_ObjCmdProc	ClockConvertlocaltoutcObjCmd;
static int		ClockGetDateFields(ClockClientData *,
			    Tcl_Interp *interp, TclDateFields *fields,
			    Tcl_Obj *timezoneObj, int changeover);


static Tcl_ObjCmdProc	ClockGetdatefieldsObjCmd;
static Tcl_ObjCmdProc	ClockGetjuliandayfromerayearmonthdayObjCmd;
static Tcl_ObjCmdProc	ClockGetjuliandayfromerayearweekdayObjCmd;
static Tcl_ObjCmdProc	ClockGetenvObjCmd;
static Tcl_ObjCmdProc	ClockMicrosecondsObjCmd;
static Tcl_ObjCmdProc	ClockMillisecondsObjCmd;
static Tcl_ObjCmdProc	ClockSecondsObjCmd;







|






>
>







>
>







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
			    TclDateFields *, Tcl_Size, Tcl_Obj *const[],
			    Tcl_WideInt *rangesVal);
static int		ConvertUTCToLocalUsingC(Tcl_Interp *,
			    TclDateFields *, int);
static int		ConvertLocalToUTC(ClockClientData *, Tcl_Interp *,
			    TclDateFields *, Tcl_Obj *timezoneObj, int);
static int		ConvertLocalToUTCUsingTable(Tcl_Interp *,
			    TclDateFields *, Tcl_Size, Tcl_Obj *const[],
			    Tcl_WideInt *rangesVal);
static int		ConvertLocalToUTCUsingC(Tcl_Interp *,
			    TclDateFields *, int);
static Tcl_ObjCmdProc	ClockConfigureObjCmd;
static void		GetYearWeekDay(TclDateFields *, int);
static void		GetGregorianEraYearDay(TclDateFields *, int);
static void		GetJulianDayFromEraYearMonthDay(
			    TclDateFields *fields, int changeover);
static void		GetMonthDay(TclDateFields *);
static Tcl_WideInt	WeekdayOnOrBefore(int, Tcl_WideInt);
static Tcl_ObjCmdProc	ClockClicksObjCmd;
static Tcl_ObjCmdProc	ClockConvertlocaltoutcObjCmd;
static int		ClockGetDateFields(ClockClientData *,
			    Tcl_Interp *interp, TclDateFields *fields,
			    Tcl_Obj *timezoneObj, int changeover);
static void		GetJulianDayFromEraYearWeekDay(
			    TclDateFields *fields, int changeover);
static Tcl_ObjCmdProc	ClockGetdatefieldsObjCmd;
static Tcl_ObjCmdProc	ClockGetjuliandayfromerayearmonthdayObjCmd;
static Tcl_ObjCmdProc	ClockGetjuliandayfromerayearweekdayObjCmd;
static Tcl_ObjCmdProc	ClockGetenvObjCmd;
static Tcl_ObjCmdProc	ClockMicrosecondsObjCmd;
static Tcl_ObjCmdProc	ClockMillisecondsObjCmd;
static Tcl_ObjCmdProc	ClockSecondsObjCmd;
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
 *----------------------------------------------------------------------
 */

static void
ClockConfigureClear(
    ClockClientData *data)
{
    ClockFrmScnClearCaches();

    data->lastTZEpoch = 0;
    TclUnsetObjRef(data->systemTimeZone);
    TclUnsetObjRef(data->systemSetupTZData);
    TclUnsetObjRef(data->gmtSetupTimeZoneUnnorm);
    TclUnsetObjRef(data->gmtSetupTimeZone);
    TclUnsetObjRef(data->gmtSetupTZData);







|







299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
 *----------------------------------------------------------------------
 */

static void
ClockConfigureClear(
    ClockClientData *data)
{
    TclClockFrmScnClearCaches();

    data->lastTZEpoch = 0;
    TclUnsetObjRef(data->systemTimeZone);
    TclUnsetObjRef(data->systemSetupTZData);
    TclUnsetObjRef(data->gmtSetupTimeZoneUnnorm);
    TclUnsetObjRef(data->gmtSetupTimeZone);
    TclUnsetObjRef(data->gmtSetupTZData);
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
    *mcDictObj = NULL;
    return localeObj;
}

/*
 *----------------------------------------------------------------------
 *
 * ClockMCDict --
 *
 *	Retrieves a localized storage dictionary object for the given
 *	locale object.
 *
 *	This corresponds with call `::tcl::clock::mcget locale`.
 *	Cached representation stored in options (for further access).
 *
 * Results:
 *	Tcl-object contains smart reference to msgcat dictionary.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
ClockMCDict(
    ClockFmtScnCmdArgs *opts)
{
    ClockClientData *dataPtr = opts->dataPtr;

    /* if dict not yet retrieved */
    if (opts->mcDictObj == NULL) {








|












<

|







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
    *mcDictObj = NULL;
    return localeObj;
}

/*
 *----------------------------------------------------------------------
 *
 * TclClockMCDict --
 *
 *	Retrieves a localized storage dictionary object for the given
 *	locale object.
 *
 *	This corresponds with call `::tcl::clock::mcget locale`.
 *	Cached representation stored in options (for further access).
 *
 * Results:
 *	Tcl-object contains smart reference to msgcat dictionary.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
TclClockMCDict(
    ClockFmtScnCmdArgs *opts)
{
    ClockClientData *dataPtr = opts->dataPtr;

    /* if dict not yet retrieved */
    if (opts->mcDictObj == NULL) {

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

    return opts->mcDictObj;
}

/*
 *----------------------------------------------------------------------
 *
 * ClockMCGet --
 *
 *	Retrieves a msgcat value for the given literal integer mcKey
 *	from localized storage (corresponding given locale object)
 *	by mcLiterals[mcKey] (e. g. MONTHS_FULL).
 *
 * Results:
 *	Tcl-object contains localized value.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
ClockMCGet(
    ClockFmtScnCmdArgs *opts,
    int mcKey)
{
    Tcl_Obj *valObj = NULL;

    if (opts->mcDictObj == NULL) {
	ClockMCDict(opts);
	if (opts->mcDictObj == NULL) {
	    return NULL;
	}
    }

    Tcl_DictObjGet(opts->interp, opts->mcDictObj,
	    opts->dataPtr->mcLiterals[mcKey], &valObj);
    return valObj; /* or NULL in obscure case if Tcl_DictObjGet failed */
}

/*
 *----------------------------------------------------------------------
 *
 * ClockMCGetIdx --
 *
 *	Retrieves an indexed msgcat value for the given literal integer mcKey
 *	from localized storage (corresponding given locale object)
 *	by mcLitIdxs[mcKey] (e. g. _IDX_MONTHS_FULL).
 *
 * Results:
 *	Tcl-object contains localized indexed value.
 *
 *----------------------------------------------------------------------
 */

MODULE_SCOPE Tcl_Obj *
ClockMCGetIdx(
    ClockFmtScnCmdArgs *opts,
    int mcKey)
{
    ClockClientData *dataPtr = opts->dataPtr;
    Tcl_Obj *valObj = NULL;

    if (opts->mcDictObj == NULL) {
	ClockMCDict(opts);
	if (opts->mcDictObj == NULL) {
	    return NULL;
	}
    }

    /* try to get indices object */
    if (dataPtr->mcLitIdxs == NULL) {
	return NULL;
    }

    if (Tcl_DictObjGet(NULL, opts->mcDictObj,
	    dataPtr->mcLitIdxs[mcKey], &valObj) != TCL_OK) {
	return NULL;
    }
    return valObj;
}

/*
 *----------------------------------------------------------------------
 *
 * ClockMCSetIdx --
 *
 *	Sets an indexed msgcat value for the given literal integer mcKey
 *	in localized storage (corresponding given locale object)
 *	by mcLitIdxs[mcKey] (e. g. _IDX_MONTHS_FULL).
 *
 * Results:
 *	Returns a standard Tcl result.
 *
 *----------------------------------------------------------------------
 */

int
ClockMCSetIdx(
    ClockFmtScnCmdArgs *opts,
    int mcKey,
    Tcl_Obj *valObj)
{
    ClockClientData *dataPtr = opts->dataPtr;

    if (opts->mcDictObj == NULL) {
	ClockMCDict(opts);
	if (opts->mcDictObj == NULL) {
	    return TCL_ERROR;
	}
    }

    /* if literal storage for indices not yet created */
    if (dataPtr->mcLitIdxs == NULL) {







|










<

|






|













|










<
|
|







|




















|










<

|







|







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

    return opts->mcDictObj;
}

/*
 *----------------------------------------------------------------------
 *
 * TclClockMCGet --
 *
 *	Retrieves a msgcat value for the given literal integer mcKey
 *	from localized storage (corresponding given locale object)
 *	by mcLiterals[mcKey] (e. g. MONTHS_FULL).
 *
 * Results:
 *	Tcl-object contains localized value.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
TclClockMCGet(
    ClockFmtScnCmdArgs *opts,
    int mcKey)
{
    Tcl_Obj *valObj = NULL;

    if (opts->mcDictObj == NULL) {
	TclClockMCDict(opts);
	if (opts->mcDictObj == NULL) {
	    return NULL;
	}
    }

    Tcl_DictObjGet(opts->interp, opts->mcDictObj,
	    opts->dataPtr->mcLiterals[mcKey], &valObj);
    return valObj; /* or NULL in obscure case if Tcl_DictObjGet failed */
}

/*
 *----------------------------------------------------------------------
 *
 * TclClockMCGetIdx --
 *
 *	Retrieves an indexed msgcat value for the given literal integer mcKey
 *	from localized storage (corresponding given locale object)
 *	by mcLitIdxs[mcKey] (e. g. _IDX_MONTHS_FULL).
 *
 * Results:
 *	Tcl-object contains localized indexed value.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
TclClockMCGetIdx(
    ClockFmtScnCmdArgs *opts,
    int mcKey)
{
    ClockClientData *dataPtr = opts->dataPtr;
    Tcl_Obj *valObj = NULL;

    if (opts->mcDictObj == NULL) {
	TclClockMCDict(opts);
	if (opts->mcDictObj == NULL) {
	    return NULL;
	}
    }

    /* try to get indices object */
    if (dataPtr->mcLitIdxs == NULL) {
	return NULL;
    }

    if (Tcl_DictObjGet(NULL, opts->mcDictObj,
	    dataPtr->mcLitIdxs[mcKey], &valObj) != TCL_OK) {
	return NULL;
    }
    return valObj;
}

/*
 *----------------------------------------------------------------------
 *
 * TclClockMCSetIdx --
 *
 *	Sets an indexed msgcat value for the given literal integer mcKey
 *	in localized storage (corresponding given locale object)
 *	by mcLitIdxs[mcKey] (e. g. _IDX_MONTHS_FULL).
 *
 * Results:
 *	Returns a standard Tcl result.
 *
 *----------------------------------------------------------------------
 */

int
TclClockMCSetIdx(
    ClockFmtScnCmdArgs *opts,
    int mcKey,
    Tcl_Obj *valObj)
{
    ClockClientData *dataPtr = opts->dataPtr;

    if (opts->mcDictObj == NULL) {
	TclClockMCDict(opts);
	if (opts->mcDictObj == NULL) {
	    return TCL_ERROR;
	}
    }

    /* if literal storage for indices not yet created */
    if (dataPtr->mcLitIdxs == NULL) {
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
    Tcl_ResetResult(interp);
    return dataPtr->systemTimeZone;
}

/*
 *----------------------------------------------------------------------
 *
 * ClockSetupTimeZone --
 *
 *	Sets up the timezone. Loads tzdata, etc.
 *
 * Results:
 *	Returns normalized timezone object.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
ClockSetupTimeZone(
    ClockClientData *dataPtr,	/* Pointer to literal pool, etc. */
    Tcl_Interp *interp,		/* Tcl interpreter */
    Tcl_Obj *timezoneObj)
{
    int loaded;
    Tcl_Obj *callargs[2];








|










|







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
    Tcl_ResetResult(interp);
    return dataPtr->systemTimeZone;
}

/*
 *----------------------------------------------------------------------
 *
 * TclClockSetupTimeZone --
 *
 *	Sets up the timezone. Loads tzdata, etc.
 *
 * Results:
 *	Returns normalized timezone object.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
TclClockSetupTimeZone(
    ClockClientData *dataPtr,	/* Pointer to literal pool, etc. */
    Tcl_Interp *interp,		/* Tcl interpreter */
    Tcl_Obj *timezoneObj)
{
    int loaded;
    Tcl_Obj *callargs[2];

1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
 *	Returns the time zone object (formatted in a numeric form)
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
ClockFormatNumericTimeZone(
    int z)
{
    char buf[12 + 1], *p;

    if (z < 0) {
	z = -z;







<
|







1340
1341
1342
1343
1344
1345
1346

1347
1348
1349
1350
1351
1352
1353
1354
 *	Returns the time zone object (formatted in a numeric form)
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static Tcl_Obj *
ClockFormatNumericTimeZone(
    int z)
{
    char buf[12 + 1], *p;

    if (z < 0) {
	z = -z;
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
    Tcl_Obj *timezoneObj,	/* Time zone object or NULL for gmt */
    int changeover)		/* Julian Day Number */
{
    /*
     * Convert UTC time to local.
     */

    if (ConvertUTCToLocal(dataPtr, interp, fields, timezoneObj,
	    changeover) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * Extract Julian day and seconds of the day.
     */







|







1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
    Tcl_Obj *timezoneObj,	/* Time zone object or NULL for gmt */
    int changeover)		/* Julian Day Number */
{
    /*
     * Convert UTC time to local.
     */

    if (TclConvertUTCToLocal(dataPtr, interp, fields, timezoneObj,
	    changeover) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * Extract Julian day and seconds of the day.
     */
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
 *----------------------------------------------------------------------
 */

static int
ConvertLocalToUTCUsingTable(
    Tcl_Interp *interp,		/* Tcl interpreter */
    TclDateFields *fields,	/* Time to convert, with 'seconds' filled in */
    int rowc,			/* Number of points at which time changes */
    Tcl_Obj *const rowv[],	/* Points at which time changes */
    Tcl_WideInt *rangesVal)	/* Return bounds for time period */
{
    Tcl_Obj *row;
    Tcl_Size cellc;
    Tcl_Obj **cellv;
    struct {







|







1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
 *----------------------------------------------------------------------
 */

static int
ConvertLocalToUTCUsingTable(
    Tcl_Interp *interp,		/* Tcl interpreter */
    TclDateFields *fields,	/* Time to convert, with 'seconds' filled in */
    Tcl_Size rowc,			/* Number of points at which time changes */
    Tcl_Obj *const rowv[],	/* Points at which time changes */
    Tcl_WideInt *rangesVal)	/* Return bounds for time period */
{
    Tcl_Obj *row;
    Tcl_Size cellc;
    Tcl_Obj **cellv;
    struct {
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
     * convert a non-existent time such as 02:30 during the US Spring Daylight
     * Saving Time transition.
     */

    fields->tzOffset = 0;
    fields->seconds = fields->localSeconds;
    while (1) {
	row = LookupLastTransition(interp, fields->seconds, rowc, rowv,
		rangesVal);
	if ((row == NULL)
		|| TclListObjGetElements(interp, row, &cellc,
		    &cellv) != TCL_OK
		|| TclGetIntFromObj(interp, cellv[1],
		    &fields->tzOffset) != TCL_OK) {
	    return TCL_ERROR;







|







2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
     * convert a non-existent time such as 02:30 during the US Spring Daylight
     * Saving Time transition.
     */

    fields->tzOffset = 0;
    fields->seconds = fields->localSeconds;
    while (1) {
	row = TclClockLookupLastTransition(interp, fields->seconds, rowc, rowv,
		rangesVal);
	if ((row == NULL)
		|| TclListObjGetElements(interp, row, &cellc,
		    &cellv) != TCL_OK
		|| TclGetIntFromObj(interp, cellv[1],
		    &fields->tzOffset) != TCL_OK) {
	    return TCL_ERROR;
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ConvertUTCToLocal --
 *
 *	Converts a time (in a TclDateFields structure) from UTC to local time.
 *
 * Results:
 *	Returns a standard Tcl result.
 *
 * Side effects:
 *	Populates the 'tzName' and 'tzOffset' fields.
 *
 *----------------------------------------------------------------------
 */

int
ConvertUTCToLocal(
    ClockClientData *dataPtr,	/* Literal pool, etc. */
    Tcl_Interp *interp,		/* Tcl interpreter */
    TclDateFields *fields,	/* Fields of the time */
    Tcl_Obj *timezoneObj,	/* Time zone */
    int changeover)		/* Julian Day of the Gregorian transition */
{
    Tcl_Obj *tzdata;		/* Time zone data */







|













|







2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclConvertUTCToLocal --
 *
 *	Converts a time (in a TclDateFields structure) from UTC to local time.
 *
 * Results:
 *	Returns a standard Tcl result.
 *
 * Side effects:
 *	Populates the 'tzName' and 'tzOffset' fields.
 *
 *----------------------------------------------------------------------
 */

int
TclConvertUTCToLocal(
    ClockClientData *dataPtr,	/* Literal pool, etc. */
    Tcl_Interp *interp,		/* Tcl interpreter */
    TclDateFields *fields,	/* Fields of the time */
    Tcl_Obj *timezoneObj,	/* Time zone */
    int changeover)		/* Julian Day of the Gregorian transition */
{
    Tcl_Obj *tzdata;		/* Time zone data */
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
    Tcl_Size cellc;		/* Count of cells in the row (must be 4) */
    Tcl_Obj **cellv;		/* Pointers to the cells */

    /*
     * Look up the nearest transition time.
     */

    row = LookupLastTransition(interp, fields->seconds, rowc, rowv, rangesVal);
    if (row == NULL
	    || TclListObjGetElements(interp, row, &cellc, &cellv) != TCL_OK
	    || TclGetIntFromObj(interp, cellv[1], &fields->tzOffset) != TCL_OK) {
	return TCL_ERROR;
    }

    /*







|







2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
    Tcl_Size cellc;		/* Count of cells in the row (must be 4) */
    Tcl_Obj **cellv;		/* Pointers to the cells */

    /*
     * Look up the nearest transition time.
     */

    row = TclClockLookupLastTransition(interp, fields->seconds, rowc, rowv, rangesVal);
    if (row == NULL
	    || TclListObjGetElements(interp, row, &cellc, &cellv) != TCL_OK
	    || TclGetIntFromObj(interp, cellv[1], &fields->tzOffset) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
    TclSetObjRef(fields->tzName, Tcl_NewStringObj(buffer, p - buffer));
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * LookupLastTransition --
 *
 *	Given a UTC time and a tzdata array, looks up the last transition on
 *	or before the given time.
 *
 * Results:
 *	Returns a pointer to the row, or NULL if an error occurs.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
LookupLastTransition(
    Tcl_Interp *interp,		/* Interpreter for error messages */
    Tcl_WideInt tick,		/* Time from the epoch */
    Tcl_Size rowc,		/* Number of rows of tzdata */
    Tcl_Obj *const *rowv,	/* Rows in tzdata */
    Tcl_WideInt *rangesVal)	/* Return bounds for time period */
{
    Tcl_Size l, u;







|











|







2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
    TclSetObjRef(fields->tzName, Tcl_NewStringObj(buffer, p - buffer));
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclClockLookupLastTransition --
 *
 *	Given a UTC time and a tzdata array, looks up the last transition on
 *	or before the given time.
 *
 * Results:
 *	Returns a pointer to the row, or NULL if an error occurs.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
TclClockLookupLastTransition(
    Tcl_Interp *interp,		/* Interpreter for error messages */
    Tcl_WideInt tick,		/* Time from the epoch */
    Tcl_Size rowc,		/* Number of rows of tzdata */
    Tcl_Obj *const *rowv,	/* Rows in tzdata */
    Tcl_WideInt *rangesVal)	/* Return bounds for time period */
{
    Tcl_Size l, u;
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
	} else {
	    temp.iso8601Year -= 1;
	}
	GetJulianDayFromEraYearWeekDay(&temp, changeover);
    }

    fields->iso8601Year = temp.iso8601Year;
    dayOfFiscalYear = fields->julianDay - temp.julianDay;
    fields->iso8601Week = (dayOfFiscalYear / 7) + 1;
    fields->dayOfWeek = (dayOfFiscalYear + 1) % 7;
    if (fields->dayOfWeek < 1) { /* Mon .. Sun == 1 .. 7 */
	fields->dayOfWeek += 7;
    }
}








|







2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
	} else {
	    temp.iso8601Year -= 1;
	}
	GetJulianDayFromEraYearWeekDay(&temp, changeover);
    }

    fields->iso8601Year = temp.iso8601Year;
    dayOfFiscalYear = (int)(fields->julianDay - temp.julianDay);
    fields->iso8601Week = (dayOfFiscalYear / 7) + 1;
    fields->dayOfWeek = (dayOfFiscalYear + 1) % 7;
    if (fields->dayOfWeek < 1) { /* Mon .. Sun == 1 .. 7 */
	fields->dayOfWeek += 7;
    }
}

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
static void
GetGregorianEraYearDay(
    TclDateFields *fields,	/* Date fields containing 'julianDay' */
    int changeover)		/* Gregorian transition date */
{
    Tcl_WideInt jday = fields->julianDay;
    Tcl_WideInt day;
    Tcl_WideInt year;
    Tcl_WideInt n;

    if (jday >= changeover) {
	/*
	 * Gregorian calendar.
	 */

	fields->gregorian = 1;
	year = 1;

	/*
	 * n = Number of 400-year cycles since 1 January, 1 CE in the
	 * proleptic Gregorian calendar. day = remaining days.
	 */

	day = jday - JDAY_1_JAN_1_CE_GREGORIAN;
	n = day / FOUR_CENTURIES;
	day %= FOUR_CENTURIES;
	if (day < 0) {
	    day += FOUR_CENTURIES;
	    n--;
	}
	year += 400 * n;

	/*
	 * n = number of centuries since the start of (year);
	 * day = remaining days
	 */

	n = day / ONE_CENTURY_GREGORIAN;
	day %= ONE_CENTURY_GREGORIAN;
	if (n > 3) {
	    /*
	     * 31 December in the last year of a 400-year cycle.
	     */

	    n = 3;







|
|















|












|







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
static void
GetGregorianEraYearDay(
    TclDateFields *fields,	/* Date fields containing 'julianDay' */
    int changeover)		/* Gregorian transition date */
{
    Tcl_WideInt jday = fields->julianDay;
    Tcl_WideInt day;
    int year;
    int n;

    if (jday >= changeover) {
	/*
	 * Gregorian calendar.
	 */

	fields->gregorian = 1;
	year = 1;

	/*
	 * n = Number of 400-year cycles since 1 January, 1 CE in the
	 * proleptic Gregorian calendar. day = remaining days.
	 */

	day = jday - JDAY_1_JAN_1_CE_GREGORIAN;
	n = (int)(day / FOUR_CENTURIES);
	day %= FOUR_CENTURIES;
	if (day < 0) {
	    day += FOUR_CENTURIES;
	    n--;
	}
	year += 400 * n;

	/*
	 * n = number of centuries since the start of (year);
	 * day = remaining days
	 */

	n = (int)(day / ONE_CENTURY_GREGORIAN);
	day %= ONE_CENTURY_GREGORIAN;
	if (n > 3) {
	    /*
	     * 31 December in the last year of a 400-year cycle.
	     */

	    n = 3;
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
	day = jday - JDAY_1_JAN_1_CE_JULIAN;
    }

    /*
     * n = number of 4-year cycles; days = remaining days.
     */

    n = day / FOUR_YEARS;
    day %= FOUR_YEARS;
    if (day < 0) {
	day += FOUR_YEARS;
	n--;
    }
    year += 4 * n;

    /*
     * n = number of years; days = remaining days.
     */

    n = day / ONE_YEAR;
    day %= ONE_YEAR;
    if (n > 3) {
	/*
	 * 31 December of a leap year.
	 */

	n = 3;







|











|







2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
	day = jday - JDAY_1_JAN_1_CE_JULIAN;
    }

    /*
     * n = number of 4-year cycles; days = remaining days.
     */

    n = (int)(day / FOUR_YEARS);
    day %= FOUR_YEARS;
    if (day < 0) {
	day += FOUR_YEARS;
	n--;
    }
    year += 4 * n;

    /*
     * n = number of years; days = remaining days.
     */

    n = (int)(day / ONE_YEAR);
    day %= ONE_YEAR;
    if (n > 3) {
	/*
	 * 31 December of a leap year.
	 */

	n = 3;
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
    if (year <= 0) {
	fields->isBce = 1;
	fields->year = 1 - year;
    } else {
	fields->isBce = 0;
	fields->year = year;
    }
    fields->dayOfYear = day + 1;
}

/*
 *----------------------------------------------------------------------
 *
 * GetMonthDay --
 *







|







2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
    if (year <= 0) {
	fields->isBce = 1;
	fields->year = 1 - year;
    } else {
	fields->isBce = 0;
	fields->year = year;
    }
    fields->dayOfYear = (int)day + 1;
}

/*
 *----------------------------------------------------------------------
 *
 * GetMonthDay --
 *
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686

static void
GetMonthDay(
    TclDateFields *fields)	/* Date to convert */
{
    int day = fields->dayOfYear;
    int month;
    const int *dipm = daysInPriorMonths[IsGregorianLeapYear(fields)];

    /*
     * Estimate month by calculating `dayOfYear / (365/12)`
     */
    month = (day*12) / dipm[12];
    /* then do forwards backwards correction */
    while (1) {







|







2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685

static void
GetMonthDay(
    TclDateFields *fields)	/* Date to convert */
{
    int day = fields->dayOfYear;
    int month;
    const int *dipm = daysInPriorMonths[TclIsGregorianLeapYear(fields)];

    /*
     * Estimate month by calculating `dayOfYear / (365/12)`
     */
    month = (day*12) / dipm[12];
    /* then do forwards backwards correction */
    while (1) {
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
 */

void
GetJulianDayFromEraYearMonthDay(
    TclDateFields *fields,	/* Date to convert */
    int changeover)		/* Gregorian transition date as a Julian Day */
{
    Tcl_WideInt year, ym1, ym1o4, ym1o100, ym1o400;
    int month, mm1, q, r;

    if (fields->isBce) {
	year = 1 - fields->year;
    } else {
	year = fields->year;
    }








|
|







2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
 */

void
GetJulianDayFromEraYearMonthDay(
    TclDateFields *fields,	/* Date to convert */
    int changeover)		/* Gregorian transition date as a Julian Day */
{
    Tcl_WideInt ym1, ym1o4, ym1o100, ym1o400;
    int year, month, mm1, q, r;

    if (fields->isBce) {
	year = 1 - fields->year;
    } else {
	year = fields->year;
    }

2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
    }
    ym1o400 = ym1 / 400;
    if (ym1 % 400 < 0) {
	ym1o400--;
    }
    fields->julianDay = JDAY_1_JAN_1_CE_GREGORIAN - 1
	    + fields->dayOfMonth
	    + daysInPriorMonths[IsGregorianLeapYear(fields)][month - 1]
	    + (ONE_YEAR * ym1)
	    + ym1o4
	    - ym1o100
	    + ym1o400;

    /*
     * If the resulting date is before the Gregorian changeover, convert in







|







2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
    }
    ym1o400 = ym1 / 400;
    if (ym1 % 400 < 0) {
	ym1o400--;
    }
    fields->julianDay = JDAY_1_JAN_1_CE_GREGORIAN - 1
	    + fields->dayOfMonth
	    + daysInPriorMonths[TclIsGregorianLeapYear(fields)][month - 1]
	    + (ONE_YEAR * ym1)
	    + ym1o4
	    - ym1o100
	    + ym1o400;

    /*
     * If the resulting date is before the Gregorian changeover, convert in
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
		+ ym1o4;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * GetJulianDayFromEraYearDay --
 *
 *	Given era, year, and dayOfYear (in TclDateFields), and the
 *	Gregorian transition date, computes the Julian Day Number.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Stores day number in 'julianDay'
 *
 *----------------------------------------------------------------------
 */

void
GetJulianDayFromEraYearDay(
    TclDateFields *fields,	/* Date to convert */
    int changeover)		/* Gregorian transition date as a Julian Day */
{
    Tcl_WideInt year, ym1;

    /* Get absolute year number from the civil year */
    if (fields->isBce) {







|














|







2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
		+ ym1o4;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclGetJulianDayFromEraYearDay --
 *
 *	Given era, year, and dayOfYear (in TclDateFields), and the
 *	Gregorian transition date, computes the Julian Day Number.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Stores day number in 'julianDay'
 *
 *----------------------------------------------------------------------
 */

void
TclGetJulianDayFromEraYearDay(
    TclDateFields *fields,	/* Date to convert */
    int changeover)		/* Gregorian transition date as a Julian Day */
{
    Tcl_WideInt year, ym1;

    /* Get absolute year number from the civil year */
    if (fields->isBce) {
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
		+ (365 * ym1)
		+ (ym1 / 4);
    }
}
/*
 *----------------------------------------------------------------------
 *
 * IsGregorianLeapYear --
 *
 *	Tests whether a given year is a leap year, in either Julian or
 *	Gregorian calendar.
 *
 * Results:
 *	Returns 1 for a leap year, 0 otherwise.
 *
 *----------------------------------------------------------------------
 */

int
IsGregorianLeapYear(
    TclDateFields *fields)	/* Date to test */
{
    Tcl_WideInt year = fields->year;

    if (fields->isBce) {
	year = 1 - year;
    }







|











|







2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
		+ (365 * ym1)
		+ (ym1 / 4);
    }
}
/*
 *----------------------------------------------------------------------
 *
 * TclIsGregorianLeapYear --
 *
 *	Tests whether a given year is a leap year, in either Julian or
 *	Gregorian calendar.
 *
 * Results:
 *	Returns 1 for a leap year, 0 otherwise.
 *
 *----------------------------------------------------------------------
 */

int
TclIsGregorianLeapYear(
    TclDateFields *fields)	/* Date to test */
{
    Tcl_WideInt year = fields->year;

    if (fields->isBce) {
	year = 1 - year;
    }
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
	if (opts->timezoneObj == NULL) {
	    return TCL_ERROR;
	}
    }

    /* Setup timezone (normalize object if needed and load TZ on demand) */

    opts->timezoneObj = ClockSetupTimeZone(dataPtr, interp, opts->timezoneObj);
    if (opts->timezoneObj == NULL) {
	return TCL_ERROR;
    }

    /* Base (by scan or add) or clock value (by format) */

    if (opts->baseObj != NULL) {







|







3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
	if (opts->timezoneObj == NULL) {
	    return TCL_ERROR;
	}
    }

    /* Setup timezone (normalize object if needed and load TZ on demand) */

    opts->timezoneObj = TclClockSetupTimeZone(dataPtr, interp, opts->timezoneObj);
    if (opts->timezoneObj == NULL) {
	return TCL_ERROR;
    }

    /* Base (by scan or add) or clock value (by format) */

    if (opts->baseObj != NULL) {
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565

    /* Default format */
    if (opts.formatObj == NULL) {
	opts.formatObj = dataPtr->literals[LIT__DEFAULT_FORMAT];
    }

    /* Use compiled version of Format - */
    ret = ClockFormat(&dateFmt, &opts);

  done:
    TclUnsetObjRef(dateFmt.date.tzName);
    return ret;
}

/*----------------------------------------------------------------------







|







3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564

    /* Default format */
    if (opts.formatObj == NULL) {
	opts.formatObj = dataPtr->literals[LIT__DEFAULT_FORMAT];
    }

    /* Use compiled version of Format - */
    ret = TclClockFormat(&dateFmt, &opts);

  done:
    TclUnsetObjRef(dateFmt.date.tzName);
    return ret;
}

/*----------------------------------------------------------------------
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
    ret = ClockParseFmtScnArgs(&opts, &yy.date, objc, objv,
	    CLC_OP_SCN, "-base, -format, -gmt, -locale, -timezone or -validate");
    if (ret != TCL_OK) {
	goto done;
    }

    /* seconds are in localSeconds (relative base date), so reset time here */
    yyHour = yyMinutes = yySeconds = yySecondOfDay = 0;
    yyMeridian = MER24;

    /* If free scan */
    if (opts.formatObj == NULL) {
	/* Use compiled version of FreeScan - */

	/* [SB] TODO: Perhaps someday we'll localize the legacy code. Right now,
	 * it's not localized. */
	if (opts.localeObj != NULL) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
		    "legacy [clock scan] does not support -locale", TCL_AUTO_LENGTH));
	    Tcl_SetErrorCode(interp, "CLOCK", "flagWithLegacyFormat", (char *)NULL);
	    ret = TCL_ERROR;
	    goto done;
	}
	ret = ClockFreeScan(&yy, objv[1], &opts);
    } else {
	/* Use compiled version of Scan - */

	ret = ClockScan(&yy, objv[1], &opts);
    }

    if (ret != TCL_OK) {
	goto done;
    }

    /* Convert date info structure into UTC seconds */







|



















|







3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
    ret = ClockParseFmtScnArgs(&opts, &yy.date, objc, objv,
	    CLC_OP_SCN, "-base, -format, -gmt, -locale, -timezone or -validate");
    if (ret != TCL_OK) {
	goto done;
    }

    /* seconds are in localSeconds (relative base date), so reset time here */
    yySecondOfDay = yySeconds = yyMinutes = yyHour = 0;
    yyMeridian = MER24;

    /* If free scan */
    if (opts.formatObj == NULL) {
	/* Use compiled version of FreeScan - */

	/* [SB] TODO: Perhaps someday we'll localize the legacy code. Right now,
	 * it's not localized. */
	if (opts.localeObj != NULL) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
		    "legacy [clock scan] does not support -locale", TCL_AUTO_LENGTH));
	    Tcl_SetErrorCode(interp, "CLOCK", "flagWithLegacyFormat", (char *)NULL);
	    ret = TCL_ERROR;
	    goto done;
	}
	ret = ClockFreeScan(&yy, objv[1], &opts);
    } else {
	/* Use compiled version of Scan - */

	ret = TclClockScan(&yy, objv[1], &opts);
    }

    if (ret != TCL_OK) {
	goto done;
    }

    /* Convert date info structure into UTC seconds */
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
	if (info->flags & CLF_ISO8601WEEK) {
	    GetJulianDayFromEraYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE);
	} else if (!(info->flags & CLF_DAYOFYEAR) /* no day of year */
		|| (info->flags & (CLF_DAYOFMONTH|CLF_MONTH)) /* yymmdd over yyddd */
		== (CLF_DAYOFMONTH|CLF_MONTH)) {
	    GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
	} else {
	    GetJulianDayFromEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);
	}
	info->flags |= CLF_ASSEMBLE_SECONDS;
	info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
    }

    /* some overflow checks */
    if (info->flags & CLF_JULIANDAY) {







|







3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
	if (info->flags & CLF_ISO8601WEEK) {
	    GetJulianDayFromEraYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE);
	} else if (!(info->flags & CLF_DAYOFYEAR) /* no day of year */
		|| (info->flags & (CLF_DAYOFMONTH|CLF_MONTH)) /* yymmdd over yyddd */
		== (CLF_DAYOFMONTH|CLF_MONTH)) {
	    GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
	} else {
	    TclGetJulianDayFromEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);
	}
	info->flags |= CLF_ASSEMBLE_SECONDS;
	info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
    }

    /* some overflow checks */
    if (info->flags & CLF_JULIANDAY) {
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
    if (info->flags & (CLF_DAYOFMONTH|CLF_DAYOFWEEK)) {
	if (yyDay < 1 || yyDay > 31) {
	    errMsg = "invalid day";
	    errCode = "day";
	    goto error;
	}
	if ((info->flags & CLF_MONTH)) {
	    const int *h = hath[IsGregorianLeapYear(&yydate)];

	    if (yyDay > h[yyMonth - 1]) {
		errMsg = "invalid day";
		errCode = "day";
		goto error;
	    }
	}
    }
    if (info->flags & CLF_DAYOFYEAR) {
	if (yydate.dayOfYear < 1
		|| yydate.dayOfYear > daysInPriorMonths[IsGregorianLeapYear(&yydate)][12]) {
	    errMsg = "invalid day of year";
	    errCode = "day of year";
	    goto error;
	}
    }

    /* mmdd !~ ddd */
    if ((info->flags & (CLF_DAYOFYEAR|CLF_DAYOFMONTH|CLF_MONTH))
	    == (CLF_DAYOFYEAR|CLF_DAYOFMONTH|CLF_MONTH)) {
	if (!tempCpyFlg) {
	    memcpy(&temp, &yydate, sizeof(temp));
	    tempCpyFlg = 1;
	}
	GetJulianDayFromEraYearDay(&temp, GREGORIAN_CHANGE_DATE);
	if (temp.julianDay != yydate.julianDay) {
	    errMsg = "ambiguous day";
	    errCode = "day";
	    goto error;
	}
    }








|










|













|







3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
    if (info->flags & (CLF_DAYOFMONTH|CLF_DAYOFWEEK)) {
	if (yyDay < 1 || yyDay > 31) {
	    errMsg = "invalid day";
	    errCode = "day";
	    goto error;
	}
	if ((info->flags & CLF_MONTH)) {
	    const int *h = hath[TclIsGregorianLeapYear(&yydate)];

	    if (yyDay > h[yyMonth - 1]) {
		errMsg = "invalid day";
		errCode = "day";
		goto error;
	    }
	}
    }
    if (info->flags & CLF_DAYOFYEAR) {
	if (yydate.dayOfYear < 1
		|| yydate.dayOfYear > daysInPriorMonths[TclIsGregorianLeapYear(&yydate)][12]) {
	    errMsg = "invalid day of year";
	    errCode = "day of year";
	    goto error;
	}
    }

    /* mmdd !~ ddd */
    if ((info->flags & (CLF_DAYOFYEAR|CLF_DAYOFMONTH|CLF_MONTH))
	    == (CLF_DAYOFYEAR|CLF_DAYOFMONTH|CLF_MONTH)) {
	if (!tempCpyFlg) {
	    memcpy(&temp, &yydate, sizeof(temp));
	    tempCpyFlg = 1;
	}
	TclGetJulianDayFromEraYearDay(&temp, GREGORIAN_CHANGE_DATE);
	if (temp.julianDay != yydate.julianDay) {
	    errMsg = "ambiguous day";
	    errCode = "day";
	    goto error;
	}
    }

3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
	}
	/* minutes */
	if (yyMinutes < 0 || yyMinutes > 59) {
	    errMsg = "invalid time (minutes)";
	    errCode = "minutes";
	    goto error;
	}
	/* oldscan could return secondOfDay -1 by invalid time (see ToSeconds) */
	if (yySeconds < 0 || yySeconds > 59 || yySecondOfDay <= -1) {
	    errMsg = "invalid time";
	    errCode = "seconds";
	    goto error;
	}
    }








|







3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
	}
	/* minutes */
	if (yyMinutes < 0 || yyMinutes > 59) {
	    errMsg = "invalid time (minutes)";
	    errCode = "minutes";
	    goto error;
	}
	/* oldscan could return secondOfDay -1 by invalid time (see TclToSeconds) */
	if (yySeconds < 0 || yySeconds > 59 || yySecondOfDay <= -1) {
	    errMsg = "invalid time";
	    errCode = "seconds";
	    goto error;
	}
    }

4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
	    int minEast = -yyTimezone;
	    int dstFlag = 1 - yyDSTmode;

	    tzObjStor = ClockFormatNumericTimeZone(
		    60 * minEast + 3600 * dstFlag);
	    Tcl_IncrRefCount(tzObjStor);

	    opts->timezoneObj = ClockSetupTimeZone(dataPtr, interp, tzObjStor);

	    Tcl_DecrRefCount(tzObjStor);
	} else {
	    /* simplest case - GMT / UTC */
	    opts->timezoneObj = ClockSetupTimeZone(dataPtr, interp,
		    dataPtr->literals[LIT_GMT]);
	}
	if (opts->timezoneObj == NULL) {
	    return TCL_ERROR;
	}

	// TclSetObjRef(yydate.tzName, opts->timezoneObj);







|




|







4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
	    int minEast = -yyTimezone;
	    int dstFlag = 1 - yyDSTmode;

	    tzObjStor = ClockFormatNumericTimeZone(
		    60 * minEast + 3600 * dstFlag);
	    Tcl_IncrRefCount(tzObjStor);

	    opts->timezoneObj = TclClockSetupTimeZone(dataPtr, interp, tzObjStor);

	    Tcl_DecrRefCount(tzObjStor);
	} else {
	    /* simplest case - GMT / UTC */
	    opts->timezoneObj = TclClockSetupTimeZone(dataPtr, interp,
		    dataPtr->literals[LIT_GMT]);
	}
	if (opts->timezoneObj == NULL) {
	    return TCL_ERROR;
	}

	// TclSetObjRef(yydate.tzName, opts->timezoneObj);
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
     * Assemble date, time, zone into seconds-from-epoch
     */

    if ((info->flags & (CLF_TIME | CLF_HAVEDATE)) == CLF_HAVEDATE) {
	yySecondOfDay = 0;
	info->flags |= CLF_ASSEMBLE_SECONDS;
    } else if (info->flags & CLF_TIME) {
	yySecondOfDay = ToSeconds(yyHour, yyMinutes, yySeconds, yyMeridian);
	info->flags |= CLF_ASSEMBLE_SECONDS;
    } else if ((info->flags & (CLF_DAYOFWEEK | CLF_HAVEDATE)) == CLF_DAYOFWEEK
	    || (info->flags & CLF_ORDINALMONTH)
	    || ((info->flags & CLF_RELCONV)
	    && (yyRelMonth != 0 || yyRelDay != 0))) {
	yySecondOfDay = 0;
	info->flags |= CLF_ASSEMBLE_SECONDS;







|







4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
     * Assemble date, time, zone into seconds-from-epoch
     */

    if ((info->flags & (CLF_TIME | CLF_HAVEDATE)) == CLF_HAVEDATE) {
	yySecondOfDay = 0;
	info->flags |= CLF_ASSEMBLE_SECONDS;
    } else if (info->flags & CLF_TIME) {
	yySecondOfDay = TclToSeconds(yyHour, yyMinutes, (int)yySeconds, yyMeridian);
	info->flags |= CLF_ASSEMBLE_SECONDS;
    } else if ((info->flags & (CLF_DAYOFWEEK | CLF_HAVEDATE)) == CLF_DAYOFWEEK
	    || (info->flags & CLF_ORDINALMONTH)
	    || ((info->flags & CLF_RELCONV)
	    && (yyRelMonth != 0 || yyRelDay != 0))) {
	yySecondOfDay = 0;
	info->flags |= CLF_ASSEMBLE_SECONDS;
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
	    GetGregorianEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);
	    GetMonthDay(&yydate);
	    GetYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE);
	    info->flags &= ~CLF_ASSEMBLE_DATE;
	}

	/* add the requisite number of months */
	yyMonth += yyRelMonth - 1;
	yyYear += yyMonth / 12;
	m = yyMonth % 12;
	/* compiler fix for signed-mod - wrap y, m = (0, -1) -> (-1, 11) */
	if (m < 0) {
	    m += 12;
	    yyYear--;
	}
	yyMonth = m + 1;

	/* if the day doesn't exist in the current month, repair it */
	h = hath[IsGregorianLeapYear(&yydate)][m];
	if (yyDay > h) {
	    yyDay = h;
	}

	/* on demand (lazy) assemble julianDay using new year, month, etc. */
	info->flags |= CLF_ASSEMBLE_JULIANDAY | CLF_ASSEMBLE_SECONDS;








|










|







4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
	    GetGregorianEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);
	    GetMonthDay(&yydate);
	    GetYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE);
	    info->flags &= ~CLF_ASSEMBLE_DATE;
	}

	/* add the requisite number of months */
	yyMonth += (int)yyRelMonth - 1;
	yyYear += yyMonth / 12;
	m = yyMonth % 12;
	/* compiler fix for signed-mod - wrap y, m = (0, -1) -> (-1, 11) */
	if (m < 0) {
	    m += 12;
	    yyYear--;
	}
	yyMonth = m + 1;

	/* if the day doesn't exist in the current month, repair it */
	h = hath[TclIsGregorianLeapYear(&yydate)][m];
	if (yyDay > h) {
	    yyDay = h;
	}

	/* on demand (lazy) assemble julianDay using new year, month, etc. */
	info->flags |= CLF_ASSEMBLE_JULIANDAY | CLF_ASSEMBLE_SECONDS;

4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
	    break;
	case CLC_ADD_DAYS:
	    yyRelDay += offs;
	    break;
	case CLC_ADD_WEEKDAYS:
	    /* add number of week days (skipping Saturdays and Sundays)
	     * to a relative days value. */
	    offs = ClockWeekdaysOffs(yy.date.dayOfWeek, offs);
	    yyRelDay += offs;
	    break;
	case CLC_ADD_HOURS:
	    yyRelSeconds += offs * 60 * 60;
	    break;
	case CLC_ADD_MINUTES:
	    yyRelSeconds += offs * 60;







|







4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
	    break;
	case CLC_ADD_DAYS:
	    yyRelDay += offs;
	    break;
	case CLC_ADD_WEEKDAYS:
	    /* add number of week days (skipping Saturdays and Sundays)
	     * to a relative days value. */
	    offs = ClockWeekdaysOffs(yy.date.dayOfWeek, (int)offs);
	    yyRelDay += offs;
	    break;
	case CLC_ADD_HOURS:
	    yyRelSeconds += offs * 60 * 60;
	    break;
	case CLC_ADD_MINUTES:
	    yyRelSeconds += offs * 60;
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
#define WCHAR char
#define wcslen strlen
#define wcscmp strcmp
#define wcscpy strcpy
#endif
#define TZ_INIT_MARKER	((WCHAR *) INT2PTR(-1))

typedef struct ClockTzStatic {
    WCHAR *was;			/* Previous value of TZ. */
    long long lastRefresh;	/* Used for latency before next refresh. */
    size_t epoch;		/* Epoch, signals that TZ changed. */
    size_t envEpoch;		/* Last env epoch, for faster signaling,
				 * that TZ changed via TCL */
} ClockTzStatic;
static ClockTzStatic tz = {	/* Global timezone info; protected by







|







4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
#define WCHAR char
#define wcslen strlen
#define wcscmp strcmp
#define wcscpy strcpy
#endif
#define TZ_INIT_MARKER	((WCHAR *) INT2PTR(-1))

typedef struct {
    WCHAR *was;			/* Previous value of TZ. */
    long long lastRefresh;	/* Used for latency before next refresh. */
    size_t epoch;		/* Epoch, signals that TZ changed. */
    size_t envEpoch;		/* Last env epoch, for faster signaling,
				 * that TZ changed via TCL */
} ClockTzStatic;
static ClockTzStatic tz = {	/* Global timezone info; protected by
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
    return epoch;
}

static void
ClockFinalize(
    TCL_UNUSED(void *))
{
    ClockFrmScnFinalize();

    if (tz.was && tz.was != TZ_INIT_MARKER) {
	Tcl_Free(tz.was);
    }

    Tcl_MutexFinalize(&clockMutex);
}







|







4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
    return epoch;
}

static void
ClockFinalize(
    TCL_UNUSED(void *))
{
    TclClockFrmScnFinalize();

    if (tz.was && tz.was != TZ_INIT_MARKER) {
	Tcl_Free(tz.was);
    }

    Tcl_MutexFinalize(&clockMutex);
}
Changes to generic/tclClockFmt.c.
21
22
23
24
25
26
27


28
29
30
31
32
33
34
static void		ClockFmtObj_DupInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static void		ClockFmtObj_FreeInternalRep(Tcl_Obj *objPtr);
static int		ClockFmtObj_SetFromAny(Tcl_Interp *, Tcl_Obj *objPtr);
static void		ClockFmtObj_UpdateString(Tcl_Obj *objPtr);
static Tcl_HashEntry *	ClockFmtScnStorageAllocProc(Tcl_HashTable *, void *keyPtr);
static void		ClockFmtScnStorageFreeProc(Tcl_HashEntry *hPtr);
static void		ClockFmtScnStorageDelete(ClockFmtScnStorage *fss);



TCL_DECLARE_MUTEX(ClockFmtMutex);	/* Serializes access to common format list. */

#ifndef TCL_CLOCK_FULL_COMPAT
#define TCL_CLOCK_FULL_COMPAT 1
#endif








>
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
static void		ClockFmtObj_DupInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static void		ClockFmtObj_FreeInternalRep(Tcl_Obj *objPtr);
static int		ClockFmtObj_SetFromAny(Tcl_Interp *, Tcl_Obj *objPtr);
static void		ClockFmtObj_UpdateString(Tcl_Obj *objPtr);
static Tcl_HashEntry *	ClockFmtScnStorageAllocProc(Tcl_HashTable *, void *keyPtr);
static void		ClockFmtScnStorageFreeProc(Tcl_HashEntry *hPtr);
static void		ClockFmtScnStorageDelete(ClockFmtScnStorage *fss);
static Tcl_Obj *	ClockFrmObjGetLocFmtKey(Tcl_Interp *interp, Tcl_Obj *objPtr);
static Tcl_Obj *	ClockLocalizeFormat(ClockFmtScnCmdArgs *opts);

TCL_DECLARE_MUTEX(ClockFmtMutex);	/* Serializes access to common format list. */

#ifndef TCL_CLOCK_FULL_COMPAT
#define TCL_CLOCK_FULL_COMPAT 1
#endif

947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
    }

    /* prevents loss of key object if the format object (where key stored)
     * becomes changed (loses its internal representation during evals) */
    Tcl_IncrRefCount(keyObj);

    if (opts->mcDictObj == NULL) {
	ClockMCDict(opts);
	if (opts->mcDictObj == NULL) {
	    goto done;
	}
    }

    /* try to find in cache within locale mc-catalog */
    if (Tcl_DictObjGet(NULL, opts->mcDictObj, keyObj, &valObj) != TCL_OK) {







|







949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
    }

    /* prevents loss of key object if the format object (where key stored)
     * becomes changed (loses its internal representation during evals) */
    Tcl_IncrRefCount(keyObj);

    if (opts->mcDictObj == NULL) {
	TclClockMCDict(opts);
	if (opts->mcDictObj == NULL) {
	    goto done;
	}
    }

    /* try to find in cache within locale mc-catalog */
    if (Tcl_DictObjGet(NULL, opts->mcDictObj, keyObj, &valObj) != TCL_OK) {
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
    int maxLen)
{
    Tcl_Obj **lstv;
    Tcl_Size lstc;
    Tcl_Obj *valObj;

    /* get msgcat value */
    valObj = ClockMCGet(opts, mcKey);
    if (valObj == NULL) {
	return TCL_ERROR;
    }

    /* is a list */
    if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
	return TCL_ERROR;







|







1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
    int maxLen)
{
    Tcl_Obj **lstv;
    Tcl_Size lstc;
    Tcl_Obj *valObj;

    /* get msgcat value */
    valObj = TclClockMCGet(opts, mcKey);
    if (valObj == NULL) {
	return TCL_ERROR;
    }

    /* is a list */
    if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
	return TCL_ERROR;
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

static TclStrIdxTree *
ClockMCGetListIdxTree(
    ClockFmtScnCmdArgs *opts,
    int mcKey)
{
    TclStrIdxTree *idxTree;
    Tcl_Obj *objPtr = ClockMCGetIdx(opts, mcKey);

    if (objPtr != NULL
	    && (idxTree = TclStrIdxTreeGetFromObj(objPtr)) != NULL) {
	return idxTree;
    } else {
	/* build new index */

	Tcl_Obj **lstv;
	Tcl_Size lstc;
	Tcl_Obj *valObj;

	objPtr = TclStrIdxTreeNewObj();
	if ((idxTree = TclStrIdxTreeGetFromObj(objPtr)) == NULL) {
	    goto done;	/* unexpected, but ...*/
	}

	valObj = ClockMCGet(opts, mcKey);
	if (valObj == NULL) {
	    goto done;
	}
	if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
	    goto done;
	}
	if (TclStrIdxTreeBuildFromList(idxTree, lstc, lstv, NULL) != TCL_OK) {
	    goto done;
	}

	ClockMCSetIdx(opts, mcKey, objPtr);
	objPtr = NULL;
    }

  done:
    if (objPtr) {
	Tcl_DecrRefCount(objPtr);
	idxTree = NULL;







|
















|










|







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

static TclStrIdxTree *
ClockMCGetListIdxTree(
    ClockFmtScnCmdArgs *opts,
    int mcKey)
{
    TclStrIdxTree *idxTree;
    Tcl_Obj *objPtr = TclClockMCGetIdx(opts, mcKey);

    if (objPtr != NULL
	    && (idxTree = TclStrIdxTreeGetFromObj(objPtr)) != NULL) {
	return idxTree;
    } else {
	/* build new index */

	Tcl_Obj **lstv;
	Tcl_Size lstc;
	Tcl_Obj *valObj;

	objPtr = TclStrIdxTreeNewObj();
	if ((idxTree = TclStrIdxTreeGetFromObj(objPtr)) == NULL) {
	    goto done;	/* unexpected, but ...*/
	}

	valObj = TclClockMCGet(opts, mcKey);
	if (valObj == NULL) {
	    goto done;
	}
	if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
	    goto done;
	}
	if (TclStrIdxTreeBuildFromList(idxTree, lstc, lstv, NULL) != TCL_OK) {
	    goto done;
	}

	TclClockMCSetIdx(opts, mcKey, objPtr);
	objPtr = NULL;
    }

  done:
    if (objPtr) {
	Tcl_DecrRefCount(objPtr);
	idxTree = NULL;
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
static TclStrIdxTree *
ClockMCGetMultiListIdxTree(
    ClockFmtScnCmdArgs *opts,
    int	mcKey,
    int *mcKeys)
{
    TclStrIdxTree * idxTree;
    Tcl_Obj *objPtr = ClockMCGetIdx(opts, mcKey);

    if (objPtr != NULL
	    && (idxTree = TclStrIdxTreeGetFromObj(objPtr)) != NULL) {
	return idxTree;
    } else {
	/* build new index */

	Tcl_Obj **lstv;
	Tcl_Size lstc;
	Tcl_Obj *valObj;

	objPtr = TclStrIdxTreeNewObj();
	if ((idxTree = TclStrIdxTreeGetFromObj(objPtr)) == NULL) {
	    goto done;	/* unexpected, but ...*/
	}

	while (*mcKeys) {
	    valObj = ClockMCGet(opts, *mcKeys);
	    if (valObj == NULL) {
		goto done;
	    }
	    if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
		goto done;
	    }
	    if (TclStrIdxTreeBuildFromList(idxTree, lstc, lstv, NULL) != TCL_OK) {
		goto done;
	    }
	    mcKeys++;
	}

	ClockMCSetIdx(opts, mcKey, objPtr);
	objPtr = NULL;
    }

  done:
    if (objPtr) {
	Tcl_DecrRefCount(objPtr);
	idxTree = NULL;







|

















|












|







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
static TclStrIdxTree *
ClockMCGetMultiListIdxTree(
    ClockFmtScnCmdArgs *opts,
    int	mcKey,
    int *mcKeys)
{
    TclStrIdxTree * idxTree;
    Tcl_Obj *objPtr = TclClockMCGetIdx(opts, mcKey);

    if (objPtr != NULL
	    && (idxTree = TclStrIdxTreeGetFromObj(objPtr)) != NULL) {
	return idxTree;
    } else {
	/* build new index */

	Tcl_Obj **lstv;
	Tcl_Size lstc;
	Tcl_Obj *valObj;

	objPtr = TclStrIdxTreeNewObj();
	if ((idxTree = TclStrIdxTreeGetFromObj(objPtr)) == NULL) {
	    goto done;	/* unexpected, but ...*/
	}

	while (*mcKeys) {
	    valObj = TclClockMCGet(opts, *mcKeys);
	    if (valObj == NULL) {
		goto done;
	    }
	    if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
		goto done;
	    }
	    if (TclStrIdxTreeBuildFromList(idxTree, lstc, lstv, NULL) != TCL_OK) {
		goto done;
	    }
	    mcKeys++;
	}

	TclClockMCSetIdx(opts, mcKey, objPtr);
	objPtr = NULL;
    }

  done:
    if (objPtr) {
	Tcl_DecrRefCount(objPtr);
	idxTree = NULL;
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
{
    int ret, val;
    int minLen, maxLen;
    Tcl_Obj *amPmObj[2];

    DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);

    amPmObj[0] = ClockMCGet(opts, MCLIT_AM);
    amPmObj[1] = ClockMCGet(opts, MCLIT_PM);

    if (amPmObj[0] == NULL || amPmObj[1] == NULL) {
	return TCL_ERROR;
    }

    ret = ObjListSearch(info, &val, amPmObj, 2, minLen, maxLen);
    if (ret != TCL_OK) {







|
|







1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
{
    int ret, val;
    int minLen, maxLen;
    Tcl_Obj *amPmObj[2];

    DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);

    amPmObj[0] = TclClockMCGet(opts, MCLIT_AM);
    amPmObj[1] = TclClockMCGet(opts, MCLIT_PM);

    if (amPmObj[0] == NULL || amPmObj[1] == NULL) {
	return TCL_ERROR;
    }

    ret = ObjListSearch(info, &val, amPmObj, 2, minLen, maxLen);
    if (ret != TCL_OK) {
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707

    int ret, val;
    int minLen, maxLen;
    Tcl_Obj *eraObj[6];

    DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);

    eraObj[0] = ClockMCGet(opts, MCLIT_BCE);
    eraObj[1] = ClockMCGet(opts, MCLIT_CE);
    eraObj[2] = dataPtr->mcLiterals[MCLIT_BCE2];
    eraObj[3] = dataPtr->mcLiterals[MCLIT_CE2];
    eraObj[4] = dataPtr->mcLiterals[MCLIT_BCE3];
    eraObj[5] = dataPtr->mcLiterals[MCLIT_CE3];

    if (eraObj[0] == NULL || eraObj[1] == NULL) {
	return TCL_ERROR;







|
|







1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709

    int ret, val;
    int minLen, maxLen;
    Tcl_Obj *eraObj[6];

    DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);

    eraObj[0] = TclClockMCGet(opts, MCLIT_BCE);
    eraObj[1] = TclClockMCGet(opts, MCLIT_CE);
    eraObj[2] = dataPtr->mcLiterals[MCLIT_BCE2];
    eraObj[3] = dataPtr->mcLiterals[MCLIT_CE2];
    eraObj[4] = dataPtr->mcLiterals[MCLIT_BCE3];
    eraObj[5] = dataPtr->mcLiterals[MCLIT_CE3];

    if (eraObj[0] == NULL || eraObj[1] == NULL) {
	return TCL_ERROR;
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913

	/* convert using dict */
    }

    /* try to apply new time zone */
    Tcl_IncrRefCount(tzObjStor);

    opts->timezoneObj = ClockSetupTimeZone(opts->dataPtr, opts->interp,
	    tzObjStor);

    Tcl_DecrRefCount(tzObjStor);
    if (opts->timezoneObj == NULL) {
	return TCL_ERROR;
    }








|







1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915

	/* convert using dict */
    }

    /* try to apply new time zone */
    Tcl_IncrRefCount(tzObjStor);

    opts->timezoneObj = TclClockSetupTimeZone(opts->dataPtr, opts->interp,
	    tzObjStor);

    Tcl_DecrRefCount(tzObjStor);
    if (opts->timezoneObj == NULL) {
	return TCL_ERROR;
    }

1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997

    /* Build a date from year and fraction. */

    yydate.year = year + RODDENBERRY;
    yydate.isBce = 0;
    yydate.gregorian = 1;

    if (IsGregorianLeapYear(&yydate)) {
	fractYear *= 366;
    } else {
	fractYear *= 365;
    }
    yydate.dayOfYear = fractYear / 1000 + 1;
    if (fractYear % 1000 >= 500) {
	yydate.dayOfYear++;
    }

    GetJulianDayFromEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);

    yydate.localSeconds =
	    -210866803200LL
	    + (SECONDS_PER_DAY * yydate.julianDay)
	    + (SECONDS_PER_DAY * fractDay / fractDayDiv);

    return TCL_OK;







|









|







1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999

    /* Build a date from year and fraction. */

    yydate.year = year + RODDENBERRY;
    yydate.isBce = 0;
    yydate.gregorian = 1;

    if (TclIsGregorianLeapYear(&yydate)) {
	fractYear *= 366;
    } else {
	fractYear *= 365;
    }
    yydate.dayOfYear = fractYear / 1000 + 1;
    if (fractYear % 1000 >= 500) {
	yydate.dayOfYear++;
    }

    TclGetJulianDayFromEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);

    yydate.localSeconds =
	    -210866803200LL
	    + (SECONDS_PER_DAY * yydate.julianDay)
	    + (SECONDS_PER_DAY * fractDay / fractDayDiv);

    return TCL_OK;
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
	(tokCnt) += CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE;			 \
    }									 \
    memset(tok, 0, sizeof(*(tok)));

/*
 *----------------------------------------------------------------------
 */
ClockFmtScnStorage *
ClockGetOrParseScanFormat(
    Tcl_Interp *interp,		/* Tcl interpreter */
    Tcl_Obj *formatObj)		/* Format container */
{
    ClockFmtScnStorage *fss;

    fss = Tcl_GetClockFrmScnFromObj(interp, formatObj);







|







2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
	(tokCnt) += CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE;			 \
    }									 \
    memset(tok, 0, sizeof(*(tok)));

/*
 *----------------------------------------------------------------------
 */
static ClockFmtScnStorage *
ClockGetOrParseScanFormat(
    Tcl_Interp *interp,		/* Tcl interpreter */
    Tcl_Obj *formatObj)		/* Format container */
{
    ClockFmtScnStorage *fss;

    fss = Tcl_GetClockFrmScnFromObj(interp, formatObj);
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
    return fss;
}

/*
 *----------------------------------------------------------------------
 */
int
ClockScan(
    DateInfo *info,		/* Date fields used for parsing & converting */
    Tcl_Obj *strObj,		/* String containing the time to scan */
    ClockFmtScnCmdArgs *opts)	/* Command options */
{
    ClockClientData *dataPtr = opts->dataPtr;
    const ClockFmtScnStorage *fss;
    const ClockScanToken *tok;







|







2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
    return fss;
}

/*
 *----------------------------------------------------------------------
 */
int
TclClockScan(
    DateInfo *info,		/* Date fields used for parsing & converting */
    Tcl_Obj *strObj,		/* String containing the time to scan */
    ClockFmtScnCmdArgs *opts)	/* Command options */
{
    ClockClientData *dataPtr = opts->dataPtr;
    const ClockFmtScnStorage *fss;
    const ClockScanToken *tok;
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
	if (!(flags & (CLF_TIME | CLF_LOCALSEC | CLF_POSIXSEC))) {
	    info->flags |= CLF_ASSEMBLE_SECONDS;
	    yydate.localSeconds = 0;
	}

	if (flags & CLF_TIME) {
	    info->flags |= CLF_ASSEMBLE_SECONDS;
	    yySecondOfDay = ToSeconds(yyHour, yyMinutes,
		    yySeconds, yyMeridian);
	} else if (!(flags & (CLF_LOCALSEC | CLF_POSIXSEC))) {
	    info->flags |= CLF_ASSEMBLE_SECONDS;
	    yySecondOfDay = yydate.localSeconds % SECONDS_PER_DAY;
	}
    }








|







2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
	if (!(flags & (CLF_TIME | CLF_LOCALSEC | CLF_POSIXSEC))) {
	    info->flags |= CLF_ASSEMBLE_SECONDS;
	    yydate.localSeconds = 0;
	}

	if (flags & CLF_TIME) {
	    info->flags |= CLF_ASSEMBLE_SECONDS;
	    yySecondOfDay = TclToSeconds(yyHour, yyMinutes,
		    yySeconds, yyMeridian);
	} else if (!(flags & (CLF_LOCALSEC | CLF_POSIXSEC))) {
	    info->flags |= CLF_ASSEMBLE_SECONDS;
	    yySecondOfDay = yydate.localSeconds % SECONDS_PER_DAY;
	}
    }

2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
    int *val)
{
    Tcl_Obj *mcObj;
    const char *s;
    Tcl_Size len;

    if (*val < (SECONDS_PER_DAY / 2)) {
	mcObj = ClockMCGet(opts, MCLIT_AM);
    } else {
	mcObj = ClockMCGet(opts, MCLIT_PM);
    }
    if (mcObj == NULL) {
	return TCL_ERROR;
    }
    s = TclGetStringFromObj(mcObj, &len);
    if (FrmResultAllocate(dateFmt, len) != TCL_OK) {
	return TCL_ERROR;







|

|







2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
    int *val)
{
    Tcl_Obj *mcObj;
    const char *s;
    Tcl_Size len;

    if (*val < (SECONDS_PER_DAY / 2)) {
	mcObj = TclClockMCGet(opts, MCLIT_AM);
    } else {
	mcObj = TclClockMCGet(opts, MCLIT_PM);
    }
    if (mcObj == NULL) {
	return TCL_ERROR;
    }
    s = TclGetStringFromObj(mcObj, &len);
    if (FrmResultAllocate(dateFmt, len) != TCL_OK) {
	return TCL_ERROR;
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
    TCL_UNUSED(int *))
{
    int fractYear;
    /* Get day of year, zero based */
    int v = dateFmt->date.dayOfYear - 1;

    /* Convert day of year to a fractional year */
    if (IsGregorianLeapYear(&dateFmt->date)) {
	fractYear = 1000 * v / 366;
    } else {
	fractYear = 1000 * v / 365;
    }

    /* Put together the StarDate as "Stardate %02d%03d.%1d" */
    if (FrmResultAllocate(dateFmt, 30) != TCL_OK) {







|







2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
    TCL_UNUSED(int *))
{
    int fractYear;
    /* Get day of year, zero based */
    int v = dateFmt->date.dayOfYear - 1;

    /* Convert day of year to a fractional year */
    if (TclIsGregorianLeapYear(&dateFmt->date)) {
	fractYear = 1000 * v / 366;
    } else {
	fractYear = 1000 * v / 365;
    }

    /* Put together the StarDate as "Stardate %02d%03d.%1d" */
    if (FrmResultAllocate(dateFmt, 30) != TCL_OK) {
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
	}
    } else {
	Tcl_Obj * objPtr;
	const char *s;
	Tcl_Size len;

	/* convert seconds to local seconds to obtain tzName object */
	if (ConvertUTCToLocal(opts->dataPtr, opts->interp,
		&dateFmt->date, opts->timezoneObj,
		GREGORIAN_CHANGE_DATE) != TCL_OK) {
	    return TCL_ERROR;
	}
	objPtr = dateFmt->date.tzName;
	s = TclGetStringFromObj(objPtr, &len);
	if (FrmResultAllocate(dateFmt, len) != TCL_OK) {







|







2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
	}
    } else {
	Tcl_Obj * objPtr;
	const char *s;
	Tcl_Size len;

	/* convert seconds to local seconds to obtain tzName object */
	if (TclConvertUTCToLocal(opts->dataPtr, opts->interp,
		&dateFmt->date, opts->timezoneObj,
		GREGORIAN_CHANGE_DATE) != TCL_OK) {
	    return TCL_ERROR;
	}
	objPtr = dateFmt->date.tzName;
	s = TclGetStringFromObj(objPtr, &len);
	if (FrmResultAllocate(dateFmt, len) != TCL_OK) {
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
    TCL_UNUSED(int *))
{
    Tcl_Obj *mcObj;
    const char *s;
    Tcl_Size len;

    if (dateFmt->date.isBce) {
	mcObj = ClockMCGet(opts, MCLIT_BCE);
    } else {
	mcObj = ClockMCGet(opts, MCLIT_CE);
    }
    if (mcObj == NULL) {
	return TCL_ERROR;
    }
    s = TclGetStringFromObj(mcObj, &len);
    if (FrmResultAllocate(dateFmt, len) != TCL_OK) {
	return TCL_ERROR;







|

|







2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
    TCL_UNUSED(int *))
{
    Tcl_Obj *mcObj;
    const char *s;
    Tcl_Size len;

    if (dateFmt->date.isBce) {
	mcObj = TclClockMCGet(opts, MCLIT_BCE);
    } else {
	mcObj = TclClockMCGet(opts, MCLIT_CE);
    }
    if (mcObj == NULL) {
	return TCL_ERROR;
    }
    s = TclGetStringFromObj(mcObj, &len);
    if (FrmResultAllocate(dateFmt, len) != TCL_OK) {
	return TCL_ERROR;
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
    ClockFormatToken *tok,
    int *val)
{
    Tcl_Size rowc;
    Tcl_Obj **rowv;

    if (dateFmt->localeEra == NULL) {
	Tcl_Obj *mcObj = ClockMCGet(opts, MCLIT_LOCALE_ERAS);
	if (mcObj == NULL) {
	    return TCL_ERROR;
	}
	if (TclListObjGetElements(opts->interp, mcObj, &rowc, &rowv) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (rowc != 0) {
	    dateFmt->localeEra = LookupLastTransition(opts->interp,
		    dateFmt->date.localSeconds, rowc, rowv, NULL);
	}
	if (dateFmt->localeEra == NULL) {
	    dateFmt->localeEra = (Tcl_Obj*)1;
	}
    }








|







|







3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
    ClockFormatToken *tok,
    int *val)
{
    Tcl_Size rowc;
    Tcl_Obj **rowv;

    if (dateFmt->localeEra == NULL) {
	Tcl_Obj *mcObj = TclClockMCGet(opts, MCLIT_LOCALE_ERAS);
	if (mcObj == NULL) {
	    return TCL_ERROR;
	}
	if (TclListObjGetElements(opts->interp, mcObj, &rowc, &rowv) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (rowc != 0) {
	    dateFmt->localeEra = TclClockLookupLastTransition(opts->interp,
		    dateFmt->date.localSeconds, rowc, rowv, NULL);
	}
	if (dateFmt->localeEra == NULL) {
	    dateFmt->localeEra = (Tcl_Obj*)1;
	}
    }

3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
	    if (Tcl_GetIntFromObj(opts->interp, objPtr, val) != TCL_OK) {
		return TCL_ERROR;
	    }
	    *val = dateFmt->date.year - *val;
	    /* if year in locale numerals */
	    if (*val >= 0 && *val < 100) {
		/* year as integer */
		Tcl_Obj * mcObj = ClockMCGet(opts, MCLIT_LOCALE_NUMERALS);
		if (mcObj == NULL) {
		    return TCL_ERROR;
		}
		if (Tcl_ListObjIndex(opts->interp, mcObj, *val, &objPtr) != TCL_OK) {
		    return TCL_ERROR;
		}
	    } else {







|







3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
	    if (Tcl_GetIntFromObj(opts->interp, objPtr, val) != TCL_OK) {
		return TCL_ERROR;
	    }
	    *val = dateFmt->date.year - *val;
	    /* if year in locale numerals */
	    if (*val >= 0 && *val < 100) {
		/* year as integer */
		Tcl_Obj * mcObj = TclClockMCGet(opts, MCLIT_LOCALE_NUMERALS);
		if (mcObj == NULL) {
		    return TCL_ERROR;
		}
		if (Tcl_ListObjIndex(opts->interp, mcObj, *val, &objPtr) != TCL_OK) {
		    return TCL_ERROR;
		}
	    } else {
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
static const ClockFormatTokenMap FmtWordTokenMap = {
    CTOKT_WORD, NULL, 0, 0, 0, 0, 0, NULL, NULL
};

/*
 *----------------------------------------------------------------------
 */
ClockFmtScnStorage *
ClockGetOrParseFmtFormat(
    Tcl_Interp *interp,		/* Tcl interpreter */
    Tcl_Obj *formatObj)		/* Format container */
{
    ClockFmtScnStorage *fss;

    fss = Tcl_GetClockFrmScnFromObj(interp, formatObj);







|







3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
static const ClockFormatTokenMap FmtWordTokenMap = {
    CTOKT_WORD, NULL, 0, 0, 0, 0, 0, NULL, NULL
};

/*
 *----------------------------------------------------------------------
 */
static ClockFmtScnStorage *
ClockGetOrParseFmtFormat(
    Tcl_Interp *interp,		/* Tcl interpreter */
    Tcl_Obj *formatObj)		/* Format container */
{
    ClockFmtScnStorage *fss;

    fss = Tcl_GetClockFrmScnFromObj(interp, formatObj);
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
    return fss;
}

/*
 *----------------------------------------------------------------------
 */
int
ClockFormat(
    DateFormat *dateFmt,	/* Date fields used for parsing & converting */
    ClockFmtScnCmdArgs *opts)	/* Command options */
{
    ClockFmtScnStorage *fss;
    ClockFormatToken *tok;
    const ClockFormatTokenMap *map;
    char resMem[MIN_FMT_RESULT_BLOCK_ALLOC];







|







3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
    return fss;
}

/*
 *----------------------------------------------------------------------
 */
int
TclClockFormat(
    DateFormat *dateFmt,	/* Date fields used for parsing & converting */
    ClockFmtScnCmdArgs *opts)	/* Command options */
{
    ClockFmtScnStorage *fss;
    ClockFormatToken *tok;
    const ClockFormatTokenMap *map;
    char resMem[MIN_FMT_RESULT_BLOCK_ALLOC];
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
		    dateFmt->output = Clock_itoaw(
			    dateFmt->output, val, *map->tostr, map->width);
		} else {
		    dateFmt->output += sprintf(dateFmt->output, map->tostr, val);
		}
	    } else {
		const char *s;
		Tcl_Obj * mcObj = ClockMCGet(opts, PTR2INT(map->data) /* mcKey */);

		if (mcObj == NULL) {
		    goto error;
		}
		if (Tcl_ListObjIndex(opts->interp, mcObj, val, &mcObj) != TCL_OK
			|| mcObj == NULL) {
		    goto error;







|







3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
		    dateFmt->output = Clock_itoaw(
			    dateFmt->output, val, *map->tostr, map->width);
		} else {
		    dateFmt->output += sprintf(dateFmt->output, map->tostr, val);
		}
	    } else {
		const char *s;
		Tcl_Obj * mcObj = TclClockMCGet(opts, PTR2INT(map->data) /* mcKey */);

		if (mcObj == NULL) {
		    goto error;
		}
		if (Tcl_ListObjIndex(opts->interp, mcObj, val, &mcObj) != TCL_OK
			|| mcObj == NULL) {
		    goto error;
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
    }

    return TCL_ERROR;
}


void
ClockFrmScnClearCaches(void)
{
    Tcl_MutexLock(&ClockFmtMutex);
    /* clear caches ... */
    Tcl_MutexUnlock(&ClockFmtMutex);
}

void
ClockFrmScnFinalize(void)
{
    if (!initialized) {
	return;
    }
    Tcl_MutexLock(&ClockFmtMutex);
#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
    /* clear GC */







|







|







3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
    }

    return TCL_ERROR;
}


void
TclClockFrmScnClearCaches(void)
{
    Tcl_MutexLock(&ClockFmtMutex);
    /* clear caches ... */
    Tcl_MutexUnlock(&ClockFmtMutex);
}

void
TclClockFrmScnFinalize(void)
{
    if (!initialized) {
	return;
    }
    Tcl_MutexLock(&ClockFmtMutex);
#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
    /* clear GC */
Changes to generic/tclCmdAH.c.
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
	/* Variables */
	statePtr->vCopyList[i] = TclListObjCopy(interp, objv[1+i*2]);
	if (statePtr->vCopyList[i] == NULL) {
	    result = TCL_ERROR;
	    goto done;
	}
	result = TclListObjLength(interp, statePtr->vCopyList[i],
	    &statePtr->varcList[i]);
	if (result != TCL_OK) {
	    result = TCL_ERROR;
	    goto done;
	}
	if (statePtr->varcList[i] < 1) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"%s varlist is empty",
		(statePtr->resultList != NULL ? "lmap" : "foreach")));
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION",
		(statePtr->resultList != NULL ? "LMAP" : "FOREACH"),
		"NEEDVARS", (char *)NULL);
	    result = TCL_ERROR;
	    goto done;
	}
	TclListObjGetElements(NULL, statePtr->vCopyList[i],
	    &statePtr->varcList[i], &statePtr->varvList[i]);

	/* Values */
	if (TclObjTypeHasProc(objv[2+i*2],indexProc)) {
	    /* Special case for AbstractList */
	    statePtr->aCopyList[i] = Tcl_DuplicateObj(objv[2+i*2]);
	    if (statePtr->aCopyList[i] == NULL) {
		result = TCL_ERROR;







|















|







2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
	/* Variables */
	statePtr->vCopyList[i] = TclListObjCopy(interp, objv[1+i*2]);
	if (statePtr->vCopyList[i] == NULL) {
	    result = TCL_ERROR;
	    goto done;
	}
	result = TclListObjLength(interp, statePtr->vCopyList[i],
		&statePtr->varcList[i]);
	if (result != TCL_OK) {
	    result = TCL_ERROR;
	    goto done;
	}
	if (statePtr->varcList[i] < 1) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"%s varlist is empty",
		(statePtr->resultList != NULL ? "lmap" : "foreach")));
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION",
		(statePtr->resultList != NULL ? "LMAP" : "FOREACH"),
		"NEEDVARS", (char *)NULL);
	    result = TCL_ERROR;
	    goto done;
	}
	TclListObjGetElements(NULL, statePtr->vCopyList[i],
		&statePtr->varcList[i], &statePtr->varvList[i]);

	/* Values */
	if (TclObjTypeHasProc(objv[2+i*2],indexProc)) {
	    /* Special case for AbstractList */
	    statePtr->aCopyList[i] = Tcl_DuplicateObj(objv[2+i*2]);
	    if (statePtr->aCopyList[i] == NULL) {
		result = TCL_ERROR;
Changes to generic/tclCmdIL.c.
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
    }

    if (TclObjTypeHasProc(objv[1], getElementsProc)) {
	sortInfo.resultCode =
	    TclObjTypeGetElements(interp, listObj, &length, &listObjPtrs);
    } else {
	sortInfo.resultCode = TclListObjGetElements(interp, listObj,
	    &length, &listObjPtrs);
    }
    if (sortInfo.resultCode != TCL_OK || length <= 0) {
	goto done;
    }

    /*
     * Check for sanity when grouping elements of the overall list together







|







4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
    }

    if (TclObjTypeHasProc(objv[1], getElementsProc)) {
	sortInfo.resultCode =
	    TclObjTypeGetElements(interp, listObj, &length, &listObjPtrs);
    } else {
	sortInfo.resultCode = TclListObjGetElements(interp, listObj,
		&length, &listObjPtrs);
    }
    if (sortInfo.resultCode != TCL_OK || length <= 0) {
	goto done;
    }

    /*
     * Check for sanity when grouping elements of the overall list together
Changes to generic/tclCmdMZ.c.
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465

3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int i, mode, foundmode, splitObjs, numMatchesSaved;
    int noCase;
    Tcl_Size patternLength, j;
    const char *pattern;
    Tcl_Obj *stringObj, *indexVarObj, *matchVarObj;
    Tcl_Obj *const *savedObjv = objv;
    Tcl_RegExp regExpr = NULL;

    Interp *iPtr = (Interp *) interp;
    int pc = 0;
    int bidx = 0;		/* Index of body argument. */
    Tcl_Obj *blist = NULL;	/* List obj which is the body */
    CmdFrame *ctxPtr;		/* Copy of the topmost cmdframe, to allow us
				 * to mess with the line information */

    /*
     * If you add options that make -e and -g not unique prefixes of -exact or
     * -glob, you *must* fix TclCompileSwitchCmd's option parser as well.
     */

    static const char *const options[] = {
	"-exact", "-glob", "-indexvar", "-matchvar", "-nocase", "-regexp",
	"--", NULL
    };
    enum switchOptionsEnum {
	OPT_EXACT, OPT_GLOB, OPT_INDEXV, OPT_MATCHV, OPT_NOCASE, OPT_REGEXP,
	OPT_LAST
    } index;
    typedef int (*strCmpFn_t)(const char *, const char *);
    strCmpFn_t strCmpFn = TclUtfCmp;

    mode = OPT_EXACT;
    foundmode = 0;
    indexVarObj = NULL;







|


>













|
|


|
|







3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int i, mode, foundmode, splitObjs, numMatchesSaved;
    int noCase;
    Tcl_Size patternLength, j;
    const char *pattern;
    Tcl_Obj *valueObj, *indexVarObj, *matchVarObj;
    Tcl_Obj *const *savedObjv = objv;
    Tcl_RegExp regExpr = NULL;
    Tcl_WideInt intValue = 0, armValue;
    Interp *iPtr = (Interp *) interp;
    int pc = 0;
    int bidx = 0;		/* Index of body argument. */
    Tcl_Obj *blist = NULL;	/* List obj which is the body */
    CmdFrame *ctxPtr;		/* Copy of the topmost cmdframe, to allow us
				 * to mess with the line information */

    /*
     * If you add options that make -e and -g not unique prefixes of -exact or
     * -glob, you *must* fix TclCompileSwitchCmd's option parser as well.
     */

    static const char *const options[] = {
	"-exact", "-glob", "-indexvar", "-integer", "-matchvar", "-nocase",
	"-regexp", "--", NULL
    };
    enum switchOptionsEnum {
	OPT_EXACT, OPT_GLOB, OPT_INDEXV, OPT_INTEGER, OPT_MATCHV, OPT_NOCASE,
	OPT_REGEXP, OPT_LAST
    } index;
    typedef int (*strCmpFn_t)(const char *, const char *);
    strCmpFn_t strCmpFn = TclUtfCmp;

    mode = OPT_EXACT;
    foundmode = 0;
    indexVarObj = NULL;
3584
3585
3586
3587
3588
3589
3590






3591

3592
3593
3594
3595
3596
3597
3598
3599
    if (matchVarObj != NULL && mode != OPT_REGEXP) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"%s option requires -regexp option", "-matchvar"));
	Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH",
		"MODERESTRICTION", (char *)NULL);
	return TCL_ERROR;
    }








    stringObj = objv[i];
    objc -= i + 1;
    objv += i + 1;
    bidx = i + 1;		/* First after the match string. */

    /*
     * If all of the pattern/command pairs are lumped into a single argument,
     * split them out again.







>
>
>
>
>
>
|
>
|







3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
    if (matchVarObj != NULL && mode != OPT_REGEXP) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"%s option requires -regexp option", "-matchvar"));
	Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH",
		"MODERESTRICTION", (char *)NULL);
	return TCL_ERROR;
    }
    if (noCase && mode == OPT_INTEGER) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"-nocase option cannot be used with -integer option"));
	Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH",
		"MODERESTRICTION", (char *)NULL);
	return TCL_ERROR;
    }

    valueObj = objv[i];
    objc -= i + 1;
    objv += i + 1;
    bidx = i + 1;		/* First after the match string. */

    /*
     * If all of the pattern/command pairs are lumped into a single argument,
     * split them out again.
3676
3677
3678
3679
3680
3681
3682






3683
3684
3685
3686
3687
3688
3689
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"no body specified for pattern \"%s\"",
		TclGetString(objv[objc-2])));
	Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "BADARM",
		"FALLTHROUGH", (char *)NULL);
	return TCL_ERROR;
    }







    for (i = 0; i < objc; i += 2) {
	/*
	 * See if the pattern matches the string.
	 */

	pattern = TclGetStringFromObj(objv[i], &patternLength);







>
>
>
>
>
>







3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"no body specified for pattern \"%s\"",
		TclGetString(objv[objc-2])));
	Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "BADARM",
		"FALLTHROUGH", (char *)NULL);
	return TCL_ERROR;
    }

    if (mode == OPT_INTEGER) {
	if (Tcl_GetWideIntFromObj(interp, valueObj, &intValue) != TCL_OK) {
	    return TCL_ERROR;
	}
    }

    for (i = 0; i < objc; i += 2) {
	/*
	 * See if the pattern matches the string.
	 */

	pattern = TclGetStringFromObj(objv[i], &patternLength);
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746







3747
3748
3749
3750
3751
3752
3753
		}
	    }
	    goto matchFound;
	}

	switch (mode) {
	case OPT_EXACT:
	    if (strCmpFn(TclGetString(stringObj), pattern) == 0) {
		goto matchFound;
	    }
	    break;
	case OPT_GLOB:
	    if (Tcl_StringCaseMatch(TclGetString(stringObj),pattern,noCase)) {
		goto matchFound;
	    }
	    break;
	case OPT_REGEXP:
	    regExpr = Tcl_GetRegExpFromObj(interp, objv[i],
		    TCL_REG_ADVANCED | (noCase ? TCL_REG_NOCASE : 0));
	    if (regExpr == NULL) {
		return TCL_ERROR;
	    } else {
		int matched = Tcl_RegExpExecObj(interp, regExpr, stringObj, 0,
			numMatchesSaved, 0);

		if (matched < 0) {
		    return TCL_ERROR;
		} else if (matched) {
		    goto matchFoundRegexp;
		}
	    }







	    break;
	}
    }
    return TCL_OK;

  matchFoundRegexp:
    /*







|




|









|








>
>
>
>
>
>
>







3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
		}
	    }
	    goto matchFound;
	}

	switch (mode) {
	case OPT_EXACT:
	    if (strCmpFn(TclGetString(valueObj), pattern) == 0) {
		goto matchFound;
	    }
	    break;
	case OPT_GLOB:
	    if (Tcl_StringCaseMatch(TclGetString(valueObj),pattern,noCase)) {
		goto matchFound;
	    }
	    break;
	case OPT_REGEXP:
	    regExpr = Tcl_GetRegExpFromObj(interp, objv[i],
		    TCL_REG_ADVANCED | (noCase ? TCL_REG_NOCASE : 0));
	    if (regExpr == NULL) {
		return TCL_ERROR;
	    } else {
		int matched = Tcl_RegExpExecObj(interp, regExpr, valueObj, 0,
			numMatchesSaved, 0);

		if (matched < 0) {
		    return TCL_ERROR;
		} else if (matched) {
		    goto matchFoundRegexp;
		}
	    }
	    break;
	case OPT_INTEGER:
	    if (Tcl_GetWideIntFromObj(interp, objv[i], &armValue) != TCL_OK) {
		return TCL_ERROR;
	    } else if (intValue == armValue) {
		goto matchFound;
	    }
	    break;
	}
    }
    return TCL_OK;

  matchFoundRegexp:
    /*
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
			Tcl_NewListObj(2, rangeObjAry));
	    }

	    if (matchVarObj != NULL) {
		Tcl_Obj *substringObj;

		if (info.matches[j].end > 0) {
		    substringObj = Tcl_GetRange(stringObj,
			    info.matches[j].start, info.matches[j].end-1);
		} else {
		    TclNewObj(substringObj);
		}

		/*
		 * Never fails; the object is always clean at this point.







|







3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
			Tcl_NewListObj(2, rangeObjAry));
	    }

	    if (matchVarObj != NULL) {
		Tcl_Obj *substringObj;

		if (info.matches[j].end > 0) {
		    substringObj = Tcl_GetRange(valueObj,
			    info.matches[j].start, info.matches[j].end-1);
		} else {
		    TclNewObj(substringObj);
		}

		/*
		 * Never fails; the object is always clean at this point.
Changes to generic/tclCompCmdsSZ.c.
21
22
23
24
25
26
27

28
29
30
31
32
33
34

/*
 * Information about a single arm for [switch]. Used in an array to pass
 * information to the code-issuer functions.
 */
typedef struct SwitchArmInfo {
    Tcl_Token *valueToken;	// The value to match for the arm.

    Tcl_Token *bodyToken;	// The body of an arm; NULL if fall-through.
    Tcl_Size bodyLine;		// The line that the body starts on.
    Tcl_Size *bodyContLines;	// Continuations within the body.
} SwitchArmInfo;

/*
 * Information about a single handler for [try]. Used in an array to pass







>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

/*
 * Information about a single arm for [switch]. Used in an array to pass
 * information to the code-issuer functions.
 */
typedef struct SwitchArmInfo {
    Tcl_Token *valueToken;	// The value to match for the arm.
    Tcl_WideInt valueInt;	// The value to match in integer mode.
    Tcl_Token *bodyToken;	// The body of an arm; NULL if fall-through.
    Tcl_Size bodyLine;		// The line that the body starts on.
    Tcl_Size *bodyContLines;	// Continuations within the body.
} SwitchArmInfo;

/*
 * Information about a single handler for [try]. Used in an array to pass
66
67
68
69
70
71
72



73
74
75
76
77
78
79
			    Tcl_Parse *parsePtr, int instruction,
			    CompileEnv *envPtr);
static void		IssueSwitchChainedTests(Tcl_Interp *interp,
			    CompileEnv *envPtr, int mode, int noCase,
			    Tcl_Size numArms, SwitchArmInfo *arms);
static void		IssueSwitchJumpTable(Tcl_Interp *interp,
			    CompileEnv *envPtr, int noCase, Tcl_Size numArms,



			    SwitchArmInfo *arms);
static int		IssueTryClausesInstructions(Tcl_Interp *interp,
			    CompileEnv *envPtr, Tcl_Token *bodyToken,
			    Tcl_Size numHandlers, TryHandlerInfo *handlers);
static int		IssueTryTraplessClausesInstructions(Tcl_Interp *interp,
			    CompileEnv *envPtr, Tcl_Token *bodyToken,
			    Tcl_Size numHandlers, TryHandlerInfo *handlers);







>
>
>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
			    Tcl_Parse *parsePtr, int instruction,
			    CompileEnv *envPtr);
static void		IssueSwitchChainedTests(Tcl_Interp *interp,
			    CompileEnv *envPtr, int mode, int noCase,
			    Tcl_Size numArms, SwitchArmInfo *arms);
static void		IssueSwitchJumpTable(Tcl_Interp *interp,
			    CompileEnv *envPtr, int noCase, Tcl_Size numArms,
			    SwitchArmInfo *arms);
static void		IssueSwitchNumJumpTable(Tcl_Interp *interp,
			    CompileEnv *envPtr, Tcl_Size numArms,
			    SwitchArmInfo *arms);
static int		IssueTryClausesInstructions(Tcl_Interp *interp,
			    CompileEnv *envPtr, Tcl_Token *bodyToken,
			    Tcl_Size numHandlers, TryHandlerInfo *handlers);
static int		IssueTryTraplessClausesInstructions(Tcl_Interp *interp,
			    CompileEnv *envPtr, Tcl_Token *bodyToken,
			    Tcl_Size numHandlers, TryHandlerInfo *handlers);
1746
1747
1748
1749
1750
1751
1752








1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782

1783
1784

1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
 * Side effects:
 *	Instructions are added to envPtr to execute the "switch" command at
 *	runtime.
 *
 *----------------------------------------------------------------------
 */









int
TclCompileSwitchCmd(
    Tcl_Interp *interp,		/* Used for error reporting. */
    Tcl_Parse *parsePtr,	/* Points to a parse structure for the command
				 * created by Tcl_ParseCommand. */
    TCL_UNUSED(Command *),
    CompileEnv *envPtr)		/* Holds resulting instructions. */
{
    DefineLineInformation;	/* TIP #280 */
    Tcl_Token *tokenPtr;	/* Pointer to tokens in command. */
    Tcl_Size numWords;		/* Number of words in command. */

    Tcl_Token *valueTokenPtr;	/* Token for the value to switch on. */
    enum {Switch_Exact, Switch_Glob, Switch_Regexp} mode;
				/* What kind of switch are we doing? */

    Tcl_Token *bodyTokenArray;	/* Array of real pattern list items. */
    SwitchArmInfo *arms;	/* Array of information about switch arms. */
    int noCase;			/* Has the -nocase flag been given? */
    int foundMode = 0;		/* Have we seen a mode flag yet? */
    Tcl_Size i, valueIndex;
    int result = TCL_ERROR;
    Tcl_Size *clNext = envPtr->clNext;

    /*
     * Only handle the following versions:
     *   switch         ?--? word {pattern body ...}
     *   switch -exact  ?--? word {pattern body ...}
     *   switch -glob   ?--? word {pattern body ...}
     *   switch -regexp ?--? word {pattern body ...}

     *   switch         --   word simpleWordPattern simpleWordBody ...
     *   switch -exact  --   word simpleWordPattern simpleWordBody ...

     *   switch -glob   --   word simpleWordPattern simpleWordBody ...
     *   switch -regexp --   word simpleWordPattern simpleWordBody ...
     * When the mode is -glob, can also handle a -nocase flag.
     *
     * First off, we don't care how the command's word was generated; we're
     * compiling it anyway! So skip it...
     */

    tokenPtr = TokenAfter(parsePtr->tokenPtr);
    valueIndex = 1;







>
>
>
>
>
>
>
>













<
|
<










|
|
|
|
>
|
|
>
|
|
|







1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777

1778

1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
 * Side effects:
 *	Instructions are added to envPtr to execute the "switch" command at
 *	runtime.
 *
 *----------------------------------------------------------------------
 */

// What kind of switch are we doing?
typedef enum SwitchMode {
    Switch_Exact,		// Use exact string matching.
    Switch_Glob,		// Use glob/[string match] matching.
    Switch_Integer,		// Use integer comparisons.
    Switch_Regexp		// Use regular expression matching.
} SwitchMode;

int
TclCompileSwitchCmd(
    Tcl_Interp *interp,		/* Used for error reporting. */
    Tcl_Parse *parsePtr,	/* Points to a parse structure for the command
				 * created by Tcl_ParseCommand. */
    TCL_UNUSED(Command *),
    CompileEnv *envPtr)		/* Holds resulting instructions. */
{
    DefineLineInformation;	/* TIP #280 */
    Tcl_Token *tokenPtr;	/* Pointer to tokens in command. */
    Tcl_Size numWords;		/* Number of words in command. */

    Tcl_Token *valueTokenPtr;	/* Token for the value to switch on. */

    SwitchMode mode;		/* What kind of switch are we doing? */

    Tcl_Token *bodyTokenArray;	/* Array of real pattern list items. */
    SwitchArmInfo *arms;	/* Array of information about switch arms. */
    int noCase;			/* Has the -nocase flag been given? */
    int foundMode = 0;		/* Have we seen a mode flag yet? */
    Tcl_Size i, valueIndex;
    int result = TCL_ERROR;
    Tcl_Size *clNext = envPtr->clNext;

    /*
     * Only handle the following versions:
     *   switch          ?--? word {pattern body ...}
     *   switch -exact   ?--? word {pattern body ...}
     *   switch -glob    ?--? word {pattern body ...}
     *   switch -integer ?--? word {pattern body ...}
     *   switch -regexp  ?--? word {pattern body ...}
     *   switch          --   word simpleWordPattern simpleWordBody ...
     *   switch -exact   --   word simpleWordPattern simpleWordBody ...
     *   switch -glob    --   word simpleWordPattern simpleWordBody ...
     *   switch -integer --   word simpleWordPattern simpleWordBody ...
     *   switch -regexp  --   word simpleWordPattern simpleWordBody ...
     * When the mode is -exact or -glob, can also handle a -nocase flag.
     *
     * First off, we don't care how the command's word was generated; we're
     * compiling it anyway! So skip it...
     */

    tokenPtr = TokenAfter(parsePtr->tokenPtr);
    valueIndex = 1;
1840
1841
1842
1843
1844
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
1876
	} else if (IS_TOKEN_PREFIX(tokenPtr, 2, "-glob")) {
	    if (foundMode) {
		return TCL_ERROR;
	    }
	    mode = Switch_Glob;
	    foundMode = 1;
	    valueIndex++;








	    continue;
	} else if (IS_TOKEN_PREFIX(tokenPtr, 2, "-regexp")) {
	    if (foundMode) {
		return TCL_ERROR;
	    }
	    mode = Switch_Regexp;
	    foundMode = 1;
	    valueIndex++;
	    continue;
	} else if (IS_TOKEN_PREFIX(tokenPtr, 2, "-nocase")) {
	    noCase = 1;
	    valueIndex++;
	    continue;
	} else if (IS_TOKEN_LITERALLY(tokenPtr, "--")) {
	    valueIndex++;
	    break;








	}

	/*
	 * The switch command has many flags we cannot compile at all (e.g.
	 * all the RE-related ones) which we must have encountered. Either
	 * that or we have run off the end. The action here is the same: punt
	 * to interpreted version.
	 */

	return TCL_ERROR;
    }
    if (numWords < 3) {
	return TCL_ERROR;
    }







>
>
>
>
>
>
>
>
















>
>
>
>
>
>
>
>



<
<
|
|







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
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893


1894
1895
1896
1897
1898
1899
1900
1901
1902
	} else if (IS_TOKEN_PREFIX(tokenPtr, 2, "-glob")) {
	    if (foundMode) {
		return TCL_ERROR;
	    }
	    mode = Switch_Glob;
	    foundMode = 1;
	    valueIndex++;
	    continue;
	} else if (IS_TOKEN_PREFIX(tokenPtr, 4, "-integer")) {
	    if (foundMode) {
		return TCL_ERROR;
	    }
	    mode = Switch_Integer;
	    foundMode = 1;
	    valueIndex++;
	    continue;
	} else if (IS_TOKEN_PREFIX(tokenPtr, 2, "-regexp")) {
	    if (foundMode) {
		return TCL_ERROR;
	    }
	    mode = Switch_Regexp;
	    foundMode = 1;
	    valueIndex++;
	    continue;
	} else if (IS_TOKEN_PREFIX(tokenPtr, 2, "-nocase")) {
	    noCase = 1;
	    valueIndex++;
	    continue;
	} else if (IS_TOKEN_LITERALLY(tokenPtr, "--")) {
	    valueIndex++;
	    break;
	} else if (IS_TOKEN_PREFIX(tokenPtr, 4, "-indexvar")
		|| IS_TOKEN_PREFIX(tokenPtr, 2, "-matchvar")) {
	    /*
	     * Options that the compiler doesn't support. The bytecode engine
	     * doesn't have the machinery to extract the info from the regexp
	     * engine (yet; code welcome!).
	     */
	    return TCL_ERROR;
	}

	/*


	 * We've run off the end with something unrecognised or ambiguous.
	 * Punt to the interpreted version.
	 */

	return TCL_ERROR;
    }
    if (numWords < 3) {
	return TCL_ERROR;
    }
1900
1901
1902
1903
1904
1905
1906



1907
1908
1909
1910
1911
1912
1913
    if (numWords == 1) {
	const char *bytes;
	Tcl_Size maxLen, numBytes;
	int bline;		/* TIP #280: line of the pattern/action list,
				 * and start of list for when tracking the
				 * location. This list comes immediately after
				 * the value we switch on. */




	if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
	    return TCL_ERROR;
	}
	bytes = tokenPtr[1].start;
	numBytes = tokenPtr[1].size;








>
>
>







1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
    if (numWords == 1) {
	const char *bytes;
	Tcl_Size maxLen, numBytes;
	int bline;		/* TIP #280: line of the pattern/action list,
				 * and start of list for when tracking the
				 * location. This list comes immediately after
				 * the value we switch on. */
	int wasDefault = 0;	/* For detecting a non-terminal "default" when
				 * in [switch -integer] mode, as that's an
				 * error case. */

	if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
	    return TCL_ERROR;
	}
	bytes = tokenPtr[1].start;
	numBytes = tokenPtr[1].size;

1948
1949
1950
1951
1952
1953
1954























1955
1956
1957
1958
1959
1960
1961
		if (IsFallthroughToken(fakeToken)) {
		    arm->bodyToken = NULL;
		} else {
		    arm->bodyToken = fakeToken;
		}
	    } else {
		arm->valueToken = fakeToken;























	    }

	    /*
	     * TIP #280: Now determine the line the list element starts on
	     * (there is no need to do it earlier, due to the possibility of
	     * aborting, see above).
	     * Don't need to record the information for the values; they're







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







1977
1978
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
		if (IsFallthroughToken(fakeToken)) {
		    arm->bodyToken = NULL;
		} else {
		    arm->bodyToken = fakeToken;
		}
	    } else {
		arm->valueToken = fakeToken;
		if (mode == Switch_Integer) {
		    if (wasDefault) {
			// Non-terminal default! Error as it isn't an int...
			result = TCL_ERROR;
			goto freeTemporaries;
		    }
		    // Can't use IS_TOKEN_LITERALLY; this is an unwrapped token
		    if (arm->valueToken->size == 7 &&
			    !memcmp(arm->valueToken->start, "default", 7)) {
			wasDefault = 1;
		    } else {
			// Try to parse the token as an integer. If we can't,
			// it's an error, and we fallback to interpreted.
			Tcl_Obj *objPtr = Tcl_NewStringObj(arm->valueToken->start,
				arm->valueToken->size);
			result = Tcl_GetWideIntFromObj(interp, objPtr,
				&arm->valueInt);
			Tcl_BounceRefCount(objPtr);
			if (result != TCL_OK) {
			    goto freeTemporaries;
			}
		    }
		}
	    }

	    /*
	     * TIP #280: Now determine the line the list element starts on
	     * (there is no need to do it earlier, due to the possibility of
	     * aborting, see above).
	     * Don't need to record the information for the values; they're
1989
1990
1991
1992
1993
1994
1995



1996
1997
1998
1999
2000
2001
2002

	return TCL_ERROR;
    } else {
	/*
	 * Multi-word definition of patterns & actions.
	 */




	bodyTokenArray = NULL;
	arms = (SwitchArmInfo *) TclStackAlloc(interp,
		sizeof(SwitchArmInfo) * numWords / 2);
	for (i=0 ; i<numWords ; i++) {
	    /*
	     * We only handle the very simplest case. Anything more complex is
	     * a good reason to go to the interpreted case anyway due to







>
>
>







2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057

	return TCL_ERROR;
    } else {
	/*
	 * Multi-word definition of patterns & actions.
	 */

	int wasDefault = 0;	/* For detecting a non-terminal "default" when
				 * in [switch -integer] mode, as that's an
				 * error case. */
	bodyTokenArray = NULL;
	arms = (SwitchArmInfo *) TclStackAlloc(interp,
		sizeof(SwitchArmInfo) * numWords / 2);
	for (i=0 ; i<numWords ; i++) {
	    /*
	     * We only handle the very simplest case. Anything more complex is
	     * a good reason to go to the interpreted case anyway due to
2016
2017
2018
2019
2020
2021
2022




















2023
2024
2025
2026
2027
2028
2029
		} else {
		    arm->bodyToken = tokenPtr + 1;
		}
		arm->bodyLine = ExtCmdLocation.line[valueIndex + 1 + i];
		arm->bodyContLines = ExtCmdLocation.next[valueIndex + 1 + i];
	    } else {
		arm->valueToken = tokenPtr + 1;




















	    }
	    tokenPtr = TokenAfter(tokenPtr);
	}
    }

    /*
     * Fall back to interpreted if the last body is a continuation (it's







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







2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
		} else {
		    arm->bodyToken = tokenPtr + 1;
		}
		arm->bodyLine = ExtCmdLocation.line[valueIndex + 1 + i];
		arm->bodyContLines = ExtCmdLocation.next[valueIndex + 1 + i];
	    } else {
		arm->valueToken = tokenPtr + 1;
		if (mode == Switch_Integer) {
		    if (wasDefault) {
			// Non-terminal default! Error, as it isn't an int...
			result = TCL_ERROR;
			goto freeTemporaries;
		    } else if (IS_TOKEN_LITERALLY(tokenPtr, "default")) {
			wasDefault = 1;
		    } else {
			// Try to parse the token as an integer. If we can't,
			// it's an error, and we fallback to interpreted.
			Tcl_Obj *objPtr = Tcl_NewStringObj(arm->valueToken->start,
				arm->valueToken->size);
			result = Tcl_GetWideIntFromObj(interp, objPtr,
				&arm->valueInt);
			Tcl_BounceRefCount(objPtr);
			if (result != TCL_OK) {
			    goto freeTemporaries;
			}
		    }
		}
	    }
	    tokenPtr = TokenAfter(tokenPtr);
	}
    }

    /*
     * Fall back to interpreted if the last body is a continuation (it's
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049


2050
2051
2052
2053
2054
2055
2056
     * Now we commit to generating code; the parsing stage per se is done.
     * Check if we can generate a jump table, since if so that's faster than
     * doing an explicit compare with each body. Note that we're definitely
     * over-conservative with determining whether we can do the jump table,
     * but it handles the most common case well enough.
     */

    /* Both methods push the value to match against onto the stack. */
    PUSH_TOKEN(			valueTokenPtr, valueIndex);

    if (mode == Switch_Exact) {
	IssueSwitchJumpTable(interp, envPtr, noCase, numWords/2, arms);


    } else {
	IssueSwitchChainedTests(interp, envPtr, mode, noCase, numWords/2, arms);
    }
    result = TCL_OK;

    /*
     * Clean up all our temporary space and return.







|




>
>







2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
     * Now we commit to generating code; the parsing stage per se is done.
     * Check if we can generate a jump table, since if so that's faster than
     * doing an explicit compare with each body. Note that we're definitely
     * over-conservative with determining whether we can do the jump table,
     * but it handles the most common case well enough.
     */

    /* All methods push the value to match against onto the stack. */
    PUSH_TOKEN(			valueTokenPtr, valueIndex);

    if (mode == Switch_Exact) {
	IssueSwitchJumpTable(interp, envPtr, noCase, numWords/2, arms);
    } else if (mode == Switch_Integer) {
	IssueSwitchNumJumpTable(interp, envPtr, numWords/2, arms);
    } else {
	IssueSwitchChainedTests(interp, envPtr, mode, noCase, numWords/2, arms);
    }
    result = TCL_OK;

    /*
     * Clean up all our temporary space and return.
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
    Tcl_Interp *interp,		/* Context for compiling script bodies. */
    CompileEnv *envPtr,		/* Holds resulting instructions. */
    int mode,			/* Exact, Glob or Regexp */
    int noCase,			/* Case-insensitivity flag. */
    Tcl_Size numArms,		/* Number of arms of the switch. */
    SwitchArmInfo *arms)	/* Array of arm descriptors. */
{
    enum {Switch_Exact, Switch_Glob, Switch_Regexp};
    int foundDefault;		/* Flag to indicate whether a "default" clause
				 * is present. */
    Tcl_BytecodeLabel *fwdJumps;/* Array of forward-jump fixup locations. */
    Tcl_Size jumpCount;		/* Next cell to use in fwdJumps array. */
    Tcl_Size contJumpIdx;	/* Where the first of the jumps due to a group
				 * of continuation bodies starts, or -1 if
				 * there aren't any. */







<







2166
2167
2168
2169
2170
2171
2172

2173
2174
2175
2176
2177
2178
2179
    Tcl_Interp *interp,		/* Context for compiling script bodies. */
    CompileEnv *envPtr,		/* Holds resulting instructions. */
    int mode,			/* Exact, Glob or Regexp */
    int noCase,			/* Case-insensitivity flag. */
    Tcl_Size numArms,		/* Number of arms of the switch. */
    SwitchArmInfo *arms)	/* Array of arm descriptors. */
{

    int foundDefault;		/* Flag to indicate whether a "default" clause
				 * is present. */
    Tcl_BytecodeLabel *fwdJumps;/* Array of forward-jump fixup locations. */
    Tcl_Size jumpCount;		/* Next cell to use in fwdJumps array. */
    Tcl_Size contJumpIdx;	/* Where the first of the jumps due to a group
				 * of continuation bodies starts, or -1 if
				 * there aren't any. */
2125
2126
2127
2128
2129
2130
2131

2132
2133
2134
2135
2136
2137
2138
2139






2140
2141
2142
2143
2144
2145
2146
	if (i != numArms - 1 || !HasDefaultClause(numArms, arms)) {
	    /*
	     * Generate the test for the arm.
	     */

	    switch (mode) {
	    case Switch_Exact:

		OP(		DUP);
		TclCompileTokens(interp, arm->valueToken, 1,	envPtr);
		OP(		STR_EQ);
		break;
	    case Switch_Glob:
		TclCompileTokens(interp, arm->valueToken, 1,	envPtr);
		OP4(		OVER, 1);
		OP1(		STR_MATCH, noCase);






		break;
	    case Switch_Regexp:
		simple = exact = 0;

		/*
		 * Keep in sync with TclCompileRegexpCmd.
		 */







>








>
>
>
>
>
>







2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
	if (i != numArms - 1 || !HasDefaultClause(numArms, arms)) {
	    /*
	     * Generate the test for the arm.
	     */

	    switch (mode) {
	    case Switch_Exact:
		// I think this should be unreachable. It's buggy...
		OP(		DUP);
		TclCompileTokens(interp, arm->valueToken, 1,	envPtr);
		OP(		STR_EQ);
		break;
	    case Switch_Glob:
		TclCompileTokens(interp, arm->valueToken, 1,	envPtr);
		OP4(		OVER, 1);
		OP1(		STR_MATCH, noCase);
		break;
	    case Switch_Integer:
		// I think this should be unreachable. It's buggy...
		OP(		DUP);
		TclCompileTokens(interp, arm->valueToken, 1,	envPtr);
		OP(		EQ);
		break;
	    case Switch_Regexp:
		simple = exact = 0;

		/*
		 * Keep in sync with TclCompileRegexpCmd.
		 */
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
	    sizeof(Tcl_BytecodeLabel) * numArms);
    foundDefault = 0;
    mustGenerate = 1;

    /*
     * Next, issue the instruction to do the jump, together with what we want
     * to do if things do not work out (jump to either the default clause or
     * the "default" default, which just sets the result to empty). Note that
     * we will come back and rewrite the jump's offset parameter when we know
     * what it should be, and that all jumps we issue are of the wide kind
     * because that makes the code much easier to debug!
     */

    BACKLABEL(		jumpLocation);
    OP4(			JUMP_TABLE, infoIndex);
    FWDJUMP(			JUMP, jumpToDefault);

    for (i=0 ; i<numArms ; i++) {







|
<
<
<







2427
2428
2429
2430
2431
2432
2433
2434



2435
2436
2437
2438
2439
2440
2441
	    sizeof(Tcl_BytecodeLabel) * numArms);
    foundDefault = 0;
    mustGenerate = 1;

    /*
     * Next, issue the instruction to do the jump, together with what we want
     * to do if things do not work out (jump to either the default clause or
     * the "default" default, which just sets the result to empty).



     */

    BACKLABEL(		jumpLocation);
    OP4(			JUMP_TABLE, infoIndex);
    FWDJUMP(			JUMP, jumpToDefault);

    for (i=0 ; i<numArms ; i++) {
2388
2389
2390
2391
2392
2393
2394
































































































































































2395
2396
2397
2398
2399
2400
2401
		Tcl_Size slength = Tcl_UtfToLower(Tcl_DStringValue(&buffer));
		Tcl_DStringSetLength(&buffer, slength);
	    }
	    isNew = CreateJumptableEntry(jtPtr, Tcl_DStringValue(&buffer),
		    CurrentOffset(envPtr) - jumpLocation);
	    Tcl_DStringFree(&buffer);
	} else {
































































































































































	    /*
	     * This is a default clause, so patch up the fallthrough from the
	     * INST_JUMP_TABLE instruction to here.
	     */

	    foundDefault = 1;
	    isNew = 1;







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







2468
2469
2470
2471
2472
2473
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
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
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
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
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
		Tcl_Size slength = Tcl_UtfToLower(Tcl_DStringValue(&buffer));
		Tcl_DStringSetLength(&buffer, slength);
	    }
	    isNew = CreateJumptableEntry(jtPtr, Tcl_DStringValue(&buffer),
		    CurrentOffset(envPtr) - jumpLocation);
	    Tcl_DStringFree(&buffer);
	} else {
	    /*
	     * This is a default clause, so patch up the fallthrough from the
	     * INST_JUMP_TABLE instruction to here.
	     */

	    foundDefault = 1;
	    isNew = 1;
	    FWDLABEL(	jumpToDefault);
	}

	/*
	 * Now, for each arm we must deal with the body of the clause.
	 *
	 * If this is a continuation body (never true of a final clause,
	 * whether default or not) we're done because the next jump target
	 * will also point here, so we advance to the next clause.
	 */

	if (IsFallthroughArm(arm)) {
	    mustGenerate = 1;
	    continue;
	}

	/*
	 * Also skip this arm if its only match clause is masked. (We could
	 * probably be more aggressive about this, but that would be much more
	 * difficult to get right.)
	 */

	if (!isNew && !mustGenerate) {
	    continue;
	}
	mustGenerate = 0;

	/*
	 * Compile the body of the arm.
	 */

	SetSwitchLineInformation(arm);
	TclCompileCmdWord(interp, arm->bodyToken, 1, envPtr);

	/*
	 * Compile a jump in to the end of the command if this body is
	 * anything other than a user-supplied default arm (to either skip
	 * over the remaining bodies or the code that generates an empty
	 * result).
	 */

	if (i < numArms-1 || !foundDefault) {
	    FWDJUMP(		JUMP, finalFixups[numRealBodies++]);
	    STKDELTA(-1);
	}
    }

    /*
     * We're at the end. If we've not already done so through the processing
     * of a user-supplied default clause, add in a "default" default clause
     * now.
     */

    if (!foundDefault) {
	FWDLABEL(	jumpToDefault);
	PUSH(			"");
    }

    /*
     * No more instructions to be issued; everything that needs to jump to the
     * end of the command is fixed up at this point.
     */

    for (i=0 ; i<numRealBodies ; i++) {
	FWDLABEL(	finalFixups[i]);
    }

    /*
     * Clean up all our temporary space and return.
     */

    TclStackFree(interp, finalFixups);
}

/*
 *----------------------------------------------------------------------
 *
 * IssueSwitchNumJumpTable --
 *
 *	Generate instructions for a [switch] command that is to be compiled
 *	into a numeric jump table. This is only for the -integer mode.
 *
 *	We assume (because it was checked by our caller) that there's at least
 *	one body, all value tokens are parsed integers or "default", all body
 *	tokens are literals, and all fallthroughs eventually hit something real.
 *
 *----------------------------------------------------------------------
 */

static void
IssueSwitchNumJumpTable(
    Tcl_Interp *interp,		// Context for compiling script bodies.
    CompileEnv *envPtr,		// Holds resulting instructions.
    Tcl_Size numArms,		// Number of arms of the switch.
    SwitchArmInfo *arms)	// Array of arm descriptors.
{
    JumptableNumInfo *jtPtr;
    Tcl_AuxDataRef infoIndex;
    int isNew, mustGenerate, foundDefault;
    Tcl_Size numRealBodies = 0, i;
    Tcl_BytecodeLabel jumpLocation, jumpToDefault, *finalFixups;

    /*
     * Compile the switch by using a jump table, which is basically a
     * hashtable that maps from literal values to match against to the offset
     * (relative to the INST_JUMP_TABLE instruction) to jump to. The jump
     * table itself is independent of any invocation of the bytecode, and as
     * such is stored in an auxData block.
     *
     * Start by allocating the jump table itself, plus some workspace.
     */

    jtPtr = AllocJumptableNum();
    infoIndex = RegisterJumptableNum(jtPtr, envPtr);
    finalFixups = (Tcl_BytecodeLabel *)TclStackAlloc(interp,
	    sizeof(Tcl_BytecodeLabel) * numArms);
    foundDefault = 0;
    mustGenerate = 1;

    /*
     * Next, issue the instruction to do the jump, together with what we want
     * to do if things do not work out (jump to either the default clause or
     * the "default" default, which just sets the result to empty).
     *
     * Note that the jumpTableNum opcode enforces wide-int-ness.
     */

    BACKLABEL(		jumpLocation);
    OP4(			JUMP_TABLE_NUM, infoIndex);
    FWDJUMP(			JUMP, jumpToDefault);

    for (i=0 ; i<numArms ; i++) {
	SwitchArmInfo *arm = &arms[i];

	/*
	 * For each arm, we must first work out what to do with the match
	 * term.
	 */

	if (i != numArms-1 || !HasDefaultClause(numArms, arms)) {
	    /*
	     * This is not a default clause, so insert the current location as
	     * a target in the jump table (assuming it isn't already there,
	     * which would indicate that this clause is probably masked by an
	     * earlier one). Note that we've verified that the value is either
	     * an integer or a _terminal_ default clause.
	     *
	     * The value was parsed earlier.
	     */

	    isNew = CreateJumptableNumEntry(jtPtr, arm->valueInt,
		    CurrentOffset(envPtr) - jumpLocation);
	} else {
	    /*
	     * This is a default clause, so patch up the fallthrough from the
	     * INST_JUMP_TABLE instruction to here.
	     */

	    foundDefault = 1;
	    isNew = 1;
Changes to generic/tclCompile.c.
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
	 * strings. If it is not a local variable, look it up at runtime.
	 */

	simpleVarName = 1;

	name = varTokenPtr[1].start;
	nameLen = varTokenPtr[1].size;
	if (name[nameLen - 1] == ')') {
	    /*
	     * last char is ')' => potential array reference.
	     */
	    last = &name[nameLen - 1];

	    if (*last == ')') {
		for (p = name;  p < last;  p++) {







|







4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
	 * strings. If it is not a local variable, look it up at runtime.
	 */

	simpleVarName = 1;

	name = varTokenPtr[1].start;
	nameLen = varTokenPtr[1].size;
	if (nameLen > 0 && name[nameLen - 1] == ')') {
	    /*
	     * last char is ')' => potential array reference.
	     */
	    last = &name[nameLen - 1];

	    if (*last == ')') {
		for (p = name;  p < last;  p++) {
Changes to generic/tclDate.c.
92
93
94
95
96
97
98
99

100
101
102
103
104
105
106
/*
 * Bison generates several labels that happen to be unused. Several compilers
 * don't like that, and complain. Simply disable the warning to silence them.
 */

#ifdef _MSC_VER
#pragma warning( disable : 4102 )
#elif defined (__clang__)

#elif (__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif

#if 0
#define YYDEBUG 1
#endif







|
>







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
 * Bison generates several labels that happen to be unused. Several compilers
 * don't like that, and complain. Simply disable the warning to silence them.
 */

#ifdef _MSC_VER
#pragma warning( disable : 4102 )
#elif defined (__clang__) && (__clang_major__ > 14)
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#elif (__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif

#if 0
#define YYDEBUG 1
#endif
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236

/* Value type.  */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{

    Tcl_WideInt Number;
    enum _MERIDIAN Meridian;


};
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif







|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

/* Value type.  */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{

    Tcl_WideInt Number;
    MERIDIAN Meridian;


};
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
      15,    16,    17,    18,    19,    20,    21,    22,    23
};

#if YYDEBUG
/* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
static const yytype_int16 yyrline[] =
{
       0,   174,   174,   175,   179,   182,   185,   188,   192,   196,
     199,   202,   206,   209,   214,   220,   226,   231,   235,   239,
     243,   247,   251,   257,   258,   261,   265,   269,   273,   277,
     281,   287,   293,   297,   302,   303,   308,   312,   317,   321,
     326,   333,   337,   343,   343,   345,   350,   355,   357,   362,
     364,   365,   373,   384,   399,   404,   407,   410,   413,   416,
     419,   422,   427,   430,   435,   440,   445,   452,   455,   458,
     463,   481,   484
};
#endif

/** Accessing symbol of state STATE.  */
#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])

#if YYDEBUG || 0







|
|
|
|
|
|
|
|







716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
      15,    16,    17,    18,    19,    20,    21,    22,    23
};

#if YYDEBUG
/* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
static const yytype_int16 yyrline[] =
{
       0,   175,   175,   176,   180,   183,   186,   189,   193,   197,
     200,   203,   207,   210,   215,   221,   227,   232,   236,   240,
     244,   248,   252,   258,   259,   262,   266,   270,   274,   278,
     282,   288,   294,   298,   303,   304,   309,   313,   318,   322,
     327,   334,   338,   344,   344,   346,   351,   356,   358,   363,
     365,   366,   374,   385,   400,   405,   408,   411,   414,   417,
     420,   423,   428,   431,   436,   441,   446,   453,   456,   459,
     464,   482,   485
};
#endif

/** Accessing symbol of state STATE.  */
#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])

#if YYDEBUG || 0
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
    Tcl_AppendObjToObj(infoPtr->messages, t);
    Tcl_DecrRefCount(t);
    Tcl_AppendToObj(infoPtr->messages, ")", -1);
    infoPtr->separatrix = "\n";
}

int
ToSeconds(
    int Hours,
    int Minutes,
    int Seconds,
    MERIDIAN Meridian)
{
    switch (Meridian) {
    case MER24:







|







2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
    Tcl_AppendObjToObj(infoPtr->messages, t);
    Tcl_DecrRefCount(t);
    Tcl_AppendToObj(infoPtr->messages, ")", -1);
    infoPtr->separatrix = "\n";
}

int
TclToSeconds(
    int Hours,
    int Minutes,
    int Seconds,
    MERIDIAN Meridian)
{
    switch (Meridian) {
    case MER24:
Changes to generic/tclDate.h.
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#define TCL_MAX_SECONDS		 0x00F0000000000000LL
#define TCL_INV_SECONDS		(TCL_MIN_SECONDS - 1)

/*
 * Enumeration of the string literals used in [clock]
 */

typedef enum ClockLiteral {
    LIT__NIL,
    LIT__DEFAULT_FORMAT,
    LIT_SYSTEM,		LIT_CURRENT,		LIT_C,
    LIT_BCE,		LIT_CE,
    LIT_DAYOFMONTH,	LIT_DAYOFWEEK,		LIT_DAYOFYEAR,
    LIT_ERA,		LIT_GMT,		LIT_GREGORIAN,
    LIT_INTEGER_VALUE_TOO_LARGE,







|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#define TCL_MAX_SECONDS		 0x00F0000000000000LL
#define TCL_INV_SECONDS		(TCL_MIN_SECONDS - 1)

/*
 * Enumeration of the string literals used in [clock]
 */

typedef enum {
    LIT__NIL,
    LIT__DEFAULT_FORMAT,
    LIT_SYSTEM,		LIT_CURRENT,		LIT_C,
    LIT_BCE,		LIT_CE,
    LIT_DAYOFMONTH,	LIT_DAYOFWEEK,		LIT_DAYOFYEAR,
    LIT_ERA,		LIT_GMT,		LIT_GREGORIAN,
    LIT_INTEGER_VALUE_TOO_LARGE,
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
    "::tcl::clock::LocalizeFormat" \
}

/*
 * Enumeration of the msgcat literals used in [clock]
 */

typedef enum ClockMsgCtLiteral {
    MCLIT__NIL, /* placeholder */
    MCLIT_MONTHS_FULL,	MCLIT_MONTHS_ABBREV,  MCLIT_MONTHS_COMB,
    MCLIT_DAYS_OF_WEEK_FULL,  MCLIT_DAYS_OF_WEEK_ABBREV,  MCLIT_DAYS_OF_WEEK_COMB,
    MCLIT_AM,  MCLIT_PM,
    MCLIT_LOCALE_ERAS,
    MCLIT_BCE,	 MCLIT_CE,
    MCLIT_BCE2,	 MCLIT_CE2,







|







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
    "::tcl::clock::LocalizeFormat" \
}

/*
 * Enumeration of the msgcat literals used in [clock]
 */

typedef enum {
    MCLIT__NIL, /* placeholder */
    MCLIT_MONTHS_FULL,	MCLIT_MONTHS_ABBREV,  MCLIT_MONTHS_COMB,
    MCLIT_DAYS_OF_WEEK_FULL,  MCLIT_DAYS_OF_WEEK_ABBREV,  MCLIT_DAYS_OF_WEEK_COMB,
    MCLIT_AM,  MCLIT_PM,
    MCLIT_LOCALE_ERAS,
    MCLIT_BCE,	 MCLIT_CE,
    MCLIT_BCE2,	 MCLIT_CE2,
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
 * Structure containing the fields used in [clock format] and [clock scan]
 */

enum TclDateFieldsFlags {
    CLF_CTZ = (1 << 4)
};

typedef struct TclDateFields {
    /* Cacheable fields:	 */

    Tcl_WideInt seconds;	/* Time expressed in seconds from the Posix
				 * epoch */
    Tcl_WideInt localSeconds;	/* Local time expressed in nominal seconds
				 * from the Posix epoch */
    int tzOffset;		/* Time zone offset in seconds east of







|







158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
 * Structure containing the fields used in [clock format] and [clock scan]
 */

enum TclDateFieldsFlags {
    CLF_CTZ = (1 << 4)
};

typedef struct {
    /* Cacheable fields:	 */

    Tcl_WideInt seconds;	/* Time expressed in seconds from the Posix
				 * epoch */
    Tcl_WideInt localSeconds;	/* Local time expressed in nominal seconds
				 * from the Posix epoch */
    int tzOffset;		/* Time zone offset in seconds east of
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#define ClockCacheableDateFieldsSize \
    offsetof(TclDateFields, tzName)

/*
 * Meridian: am, pm, or 24-hour style.
 */

typedef enum _MERIDIAN {
    MERam, MERpm, MER24
} MERIDIAN;

/*
 * Structure contains return parsed fields.
 */








|







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#define ClockCacheableDateFieldsSize \
    offsetof(TclDateFields, tzName)

/*
 * Meridian: am, pm, or 24-hour style.
 */

typedef enum {
    MERam, MERpm, MER24
} MERIDIAN;

/*
 * Structure contains return parsed fields.
 */

391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
typedef struct ClockScanToken ClockScanToken;

typedef int ClockScanTokenProc(
	ClockFmtScnCmdArgs *opts,
	DateInfo *info,
	const ClockScanToken *tok);

typedef enum _CLCKTOK_TYPE {
   CTOKT_INT = 1, CTOKT_WIDE, CTOKT_PARSER, CTOKT_SPACE, CTOKT_WORD, CTOKT_CHAR,
   CFMTT_PROC
} CLCKTOK_TYPE;

typedef struct ClockScanTokenMap {
    unsigned short type;
    unsigned short flags;







|







391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
typedef struct ClockScanToken ClockScanToken;

typedef int ClockScanTokenProc(
	ClockFmtScnCmdArgs *opts,
	DateInfo *info,
	const ClockScanToken *tok);

typedef enum {
   CTOKT_INT = 1, CTOKT_WIDE, CTOKT_PARSER, CTOKT_SPACE, CTOKT_WORD, CTOKT_CHAR,
   CFMTT_PROC
} CLCKTOK_TYPE;

typedef struct ClockScanTokenMap {
    unsigned short type;
    unsigned short flags;
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
	}								\
    } while(0)

/*
 * Prototypes of module functions.
 */

MODULE_SCOPE int	ToSeconds(int Hours, int Minutes,
			    int Seconds, MERIDIAN Meridian);
MODULE_SCOPE int	IsGregorianLeapYear(TclDateFields *);
MODULE_SCOPE void	GetJulianDayFromEraYearWeekDay(
			    TclDateFields *fields, int changeover);
MODULE_SCOPE void	GetJulianDayFromEraYearMonthDay(
			    TclDateFields *fields, int changeover);
MODULE_SCOPE void	GetJulianDayFromEraYearDay(
			    TclDateFields *fields, int changeover);
MODULE_SCOPE int	ConvertUTCToLocal(ClockClientData *dataPtr, Tcl_Interp *,
			    TclDateFields *, Tcl_Obj *timezoneObj, int);
MODULE_SCOPE Tcl_Obj *	LookupLastTransition(Tcl_Interp *, Tcl_WideInt,
			    Tcl_Size, Tcl_Obj *const *, Tcl_WideInt *rangesVal);
MODULE_SCOPE int	TclClockFreeScan(Tcl_Interp *interp, DateInfo *info);

/* tclClock.c module declarations */

MODULE_SCOPE Tcl_Obj *	ClockSetupTimeZone(ClockClientData *dataPtr,
			    Tcl_Interp *interp, Tcl_Obj *timezoneObj);
MODULE_SCOPE Tcl_Obj *	ClockMCDict(ClockFmtScnCmdArgs *opts);
MODULE_SCOPE Tcl_Obj *	ClockMCGet(ClockFmtScnCmdArgs *opts, int mcKey);
MODULE_SCOPE Tcl_Obj *	ClockMCGetIdx(ClockFmtScnCmdArgs *opts, int mcKey);
MODULE_SCOPE int	ClockMCSetIdx(ClockFmtScnCmdArgs *opts, int mcKey,
			    Tcl_Obj *valObj);

/* tclClockFmt.c module declarations */

MODULE_SCOPE char *	TclItoAw(char *buf, int val, char padchar, unsigned short width);
MODULE_SCOPE int	TclAtoWIe(Tcl_WideInt *out, const char *p, const char *e, int sign);

MODULE_SCOPE Tcl_Obj*	ClockFrmObjGetLocFmtKey(Tcl_Interp *interp,
			    Tcl_Obj *objPtr);
MODULE_SCOPE ClockFmtScnStorage *Tcl_GetClockFrmScnFromObj(Tcl_Interp *interp,
			    Tcl_Obj *objPtr);
MODULE_SCOPE Tcl_Obj *	ClockLocalizeFormat(ClockFmtScnCmdArgs *opts);
MODULE_SCOPE int	ClockScan(DateInfo *info, Tcl_Obj *strObj,
			    ClockFmtScnCmdArgs *opts);
MODULE_SCOPE int	ClockFormat(DateFormat *dateFmt,
			    ClockFmtScnCmdArgs *opts);
MODULE_SCOPE void	ClockFrmScnClearCaches(void);
MODULE_SCOPE void	ClockFrmScnFinalize();

#endif /* _TCLCLOCK_H */







|

|
<
<
<
<
|

|

|





|

|
|
|
|







<
<


<
|

|

|
|


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
	}								\
    } while(0)

/*
 * Prototypes of module functions.
 */

MODULE_SCOPE int	TclToSeconds(int Hours, int Minutes,
			    int Seconds, MERIDIAN Meridian);
MODULE_SCOPE int	TclIsGregorianLeapYear(TclDateFields *);




MODULE_SCOPE void	TclGetJulianDayFromEraYearDay(
			    TclDateFields *fields, int changeover);
MODULE_SCOPE int	TclConvertUTCToLocal(ClockClientData *dataPtr, Tcl_Interp *,
			    TclDateFields *, Tcl_Obj *timezoneObj, int);
MODULE_SCOPE Tcl_Obj *	TclClockLookupLastTransition(Tcl_Interp *, Tcl_WideInt,
			    Tcl_Size, Tcl_Obj *const *, Tcl_WideInt *rangesVal);
MODULE_SCOPE int	TclClockFreeScan(Tcl_Interp *interp, DateInfo *info);

/* tclClock.c module declarations */

MODULE_SCOPE Tcl_Obj *	TclClockSetupTimeZone(ClockClientData *dataPtr,
			    Tcl_Interp *interp, Tcl_Obj *timezoneObj);
MODULE_SCOPE Tcl_Obj *	TclClockMCDict(ClockFmtScnCmdArgs *opts);
MODULE_SCOPE Tcl_Obj *	TclClockMCGet(ClockFmtScnCmdArgs *opts, int mcKey);
MODULE_SCOPE Tcl_Obj *	TclClockMCGetIdx(ClockFmtScnCmdArgs *opts, int mcKey);
MODULE_SCOPE int	TclClockMCSetIdx(ClockFmtScnCmdArgs *opts, int mcKey,
			    Tcl_Obj *valObj);

/* tclClockFmt.c module declarations */

MODULE_SCOPE char *	TclItoAw(char *buf, int val, char padchar, unsigned short width);
MODULE_SCOPE int	TclAtoWIe(Tcl_WideInt *out, const char *p, const char *e, int sign);



MODULE_SCOPE ClockFmtScnStorage *Tcl_GetClockFrmScnFromObj(Tcl_Interp *interp,
			    Tcl_Obj *objPtr);

MODULE_SCOPE int	TclClockScan(DateInfo *info, Tcl_Obj *strObj,
			    ClockFmtScnCmdArgs *opts);
MODULE_SCOPE int	TclClockFormat(DateFormat *dateFmt,
			    ClockFmtScnCmdArgs *opts);
MODULE_SCOPE void	TclClockFrmScnClearCaches(void);
MODULE_SCOPE void	TclClockFrmScnFinalize();

#endif /* _TCLCLOCK_H */
Changes to generic/tclEncoding.c.
4644
4645
4646
4647
4648
4649
4650
4651
































































4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667


4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690


4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708

4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725


4726
4727
4728
4729
4730
4731
4732
4733
4734
4735


4736
4737
4738
4739
4740
4741
4742
    objPtr = Tcl_NewListObj(n, NULL);
    for (i = 0; i < n; ++i) {
	Tcl_ListObjAppendElement(interp, objPtr,
		Tcl_NewStringObj(encodingProfiles[i].name, TCL_INDEX_NONE));
    }
    Tcl_SetObjResult(interp, objPtr);
}

































































static utf8proc_ssize_t
TclUtfNormalize(
    Tcl_Interp *interp,	/* Error messages. May be NULL */
    const char *bytes,  /* Operand encoded in Tcl internal UTF8 */
    Tcl_Size numBytes, /* Length bytes[], or -1 if NUL terminated */
    Tcl_Encoding encoding, /* Encoding - must be UTF-8. Caller passed for reuse */
    Tcl_UnicodeNormalizationForm normForm, /* TCL_{NFC,NFD,NFKC,NFKC} */
    int profile,                  /* TCL_ENCODING_PROFILE_{STRICT,REPLACE} */
    utf8proc_uint8_t **bufPtrPtr) /* On success, output length excluding nul */
{
    if (profile != TCL_ENCODING_PROFILE_REPLACE &&
	profile != TCL_ENCODING_PROFILE_STRICT) {
	if (interp) {
	    Tcl_SetObjResult(interp,
		Tcl_ObjPrintf("Invalid value %d passed for encoding profile.",
		    profile));


	}
	return -1;
    }

    utf8proc_option_t options = UTF8PROC_STABLE;
    switch (normForm) {
    case TCL_NFC:
	options |= UTF8PROC_COMPOSE;
	break;
    case TCL_NFD:
	options |= UTF8PROC_DECOMPOSE;
	break;
    case TCL_NFKC:
	options |= UTF8PROC_COMPOSE | UTF8PROC_COMPAT;
	break;
    case TCL_NFKD:
	options |= UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT;
	break;
    default:
	if (interp) {
	    Tcl_SetObjResult(interp,
		Tcl_ObjPrintf("Invalid value %d passed for normalization form.",
		    normForm));


	}
	return -1;
    }

    if (numBytes < 0) {
	numBytes = -1;
    }
    int result;
    Tcl_DString dsExt;
    result = Tcl_UtfToExternalDStringEx(interp, encoding, bytes, numBytes,
	profile, &dsExt, NULL);
    /* !!! dsExt needs to be freed even in case of error returns */

    utf8proc_ssize_t normLength = -1;
    if (result == TCL_OK) {
	normLength =
	    utf8proc_map_custom((utf8proc_uint8_t *)Tcl_DStringValue(&dsExt),
		Tcl_DStringLength(&dsExt), bufPtrPtr, options, NULL, NULL);


	if (normLength < 0) {
	    if (interp) {
		const char *errorMsg = utf8proc_errmsg(normLength);
		Tcl_SetObjResult(interp,
		    Tcl_NewStringObj(
			errorMsg ? errorMsg : "Unicode normalization failed.",
			-1));
	    }
	}
    }

    Tcl_DStringFree(&dsExt);
    return normLength;
}

/*


 * Tcl_UtfToNormalizedDString --
 *
 *	Converts the passed string to a Unicode normalization form storing
 *	it in dsPtr.
 *
 * Results:
 *	A standard Tcl error code.
 *
 * Side effects:
 *      The output string is stored in dsPtr, which is initialized.


 */
int
Tcl_UtfToNormalizedDString(
    Tcl_Interp *interp,		/* Used for error messages. May be NULL */
    const char *bytes,		/* Operand encoded in Tcl internal UTF8 */
    Tcl_Size numBytes,		/* Length of bytes[], or -1 if NUL terminated */
    Tcl_UnicodeNormalizationForm normForm, /* TCL_{NFC,NFD,NFKC,NFKC} */







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


|
|
|
|
|
|
|


|

|
|

>
>




|















|
|

>
>







<

|
|




|
|
|
>

|
|
<
|
<
<
<
<






|

>
>










>
>







4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765

4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779

4780




4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
    objPtr = Tcl_NewListObj(n, NULL);
    for (i = 0; i < n; ++i) {
	Tcl_ListObjAppendElement(interp, objPtr,
		Tcl_NewStringObj(encodingProfiles[i].name, TCL_INDEX_NONE));
    }
    Tcl_SetObjResult(interp, objPtr);
}

/*
 *------------------------------------------------------------------------
 *
 * Utf8procErrorToTclError --
 *
 *	Converts an error from the utf8proc library into a Tcl error
 *	message/code.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The interpreter result and error code are set.
 *
 *------------------------------------------------------------------------
 */
static inline void
Utf8procErrorToTclError(
    Tcl_Interp *interp,		// Interpreter to put error description into.
    utf8proc_ssize_t errcode)	// Error code to convert.
{
    const char *errorMsg = utf8proc_errmsg(errcode);
    Tcl_SetObjResult(interp, Tcl_NewStringObj(
	    errorMsg ? errorMsg : "Unicode normalization failed.",
	    TCL_AUTO_LENGTH));
    switch (errcode) {
    case UTF8PROC_ERROR_NOMEM:
	// Memory allocation failure can use the standard Tcl code.
	Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
	break;
    case UTF8PROC_ERROR_OVERFLOW:
	Tcl_SetErrorCode(interp, "TCL", "UNICODE", "OVERFLOW", NULL);
	break;
    case UTF8PROC_ERROR_INVALIDUTF8:
	Tcl_SetErrorCode(interp, "TCL", "UNICODE", "INVALIDUTF8", NULL);
	break;
    case UTF8PROC_ERROR_NOTASSIGNED:
	Tcl_SetErrorCode(interp, "TCL", "UNICODE", "NOTASSIGNED", NULL);
	break;
    case UTF8PROC_ERROR_INVALIDOPTS:
	Tcl_SetErrorCode(interp, "TCL", "UNICODE", "INVALIDOPTS", NULL);
	break;
    default:
	// Shouldn't happen...
	Tcl_SetErrorCode(interp, "TCL", "UNICODE", "UNKNOWN", NULL);
	break;
    }
}

/*
 *------------------------------------------------------------------------
 *
 * TclUtfNormalize --
 *
 *	Apply a normalization rule to a string.
 *
 * Results:
 *	The length of output string. If negative, an error occurred.
 *
 * Side effects:
 *	The interpreter may be updated on error.
 *
 *------------------------------------------------------------------------
 */
static utf8proc_ssize_t
TclUtfNormalize(
    Tcl_Interp *interp,		// Error messages. May be NULL.
    const char *bytes,		// Operand encoded in Tcl internal UTF8.
    Tcl_Size numBytes,		// Length bytes[], or -1 if NUL terminated.
    Tcl_Encoding encoding,	// Encoding - must be UTF-8. Caller passed for reuse
    Tcl_UnicodeNormalizationForm normForm, // TCL_{NFC,NFD,NFKC,NFKC}
    int profile,		// TCL_ENCODING_PROFILE_{STRICT,REPLACE}
    utf8proc_uint8_t **bufPtrPtr) // On success, output length excluding nul.
{
    if (profile != TCL_ENCODING_PROFILE_REPLACE &&
	    profile != TCL_ENCODING_PROFILE_STRICT) {
	if (interp) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		    "Invalid value %d passed for encoding profile.",
		    profile));
	    Tcl_SetErrorCode(
		    interp, "TCL", "ENCODING", "PROFILEID", (char *)NULL);
	}
	return -1;
    }

    unsigned options = UTF8PROC_STABLE;
    switch (normForm) {
    case TCL_NFC:
	options |= UTF8PROC_COMPOSE;
	break;
    case TCL_NFD:
	options |= UTF8PROC_DECOMPOSE;
	break;
    case TCL_NFKC:
	options |= UTF8PROC_COMPOSE | UTF8PROC_COMPAT;
	break;
    case TCL_NFKD:
	options |= UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT;
	break;
    default:
	if (interp) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		    "Invalid value %d passed for normalization form.",
		    normForm));
	    Tcl_SetErrorCode(
		    interp, "TCL", "ENCODING", "NORMFORM", (char *)NULL);
	}
	return -1;
    }

    if (numBytes < 0) {
	numBytes = -1;
    }

    Tcl_DString dsExt;
    int result = Tcl_UtfToExternalDStringEx(interp, encoding, bytes, numBytes,
	    profile, &dsExt, NULL);
    /* !!! dsExt needs to be freed even in case of error returns */

    utf8proc_ssize_t normLength = -1;
    if (result == TCL_OK) {
	normLength = utf8proc_map_custom(
		(utf8proc_uint8_t *)Tcl_DStringValue(&dsExt),
		Tcl_DStringLength(&dsExt), bufPtrPtr,
		(utf8proc_option_t) options, NULL, NULL);

	if (normLength < 0 && interp) {
	    // There was an error and we want to transfer it to the interpreter.

	    Utf8procErrorToTclError(interp, normLength);




	}
    }

    Tcl_DStringFree(&dsExt);
    return normLength;
}

/*
 *------------------------------------------------------------------------
 *
 * Tcl_UtfToNormalizedDString --
 *
 *	Converts the passed string to a Unicode normalization form storing
 *	it in dsPtr.
 *
 * Results:
 *	A standard Tcl error code.
 *
 * Side effects:
 *      The output string is stored in dsPtr, which is initialized.
 *
 *------------------------------------------------------------------------
 */
int
Tcl_UtfToNormalizedDString(
    Tcl_Interp *interp,		/* Used for error messages. May be NULL */
    const char *bytes,		/* Operand encoded in Tcl internal UTF8 */
    Tcl_Size numBytes,		/* Length of bytes[], or -1 if NUL terminated */
    Tcl_UnicodeNormalizationForm normForm, /* TCL_{NFC,NFD,NFKC,NFKC} */
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772


4773
4774
4775
4776
4777
4778
4779
4780
4781
4782


4783
4784
4785
4786
4787
4788
4789
	return TCL_ERROR;
    }

    utf8proc_uint8_t *normUtf8;
    utf8proc_ssize_t normLength;

    normLength = TclUtfNormalize(interp, bytes, numBytes, encoding, normForm,
	profile, &normUtf8);
    if (normLength >= 0) {
	assert(normUtf8);
	/* Convert standard UTF8 to internal UTF8 */
	int result = Tcl_ExternalToUtfDStringEx(interp, encoding,
	    (const char *)normUtf8, normLength, profile, dsPtr, NULL);
	if (result != TCL_OK) {
	    normLength = -1;
	}
	free(normUtf8); /* NOT Tcl_Free! */
    }
    Tcl_FreeEncoding(encoding);
    return normLength >= 0 ? TCL_OK : TCL_ERROR;
}

/*


 * Tcl_UtfToNormalized --
 *
 *	Converts the passed string to a Unicode normalization form storing
 *	it in the caller provided buffer.
 *
 * Results:
 *	A standard Tcl error code.
 *
 * Side effects:
 *      The output string is stored in bufPtr.


 */
int
Tcl_UtfToNormalized(
    Tcl_Interp *interp,		/* Used for error messages. May be NULL */
    const char *bytes,		/* Operand encoded in Tcl internal UTF8 */
    Tcl_Size numBytes,		/* Length of bytes[], or -1 if NUL terminated */
    Tcl_UnicodeNormalizationForm normForm, /* TCL_{NFC,NFD,NFKC,NFKC} */







|




|








|

>
>










>
>







4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
	return TCL_ERROR;
    }

    utf8proc_uint8_t *normUtf8;
    utf8proc_ssize_t normLength;

    normLength = TclUtfNormalize(interp, bytes, numBytes, encoding, normForm,
	    profile, &normUtf8);
    if (normLength >= 0) {
	assert(normUtf8);
	/* Convert standard UTF8 to internal UTF8 */
	int result = Tcl_ExternalToUtfDStringEx(interp, encoding,
		(const char *)normUtf8, normLength, profile, dsPtr, NULL);
	if (result != TCL_OK) {
	    normLength = -1;
	}
	free(normUtf8); /* NOT Tcl_Free! */
    }
    Tcl_FreeEncoding(encoding);
    return normLength >= 0 ? TCL_OK : TCL_ERROR;
}

/*
 *------------------------------------------------------------------------
 *
 * Tcl_UtfToNormalized --
 *
 *	Converts the passed string to a Unicode normalization form storing
 *	it in the caller provided buffer.
 *
 * Results:
 *	A standard Tcl error code.
 *
 * Side effects:
 *      The output string is stored in bufPtr.
 *
 *------------------------------------------------------------------------
 */
int
Tcl_UtfToNormalized(
    Tcl_Interp *interp,		/* Used for error messages. May be NULL */
    const char *bytes,		/* Operand encoded in Tcl internal UTF8 */
    Tcl_Size numBytes,		/* Length of bytes[], or -1 if NUL terminated */
    Tcl_UnicodeNormalizationForm normForm, /* TCL_{NFC,NFD,NFKC,NFKC} */
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
    if (encoding == NULL) {
	return TCL_ERROR;
    }

    utf8proc_uint8_t *normUtf8;
    utf8proc_ssize_t normLength;
    normLength = TclUtfNormalize(interp, bytes, numBytes, encoding, normForm,
	profile, &normUtf8);
    Tcl_FreeEncoding(encoding);
    if (normLength < 0) {
	return TCL_ERROR;
    }
    assert(normUtf8);

    /* Convert standard UTF8 to internal UTF8 */







|







4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
    if (encoding == NULL) {
	return TCL_ERROR;
    }

    utf8proc_uint8_t *normUtf8;
    utf8proc_ssize_t normLength;
    normLength = TclUtfNormalize(interp, bytes, numBytes, encoding, normForm,
	    profile, &normUtf8);
    Tcl_FreeEncoding(encoding);
    if (normLength < 0) {
	return TCL_ERROR;
    }
    assert(normUtf8);

    /* Convert standard UTF8 to internal UTF8 */
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
		break;
	    }
	    *to++ = 0x80;
	    from++;
	}
    }
    if (from < fromEnd) {
	Tcl_SetObjResult(interp,
	    Tcl_NewStringObj("Output buffer too small.", -1));
	result = TCL_CONVERT_NOSPACE;
    } else {
	assert(to <= toEnd);
	*to = '\0'; /* NUL terminate the output */
	if (lengthPtr) {
	    *lengthPtr = to-bufPtr;
	}
	result = TCL_OK;
    }

    free(normUtf8); /* NOT Tcl_Free! */
    return result;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







|
|













|







4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
		break;
	    }
	    *to++ = 0x80;
	    from++;
	}
    }
    if (from < fromEnd) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(
		"Output buffer too small.", -1));
	result = TCL_CONVERT_NOSPACE;
    } else {
	assert(to <= toEnd);
	*to = '\0'; /* NUL terminate the output */
	if (lengthPtr) {
	    *lengthPtr = to-bufPtr;
	}
	result = TCL_OK;
    }

    free(normUtf8); /* NOT Tcl_Free! */
    return result;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */
Changes to generic/tclExecute.c.
4633
4634
4635
4636
4637
4638
4639


4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
	}
#endif
	NEXT_INST_F0(jmpOffset[b], 1);
    }

    {
	Tcl_HashEntry *hPtr;



	/*
	 * Jump to location looked up in a hashtable; fall through to next
	 * instr if lookup fails. Lookup by string.
	 */

    case INST_JUMP_TABLE:
	tblIdx = TclGetInt4AtPtr(pc + 1);
	JumptableInfo *jtPtr = (JumptableInfo *)
		codePtr->auxDataArrayPtr[tblIdx].clientData;
	TRACE(("%u \"%.20s\" => ", tblIdx, O2S(OBJ_AT_TOS)));
	hPtr = Tcl_FindHashEntry(&jtPtr->hashTable, TclGetString(OBJ_AT_TOS));
	goto processJumpTableEntry;

	/*
	 * Jump to location looked up in a hashtable; fall through to next
	 * instr if lookup fails or key is non-integer. Lookup by integer.
	 */

    case INST_JUMP_TABLE_NUM:
	tblIdx = TclGetInt4AtPtr(pc + 1);
	JumptableNumInfo *jtnPtr = (JumptableNumInfo *)
		codePtr->auxDataArrayPtr[tblIdx].clientData;
	TRACE(("%u \"%.20s\" => ", tblIdx, O2S(OBJ_AT_TOS)));
	DECACHE_STACK_INFO();
	Tcl_WideInt key;
	if (Tcl_GetWideIntFromObj(interp, OBJ_AT_TOS, &key) != TCL_OK) {
	    TRACE_ERROR(interp);
	    goto gotError;







>
>








|












|







4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
	}
#endif
	NEXT_INST_F0(jmpOffset[b], 1);
    }

    {
	Tcl_HashEntry *hPtr;
	JumptableInfo *jtPtr;
	JumptableNumInfo *jtnPtr;

	/*
	 * Jump to location looked up in a hashtable; fall through to next
	 * instr if lookup fails. Lookup by string.
	 */

    case INST_JUMP_TABLE:
	tblIdx = TclGetInt4AtPtr(pc + 1);
	jtPtr = (JumptableInfo *)
		codePtr->auxDataArrayPtr[tblIdx].clientData;
	TRACE(("%u \"%.20s\" => ", tblIdx, O2S(OBJ_AT_TOS)));
	hPtr = Tcl_FindHashEntry(&jtPtr->hashTable, TclGetString(OBJ_AT_TOS));
	goto processJumpTableEntry;

	/*
	 * Jump to location looked up in a hashtable; fall through to next
	 * instr if lookup fails or key is non-integer. Lookup by integer.
	 */

    case INST_JUMP_TABLE_NUM:
	tblIdx = TclGetInt4AtPtr(pc + 1);
	jtnPtr = (JumptableNumInfo *)
		codePtr->auxDataArrayPtr[tblIdx].clientData;
	TRACE(("%u \"%.20s\" => ", tblIdx, O2S(OBJ_AT_TOS)));
	DECACHE_STACK_INFO();
	Tcl_WideInt key;
	if (Tcl_GetWideIntFromObj(interp, OBJ_AT_TOS, &key) != TCL_OK) {
	    TRACE_ERROR(interp);
	    goto gotError;
5013
5014
5015
5016
5017
5018
5019

5020
5021
5022

5023
5024
5025
5026
5027
5028
5029
	goto gotError;

    case INST_TCLOO_IS_OBJECT:
	TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
	DECACHE_STACK_INFO();
	oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
	CACHE_STACK_INFO();

	int match = oPtr != NULL;
	TRACE_APPEND(("%d\n", match));
	JUMP_PEEPHOLE_F(match, 1, 1);

    case INST_TCLOO_CLASS:
    case INST_TCLOO_NS:
    case INST_TCLOO_ID:
	DECACHE_STACK_INFO();
	oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
	CACHE_STACK_INFO();
	if (oPtr == NULL) {







>
|
|
|
>







5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
	goto gotError;

    case INST_TCLOO_IS_OBJECT:
	TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
	DECACHE_STACK_INFO();
	oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
	CACHE_STACK_INFO();
	{
	    int match = oPtr != NULL;
	    TRACE_APPEND(("%d\n", match));
	    JUMP_PEEPHOLE_F(match, 1, 1);
	}
    case INST_TCLOO_CLASS:
    case INST_TCLOO_NS:
    case INST_TCLOO_ID:
	DECACHE_STACK_INFO();
	oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
	CACHE_STACK_INFO();
	if (oPtr == NULL) {
5157
5158
5159
5160
5161
5162
5163

5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204

5205
5206
5207
5208
5209
5210
5211
				 * stream */

	/*
	 * Pop the list and get the index.
	 */

	valuePtr = OBJ_AT_TOS;

	int encIndex = TclGetInt4AtPtr(pc + 1);
	TRACE(("\"%.30s\" %d => ", O2S(valuePtr), encIndex));

	/*
	 * Get the contents of the list, making sure that it really is a list
	 * in the process.
	 */

	/* special case for AbstractList */
	if (TclObjTypeHasProc(valuePtr, indexProc)) {
	    length = TclObjTypeLength(valuePtr);

	    /* Decode end-offset index values. */
	    index = TclIndexDecode(encIndex, length - 1);

	    if (index >= 0 && index < length) {
		/* Compute value @ index */
		DECACHE_STACK_INFO();
		int code = TclObjTypeIndex(interp, valuePtr, index, &objResultPtr);
		CACHE_STACK_INFO();
		if (code != TCL_OK) {
		    TRACE_ERROR(interp);
		    goto gotError;
		}
	    } else {
		TclNewObj(objResultPtr);
	    }

	    pcAdjustment = 5;
	    goto lindexFastPath2;
	}

	/* List case */
	if (TclListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK) {
	    TRACE_ERROR(interp);
	    goto gotError;
	}

	/* Decode end-offset index values. */

	index = TclIndexDecode(encIndex, objc - 1);

	pcAdjustment = 5;

    lindexFastPath:
	if (index >= 0 && index < objc) {
	    objResultPtr = objv[index];
	} else {
	    TclNewObj(objResultPtr);







>
|
|

|
|
|
|

|
|
|

|
|

|
|
|
|
|
|
|
|
|
|
|
|

|
|
|

|
|
|
|
|

|

|
>







5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
				 * stream */

	/*
	 * Pop the list and get the index.
	 */

	valuePtr = OBJ_AT_TOS;
	{
	    int encIndex = TclGetInt4AtPtr(pc + 1);
	    TRACE(("\"%.30s\" %d => ", O2S(valuePtr), encIndex));

	    /*
	     * Get the contents of the list, making sure that it really is a list
	     * in the process.
	     */

	    /* special case for AbstractList */
	    if (TclObjTypeHasProc(valuePtr, indexProc)) {
		length = TclObjTypeLength(valuePtr);

		/* Decode end-offset index values. */
		index = TclIndexDecode(encIndex, length - 1);

		if (index >= 0 && index < length) {
		    /* Compute value @ index */
		    DECACHE_STACK_INFO();
		    int code = TclObjTypeIndex(interp, valuePtr, index, &objResultPtr);
		    CACHE_STACK_INFO();
		    if (code != TCL_OK) {
			TRACE_ERROR(interp);
			goto gotError;
		    }
		} else {
		    TclNewObj(objResultPtr);
		}

		pcAdjustment = 5;
		goto lindexFastPath2;
	    }

	    /* List case */
	    if (TclListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK) {
		TRACE_ERROR(interp);
		goto gotError;
	    }

	    /* Decode end-offset index values. */

	    index = TclIndexDecode(encIndex, objc - 1);
	}
	pcAdjustment = 5;

    lindexFastPath:
	if (index >= 0 && index < objc) {
	    objResultPtr = objv[index];
	} else {
	    TclNewObj(objResultPtr);
Changes to generic/tclGetDate.y.
41
42
43
44
45
46
47
48

49
50
51
52
53
54
55
/*
 * Bison generates several labels that happen to be unused. Several compilers
 * don't like that, and complain. Simply disable the warning to silence them.
 */

#ifdef _MSC_VER
#pragma warning( disable : 4102 )
#elif defined (__clang__)

#elif (__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif

#if 0
#define YYDEBUG 1
#endif







|
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
 * Bison generates several labels that happen to be unused. Several compilers
 * don't like that, and complain. Simply disable the warning to silence them.
 */

#ifdef _MSC_VER
#pragma warning( disable : 4102 )
#elif defined (__clang__) && (__clang_major__ > 14)
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#elif (__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif

#if 0
#define YYDEBUG 1
#endif
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
    DSTon, DSToff, DSTmaybe
} DSTMODE;

%}

%union {
    Tcl_WideInt Number;
    enum _MERIDIAN Meridian;
}

%{

/*
 * Prototypes of internal functions.
 */







|







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
    DSTon, DSToff, DSTmaybe
} DSTMODE;

%}

%union {
    Tcl_WideInt Number;
    MERIDIAN Meridian;
}

%{

/*
 * Prototypes of internal functions.
 */
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
    Tcl_AppendObjToObj(infoPtr->messages, t);
    Tcl_DecrRefCount(t);
    Tcl_AppendToObj(infoPtr->messages, ")", -1);
    infoPtr->separatrix = "\n";
}

int
ToSeconds(
    int Hours,
    int Minutes,
    int Seconds,
    MERIDIAN Meridian)
{
    switch (Meridian) {
    case MER24:







|







714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
    Tcl_AppendObjToObj(infoPtr->messages, t);
    Tcl_DecrRefCount(t);
    Tcl_AppendToObj(infoPtr->messages, ")", -1);
    infoPtr->separatrix = "\n";
}

int
TclToSeconds(
    int Hours,
    int Minutes,
    int Seconds,
    MERIDIAN Meridian)
{
    switch (Meridian) {
    case MER24:
Changes to generic/tclIO.c.
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
			    const char *src, int *dstLenPtr, int *srcLenPtr);
static void		UpdateInterest(Channel *chanPtr);
static Tcl_Size		Write(Channel *chanPtr, const char *src,
			    Tcl_Size srcLen, Tcl_Encoding encoding);
static Tcl_Obj *	FixLevelCode(Tcl_Obj *msg);
static void		SpliceChannel(Tcl_Channel chan);
static void		CutChannel(Tcl_Channel chan);
static int	      WillRead(Channel *chanPtr);

#define WriteChars(chanPtr, src, srcLen) \
			Write(chanPtr, src, srcLen, chanPtr->state->encoding)
#define WriteBytes(chanPtr, src, srcLen) \
			Write(chanPtr, src, srcLen, tclIdentityEncoding)

/*
 * Simplifying helper macros. All may use their argument(s) multiple times.
 * The ANSI C "prototypes" for the macros are listed below, together with a
 * short description of what the macro does.
 *
 * --------------------------------------------------------------------------







|


|

|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
			    const char *src, int *dstLenPtr, int *srcLenPtr);
static void		UpdateInterest(Channel *chanPtr);
static Tcl_Size		Write(Channel *chanPtr, const char *src,
			    Tcl_Size srcLen, Tcl_Encoding encoding);
static Tcl_Obj *	FixLevelCode(Tcl_Obj *msg);
static void		SpliceChannel(Tcl_Channel chan);
static void		CutChannel(Tcl_Channel chan);
static int		WillRead(Channel *chanPtr);

#define WriteChars(chanPtr, src, srcLen) \
	Write(chanPtr, src, srcLen, chanPtr->state->encoding)
#define WriteBytes(chanPtr, src, srcLen) \
	Write(chanPtr, src, srcLen, tclIdentityEncoding)

/*
 * Simplifying helper macros. All may use their argument(s) multiple times.
 * The ANSI C "prototypes" for the macros are listed below, together with a
 * short description of what the macro does.
 *
 * --------------------------------------------------------------------------
8065
8066
8067
8068
8069
8070
8071
8072
8073
8074
8075
8076
8077
8078
8079
	}
    }
    if (len == 0 || HaveOpt(2, "-encoding")) {
	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-encoding");
	}
	Tcl_DStringAppendElement(dsPtr,
	    Tcl_GetEncodingName(statePtr->encoding));
	if (len > 0) {
	    return TCL_OK;
	}
    }
    if (len == 0 || HaveOpt(2, "-eofchar")) {
	char buf[4] = "";
	if (len == 0) {







|







8065
8066
8067
8068
8069
8070
8071
8072
8073
8074
8075
8076
8077
8078
8079
	}
    }
    if (len == 0 || HaveOpt(2, "-encoding")) {
	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-encoding");
	}
	Tcl_DStringAppendElement(dsPtr,
		Tcl_GetEncodingName(statePtr->encoding));
	if (len > 0) {
	    return TCL_OK;
	}
    }
    if (len == 0 || HaveOpt(2, "-eofchar")) {
	char buf[4] = "";
	if (len == 0) {
11530
11531
11532
11533
11534
11535
11536
11537

11538
11539
11540
11541
11542
11543
11544
DumpFlags(
    char *str,
    int flags)
{
    int i = 0;
    char buf[24];

#define ChanFlag(chr, bit)      (buf[i++] = ((flags & (bit)) ? (chr) : '_'))


    ChanFlag('r', TCL_READABLE);
    ChanFlag('w', TCL_WRITABLE);
    ChanFlag('n', CHANNEL_NONBLOCKING);
    ChanFlag('l', CHANNEL_LINEBUFFERED);
    ChanFlag('u', CHANNEL_UNBUFFERED);
    ChanFlag('F', BG_FLUSH_SCHEDULED);







|
>







11530
11531
11532
11533
11534
11535
11536
11537
11538
11539
11540
11541
11542
11543
11544
11545
DumpFlags(
    char *str,
    int flags)
{
    int i = 0;
    char buf[24];

#define ChanFlag(chr, bit) \
	(buf[i++] = ((flags & (bit)) ? (chr) : '_'))

    ChanFlag('r', TCL_READABLE);
    ChanFlag('w', TCL_WRITABLE);
    ChanFlag('n', CHANNEL_NONBLOCKING);
    ChanFlag('l', CHANNEL_LINEBUFFERED);
    ChanFlag('u', CHANNEL_UNBUFFERED);
    ChanFlag('F', BG_FLUSH_SCHEDULED);
Changes to generic/tclIOCmd.c.
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
    /* Bug [0f1ddc0df7] - encoding errors - use replace profile */
    if (Tcl_SetChannelOption(interp, chan, "-profile", "replace") != TCL_OK) {
	goto errorWithOpenChannel;
    }

    /* TIP 716 */
    if (encodingObj &&
	Tcl_SetChannelOption(interp, chan, "-encoding",
	    Tcl_GetString(encodingObj)) != TCL_OK) {
	goto errorWithOpenChannel;
    }

    TclNewObj(resultPtr);
    if (Tcl_GetChannelHandle(chan, TCL_READABLE, NULL) == TCL_OK) {
	if (Tcl_ReadChars(chan, resultPtr, -1, 0) == TCL_IO_FAILURE) {
	    /*







|
|







1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
    /* Bug [0f1ddc0df7] - encoding errors - use replace profile */
    if (Tcl_SetChannelOption(interp, chan, "-profile", "replace") != TCL_OK) {
	goto errorWithOpenChannel;
    }

    /* TIP 716 */
    if (encodingObj &&
	    Tcl_SetChannelOption(interp, chan, "-encoding",
		    Tcl_GetString(encodingObj)) != TCL_OK) {
	goto errorWithOpenChannel;
    }

    TclNewObj(resultPtr);
    if (Tcl_GetChannelHandle(chan, TCL_READABLE, NULL) == TCL_OK) {
	if (Tcl_ReadChars(chan, resultPtr, -1, 0) == TCL_IO_FAILURE) {
	    /*
Changes to generic/tclIORChan.c.
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

static void		ForwardOpToHandlerThread(ReflectedChannel *rcPtr,
			    ForwardedOperation op, const void *param);
static int		ForwardProc(Tcl_Event *evPtr, int mask);
static void		SrcExitProc(void *clientData);

#define FreeReceivedError(p) \

	if ((p)->base.mustFree) {                               \
	    Tcl_Free((p)->base.msgStr);                           \
	}

#define PassReceivedErrorInterp(i,p) \

	if ((i) != NULL) {                                      \
	    Tcl_SetChannelErrorInterp((i),                      \
		    Tcl_NewStringObj((p)->base.msgStr, -1));    \
	}                                                       \

	FreeReceivedError(p)

#define PassReceivedError(c,p) \


	Tcl_SetChannelError((c), Tcl_NewStringObj((p)->base.msgStr, -1)); \
	FreeReceivedError(p)

#define ForwardSetStaticError(p,emsg) \

	(p)->base.code = TCL_ERROR;                             \
	(p)->base.mustFree = 0;                                 \
	(p)->base.msgStr = (char *) (emsg)

#define ForwardSetDynamicError(p,emsg) \

	(p)->base.code = TCL_ERROR;                             \
	(p)->base.mustFree = 1;                                 \
	(p)->base.msgStr = (char *) (emsg)


static void		ForwardSetObjError(ForwardParam *p, Tcl_Obj *objPtr);

static ReflectedChannelMap *	GetThreadReflectedChannelMap(void);
static Tcl_ExitProc	DeleteThreadReflectedChannelMap;

#endif /* TCL_THREADS */







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







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

static void		ForwardOpToHandlerThread(ReflectedChannel *rcPtr,
			    ForwardedOperation op, const void *param);
static int		ForwardProc(Tcl_Event *evPtr, int mask);
static void		SrcExitProc(void *clientData);

#define FreeReceivedError(p) \
    do {							\
	if ((p)->base.mustFree) {				\
	    Tcl_Free((p)->base.msgStr);				\
	}							\
    } while (0)
#define PassReceivedErrorInterp(interp, p) \
    do {							\
	if ((interp) != NULL) {					\
	    Tcl_SetChannelErrorInterp((interp),			\
		    Tcl_NewStringObj((p)->base.msgStr, -1));	\

	}							\
	FreeReceivedError(p);					\
    } while (0)
#define PassReceivedError(chan, p) \
    do {							\
	Tcl_SetChannelError((chan),				\
		Tcl_NewStringObj((p)->base.msgStr, -1));	\
	FreeReceivedError(p);					\
    } while (0)
#define ForwardSetStaticError(p, emsg) \
    do {							\
	(p)->base.code = TCL_ERROR;				\
	(p)->base.mustFree = 0;					\
	(p)->base.msgStr = (char *) (emsg);			\
    } while (0)
#define ForwardSetDynamicError(p, emsg) \
    do {							\
	(p)->base.code = TCL_ERROR;				\
	(p)->base.mustFree = 1;					\
	(p)->base.msgStr = (char *) (emsg);			\
    } while (0)

static void		ForwardSetObjError(ForwardParam *p, Tcl_Obj *objPtr);

static ReflectedChannelMap *	GetThreadReflectedChannelMap(void);
static Tcl_ExitProc	DeleteThreadReflectedChannelMap;

#endif /* TCL_THREADS */
Changes to generic/tclIORTrans.c.
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

static void		ForwardOpToOwnerThread(ReflectedTransform *rtPtr,
			    ForwardedOperation op, const void *param);
static int		ForwardProc(Tcl_Event *evPtr, int mask);
static void		SrcExitProc(void *clientData);

#define FreeReceivedError(p) \
	do {								\
	    if ((p)->base.mustFree) {					\
		Tcl_Free((p)->base.msgStr);				\
	    }								\
	} while (0)
#define PassReceivedErrorInterp(i,p) \
	do {								\
	    if ((i) != NULL) {						\
		Tcl_SetChannelErrorInterp((i),				\
			Tcl_NewStringObj((p)->base.msgStr, -1));	\
	    }								\
	    FreeReceivedError(p);					\
	} while (0)
#define PassReceivedError(c,p) \
	do {								\
	    Tcl_SetChannelError((c),					\
		    Tcl_NewStringObj((p)->base.msgStr, -1));		\
	    FreeReceivedError(p);					\
	} while (0)
#define ForwardSetStaticError(p,emsg) \
	do {								\
	    (p)->base.code = TCL_ERROR;					\
	    (p)->base.mustFree = 0;					\
	    (p)->base.msgStr = (char *) (emsg);				\
	} while (0)
#define ForwardSetDynamicError(p,emsg) \
	do {								\
	    (p)->base.code = TCL_ERROR;					\
	    (p)->base.mustFree = 1;					\
	    (p)->base.msgStr = (char *) (emsg);				\
	} while (0)

static void		ForwardSetObjError(ForwardParam *p,
			    Tcl_Obj *objPtr);
static ReflectedTransformMap *	GetThreadReflectedTransformMap(void);
static void		DeleteThreadReflectedTransformMap(
			    void *clientData);
#endif /* TCL_THREADS */







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







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

static void		ForwardOpToOwnerThread(ReflectedTransform *rtPtr,
			    ForwardedOperation op, const void *param);
static int		ForwardProc(Tcl_Event *evPtr, int mask);
static void		SrcExitProc(void *clientData);

#define FreeReceivedError(p) \
    do {							\
	if ((p)->base.mustFree) {				\
	    Tcl_Free((p)->base.msgStr);				\
	}							\
    } while (0)
#define PassReceivedErrorInterp(interp, p) \
    do {							\
	if ((interp) != NULL) {					\
	    Tcl_SetChannelErrorInterp((interp),			\
		    Tcl_NewStringObj((p)->base.msgStr, -1));	\
	}							\
	FreeReceivedError(p);					\
    } while (0)
#define PassReceivedError(chan, p) \
    do {							\
	Tcl_SetChannelError((chan),				\
		Tcl_NewStringObj((p)->base.msgStr, -1));	\
	FreeReceivedError(p);					\
    } while (0)
#define ForwardSetStaticError(p, emsg) \
    do {							\
	(p)->base.code = TCL_ERROR;				\
	(p)->base.mustFree = 0;					\
	(p)->base.msgStr = (char *) (emsg);			\
    } while (0)
#define ForwardSetDynamicError(p, emsg) \
    do {							\
	(p)->base.code = TCL_ERROR;				\
	(p)->base.mustFree = 1;					\
	(p)->base.msgStr = (char *) (emsg);			\
    } while (0)

static void		ForwardSetObjError(ForwardParam *p,
			    Tcl_Obj *objPtr);
static ReflectedTransformMap *	GetThreadReflectedTransformMap(void);
static void		DeleteThreadReflectedTransformMap(
			    void *clientData);
#endif /* TCL_THREADS */
Changes to generic/tclIcu.c.
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
    if (IcuParseConvertOptions(interp, objc, objv, &strict, &failindexVar) != TCL_OK) {
	return TCL_ERROR;
    }

    Tcl_DString dsIn;
    Tcl_DString dsOut;
    if (IcuObjToUCharDString(interp, objv[objc - 1], strict, &dsIn) != TCL_OK ||
	IcuConverttoDString(interp, &dsIn,
	    Tcl_GetString(objv[objc-2]), strict, &dsOut) != TCL_OK) {
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp,
	Tcl_NewByteArrayObj((unsigned char *)Tcl_DStringValue(&dsOut),
			    Tcl_DStringLength(&dsOut)));
    Tcl_DStringFree(&dsOut);
    return TCL_OK;
}

/*
 *------------------------------------------------------------------------
 *







|
|


|
|
|







1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
    if (IcuParseConvertOptions(interp, objc, objv, &strict, &failindexVar) != TCL_OK) {
	return TCL_ERROR;
    }

    Tcl_DString dsIn;
    Tcl_DString dsOut;
    if (IcuObjToUCharDString(interp, objv[objc - 1], strict, &dsIn) != TCL_OK ||
	    IcuConverttoDString(interp, &dsIn,
		    Tcl_GetString(objv[objc-2]), strict, &dsOut) != TCL_OK) {
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(
	    (unsigned char *)Tcl_DStringValue(&dsOut),
	    Tcl_DStringLength(&dsOut)));
    Tcl_DStringFree(&dsOut);
    return TCL_OK;
}

/*
 *------------------------------------------------------------------------
 *
Changes to generic/tclInt.h.
64
65
66
67
68
69
70

71
72
73
74
75
76
77

#include <stdio.h>

#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdint.h>

#include <string.h>
#include <locale.h>

/*
 * Ensure WORDS_BIGENDIAN is defined correctly:
 * Needs to happen here in addition to configure to work with fat compiles on
 * Darwin (where configure runs only once for multiple architectures).







>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

#include <stdio.h>

#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <locale.h>

/*
 * Ensure WORDS_BIGENDIAN is defined correctly:
 * Needs to happen here in addition to configure to work with fat compiles on
 * Darwin (where configure runs only once for multiple architectures).
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#ifndef TCL_UNREACHABLE
#if defined(__STDC__) && __STDC__ >= 202311L
#include <stddef.h>
#define TCL_UNREACHABLE()	unreachable()
#elif defined(__GNUC__)
#define TCL_UNREACHABLE()	__builtin_unreachable()
#elif defined(_MSC_VER)
#include <stdbool.h>
#define TCL_UNREACHABLE()	__assume(false)
#else
#define TCL_UNREACHABLE()	((void) 0)
#endif
#endif // TCL_UNREACHABLE

#ifndef TCL_FALLTHROUGH







<







146
147
148
149
150
151
152

153
154
155
156
157
158
159
#ifndef TCL_UNREACHABLE
#if defined(__STDC__) && __STDC__ >= 202311L
#include <stddef.h>
#define TCL_UNREACHABLE()	unreachable()
#elif defined(__GNUC__)
#define TCL_UNREACHABLE()	__builtin_unreachable()
#elif defined(_MSC_VER)

#define TCL_UNREACHABLE()	__assume(false)
#else
#define TCL_UNREACHABLE()	((void) 0)
#endif
#endif // TCL_UNREACHABLE

#ifndef TCL_FALLTHROUGH
Changes to generic/tclInterp.c.
252
253
254
255
256
257
258



259
260
261
262
263
264
265
static int		ChildInvokeHidden(Tcl_Interp *interp,
			    Tcl_Interp *childInterp,
			    const char *namespaceName,
			    Tcl_Size objc, Tcl_Obj *const objv[]);
static int		ChildMarkTrusted(Tcl_Interp *interp,
			    Tcl_Interp *childInterp);
static Tcl_CmdDeleteProc	ChildObjCmdDeleteProc;



static int		ChildRecursionLimit(Tcl_Interp *interp,
			    Tcl_Interp *childInterp, Tcl_Size objc,
			    Tcl_Obj *const objv[]);
static int		ChildCommandLimitCmd(Tcl_Interp *interp,
			    Tcl_Interp *childInterp, Tcl_Size consumedObjc,
			    Tcl_Size objc, Tcl_Obj *const objv[]);
static int		ChildTimeLimitCmd(Tcl_Interp *interp,







>
>
>







252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
static int		ChildInvokeHidden(Tcl_Interp *interp,
			    Tcl_Interp *childInterp,
			    const char *namespaceName,
			    Tcl_Size objc, Tcl_Obj *const objv[]);
static int		ChildMarkTrusted(Tcl_Interp *interp,
			    Tcl_Interp *childInterp);
static Tcl_CmdDeleteProc	ChildObjCmdDeleteProc;
static int		ChildSet(Tcl_Interp *interp,
			    Tcl_Interp *childInterp, Tcl_Obj *varNameObj,
			    Tcl_Obj *valueObj);
static int		ChildRecursionLimit(Tcl_Interp *interp,
			    Tcl_Interp *childInterp, Tcl_Size objc,
			    Tcl_Obj *const objv[]);
static int		ChildCommandLimitCmd(Tcl_Interp *interp,
			    Tcl_Interp *childInterp, Tcl_Size consumedObjc,
			    Tcl_Size objc, Tcl_Obj *const objv[]);
static int		ChildTimeLimitCmd(Tcl_Interp *interp,
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
    Tcl_Interp *childInterp;
    static const char *const options[] = {
	"alias",	"aliases",	"bgerror",	"cancel",
	"children",	"create",	"debug",	"delete",
	"eval",		"exists",	"expose",	"hide",
	"hidden",	"issafe",	"invokehidden",
	"limit",	"marktrusted",	"recursionlimit",
	"share",
#ifndef TCL_NO_DEPRECATED
	"slaves",
#endif
	"target",	"transfer",	NULL
    };
    static const char *const optionsNoSlaves[] = {
	"alias",	"aliases",	"bgerror",	"cancel",
	"children",	"create",	"debug",	"delete",
	"eval",		"exists",	"expose",
	"hide",		"hidden",	"issafe",
	"invokehidden",	"limit",	"marktrusted",	"recursionlimit",
	"share",	"target",	"transfer",
	NULL
    };
    enum interpOptionEnum {
	OPT_ALIAS,	OPT_ALIASES,	OPT_BGERROR,	OPT_CANCEL,
	OPT_CHILDREN,	OPT_CREATE,	OPT_DEBUG,	OPT_DELETE,
	OPT_EVAL,	OPT_EXISTS,	OPT_EXPOSE,	OPT_HIDE,
	OPT_HIDDEN,	OPT_ISSAFE,	OPT_INVOKEHID,
	OPT_LIMIT,	OPT_MARKTRUSTED, OPT_RECLIMIT, OPT_SHARE,

#ifndef TCL_NO_DEPRECATED
	OPT_SLAVES,
#endif
	OPT_TARGET,	OPT_TRANSFER
    } index;
    Tcl_Size i;








|











|







|
>







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
    Tcl_Interp *childInterp;
    static const char *const options[] = {
	"alias",	"aliases",	"bgerror",	"cancel",
	"children",	"create",	"debug",	"delete",
	"eval",		"exists",	"expose",	"hide",
	"hidden",	"issafe",	"invokehidden",
	"limit",	"marktrusted",	"recursionlimit",
	"set",		"share",
#ifndef TCL_NO_DEPRECATED
	"slaves",
#endif
	"target",	"transfer",	NULL
    };
    static const char *const optionsNoSlaves[] = {
	"alias",	"aliases",	"bgerror",	"cancel",
	"children",	"create",	"debug",	"delete",
	"eval",		"exists",	"expose",
	"hide",		"hidden",	"issafe",
	"invokehidden",	"limit",	"marktrusted",	"recursionlimit",
	"set",		"share",	"target",	"transfer",
	NULL
    };
    enum interpOptionEnum {
	OPT_ALIAS,	OPT_ALIASES,	OPT_BGERROR,	OPT_CANCEL,
	OPT_CHILDREN,	OPT_CREATE,	OPT_DEBUG,	OPT_DELETE,
	OPT_EVAL,	OPT_EXISTS,	OPT_EXPOSE,	OPT_HIDE,
	OPT_HIDDEN,	OPT_ISSAFE,	OPT_INVOKEHID,
	OPT_LIMIT,	OPT_MARKTRUSTED, OPT_RECLIMIT,	OPT_SET,
	OPT_SHARE,
#ifndef TCL_NO_DEPRECATED
	OPT_SLAVES,
#endif
	OPT_TARGET,	OPT_TRANSFER
    } index;
    Tcl_Size i;

901
902
903
904
905
906
907











908
909
910
911
912
913
914
	    return TCL_ERROR;
	}
	childInterp = GetInterp(interp, objv[2]);
	if (childInterp == NULL) {
	    return TCL_ERROR;
	}
	return ChildEval(interp, childInterp, objc - 3, objv + 3);











    case OPT_EXISTS: {
	int exists = 1;

	childInterp = GetInterp2(interp, objc, objv);
	if (childInterp == NULL) {
	    if (objc > 3) {
		return TCL_ERROR;







>
>
>
>
>
>
>
>
>
>
>







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
	    return TCL_ERROR;
	}
	childInterp = GetInterp(interp, objv[2]);
	if (childInterp == NULL) {
	    return TCL_ERROR;
	}
	return ChildEval(interp, childInterp, objc - 3, objv + 3);
    case OPT_SET:
	if (objc < 4 || objc > 5) {
	    Tcl_WrongNumArgs(interp, 2, objv, "path varName ?value?");
	    return TCL_ERROR;
	}
	childInterp = GetInterp(interp, objv[2]);
	if (childInterp == NULL) {
	    return TCL_ERROR;
	}
	return ChildSet(interp, childInterp, objv[3],
		objc > 4 ? objv[4] : NULL);
    case OPT_EXISTS: {
	int exists = 1;

	childInterp = GetInterp2(interp, objc, objv);
	if (childInterp == NULL) {
	    if (objc > 3) {
		return TCL_ERROR;
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Interp *childInterp = (Tcl_Interp *) clientData;
    static const char *const options[] = {
	"alias",	"aliases",	"bgerror",	"debug",
	"eval",		"expose",	"hide",		"hidden",
	"issafe",	"invokehidden",	"limit",	"marktrusted",
	"recursionlimit", NULL
    };
    enum childCmdOptionsEnum {
	OPT_ALIAS,	OPT_ALIASES,	OPT_BGERROR,	OPT_DEBUG,
	OPT_EVAL,	OPT_EXPOSE,	OPT_HIDE,	OPT_HIDDEN,
	OPT_ISSAFE,	OPT_INVOKEHIDDEN, OPT_LIMIT,	OPT_MARKTRUSTED,
	OPT_RECLIMIT
    } index;

    if (childInterp == NULL) {
	Tcl_Panic("TclChildObjCmd: interpreter has been deleted");
    }

    if (objc < 2) {







|





|







2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Interp *childInterp = (Tcl_Interp *) clientData;
    static const char *const options[] = {
	"alias",	"aliases",	"bgerror",	"debug",
	"eval",		"expose",	"hide",		"hidden",
	"issafe",	"invokehidden",	"limit",	"marktrusted",
	"recursionlimit", "set",	NULL
    };
    enum childCmdOptionsEnum {
	OPT_ALIAS,	OPT_ALIASES,	OPT_BGERROR,	OPT_DEBUG,
	OPT_EVAL,	OPT_EXPOSE,	OPT_HIDE,	OPT_HIDDEN,
	OPT_ISSAFE,	OPT_INVOKEHIDDEN, OPT_LIMIT,	OPT_MARKTRUSTED,
	OPT_RECLIMIT,	OPT_SET
    } index;

    if (childInterp == NULL) {
	Tcl_Panic("TclChildObjCmd: interpreter has been deleted");
    }

    if (objc < 2) {
2687
2688
2689
2690
2691
2692
2693






2694
2695
2696
2697
2698
2699
2700
	return ChildMarkTrusted(interp, childInterp);
    case OPT_RECLIMIT:
	if (objc != 2 && objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?newlimit?");
	    return TCL_ERROR;
	}
	return ChildRecursionLimit(interp, childInterp, objc - 2, objv + 2);






    default:
	TCL_UNREACHABLE();
    }

    return TCL_ERROR;
}








>
>
>
>
>
>







2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
	return ChildMarkTrusted(interp, childInterp);
    case OPT_RECLIMIT:
	if (objc != 2 && objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?newlimit?");
	    return TCL_ERROR;
	}
	return ChildRecursionLimit(interp, childInterp, objc - 2, objv + 2);
    case OPT_SET:
	if (objc < 3 || objc > 4) {
	    Tcl_WrongNumArgs(interp, 2, objv, "varName ?value?");
	    return TCL_ERROR;
	}
	return ChildSet(interp, childInterp, objv[2], objc>3 ? objv[3] : NULL);
    default:
	TCL_UNREACHABLE();
    }

    return TCL_ERROR;
}

2875
2876
2877
2878
2879
2880
2881













































2882
2883
2884
2885
2886
2887
2888
	Tcl_DecrRefCount(objPtr);
    }
    Tcl_TransferResult(childInterp, result, interp);

    Tcl_Release(childInterp);
    return result;
}














































/*
 *----------------------------------------------------------------------
 *
 * ChildExpose --
 *
 *	Helper function to expose a command in a child interpreter.







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







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
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
	Tcl_DecrRefCount(objPtr);
    }
    Tcl_TransferResult(childInterp, result, interp);

    Tcl_Release(childInterp);
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * ChildSet --
 *
 *	Helper function to read and write a variable in a child interpreter.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	Depends on whether the variable has traces. If so, this can have
 *	extensive arbitrary side effects.
 *
 *----------------------------------------------------------------------
 */
static int
ChildSet(
    Tcl_Interp *interp,
    Tcl_Interp *childInterp,
    Tcl_Obj *varNameObj,
    Tcl_Obj *valueObj)
{
    int result = TCL_ERROR;
    Tcl_Obj *resultObj;
    Tcl_Preserve(childInterp);

    // Modelled after the guts of Tcl_SetObjCmd().
    if (valueObj) {
	resultObj = Tcl_ObjSetVar2(childInterp, varNameObj, NULL, valueObj,
		TCL_LEAVE_ERR_MSG);
    } else {
	resultObj = Tcl_ObjGetVar2(childInterp, varNameObj, NULL,
		TCL_LEAVE_ERR_MSG);
    }
    if (resultObj) {
	Tcl_SetObjResult(childInterp, resultObj);
	result = TCL_OK;
    }

    Tcl_TransferResult(childInterp, result, interp);
    Tcl_Release(childInterp);
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * ChildExpose --
 *
 *	Helper function to expose a command in a child interpreter.
Changes to generic/tclListObj.c.
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
{
    /*
     * As an aside, note there is no parameter passed for the bad length
     * because the cverflow is computationally detected and does not fit
     * in Tcl_Size.
     */
    if (interp != NULL) {
	Tcl_SetObjResult(interp,
	    Tcl_ObjPrintf("max length (%" TCL_SIZE_MODIFIER
		"d) of a Tcl list exceeded", (Tcl_Size)LIST_MAX));
	Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL);
    }
    return TCL_ERROR;
}

/*
 *------------------------------------------------------------------------







|
|
|







499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
{
    /*
     * As an aside, note there is no parameter passed for the bad length
     * because the cverflow is computationally detected and does not fit
     * in Tcl_Size.
     */
    if (interp != NULL) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"max length (%" TCL_SIZE_MODIFIER "d) of a Tcl list exceeded",
		(Tcl_Size)LIST_MAX));
	Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL);
    }
    return TCL_ERROR;
}

/*
 *------------------------------------------------------------------------
Changes to generic/tclPlatDecls.h.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

/*
 * TCHAR is needed here for win32, so if it is not defined yet do it here.
 * This way, we don't need to include <tchar.h> just for one define.
 */
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(_TCHAR_DEFINED)
#   if defined(_UNICODE)
	typedef wchar_t TCHAR;
#   else
	typedef char TCHAR;
#   endif
#   define _TCHAR_DEFINED
#endif

#ifndef MODULE_SCOPE







|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

/*
 * TCHAR is needed here for win32, so if it is not defined yet do it here.
 * This way, we don't need to include <tchar.h> just for one define.
 */
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(_TCHAR_DEFINED)
#   if defined(_UNICODE)
	typedef unsigned short TCHAR;
#   else
	typedef char TCHAR;
#   endif
#   define _TCHAR_DEFINED
#endif

#ifndef MODULE_SCOPE
Changes to generic/tclProc.c.
2902
2903
2904
2905
2906
2907
2908

2909
2910
2911
2912
2913
2914
2915
    Tcl_Interp *interp,
    Namespace *nsPtr,
    const char *cmdName,
    const Proc *origProc,
    const Command *origCmd)
{
    Interp *iPtr = (Interp *) interp;


    // Duplicate the string of body, not the bytecode.
    Tcl_Size length;
    const char *bytes = TclGetStringFromObj(origProc->bodyPtr, &length);
    Tcl_Obj *bodyPtr = Tcl_NewStringObj(bytes, length);
    TclContinuationsCopy(bodyPtr, origProc->bodyPtr);
    Tcl_IncrRefCount(bodyPtr);







>







2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
    Tcl_Interp *interp,
    Namespace *nsPtr,
    const char *cmdName,
    const Proc *origProc,
    const Command *origCmd)
{
    Interp *iPtr = (Interp *) interp;
    Tcl_HashEntry *origHePtr;

    // Duplicate the string of body, not the bytecode.
    Tcl_Size length;
    const char *bytes = TclGetStringFromObj(origProc->bodyPtr, &length);
    Tcl_Obj *bodyPtr = Tcl_NewStringObj(bytes, length);
    TclContinuationsCopy(bodyPtr, origProc->bodyPtr);
    Tcl_IncrRefCount(bodyPtr);
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951

    // Create the new command backed by the procedure.
    newProc->cmdPtr = (Command *) TclNRCreateCommandInNs(interp, cmdName,
	    (Tcl_Namespace *) nsPtr, TclObjInterpProc, NRInterpProc, newProc,
	    TclProcDeleteProc);

    // TIP #280: Duplicate the origin information (if we have it).
    Tcl_HashEntry *origHePtr = Tcl_FindHashEntry(iPtr->linePBodyPtr, origProc);
    if (origHePtr) {
	CmdFrame *newCfPtr = (CmdFrame *) Tcl_Alloc(sizeof(CmdFrame));
	const CmdFrame *origCfPtr = (CmdFrame *) Tcl_GetHashValue(origHePtr);

	// Copy info, then fix up bits that need different treatment.
	memcpy(newCfPtr, origCfPtr, sizeof(CmdFrame));
	newCfPtr->line = (int *)Tcl_Alloc(sizeof(int));







|







2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952

    // Create the new command backed by the procedure.
    newProc->cmdPtr = (Command *) TclNRCreateCommandInNs(interp, cmdName,
	    (Tcl_Namespace *) nsPtr, TclObjInterpProc, NRInterpProc, newProc,
	    TclProcDeleteProc);

    // TIP #280: Duplicate the origin information (if we have it).
    origHePtr = Tcl_FindHashEntry(iPtr->linePBodyPtr, origProc);
    if (origHePtr) {
	CmdFrame *newCfPtr = (CmdFrame *) Tcl_Alloc(sizeof(CmdFrame));
	const CmdFrame *origCfPtr = (CmdFrame *) Tcl_GetHashValue(origHePtr);

	// Copy info, then fix up bits that need different treatment.
	memcpy(newCfPtr, origCfPtr, sizeof(CmdFrame));
	newCfPtr->line = (int *)Tcl_Alloc(sizeof(int));
Changes to generic/tclTest.c.
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
	    break;
	default: /* Keep gcc happy */
	    Tcl_Panic("Unknown list API command %d", cmdIndex);
	    return TCL_ERROR; /* Not reached */
	}
    }

#define APPENDINT(name_, var_)                                    \
    do {                                                           \
	Tcl_ListObjAppendElement(                                  \
	    NULL, objPtr, Tcl_NewStringObj((#name_), -1));      \
	Tcl_ListObjAppendElement(                                  \
	    NULL, objPtr, Tcl_NewWideIntObj((intptr_t)(var_))); \
    } while (0)
#define APPENDSTR(name_, var_)                                    \
    do {                                                           \
	Tcl_ListObjAppendElement(                                  \
	    NULL, objPtr, Tcl_NewStringObj((#name_), -1));      \
	Tcl_ListObjAppendElement(                                  \
	    NULL, objPtr, Tcl_NewStringObj((var_), -1)); \
    } while (0)

    Tcl_Obj *objPtr = Tcl_NewListObj(0, NULL);
    APPENDINT(status, status);
    APPENDINT(srcPtr, srcPtr);
    if (srcPtr) {
	APPENDINT(srcRefCount, srcPtr->refCount);







|
|
|
|
|
|

|
|
|
|
|
|







4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
	    break;
	default: /* Keep gcc happy */
	    Tcl_Panic("Unknown list API command %d", cmdIndex);
	    return TCL_ERROR; /* Not reached */
	}
    }

#define APPENDINT(name_, var_) \
    do {							\
	Tcl_ListObjAppendElement(NULL,				\
		objPtr, Tcl_NewStringObj((#name_), -1));	\
	Tcl_ListObjAppendElement(NULL,				\
		objPtr, Tcl_NewWideIntObj((intptr_t)(var_)));	\
    } while (0)
#define APPENDSTR(name_, var_) \
    do {							\
	Tcl_ListObjAppendElement(NULL,				\
		objPtr, Tcl_NewStringObj((#name_), -1));	\
	Tcl_ListObjAppendElement(NULL,				\
		objPtr, Tcl_NewStringObj((var_), -1));		\
    } while (0)

    Tcl_Obj *objPtr = Tcl_NewListObj(0, NULL);
    APPENDINT(status, status);
    APPENDINT(srcPtr, srcPtr);
    if (srcPtr) {
	APPENDINT(srcRefCount, srcPtr->refCount);
9156
9157
9158
9159
9160
9161
9162
9163
9164
9165
9166
9167
9168
9169
9170
9171
9172
9173
9174
9175
9176
9177
9178
9179
9180
9181
9182
9183
9184
9185
9186
9187
9188
9189
9190
9191
9192
    if (objc == 5) {
	len = slen;
    } else {
	if (Tcl_GetSizeIntFromObj(interp, objv[4], &len) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (len > slen) {
	    Tcl_SetObjResult(interp,
		Tcl_ObjPrintf(
		    "Passed length %" TCL_SIZE_MODIFIER
		    "d is greater than string length %" TCL_SIZE_MODIFIER
		    "d.", len, slen));
	    return TCL_ERROR;
	}
    }
    int result;
    char buffer[20] = {0x80};
    char *bufPtr;
    Tcl_Size bufStored = 0;
    if (bufLen > (int)sizeof(buffer)) {
	bufPtr = (char *)Tcl_Alloc(bufLen);
    } else {
	bufPtr = buffer;
    }
    result = Tcl_UtfToNormalized(interp, (char *) s, len,
	(Tcl_UnicodeNormalizationForm)normForm, profile, bufPtr, bufLen, &bufStored);
    if (result == TCL_OK) {
	/* Return as raw bytes, not string */
	Tcl_SetObjResult(interp,
	    Tcl_NewByteArrayObj((unsigned char *)bufPtr, bufStored));
    }
    if (bufPtr != buffer) {
	Tcl_Free(bufPtr);
    }
    return result;
}








|
<



















|
|







9156
9157
9158
9159
9160
9161
9162
9163

9164
9165
9166
9167
9168
9169
9170
9171
9172
9173
9174
9175
9176
9177
9178
9179
9180
9181
9182
9183
9184
9185
9186
9187
9188
9189
9190
9191
    if (objc == 5) {
	len = slen;
    } else {
	if (Tcl_GetSizeIntFromObj(interp, objv[4], &len) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (len > slen) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(

		    "Passed length %" TCL_SIZE_MODIFIER
		    "d is greater than string length %" TCL_SIZE_MODIFIER
		    "d.", len, slen));
	    return TCL_ERROR;
	}
    }
    int result;
    char buffer[20] = {0x80};
    char *bufPtr;
    Tcl_Size bufStored = 0;
    if (bufLen > (int)sizeof(buffer)) {
	bufPtr = (char *)Tcl_Alloc(bufLen);
    } else {
	bufPtr = buffer;
    }
    result = Tcl_UtfToNormalized(interp, (char *) s, len,
	(Tcl_UnicodeNormalizationForm)normForm, profile, bufPtr, bufLen, &bufStored);
    if (result == TCL_OK) {
	/* Return as raw bytes, not string */
	Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(
		(unsigned char *)bufPtr, bufStored));
    }
    if (bufPtr != buffer) {
	Tcl_Free(bufPtr);
    }
    return result;
}

9234
9235
9236
9237
9238
9239
9240
9241
9242
9243
9244
9245
9246
9247
9248
9249
9250
9251
9252
9253
9254
9255
9256
9257
9258
9259
9260
9261
9262
9263
    if (objc == 4) {
	len = slen;
    } else {
	if (Tcl_GetSizeIntFromObj(interp, objv[5], &len) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (len > slen) {
	    Tcl_SetObjResult(interp,
		Tcl_ObjPrintf(
		    "Passed length %" TCL_SIZE_MODIFIER
		    "d is greater than string length %" TCL_SIZE_MODIFIER
		    "d.", len, slen));
	    return TCL_ERROR;
	}
    }
    Tcl_DString ds;
    int result;
    result = Tcl_UtfToNormalizedDString(interp, (char *) s, len,
	(Tcl_UnicodeNormalizationForm)normForm, profile, &ds);
    if (result == TCL_OK) {
	/* Return as raw bytes, not string */
	Tcl_SetObjResult(interp,
	    Tcl_NewByteArrayObj((unsigned char *)Tcl_DStringValue(&ds),
		Tcl_DStringLength(&ds)));
	Tcl_DStringFree(&ds);
    }
    return result;
}

#ifdef _WIN32







|
<












|
|







9233
9234
9235
9236
9237
9238
9239
9240

9241
9242
9243
9244
9245
9246
9247
9248
9249
9250
9251
9252
9253
9254
9255
9256
9257
9258
9259
9260
9261
    if (objc == 4) {
	len = slen;
    } else {
	if (Tcl_GetSizeIntFromObj(interp, objv[5], &len) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (len > slen) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(

		    "Passed length %" TCL_SIZE_MODIFIER
		    "d is greater than string length %" TCL_SIZE_MODIFIER
		    "d.", len, slen));
	    return TCL_ERROR;
	}
    }
    Tcl_DString ds;
    int result;
    result = Tcl_UtfToNormalizedDString(interp, (char *) s, len,
	(Tcl_UnicodeNormalizationForm)normForm, profile, &ds);
    if (result == TCL_OK) {
	/* Return as raw bytes, not string */
	Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(
		(unsigned char *)Tcl_DStringValue(&ds),
		Tcl_DStringLength(&ds)));
	Tcl_DStringFree(&ds);
    }
    return result;
}

#ifdef _WIN32
Changes to generic/tclZipfs.c.
4405
4406
4407
4408
4409
4410
4411
4412

4413
4414
4415
4416
4417
4418
4419
4420
4421
 */

Tcl_Obj *
TclZipfs_TclLibrary(void)
{
    /*
     * Assumes TclZipfsLocateTclLibrary has already been called at startup
     * through Tcl_InitSubsystems.

     */
    assert(zipfs_tcl_library_init);
    if (zipfs_literal_tcl_library) {
	return Tcl_NewStringObj(zipfs_literal_tcl_library, -1);
    }
    return NULL;
}

/*







|
>

<







4405
4406
4407
4408
4409
4410
4411
4412
4413
4414

4415
4416
4417
4418
4419
4420
4421
 */

Tcl_Obj *
TclZipfs_TclLibrary(void)
{
    /*
     * Assumes TclZipfsLocateTclLibrary has already been called at startup
     * through TclZipfs_AppHook. Custom applications that fail to do so will not
     * have the embedded zipfs tcl library feature available.
     */

    if (zipfs_literal_tcl_library) {
	return Tcl_NewStringObj(zipfs_literal_tcl_library, -1);
    }
    return NULL;
}

/*
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432

6433
6434
6435
6436
6437

6438
6439
6440
6441
6442
6443
6444
6445
6446
 */
static int
TclZipfsInitEncodingDirs(void)
{
    if (zipfs_literal_tcl_library == NULL) {
	return TCL_ERROR;
    }
    Tcl_Obj *libDirObj = Tcl_NewStringObj(zipfs_literal_tcl_library, -1);
    Tcl_Obj *subDirObj, *searchPathObj;


    TclNewLiteralStringObj(subDirObj, "encoding");
    Tcl_IncrRefCount(subDirObj);
    TclNewObj(searchPathObj);
    Tcl_ListObjAppendElement(NULL, searchPathObj,
	    Tcl_FSJoinToPath(libDirObj, 1, &subDirObj));

    Tcl_DecrRefCount(subDirObj);
    Tcl_IncrRefCount(searchPathObj);
    Tcl_SetEncodingSearchPath(searchPathObj);
    Tcl_DecrRefCount(searchPathObj);
    /* Reinit system encoding after setting search path */
    TclpSetInitialEncodings();
    return TCL_OK;
}








<

|
>





>

|







6423
6424
6425
6426
6427
6428
6429

6430
6431
6432
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
 */
static int
TclZipfsInitEncodingDirs(void)
{
    if (zipfs_literal_tcl_library == NULL) {
	return TCL_ERROR;
    }

    Tcl_Obj *subDirObj, *searchPathObj;
    Tcl_Obj *libDirObj = Tcl_NewStringObj(zipfs_literal_tcl_library, -1);
    Tcl_IncrRefCount(libDirObj);
    TclNewLiteralStringObj(subDirObj, "encoding");
    Tcl_IncrRefCount(subDirObj);
    TclNewObj(searchPathObj);
    Tcl_ListObjAppendElement(NULL, searchPathObj,
	    Tcl_FSJoinToPath(libDirObj, 1, &subDirObj));
    Tcl_IncrRefCount(searchPathObj);
    Tcl_DecrRefCount(subDirObj);
    Tcl_DecrRefCount(libDirObj);
    Tcl_SetEncodingSearchPath(searchPathObj);
    Tcl_DecrRefCount(searchPathObj);
    /* Reinit system encoding after setting search path */
    TclpSetInitialEncodings();
    return TCL_OK;
}

6458
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
TclZipfs_AppHook(
#ifdef SUPPORT_BUILTIN_ZIP_INSTALL
    int *argcPtr,		/* Pointer to argc */
#else
    TCL_UNUSED(int *), /*argcPtr*/
#endif
#ifdef _WIN32
    TCL_UNUSED(WCHAR ***)) /* argvPtr */
#else /* !_WIN32 */
    char ***argvPtr)		/* Pointer to argv */
#endif /* _WIN32 */
{
    const char *archive;
    const char *result;








|







6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
6473
TclZipfs_AppHook(
#ifdef SUPPORT_BUILTIN_ZIP_INSTALL
    int *argcPtr,		/* Pointer to argc */
#else
    TCL_UNUSED(int *), /*argcPtr*/
#endif
#ifdef _WIN32
    TCL_UNUSED(unsigned short ***)) /* argvPtr */
#else /* !_WIN32 */
    char ***argvPtr)		/* Pointer to argv */
#endif /* _WIN32 */
{
    const char *archive;
    const char *result;

Changes to library/cookiejar/idna.tcl.
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
		set part [punydecode [string range $part 4 end]]
	    }
	    lappend parts $part
	}
	return [join $parts .]
    }

    variable digits [split "abcdefghijklmnopqrstuvwxyz0123456789" ""]
    # Bootstring parameters for Punycode
    variable base 36
    variable tmin 1
    variable tmax 26
    variable skew 38
    variable damp 700
    variable initial_bias 72
    variable initial_n 0x80

    variable max_codepoint 0x10FFFF

    proc adapt {delta first numchars} {
	variable base
	variable tmin
	variable tmax
	variable damp
	variable skew







|

|
|
|
|
|
|
|

|







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
		set part [punydecode [string range $part 4 end]]
	    }
	    lappend parts $part
	}
	return [join $parts .]
    }

    const digits [split "abcdefghijklmnopqrstuvwxyz0123456789" ""]
    # Bootstring parameters for Punycode
    const base 36
    const tmin 1
    const tmax 26
    const skew 38
    const damp 700
    const initial_bias 72
    const initial_n 0x80

    const max_codepoint 0x10FFFF

    proc adapt {delta first numchars} {
	variable base
	variable tmin
	variable tmax
	variable damp
	variable skew
Changes to library/cookiejar/pkgIndex.tcl.
1
2
3
if {![package vsatisfies [package provide Tcl] 8.6-]} {return}
package ifneeded cookiejar 0.2.0 [list source [file join $dir cookiejar.tcl]]
package ifneeded tcl::idna 1.0.1 [list source [file join $dir idna.tcl]]
|


1
2
3
if {![package vsatisfies [package provide Tcl] 9.0-]} {return}
package ifneeded cookiejar 0.2.0 [list source [file join $dir cookiejar.tcl]]
package ifneeded tcl::idna 1.0.1 [list source [file join $dir idna.tcl]]
Changes to library/opt/optparse.tcl.
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
	    set state "args"
	}

	# apply 'smart' 'fuzzy' logic to try to make
	# description writer's life easy, and our's difficult :
	# let's guess the missing arguments :-)

	switch $lg {
	    1 {
		if {$isflag} {
		    return [OptNewInst $state $varname boolflag false ""]
		} else {
		    return [OptNewInst $state $varname any "" ""]
		}
	    }







|







747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
	    set state "args"
	}

	# apply 'smart' 'fuzzy' logic to try to make
	# description writer's life easy, and our's difficult :
	# let's guess the missing arguments :-)

	switch -integer -- $lg {
	    1 {
		if {$isflag} {
		    return [OptNewInst $state $varname boolflag false ""]
		} else {
		    return [OptNewInst $state $varname any "" ""]
		}
	    }
Changes to library/package.tcl.
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
	    $c eval [list proc $p [info args $p] [info body $p]]
	}

	try {
	    $c eval [list ::tcl::DiscoverPackageContents $dir $file $direct]
	} on error msg {
	    if {$doVerbose} {
		set what [$c eval set ::tcl::debug]
		tclLog "warning: error while $what $file: $msg"
	    }
	} on ok {} {
	    if {$doVerbose} {
		set what [$c eval set ::tcl::debug]
		tclLog "successful $what of $file"
	    }
	    set type [$c eval set ::tcl::type]
	    set cmds [lsort [dict keys [$c eval set ::tcl::newCmds]]]
	    set pkgs [$c eval set ::tcl::newPkgs]
	    if {$doVerbose} {
		if {!$direct} {
		    tclLog "commands provided were $cmds"
		}
		tclLog "packages provided were $pkgs"
	    }
	    if {[llength $pkgs] > 1} {







|




|


|
|
|







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
	    $c eval [list proc $p [info args $p] [info body $p]]
	}

	try {
	    $c eval [list ::tcl::DiscoverPackageContents $dir $file $direct]
	} on error msg {
	    if {$doVerbose} {
		set what [$c set ::tcl::debug]
		tclLog "warning: error while $what $file: $msg"
	    }
	} on ok {} {
	    if {$doVerbose} {
		set what [$c set ::tcl::debug]
		tclLog "successful $what of $file"
	    }
	    set type [$c set ::tcl::type]
	    set cmds [lsort [dict keys [$c set ::tcl::newCmds]]]
	    set pkgs [$c set ::tcl::newPkgs]
	    if {$doVerbose} {
		if {!$direct} {
		    tclLog "commands provided were $cmds"
		}
		tclLog "packages provided were $pkgs"
	    }
	    if {[llength $pkgs] > 1} {
Changes to library/platform/pkgIndex.tcl.

1
2
3

package ifneeded platform        1.1.0 [list source -encoding utf-8 [file join $dir platform.tcl]]
package ifneeded platform::shell 1.1.4 [list source -encoding utf-8 [file join $dir shell.tcl]]

>


<
1
2
3

if {![package vsatisfies [package provide Tcl] 8.6-]} {return}
package ifneeded platform        1.1.0 [list source -encoding utf-8 [file join $dir platform.tcl]]
package ifneeded platform::shell 1.1.4 [list source -encoding utf-8 [file join $dir shell.tcl]]

Changes to library/platform/platform.tcl.
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
	    # TODO: Determine the prefixes (i386, x86_64, ...) for
	    # other cpus.  The path after the generic one is utterly
	    # specific to intel right now.  Ok, on Ubuntu, possibly
	    # other Debian systems we may apparently be able to query
	    # the necessary CPU code. If we can't we simply use the
	    # hardwired fallback.

	    switch -exact -- $tcl_platform(wordSize) {
		4 {
		    lappend bases /lib
		    if {[catch {
			exec dpkg-architecture -qDEB_HOST_MULTIARCH
		    } res]} {
			lappend bases /lib/i386-linux-gnu
		    } else {
			# dpkg-arch returns the full tripled, not just cpu.
			lappend bases /lib/$res
		    }
		}
		8 {
		    lappend bases /lib64
		    if {[catch {
			exec dpkg-architecture -qDEB_HOST_MULTIARCH
		    } res]} {
			lappend bases /lib/x86_64-linux-gnu
		    } else {
			# dpkg-arch returns the full tripled, not just cpu.
			lappend bases /lib/$res
		    }
		}
		default {
		    return -code error "Bad wordSize $tcl_platform(wordSize), expected 4 or 8"
		}
	    }








|


|
|
|
|
|
<
|




|
|
|
|
|
<
|







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
	    # TODO: Determine the prefixes (i386, x86_64, ...) for
	    # other cpus.  The path after the generic one is utterly
	    # specific to intel right now.  Ok, on Ubuntu, possibly
	    # other Debian systems we may apparently be able to query
	    # the necessary CPU code. If we can't we simply use the
	    # hardwired fallback.

	    switch -- $tcl_platform(wordSize) {
		4 {
		    lappend bases /lib
		    try {
			set res [exec dpkg-architecture -qDEB_HOST_MULTIARCH]
			# dpkg-arch returns the full triple, not just cpu.
			lappend bases /lib/$res
		    } on error {} {

			lappend bases /lib/i386-linux-gnu
		    }
		}
		8 {
		    lappend bases /lib64
		    try {
			set res [exec dpkg-architecture -qDEB_HOST_MULTIARCH]
			# dpkg-arch returns the full triple, not just cpu.
			lappend bases /lib/$res
		    } on error {} {

			lappend bases /lib/x86_64-linux-gnu
		    }
		}
		default {
		    return -code error "Bad wordSize $tcl_platform(wordSize), expected 4 or 8"
		}
	    }

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
    set libclist [lsort [glob -nocomplain -directory $base libc*]]

    if {![llength $libclist]} { return 0 }

    set libc [lindex $libclist 0]

    # Try executing the library first. This should succeed
    # for a glibc library, and return the version
    # information.

    if {![catch {
	set vdata [lindex [split [exec $libc] \n] 0]
    }]} {
	regexp {version ([0-9]+(\.[0-9]+)*)} $vdata -> v
	foreach {major minor} [split $v .] break
	set v glibc${major}.${minor}
	return 1
    } else {
	# We had trouble executing the library. We are now
	# inspecting its name to determine the version
	# number. This code by Larry McVoy.

	if {[regexp -- {libc-([0-9]+)\.([0-9]+)} $libc -> major minor]} {
	    set v glibc${major}.${minor}
	    return 1







|
<

|

|

|


|







266
267
268
269
270
271
272
273

274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
    set libclist [lsort [glob -nocomplain -directory $base libc*]]

    if {![llength $libclist]} { return 0 }

    set libc [lindex $libclist 0]

    # Try executing the library first. This should succeed
    # for a glibc library, and return the version information.


    try {
	set vdata [lindex [split [exec $libc] \n] 0]
    } on ok {} {
	regexp {version ([0-9]+(\.[0-9]+)*)} $vdata -> v
	lassign [split $v .] major minor
	set v glibc${major}.${minor}
	return 1
    } on error {} {
	# We had trouble executing the library. We are now
	# inspecting its name to determine the version
	# number. This code by Larry McVoy.

	if {[regexp -- {libc-([0-9]+)\.([0-9]+)} $libc -> major minor]} {
	    set v glibc${major}.${minor}
	    return 1
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
    set res [list $id]
    if {$id eq "tcl"} {return $res}

    switch -glob --  $id {
	solaris*-* {
	    if {[regexp {solaris([^-]*)-(.*)} $id -> v cpu]} {
		if {$v eq ""} {return $id}
		foreach {major minor} [split $v .] break
		incr minor -1
		for {set j $minor} {$j >= 6} {incr j -1} {
		    lappend res solaris${major}.${j}-${cpu}
		}
	    }
	}
	linux*-* {
	    if {[regexp {linux-glibc([^-]*)-(.*)} $id -> v cpu]} {
		foreach {major minor} [split $v .] break
		incr minor -1
		for {set j $minor} {$j >= 0} {incr j -1} {
		    lappend res linux-glibc${major}.${j}-${cpu}
		}
	    }
	}
	macosx-powerpc {
	    lappend res macosx-universal
	}
	macosx-x86_64 {
	    lappend res macosx-i386-x86_64
	}
	macosx-ix86 {
	    lappend res macosx-universal macosx-i386-x86_64
	}
	macos*-*    {
	    # 10.5+,11.0+
	    if {[regexp {macosx?([^-]*)-(.*)} $id -> v cpu]} {

		foreach {major minor} [split $v.15 .] break
		switch -exact -- $cpu {
		    ix86    {
			lappend alt i386-x86_64
			lappend alt universal
		    }
		    x86_64  {
			if {$major < 11 && $minor < 15} {







|








|



















|







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
    set res [list $id]
    if {$id eq "tcl"} {return $res}

    switch -glob --  $id {
	solaris*-* {
	    if {[regexp {solaris([^-]*)-(.*)} $id -> v cpu]} {
		if {$v eq ""} {return $id}
		lassign [split $v .] major minor
		incr minor -1
		for {set j $minor} {$j >= 6} {incr j -1} {
		    lappend res solaris${major}.${j}-${cpu}
		}
	    }
	}
	linux*-* {
	    if {[regexp {linux-glibc([^-]*)-(.*)} $id -> v cpu]} {
		lassign [split $v .] major minor
		incr minor -1
		for {set j $minor} {$j >= 0} {incr j -1} {
		    lappend res linux-glibc${major}.${j}-${cpu}
		}
	    }
	}
	macosx-powerpc {
	    lappend res macosx-universal
	}
	macosx-x86_64 {
	    lappend res macosx-i386-x86_64
	}
	macosx-ix86 {
	    lappend res macosx-universal macosx-i386-x86_64
	}
	macos*-*    {
	    # 10.5+,11.0+
	    if {[regexp {macosx?([^-]*)-(.*)} $id -> v cpu]} {

		lassign [split $v.15 .] major minor
		switch -exact -- $cpu {
		    ix86    {
			lappend alt i386-x86_64
			lappend alt universal
		    }
		    x86_64  {
			if {$major < 11 && $minor < 15} {
Changes to library/safe.tcl.
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# This is even more complicated by the boolean flags with no values that
# we had the bad idea to support for the sake of user simplicity in
# create/init but which makes life hard in configure...
# So this will be hopefully written and some integrated with opt1.0
# (hopefully for tcl9.0 ?)
proc ::safe::interpConfigure {args} {
    variable AutoPathSync
    switch [llength $args] {
	1 {
	    # If we have exactly 1 argument the semantic is to return all
	    # the current configuration. We still call OptKeyParse though
	    # we know that "child" is our given argument because it also
	    # checks for the "-help" option.
	    set Args [::tcl::OptKeyParse ::safe::interpIC $args]
	    CheckInterp $child







|







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# This is even more complicated by the boolean flags with no values that
# we had the bad idea to support for the sake of user simplicity in
# create/init but which makes life hard in configure...
# So this will be hopefully written and some integrated with opt1.0
# (hopefully for tcl9.0 ?)
proc ::safe::interpConfigure {args} {
    variable AutoPathSync
    switch -integer -- [llength $args] {
	1 {
	    # If we have exactly 1 argument the semantic is to return all
	    # the current configuration. We still call OptKeyParse though
	    # we know that "child" is our given argument because it also
	    # checks for the "-help" option.
	    set Args [::tcl::OptKeyParse ::safe::interpIC $args]
	    CheckInterp $child
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
    # If ![setSyncMode], Safe Base code will not change this value.
    set tokens_auto_path {}
    foreach dir $raw_auto_path {
	if {[dict exists $remap_access_path $dir]} {
	    lappend tokens_auto_path [dict get $remap_access_path $dir]
	}
    }
    ::interp eval $child [list set auto_path $tokens_auto_path]

    # Add the tcl::tm directories to the access path.
    set morepaths [::tcl::tm::list]
    set firstpass 1
    while {[llength $morepaths]} {
	set addpaths $morepaths
	set morepaths {}







|







424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
    # If ![setSyncMode], Safe Base code will not change this value.
    set tokens_auto_path {}
    foreach dir $raw_auto_path {
	if {[dict exists $remap_access_path $dir]} {
	    lappend tokens_auto_path [dict get $remap_access_path $dir]
	}
    }
    ::interp set $child auto_path $tokens_auto_path

    # Add the tcl::tm directories to the access path.
    set morepaths [::tcl::tm::list]
    set firstpass 1
    while {[llength $morepaths]} {
	set addpaths $morepaths
	set morepaths {}
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
#
proc ::safe::SyncAccessPath {child} {
    variable AutoPathSync
    namespace upvar ::safe [VarName $child] state

    set child_access_path $state(access_path,child)
    if {$AutoPathSync} {
	::interp eval $child [list set auto_path $child_access_path]

	Log $child "auto_path in $child has been set to $child_access_path"\
		NOTICE
    }

    # This code assumes that info library is the first element in the
    # list of access path's. See -> InterpSetConfig for the code which
    # ensures this condition.

    ::interp eval $child [list \
	      set tcl_library [lindex $child_access_path 0]]
    return
}

# Returns the virtual token for directory number N.
proc ::safe::PathToken {n} {
    # We need to have a ":" in the token string so [file join] on the
    # mac won't turn it into a relative path.







|









<
|







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
#
proc ::safe::SyncAccessPath {child} {
    variable AutoPathSync
    namespace upvar ::safe [VarName $child] state

    set child_access_path $state(access_path,child)
    if {$AutoPathSync} {
	::interp set $child auto_path $child_access_path

	Log $child "auto_path in $child has been set to $child_access_path"\
		NOTICE
    }

    # This code assumes that info library is the first element in the
    # list of access path's. See -> InterpSetConfig for the code which
    # ensures this condition.


    ::interp set $child tcl_library [lindex $child_access_path 0]
    return
}

# Returns the virtual token for directory number N.
proc ::safe::PathToken {n} {
    # We need to have a ":" in the token string so [file join] on the
    # mac won't turn it into a relative path.
Changes to library/writefile.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# writeFile:
# Write the contents of a file.
#
# Copyright © 2023 Donal K Fellows.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#

proc writeFile {args} {
    # Parse the arguments
    switch [llength $args] {
	2 {
	    lassign $args filename data
	    set mode text
	}
	3 {
	    lassign $args filename mode data
	    set MODES {binary text}











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# writeFile:
# Write the contents of a file.
#
# Copyright © 2023 Donal K Fellows.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#

proc writeFile {args} {
    # Parse the arguments
    switch -integer -- [llength $args] {
	2 {
	    lassign $args filename data
	    set mode text
	}
	3 {
	    lassign $args filename mode data
	    set MODES {binary text}
Changes to tests/http.test.
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
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
    # proper exception with Tcl 9.0
    http::config -urlencoding "iso8859-1"
    http::mapReply "∈"
} -cleanup {
    http::config -urlencoding $enc
} -errorCode {TCL ENCODING ILLEGALSEQUENCE 0} -result {unexpected character at index 0: 'U+002208'}

package require tcl::idna 1.0

test http-idna-1.1.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna
} -result {wrong # args: should be "::tcl::idna subcommand ?arg ...?"}
test http-idna-1.2.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna ?
} -result {unknown or ambiguous subcommand "?": must be decode, encode, puny, or version}
test http-idna-1.3.$ThreadLevel {IDNA package: basics} -body {
    ::tcl::idna version
} -result 1.0.1
test http-idna-1.4.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna version what
} -result {wrong # args: should be "::tcl::idna version"}
test http-idna-1.5.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny
} -result {wrong # args: should be "::tcl::idna puny subcommand ?arg ...?"}
test http-idna-1.6.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny ?
} -result {unknown or ambiguous subcommand "?": must be decode, or encode}
test http-idna-1.7.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny encode
} -result {wrong # args: should be "::tcl::idna puny encode string ?case?"}
test http-idna-1.8.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny encode a b c
} -result {wrong # args: should be "::tcl::idna puny encode string ?case?"}
test http-idna-1.9.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny decode
} -result {wrong # args: should be "::tcl::idna puny decode string ?case?"}
test http-idna-1.10.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny decode a b c
} -result {wrong # args: should be "::tcl::idna puny decode string ?case?"}
test http-idna-1.11.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna decode
} -result {wrong # args: should be "::tcl::idna decode hostname"}
test http-idna-1.12.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna encode
} -result {wrong # args: should be "::tcl::idna encode hostname"}

test http-idna-2.1.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode abc
} abc-
test http-idna-2.2.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode a€b€c
} abc-k50ab
test http-idna-2.3.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode ABC
} ABC-
test http-idna-2.4.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode A€B€C
} ABC-k50ab
test http-idna-2.5.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode ABC 0
} abc-
test http-idna-2.6.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode A€B€C 0
} abc-k50ab
test http-idna-2.7.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode ABC 1
} ABC-
test http-idna-2.8.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode A€B€C 1
} ABC-k50ab
test http-idna-2.9.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode abc 0
} abc-
test http-idna-2.10.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode a€b€c 0
} abc-k50ab
test http-idna-2.11.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode abc 1
} ABC-
test http-idna-2.12.$ThreadLevel {puny encode: functional test} {
    ::tcl::idna puny encode a€b€c 1
} ABC-k50ab
test http-idna-2.13.$ThreadLevel {puny encode: edge cases} {
    ::tcl::idna puny encode ""
} ""
test http-idna-2.14-A.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0644 u+064A u+0647 u+0645 u+0627 u+0628 u+062A u+0643 u+0644
	u+0645 u+0648 u+0634 u+0639 u+0631 u+0628 u+064A u+061F
    }]] ""]
} egbpdaj6bu4bxfgehfvwxn
test http-idna-2.14-B.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+4ED6 u+4EEC u+4E3A u+4EC0 u+4E48 u+4E0D u+8BF4 u+4E2D u+6587
    }]] ""]
} ihqwcrb4cv8a8dqg056pqjye
test http-idna-2.14-C.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+4ED6 u+5011 u+7232 u+4EC0 u+9EBD u+4E0D u+8AAA u+4E2D u+6587
    }]] ""]
} ihqwctvzc91f659drss3x8bo0yb
test http-idna-2.14-D.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0050 u+0072 u+006F u+010D u+0070 u+0072 u+006F u+0073 u+0074
	u+011B u+006E u+0065 u+006D u+006C u+0075 u+0076 u+00ED u+010D
	u+0065 u+0073 u+006B u+0079
    }]] ""]
} Proprostnemluvesky-uyb24dma41a
test http-idna-2.14-E.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+05DC u+05DE u+05D4 u+05D4 u+05DD u+05E4 u+05E9 u+05D5 u+05D8
	u+05DC u+05D0 u+05DE u+05D3 u+05D1 u+05E8 u+05D9 u+05DD u+05E2
	u+05D1 u+05E8 u+05D9 u+05EA
    }]] ""]
} 4dbcagdahymbxekheh6e0a7fei0b
test http-idna-2.14-F.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+092F u+0939 u+0932 u+094B u+0917 u+0939 u+093F u+0928 u+094D
	u+0926 u+0940 u+0915 u+094D u+092F u+094B u+0902 u+0928 u+0939
	u+0940 u+0902 u+092C u+094B u+0932 u+0938 u+0915 u+0924 u+0947
	u+0939 u+0948 u+0902
    }]] ""]
} i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd
test http-idna-2.14-G.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+306A u+305C u+307F u+3093 u+306A u+65E5 u+672C u+8A9E u+3092
	u+8A71 u+3057 u+3066 u+304F u+308C u+306A u+3044 u+306E u+304B
    }]] ""]
} n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa
test http-idna-2.14-H.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+C138 u+ACC4 u+C758 u+BAA8 u+B4E0 u+C0AC u+B78C u+B4E4 u+C774
	u+D55C u+AD6D u+C5B4 u+B97C u+C774 u+D574 u+D55C u+B2E4 u+BA74
	u+C5BC u+B9C8 u+B098 u+C88B u+C744 u+AE4C
    }]] ""]
} 989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c
test http-idna-2.14-I.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+043F u+043E u+0447 u+0435 u+043C u+0443 u+0436 u+0435 u+043E
	u+043D u+0438 u+043D u+0435 u+0433 u+043E u+0432 u+043E u+0440
	u+044F u+0442 u+043F u+043E u+0440 u+0443 u+0441 u+0441 u+043A
	u+0438
    }]] ""]
} b1abfaaepdrnnbgefbadotcwatmq2g4l
test http-idna-2.14-J.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0050 u+006F u+0072 u+0071 u+0075 u+00E9 u+006E u+006F u+0070
	u+0075 u+0065 u+0064 u+0065 u+006E u+0073 u+0069 u+006D u+0070
	u+006C u+0065 u+006D u+0065 u+006E u+0074 u+0065 u+0068 u+0061
	u+0062 u+006C u+0061 u+0072 u+0065 u+006E u+0045 u+0073 u+0070
	u+0061 u+00F1 u+006F u+006C
    }]] ""]
} PorqunopuedensimplementehablarenEspaol-fmd56a
test http-idna-2.14-K.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0054 u+1EA1 u+0069 u+0073 u+0061 u+006F u+0068 u+1ECD u+006B
	u+0068 u+00F4 u+006E u+0067 u+0074 u+0068 u+1EC3 u+0063 u+0068
	u+1EC9 u+006E u+00F3 u+0069 u+0074 u+0069 u+1EBF u+006E u+0067
	u+0056 u+0069 u+1EC7 u+0074
    }]] ""]
} TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g
test http-idna-2.14-L.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0033 u+5E74 u+0042 u+7D44 u+91D1 u+516B u+5148 u+751F
    }]] ""]
} 3B-ww4c5e180e575a65lsy2b
test http-idna-2.14-M.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+5B89 u+5BA4 u+5948 u+7F8E u+6075 u+002D u+0077 u+0069 u+0074
	u+0068 u+002D u+0053 u+0055 u+0050 u+0045 u+0052 u+002D u+004D
	u+004F u+004E u+004B u+0045 u+0059 u+0053
    }]] ""]
} -with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n
test http-idna-2.14-N.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0048 u+0065 u+006C u+006C u+006F u+002D u+0041 u+006E u+006F
	u+0074 u+0068 u+0065 u+0072 u+002D u+0057 u+0061 u+0079 u+002D
	u+305D u+308C u+305E u+308C u+306E u+5834 u+6240
    }]] ""]
} Hello-Another-Way--fc4qua05auwb3674vfr0b
test http-idna-2.14-O.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+3072 u+3068 u+3064 u+5C4B u+6839 u+306E u+4E0B u+0032
    }]] ""]
} 2-u9tlzr9756bt3uc0v
test http-idna-2.14-P.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+004D u+0061 u+006A u+0069 u+3067 u+004B u+006F u+0069 u+3059
	u+308B u+0035 u+79D2 u+524D
    }]] ""]
} MajiKoi5-783gue6qz075azm5e
test http-idna-2.14-Q.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+30D1 u+30D5 u+30A3 u+30FC u+0064 u+0065 u+30EB u+30F3 u+30D0
    }]] ""]
} de-jg4avhby1noc0d
test http-idna-2.14-R.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+305D u+306E u+30B9 u+30D4 u+30FC u+30C9 u+3067
    }]] ""]
} d9juau41awczczp
test http-idna-2.14-S.$ThreadLevel {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode {-> $1.00 <-}
} {-> $1.00 <--}

test http-idna-3.1.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode abc-
} abc
test http-idna-3.2.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode abc-k50ab
} a€b€c
test http-idna-3.3.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode ABC-
} ABC
test http-idna-3.4.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode ABC-k50ab
} A€B€C
test http-idna-3.5.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode ABC-K50AB
} A€B€C
test http-idna-3.6.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode abc-K50AB
} a€b€c
test http-idna-3.7.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode ABC- 0
} abc
test http-idna-3.8.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode ABC-K50AB 0
} a€b€c
test http-idna-3.9.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode ABC- 1
} ABC
test http-idna-3.10.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode ABC-K50AB 1
} A€B€C
test http-idna-3.11.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode abc- 0
} abc
test http-idna-3.12.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode abc-k50ab 0
} a€b€c
test http-idna-3.13.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode abc- 1
} ABC
test http-idna-3.14.$ThreadLevel {puny decode: functional test} {
    ::tcl::idna puny decode abc-k50ab 1
} A€B€C
test http-idna-3.15.$ThreadLevel {puny decode: edge cases and errors} {
    # Is this case actually correct?
    binary encode hex [encoding convertto utf-8 [::tcl::idna puny decode abc]]
} c282c281c280
test http-idna-3.16.$ThreadLevel {puny decode: edge cases and errors} -returnCodes error -body {
    ::tcl::idna puny decode abc!
} -result {bad decode character "!"}
test http-idna-3.17.$ThreadLevel {puny decode: edge cases and errors} {
    catch {::tcl::idna puny decode abc!} -> opt
    dict get $opt -errorcode
} {PUNYCODE BAD_INPUT CHAR}
test http-idna-3.18.$ThreadLevel {puny decode: edge cases and errors} {
    ::tcl::idna puny decode ""
} {}
# A helper so we don't get lots of crap in failures
proc hexify s {lmap c [split $s ""] {format u+%04X [scan $c %c]}}
test http-idna-3.19-A.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode egbpdaj6bu4bxfgehfvwxn]
} [list {*}{
    u+0644 u+064A u+0647 u+0645 u+0627 u+0628 u+062A u+0643 u+0644
    u+0645 u+0648 u+0634 u+0639 u+0631 u+0628 u+064A u+061F
}]
test http-idna-3.19-B.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode ihqwcrb4cv8a8dqg056pqjye]
} {u+4ED6 u+4EEC u+4E3A u+4EC0 u+4E48 u+4E0D u+8BF4 u+4E2D u+6587}
test http-idna-3.19-C.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode ihqwctvzc91f659drss3x8bo0yb]
} {u+4ED6 u+5011 u+7232 u+4EC0 u+9EBD u+4E0D u+8AAA u+4E2D u+6587}
test http-idna-3.19-D.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode Proprostnemluvesky-uyb24dma41a]
} [list {*}{
    u+0050 u+0072 u+006F u+010D u+0070 u+0072 u+006F u+0073 u+0074
    u+011B u+006E u+0065 u+006D u+006C u+0075 u+0076 u+00ED u+010D
    u+0065 u+0073 u+006B u+0079
}]
test http-idna-3.19-E.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode 4dbcagdahymbxekheh6e0a7fei0b]
} [list {*}{
    u+05DC u+05DE u+05D4 u+05D4 u+05DD u+05E4 u+05E9 u+05D5 u+05D8
    u+05DC u+05D0 u+05DE u+05D3 u+05D1 u+05E8 u+05D9 u+05DD u+05E2
    u+05D1 u+05E8 u+05D9 u+05EA
}]
test http-idna-3.19-F.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode \
	i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd]
} [list {*}{
    u+092F u+0939 u+0932 u+094B u+0917 u+0939 u+093F u+0928 u+094D
    u+0926 u+0940 u+0915 u+094D u+092F u+094B u+0902 u+0928 u+0939
    u+0940 u+0902 u+092C u+094B u+0932 u+0938 u+0915 u+0924 u+0947
    u+0939 u+0948 u+0902
}]
test http-idna-3.19-G.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa]
} [list {*}{
    u+306A u+305C u+307F u+3093 u+306A u+65E5 u+672C u+8A9E u+3092
    u+8A71 u+3057 u+3066 u+304F u+308C u+306A u+3044 u+306E u+304B
}]
test http-idna-3.19-H.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode \
	989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c]
} [list {*}{
    u+C138 u+ACC4 u+C758 u+BAA8 u+B4E0 u+C0AC u+B78C u+B4E4 u+C774
    u+D55C u+AD6D u+C5B4 u+B97C u+C774 u+D574 u+D55C u+B2E4 u+BA74
    u+C5BC u+B9C8 u+B098 u+C88B u+C744 u+AE4C
}]
test http-idna-3.19-I.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode b1abfaaepdrnnbgefbadotcwatmq2g4l]
} [list {*}{
    u+043F u+043E u+0447 u+0435 u+043C u+0443 u+0436 u+0435 u+043E
    u+043D u+0438 u+043D u+0435 u+0433 u+043E u+0432 u+043E u+0440
    u+044F u+0442 u+043F u+043E u+0440 u+0443 u+0441 u+0441 u+043A
    u+0438
}]
test http-idna-3.19-J.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode \
	PorqunopuedensimplementehablarenEspaol-fmd56a]
} [list {*}{
    u+0050 u+006F u+0072 u+0071 u+0075 u+00E9 u+006E u+006F u+0070
    u+0075 u+0065 u+0064 u+0065 u+006E u+0073 u+0069 u+006D u+0070
    u+006C u+0065 u+006D u+0065 u+006E u+0074 u+0065 u+0068 u+0061
    u+0062 u+006C u+0061 u+0072 u+0065 u+006E u+0045 u+0073 u+0070
    u+0061 u+00F1 u+006F u+006C
}]
test http-idna-3.19-K.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode \
	TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g]
} [list {*}{
    u+0054 u+1EA1 u+0069 u+0073 u+0061 u+006F u+0068 u+1ECD u+006B
    u+0068 u+00F4 u+006E u+0067 u+0074 u+0068 u+1EC3 u+0063 u+0068
    u+1EC9 u+006E u+00F3 u+0069 u+0074 u+0069 u+1EBF u+006E u+0067
    u+0056 u+0069 u+1EC7 u+0074
}]
test http-idna-3.19-L.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode 3B-ww4c5e180e575a65lsy2b]
} {u+0033 u+5E74 u+0042 u+7D44 u+91D1 u+516B u+5148 u+751F}
test http-idna-3.19-M.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode -with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n]
} [list {*}{
    u+5B89 u+5BA4 u+5948 u+7F8E u+6075 u+002D u+0077 u+0069 u+0074
    u+0068 u+002D u+0053 u+0055 u+0050 u+0045 u+0052 u+002D u+004D
    u+004F u+004E u+004B u+0045 u+0059 u+0053
}]
test http-idna-3.19-N.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode Hello-Another-Way--fc4qua05auwb3674vfr0b]
} [list {*}{
    u+0048 u+0065 u+006C u+006C u+006F u+002D u+0041 u+006E u+006F
    u+0074 u+0068 u+0065 u+0072 u+002D u+0057 u+0061 u+0079 u+002D
    u+305D u+308C u+305E u+308C u+306E u+5834 u+6240
}]
test http-idna-3.19-O.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode 2-u9tlzr9756bt3uc0v]
} {u+3072 u+3068 u+3064 u+5C4B u+6839 u+306E u+4E0B u+0032}
test http-idna-3.19-P.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode MajiKoi5-783gue6qz075azm5e]
} [list {*}{
    u+004D u+0061 u+006A u+0069 u+3067 u+004B u+006F u+0069 u+3059
    u+308B u+0035 u+79D2 u+524D
}]
test http-idna-3.19-Q.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode de-jg4avhby1noc0d]
} {u+30D1 u+30D5 u+30A3 u+30FC u+0064 u+0065 u+30EB u+30F3 u+30D0}
test http-idna-3.19-R.$ThreadLevel {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode d9juau41awczczp]
} {u+305D u+306E u+30B9 u+30D4 u+30FC u+30C9 u+3067}
test http-idna-3.19-S.$ThreadLevel {puny decode: examples from RFC 3492} {
    ::tcl::idna puny decode {-> $1.00 <--}
} {-> $1.00 <-}
rename hexify ""

test http-idna-4.1.$ThreadLevel {IDNA encoding} {
    ::tcl::idna encode abc.def
} abc.def
test http-idna-4.2.$ThreadLevel {IDNA encoding} {
    ::tcl::idna encode a€b€c.def
} xn--abc-k50ab.def
test http-idna-4.3.$ThreadLevel {IDNA encoding} {
    ::tcl::idna encode def.a€b€c
} def.xn--abc-k50ab
test http-idna-4.4.$ThreadLevel {IDNA encoding} {
    ::tcl::idna encode ABC.DEF
} ABC.DEF
test http-idna-4.5.$ThreadLevel {IDNA encoding} {
    ::tcl::idna encode A€B€C.def
} xn--ABC-k50ab.def
test http-idna-4.6.$ThreadLevel {IDNA encoding: invalid edge case} {
    # Should this be an error?
    ::tcl::idna encode abc..def
} abc..def
test http-idna-4.7.$ThreadLevel {IDNA encoding: invalid char} -returnCodes error -body {
    ::tcl::idna encode abc.$.def
} -result {bad character "$" in DNS name}
test http-idna-4.7.1.$ThreadLevel {IDNA encoding: invalid char} {
    catch {::tcl::idna encode abc.$.def} -> opt
    dict get $opt -errorcode
} {IDNA INVALID_NAME_CHARACTER {$}}
test http-idna-4.8.$ThreadLevel {IDNA encoding: empty} {
    ::tcl::idna encode ""
} {}
set overlong www.[join [subst [string map {u+ \\u} {
    u+C138 u+ACC4 u+C758 u+BAA8 u+B4E0 u+C0AC u+B78C u+B4E4 u+C774
    u+D55C u+AD6D u+C5B4 u+B97C u+C774 u+D574 u+D55C u+B2E4 u+BA74
    u+C5BC u+B9C8 u+B098 u+C88B u+C744 u+AE4C
}]] ""].com
test http-idna-4.9.$ThreadLevel {IDNA encoding: max lengths from RFC 5890} -body {
    ::tcl::idna encode $overlong
} -returnCodes error -result "hostname part too long"
test http-idna-4.9.1.$ThreadLevel {IDNA encoding: max lengths from RFC 5890} {
    catch {::tcl::idna encode $overlong} -> opt
    dict get $opt -errorcode
} {IDNA OVERLONG_PART xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c}
unset overlong
test http-idna-4.10.$ThreadLevel {IDNA encoding: edge cases} {
    ::tcl::idna encode passé.example.com
} xn--pass-epa.example.com

test http-idna-5.1.$ThreadLevel {IDNA decoding} {
    ::tcl::idna decode abc.def
} abc.def
test http-idna-5.2.$ThreadLevel {IDNA decoding} {
    # Invalid entry that's just a wrapper
    ::tcl::idna decode xn--abc-.def
} abc.def
test http-idna-5.3.$ThreadLevel {IDNA decoding} {
    # Invalid entry that's just a wrapper
    ::tcl::idna decode xn--abc-.xn--def-
} abc.def
test http-idna-5.4.$ThreadLevel {IDNA decoding} {
    # Invalid entry that's just a wrapper
    ::tcl::idna decode XN--abc-.XN--def-
} abc.def
test http-idna-5.5.$ThreadLevel {IDNA decoding: error cases} -returnCodes error -body {
    ::tcl::idna decode xn--$$$.example.com
} -result {bad decode character "$"}
test http-idna-5.5.1.$ThreadLevel {IDNA decoding: error cases} {
    catch {::tcl::idna decode xn--$$$.example.com} -> opt
    dict get $opt -errorcode
} {PUNYCODE BAD_INPUT CHAR}
test http-idna-5.6.$ThreadLevel {IDNA decoding: error cases} -returnCodes error -body {
    ::tcl::idna decode xn--a-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.def
} -result {exceeded input data}
test http-idna-5.6.1.$ThreadLevel {IDNA decoding: error cases} {
    catch {::tcl::idna decode xn--a-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.def} -> opt
    dict get $opt -errorcode
} {PUNYCODE BAD_INPUT LENGTH}

# cleanup
catch {unset url}
catch {unset badurl}
catch {unset port}
catch {unset data}
if {[llength $threadStack]} {
    eval [lpop threadStack]







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







748
749
750
751
752
753
754





























































































































































































































































































































































































































































755
756
757
758
759
760
761
    # proper exception with Tcl 9.0
    http::config -urlencoding "iso8859-1"
    http::mapReply "∈"
} -cleanup {
    http::config -urlencoding $enc
} -errorCode {TCL ENCODING ILLEGALSEQUENCE 0} -result {unexpected character at index 0: 'U+002208'}






























































































































































































































































































































































































































































# cleanup
catch {unset url}
catch {unset badurl}
catch {unset port}
catch {unset data}
if {[llength $threadStack]} {
    eval [lpop threadStack]
Added tests/idna.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
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
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
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
# Commands covered:  tcl::idna
#
# This file contains a collection of tests for the IDNA conversion library.
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright © 2014-2025 Donal K. Fellows.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.

if {"::tcltest" ni [namespace children]} {
    package require tcltest 2.5
    namespace import -force ::tcltest::*
}

package require tcl::idna 1.0

test idna-1.1 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna
} -result {wrong # args: should be "::tcl::idna subcommand ?arg ...?"}
test idna-1.2 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna ?
} -result {unknown or ambiguous subcommand "?": must be decode, encode, puny, or version}
test idna-1.3 {IDNA package: basics} -body {
    ::tcl::idna version
} -result 1.0.1
test idna-1.4 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna version what
} -result {wrong # args: should be "::tcl::idna version"}
test idna-1.5 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny
} -result {wrong # args: should be "::tcl::idna puny subcommand ?arg ...?"}
test idna-1.6 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny ?
} -result {unknown or ambiguous subcommand "?": must be decode, or encode}
test idna-1.7 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny encode
} -result {wrong # args: should be "::tcl::idna puny encode string ?case?"}
test idna-1.8 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny encode a b c
} -result {wrong # args: should be "::tcl::idna puny encode string ?case?"}
test idna-1.9 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny decode
} -result {wrong # args: should be "::tcl::idna puny decode string ?case?"}
test idna-1.10 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna puny decode a b c
} -result {wrong # args: should be "::tcl::idna puny decode string ?case?"}
test idna-1.11 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna decode
} -result {wrong # args: should be "::tcl::idna decode hostname"}
test idna-1.12 {IDNA package: basics} -returnCodes error -body {
    ::tcl::idna encode
} -result {wrong # args: should be "::tcl::idna encode hostname"}

test idna-2.1 {puny encode: functional test} {
    ::tcl::idna puny encode abc
} abc-
test idna-2.2 {puny encode: functional test} {
    ::tcl::idna puny encode a€b€c
} abc-k50ab
test idna-2.3 {puny encode: functional test} {
    ::tcl::idna puny encode ABC
} ABC-
test idna-2.4 {puny encode: functional test} {
    ::tcl::idna puny encode A€B€C
} ABC-k50ab
test idna-2.5 {puny encode: functional test} {
    ::tcl::idna puny encode ABC 0
} abc-
test idna-2.6 {puny encode: functional test} {
    ::tcl::idna puny encode A€B€C 0
} abc-k50ab
test idna-2.7 {puny encode: functional test} {
    ::tcl::idna puny encode ABC 1
} ABC-
test idna-2.8 {puny encode: functional test} {
    ::tcl::idna puny encode A€B€C 1
} ABC-k50ab
test idna-2.9 {puny encode: functional test} {
    ::tcl::idna puny encode abc 0
} abc-
test idna-2.10 {puny encode: functional test} {
    ::tcl::idna puny encode a€b€c 0
} abc-k50ab
test idna-2.11 {puny encode: functional test} {
    ::tcl::idna puny encode abc 1
} ABC-
test idna-2.12 {puny encode: functional test} {
    ::tcl::idna puny encode a€b€c 1
} ABC-k50ab
test idna-2.13 {puny encode: edge cases} {
    ::tcl::idna puny encode ""
} ""
test idna-2.14-A {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0644 u+064A u+0647 u+0645 u+0627 u+0628 u+062A u+0643 u+0644
	u+0645 u+0648 u+0634 u+0639 u+0631 u+0628 u+064A u+061F
    }]] ""]
} egbpdaj6bu4bxfgehfvwxn
test idna-2.14-B {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+4ED6 u+4EEC u+4E3A u+4EC0 u+4E48 u+4E0D u+8BF4 u+4E2D u+6587
    }]] ""]
} ihqwcrb4cv8a8dqg056pqjye
test idna-2.14-C {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+4ED6 u+5011 u+7232 u+4EC0 u+9EBD u+4E0D u+8AAA u+4E2D u+6587
    }]] ""]
} ihqwctvzc91f659drss3x8bo0yb
test idna-2.14-D {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0050 u+0072 u+006F u+010D u+0070 u+0072 u+006F u+0073 u+0074
	u+011B u+006E u+0065 u+006D u+006C u+0075 u+0076 u+00ED u+010D
	u+0065 u+0073 u+006B u+0079
    }]] ""]
} Proprostnemluvesky-uyb24dma41a
test idna-2.14-E {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+05DC u+05DE u+05D4 u+05D4 u+05DD u+05E4 u+05E9 u+05D5 u+05D8
	u+05DC u+05D0 u+05DE u+05D3 u+05D1 u+05E8 u+05D9 u+05DD u+05E2
	u+05D1 u+05E8 u+05D9 u+05EA
    }]] ""]
} 4dbcagdahymbxekheh6e0a7fei0b
test idna-2.14-F {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+092F u+0939 u+0932 u+094B u+0917 u+0939 u+093F u+0928 u+094D
	u+0926 u+0940 u+0915 u+094D u+092F u+094B u+0902 u+0928 u+0939
	u+0940 u+0902 u+092C u+094B u+0932 u+0938 u+0915 u+0924 u+0947
	u+0939 u+0948 u+0902
    }]] ""]
} i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd
test idna-2.14-G {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+306A u+305C u+307F u+3093 u+306A u+65E5 u+672C u+8A9E u+3092
	u+8A71 u+3057 u+3066 u+304F u+308C u+306A u+3044 u+306E u+304B
    }]] ""]
} n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa
test idna-2.14-H {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+C138 u+ACC4 u+C758 u+BAA8 u+B4E0 u+C0AC u+B78C u+B4E4 u+C774
	u+D55C u+AD6D u+C5B4 u+B97C u+C774 u+D574 u+D55C u+B2E4 u+BA74
	u+C5BC u+B9C8 u+B098 u+C88B u+C744 u+AE4C
    }]] ""]
} 989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c
test idna-2.14-I {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+043F u+043E u+0447 u+0435 u+043C u+0443 u+0436 u+0435 u+043E
	u+043D u+0438 u+043D u+0435 u+0433 u+043E u+0432 u+043E u+0440
	u+044F u+0442 u+043F u+043E u+0440 u+0443 u+0441 u+0441 u+043A
	u+0438
    }]] ""]
} b1abfaaepdrnnbgefbadotcwatmq2g4l
test idna-2.14-J {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0050 u+006F u+0072 u+0071 u+0075 u+00E9 u+006E u+006F u+0070
	u+0075 u+0065 u+0064 u+0065 u+006E u+0073 u+0069 u+006D u+0070
	u+006C u+0065 u+006D u+0065 u+006E u+0074 u+0065 u+0068 u+0061
	u+0062 u+006C u+0061 u+0072 u+0065 u+006E u+0045 u+0073 u+0070
	u+0061 u+00F1 u+006F u+006C
    }]] ""]
} PorqunopuedensimplementehablarenEspaol-fmd56a
test idna-2.14-K {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0054 u+1EA1 u+0069 u+0073 u+0061 u+006F u+0068 u+1ECD u+006B
	u+0068 u+00F4 u+006E u+0067 u+0074 u+0068 u+1EC3 u+0063 u+0068
	u+1EC9 u+006E u+00F3 u+0069 u+0074 u+0069 u+1EBF u+006E u+0067
	u+0056 u+0069 u+1EC7 u+0074
    }]] ""]
} TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g
test idna-2.14-L {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0033 u+5E74 u+0042 u+7D44 u+91D1 u+516B u+5148 u+751F
    }]] ""]
} 3B-ww4c5e180e575a65lsy2b
test idna-2.14-M {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+5B89 u+5BA4 u+5948 u+7F8E u+6075 u+002D u+0077 u+0069 u+0074
	u+0068 u+002D u+0053 u+0055 u+0050 u+0045 u+0052 u+002D u+004D
	u+004F u+004E u+004B u+0045 u+0059 u+0053
    }]] ""]
} -with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n
test idna-2.14-N {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+0048 u+0065 u+006C u+006C u+006F u+002D u+0041 u+006E u+006F
	u+0074 u+0068 u+0065 u+0072 u+002D u+0057 u+0061 u+0079 u+002D
	u+305D u+308C u+305E u+308C u+306E u+5834 u+6240
    }]] ""]
} Hello-Another-Way--fc4qua05auwb3674vfr0b
test idna-2.14-O {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+3072 u+3068 u+3064 u+5C4B u+6839 u+306E u+4E0B u+0032
    }]] ""]
} 2-u9tlzr9756bt3uc0v
test idna-2.14-P {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+004D u+0061 u+006A u+0069 u+3067 u+004B u+006F u+0069 u+3059
	u+308B u+0035 u+79D2 u+524D
    }]] ""]
} MajiKoi5-783gue6qz075azm5e
test idna-2.14-Q {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+30D1 u+30D5 u+30A3 u+30FC u+0064 u+0065 u+30EB u+30F3 u+30D0
    }]] ""]
} de-jg4avhby1noc0d
test idna-2.14-R {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode [join [subst [string map {u+ \\u} {
	u+305D u+306E u+30B9 u+30D4 u+30FC u+30C9 u+3067
    }]] ""]
} d9juau41awczczp
test idna-2.14-S {puny encode: examples from RFC 3492} {
    ::tcl::idna puny encode {-> $1.00 <-}
} {-> $1.00 <--}

test idna-3.1 {puny decode: functional test} {
    ::tcl::idna puny decode abc-
} abc
test idna-3.2 {puny decode: functional test} {
    ::tcl::idna puny decode abc-k50ab
} a€b€c
test idna-3.3 {puny decode: functional test} {
    ::tcl::idna puny decode ABC-
} ABC
test idna-3.4 {puny decode: functional test} {
    ::tcl::idna puny decode ABC-k50ab
} A€B€C
test idna-3.5 {puny decode: functional test} {
    ::tcl::idna puny decode ABC-K50AB
} A€B€C
test idna-3.6 {puny decode: functional test} {
    ::tcl::idna puny decode abc-K50AB
} a€b€c
test idna-3.7 {puny decode: functional test} {
    ::tcl::idna puny decode ABC- 0
} abc
test idna-3.8 {puny decode: functional test} {
    ::tcl::idna puny decode ABC-K50AB 0
} a€b€c
test idna-3.9 {puny decode: functional test} {
    ::tcl::idna puny decode ABC- 1
} ABC
test idna-3.10 {puny decode: functional test} {
    ::tcl::idna puny decode ABC-K50AB 1
} A€B€C
test idna-3.11 {puny decode: functional test} {
    ::tcl::idna puny decode abc- 0
} abc
test idna-3.12 {puny decode: functional test} {
    ::tcl::idna puny decode abc-k50ab 0
} a€b€c
test idna-3.13 {puny decode: functional test} {
    ::tcl::idna puny decode abc- 1
} ABC
test idna-3.14 {puny decode: functional test} {
    ::tcl::idna puny decode abc-k50ab 1
} A€B€C
test idna-3.15 {puny decode: edge cases and errors} {
    # Is this case actually correct?
    binary encode hex [encoding convertto utf-8 [::tcl::idna puny decode abc]]
} c282c281c280
test idna-3.16 {puny decode: edge cases and errors} -returnCodes error -body {
    ::tcl::idna puny decode abc!
} -result {bad decode character "!"}
test idna-3.17 {puny decode: edge cases and errors} {
    catch {::tcl::idna puny decode abc!} -> opt
    dict get $opt -errorcode
} {PUNYCODE BAD_INPUT CHAR}
test idna-3.18 {puny decode: edge cases and errors} {
    ::tcl::idna puny decode ""
} {}
# A helper so we don't get lots of crap in failures
proc hexify s {lmap c [split $s ""] {format u+%04X [scan $c %c]}}
test idna-3.19-A {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode egbpdaj6bu4bxfgehfvwxn]
} [list {*}{
    u+0644 u+064A u+0647 u+0645 u+0627 u+0628 u+062A u+0643 u+0644
    u+0645 u+0648 u+0634 u+0639 u+0631 u+0628 u+064A u+061F
}]
test idna-3.19-B {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode ihqwcrb4cv8a8dqg056pqjye]
} {u+4ED6 u+4EEC u+4E3A u+4EC0 u+4E48 u+4E0D u+8BF4 u+4E2D u+6587}
test idna-3.19-C {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode ihqwctvzc91f659drss3x8bo0yb]
} {u+4ED6 u+5011 u+7232 u+4EC0 u+9EBD u+4E0D u+8AAA u+4E2D u+6587}
test idna-3.19-D {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode Proprostnemluvesky-uyb24dma41a]
} [list {*}{
    u+0050 u+0072 u+006F u+010D u+0070 u+0072 u+006F u+0073 u+0074
    u+011B u+006E u+0065 u+006D u+006C u+0075 u+0076 u+00ED u+010D
    u+0065 u+0073 u+006B u+0079
}]
test idna-3.19-E {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode 4dbcagdahymbxekheh6e0a7fei0b]
} [list {*}{
    u+05DC u+05DE u+05D4 u+05D4 u+05DD u+05E4 u+05E9 u+05D5 u+05D8
    u+05DC u+05D0 u+05DE u+05D3 u+05D1 u+05E8 u+05D9 u+05DD u+05E2
    u+05D1 u+05E8 u+05D9 u+05EA
}]
test idna-3.19-F {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode \
	i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd]
} [list {*}{
    u+092F u+0939 u+0932 u+094B u+0917 u+0939 u+093F u+0928 u+094D
    u+0926 u+0940 u+0915 u+094D u+092F u+094B u+0902 u+0928 u+0939
    u+0940 u+0902 u+092C u+094B u+0932 u+0938 u+0915 u+0924 u+0947
    u+0939 u+0948 u+0902
}]
test idna-3.19-G {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa]
} [list {*}{
    u+306A u+305C u+307F u+3093 u+306A u+65E5 u+672C u+8A9E u+3092
    u+8A71 u+3057 u+3066 u+304F u+308C u+306A u+3044 u+306E u+304B
}]
test idna-3.19-H {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode \
	989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c]
} [list {*}{
    u+C138 u+ACC4 u+C758 u+BAA8 u+B4E0 u+C0AC u+B78C u+B4E4 u+C774
    u+D55C u+AD6D u+C5B4 u+B97C u+C774 u+D574 u+D55C u+B2E4 u+BA74
    u+C5BC u+B9C8 u+B098 u+C88B u+C744 u+AE4C
}]
test idna-3.19-I {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode b1abfaaepdrnnbgefbadotcwatmq2g4l]
} [list {*}{
    u+043F u+043E u+0447 u+0435 u+043C u+0443 u+0436 u+0435 u+043E
    u+043D u+0438 u+043D u+0435 u+0433 u+043E u+0432 u+043E u+0440
    u+044F u+0442 u+043F u+043E u+0440 u+0443 u+0441 u+0441 u+043A
    u+0438
}]
test idna-3.19-J {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode \
	PorqunopuedensimplementehablarenEspaol-fmd56a]
} [list {*}{
    u+0050 u+006F u+0072 u+0071 u+0075 u+00E9 u+006E u+006F u+0070
    u+0075 u+0065 u+0064 u+0065 u+006E u+0073 u+0069 u+006D u+0070
    u+006C u+0065 u+006D u+0065 u+006E u+0074 u+0065 u+0068 u+0061
    u+0062 u+006C u+0061 u+0072 u+0065 u+006E u+0045 u+0073 u+0070
    u+0061 u+00F1 u+006F u+006C
}]
test idna-3.19-K {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode \
	TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g]
} [list {*}{
    u+0054 u+1EA1 u+0069 u+0073 u+0061 u+006F u+0068 u+1ECD u+006B
    u+0068 u+00F4 u+006E u+0067 u+0074 u+0068 u+1EC3 u+0063 u+0068
    u+1EC9 u+006E u+00F3 u+0069 u+0074 u+0069 u+1EBF u+006E u+0067
    u+0056 u+0069 u+1EC7 u+0074
}]
test idna-3.19-L {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode 3B-ww4c5e180e575a65lsy2b]
} {u+0033 u+5E74 u+0042 u+7D44 u+91D1 u+516B u+5148 u+751F}
test idna-3.19-M {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode -with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n]
} [list {*}{
    u+5B89 u+5BA4 u+5948 u+7F8E u+6075 u+002D u+0077 u+0069 u+0074
    u+0068 u+002D u+0053 u+0055 u+0050 u+0045 u+0052 u+002D u+004D
    u+004F u+004E u+004B u+0045 u+0059 u+0053
}]
test idna-3.19-N {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode Hello-Another-Way--fc4qua05auwb3674vfr0b]
} [list {*}{
    u+0048 u+0065 u+006C u+006C u+006F u+002D u+0041 u+006E u+006F
    u+0074 u+0068 u+0065 u+0072 u+002D u+0057 u+0061 u+0079 u+002D
    u+305D u+308C u+305E u+308C u+306E u+5834 u+6240
}]
test idna-3.19-O {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode 2-u9tlzr9756bt3uc0v]
} {u+3072 u+3068 u+3064 u+5C4B u+6839 u+306E u+4E0B u+0032}
test idna-3.19-P {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode MajiKoi5-783gue6qz075azm5e]
} [list {*}{
    u+004D u+0061 u+006A u+0069 u+3067 u+004B u+006F u+0069 u+3059
    u+308B u+0035 u+79D2 u+524D
}]
test idna-3.19-Q {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode de-jg4avhby1noc0d]
} {u+30D1 u+30D5 u+30A3 u+30FC u+0064 u+0065 u+30EB u+30F3 u+30D0}
test idna-3.19-R {puny decode: examples from RFC 3492} {
    hexify [::tcl::idna puny decode d9juau41awczczp]
} {u+305D u+306E u+30B9 u+30D4 u+30FC u+30C9 u+3067}
test idna-3.19-S {puny decode: examples from RFC 3492} {
    ::tcl::idna puny decode {-> $1.00 <--}
} {-> $1.00 <-}
rename hexify ""

test idna-4.1 {IDNA encoding} {
    ::tcl::idna encode abc.def
} abc.def
test idna-4.2 {IDNA encoding} {
    ::tcl::idna encode a€b€c.def
} xn--abc-k50ab.def
test idna-4.3 {IDNA encoding} {
    ::tcl::idna encode def.a€b€c
} def.xn--abc-k50ab
test idna-4.4 {IDNA encoding} {
    ::tcl::idna encode ABC.DEF
} ABC.DEF
test idna-4.5 {IDNA encoding} {
    ::tcl::idna encode A€B€C.def
} xn--ABC-k50ab.def
test idna-4.6 {IDNA encoding: invalid edge case} {
    # Should this be an error?
    ::tcl::idna encode abc..def
} abc..def
test idna-4.7 {IDNA encoding: invalid char} -returnCodes error -body {
    ::tcl::idna encode abc.$.def
} -result {bad character "$" in DNS name}
test idna-4.7.1 {IDNA encoding: invalid char} {
    catch {::tcl::idna encode abc.$.def} -> opt
    dict get $opt -errorcode
} {IDNA INVALID_NAME_CHARACTER {$}}
test idna-4.8 {IDNA encoding: empty} {
    ::tcl::idna encode ""
} {}
set overlong www.[join [subst [string map {u+ \\u} {
    u+C138 u+ACC4 u+C758 u+BAA8 u+B4E0 u+C0AC u+B78C u+B4E4 u+C774
    u+D55C u+AD6D u+C5B4 u+B97C u+C774 u+D574 u+D55C u+B2E4 u+BA74
    u+C5BC u+B9C8 u+B098 u+C88B u+C744 u+AE4C
}]] ""].com
test idna-4.9 {IDNA encoding: max lengths from RFC 5890} -body {
    ::tcl::idna encode $overlong
} -returnCodes error -result "hostname part too long"
test idna-4.9.1 {IDNA encoding: max lengths from RFC 5890} {
    catch {::tcl::idna encode $overlong} -> opt
    dict get $opt -errorcode
} {IDNA OVERLONG_PART xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c}
unset overlong
test idna-4.10 {IDNA encoding: edge cases} {
    ::tcl::idna encode passé.example.com
} xn--pass-epa.example.com

test idna-5.1 {IDNA decoding} {
    ::tcl::idna decode abc.def
} abc.def
test idna-5.2 {IDNA decoding} {
    # Invalid entry that's just a wrapper
    ::tcl::idna decode xn--abc-.def
} abc.def
test idna-5.3 {IDNA decoding} {
    # Invalid entry that's just a wrapper
    ::tcl::idna decode xn--abc-.xn--def-
} abc.def
test idna-5.4 {IDNA decoding} {
    # Invalid entry that's just a wrapper
    ::tcl::idna decode XN--abc-.XN--def-
} abc.def
test idna-5.5 {IDNA decoding: error cases} -returnCodes error -body {
    ::tcl::idna decode xn--$$$.example.com
} -result {bad decode character "$"}
test idna-5.5.1 {IDNA decoding: error cases} {
    catch {::tcl::idna decode xn--$$$.example.com} -> opt
    dict get $opt -errorcode
} {PUNYCODE BAD_INPUT CHAR}
test idna-5.6 {IDNA decoding: error cases} -returnCodes error -body {
    ::tcl::idna decode xn--a-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.def
} -result {exceeded input data}
test idna-5.6.1 {IDNA decoding: error cases} {
    catch {::tcl::idna decode xn--a-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.def} -> opt
    dict get $opt -errorcode
} {PUNYCODE BAD_INPUT LENGTH}

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/interp.test.
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

# Part 0: Check out options for interp command
test interp-1.1 {options for interp command} -returnCodes error -body {
    interp
} -result {wrong # args: should be "interp cmd ?arg ...?"}
test interp-1.2 {options for interp command} -returnCodes error -body {
    interp frobox
} -result {bad option "frobox": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, share, target, or transfer}
test interp-1.3 {options for interp command} {
    interp delete
} ""
test interp-1.4 {options for interp command} -returnCodes error -body {
    interp delete foo bar
} -result {could not find interpreter "foo"}
test interp-1.5 {options for interp command} -returnCodes error -body {
    interp exists foo bar
} -result {wrong # args: should be "interp exists ?path?"}
#
# test interp-0.6 was removed
#
test interp-1.6 {options for interp command} -returnCodes error -body {
    interp children foo bar zop
} -result {wrong # args: should be "interp children ?path?"}
test interp-1.7 {options for interp command} -returnCodes error -body {
    interp hello
} -result {bad option "hello": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, share, target, or transfer}
test interp-1.8 {options for interp command} -returnCodes error -body {
    interp -froboz
} -result {bad option "-froboz": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, share, target, or transfer}
test interp-1.9 {options for interp command} -returnCodes error -body {
    interp -froboz -safe
} -result {bad option "-froboz": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, share, target, or transfer}
test interp-1.10 {options for interp command} -returnCodes error -body {
    interp target
} -result {wrong # args: should be "interp target path alias"}








# Part 1: Basic interpreter creation tests:
test interp-2.1 {basic interpreter creation} {
    interp create a
} a
test interp-2.2 {basic interpreter creation} {
    catch {interp create}







|

















|


|


|



>
>
>
>
>
>
>







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

# Part 0: Check out options for interp command
test interp-1.1 {options for interp command} -returnCodes error -body {
    interp
} -result {wrong # args: should be "interp cmd ?arg ...?"}
test interp-1.2 {options for interp command} -returnCodes error -body {
    interp frobox
} -result {bad option "frobox": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, set, share, target, or transfer}
test interp-1.3 {options for interp command} {
    interp delete
} ""
test interp-1.4 {options for interp command} -returnCodes error -body {
    interp delete foo bar
} -result {could not find interpreter "foo"}
test interp-1.5 {options for interp command} -returnCodes error -body {
    interp exists foo bar
} -result {wrong # args: should be "interp exists ?path?"}
#
# test interp-0.6 was removed
#
test interp-1.6 {options for interp command} -returnCodes error -body {
    interp children foo bar zop
} -result {wrong # args: should be "interp children ?path?"}
test interp-1.7 {options for interp command} -returnCodes error -body {
    interp hello
} -result {bad option "hello": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, set, share, target, or transfer}
test interp-1.8 {options for interp command} -returnCodes error -body {
    interp -froboz
} -result {bad option "-froboz": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, set, share, target, or transfer}
test interp-1.9 {options for interp command} -returnCodes error -body {
    interp -froboz -safe
} -result {bad option "-froboz": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, set, share, target, or transfer}
test interp-1.10 {options for interp command} -returnCodes error -body {
    interp target
} -result {wrong # args: should be "interp target path alias"}
test interp-1.11 {options for interp child command} -returnCodes error -setup {
    interp create child
} -body {
    child gorp
} -cleanup {
    interp delete child
} -result {bad option "gorp": must be alias, aliases, bgerror, debug, eval, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, or set}

# Part 1: Basic interpreter creation tests:
test interp-2.1 {basic interpreter creation} {
    interp create a
} a
test interp-2.2 {basic interpreter creation} {
    catch {interp create}
3745
3746
3747
3748
3749
3750
3751













































































































































































3752
3753
3754
3755
3756
3757
3758
    interp debug {} -frames
} -returnCodes error -result {bad debug option "-frames": must be -frame}
test interp-38.8 {interp debug basic setup} -body {
    interp debug {} -frame 0 bogus
} -returnCodes {
    error
} -result {wrong # args: should be "interp debug path ?-frame ?bool??"}














































































































































































# cleanup
unset -nocomplain hidden_cmds
foreach i [interp children] {
    interp delete $i
}
rename _ms_limit_args {}







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







3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
    interp debug {} -frames
} -returnCodes error -result {bad debug option "-frames": must be -frame}
test interp-38.8 {interp debug basic setup} -body {
    interp debug {} -frame 0 bogus
} -returnCodes {
    error
} -result {wrong # args: should be "interp debug path ?-frame ?bool??"}

test interp-39.1 {interp set: syntax} -returnCodes error -body {
    interp set {}
} -result {wrong # args: should be "interp set path varName ?value?"}
test interp-39.2 {interp set: syntax} -returnCodes error -body {
    interp set {} foo bar gorp
} -result {wrong # args: should be "interp set path varName ?value?"}
test interp-39.3 {interp set} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	set x foo
	list [interp set {} x bar] $x
    }}
} -result {bar bar}
test interp-39.4 {interp set} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	set x foo
	list [interp set {} x] $x
    }}
} -result {foo foo}
test interp-39.5 {interp set} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	const x foo
	interp set {} x
    }}
} -result foo
test interp-39.6 {interp set} -returnCodes error -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	const x foo
	interp set {} x bar
    }}
} -result {can't set "x": variable is a constant}
test interp-39.7 {interp set} -setup {
    unset -nocomplain x
} -body {
    set x foo
    trace add variable x write {apply {args {
	global x
	set x gorp
	return
    }}}
    list [interp set {} x bar] $x
} -result {gorp gorp} -cleanup {
    unset -nocomplain x
}
test interp-39.8 {interp set} -setup {
    unset -nocomplain x
} -body {
    set x foo
    trace add variable x read {apply {args {
	global x
	set x gorp
	return
    }}}
    list [interp set {} x] $x
} -result {gorp gorp} -cleanup {
    unset -nocomplain x
}
test interp-39.9 {interp set} -setup {
    set i [interp create]
} -body {
    interp eval $i {
	proc readX {} {
	    global x
	    return $x
	}
    }
    interp set $i x "123 45"
    interp eval $i readX
} -result {123 45} -cleanup {
    interp delete $i
}

test interp-40.1 {interp child set: syntax} -setup {
    set i [interp create child]
} -returnCodes error -body {
    $i set
} -cleanup {
    interp delete child
} -result {wrong # args: should be "child set varName ?value?"}
test interp-40.2 {interp child set: syntax} -setup {
    set i [interp create child]
} -returnCodes error -body {
    $i set foo bar gorp
} -cleanup {
    interp delete child
} -result {wrong # args: should be "child set varName ?value?"}
test interp-40.3 {interp child set} -setup {
    set i [interp create]
} -body {
    $i eval set x foo
    list [$i set x bar] [$i eval set x]
} -cleanup {
    interp delete $i
} -result {bar bar}
test interp-40.4 {interp child set} -setup {
    set i [interp create]
} -body {
    $i eval set x foo
    list [$i set x] [$i eval set x]
} -cleanup {
    interp delete $i
} -result {foo foo}
test interp-40.5 {interp child set} -setup {
    set i [interp create]
} -body {
    $i eval const x foo
    $i set x
} -cleanup {
    interp delete $i
} -result foo
test interp-40.6 {interp child set} -setup {
    set i [interp create]
} -body {
    $i eval const x foo
    catch {$i set x bar} msg opt
    list $msg [dict get $opt -errorinfo]
} -cleanup {
    interp delete $i
} -result {{can't set "x": variable is a constant} {can't set "x": variable is a constant
    invoked from within
"$i set x bar"}}
test interp-40.7 {interp child set} -setup {
    set i [interp create]
} -body {
    $i eval {
	set x foo
	trace add variable x write {apply {args {
	    global x
	    set x gorp
	    return
	}}}
    }
    list [$i set x bar] [$i eval set x]
} -result {gorp gorp} -cleanup {
    interp delete $i
}
test interp-40.8 {interp child set} -setup {
    set i [interp create]
} -body {
    $i eval {
	set x foo
	trace add variable x read {apply {args {
	    global x
	    set x gorp
	    return
	}}}
    }
    list [$i set x] [$i eval set x]
} -result {gorp gorp} -cleanup {
    interp delete $i
}
test interp-40.9 {interp child set} -setup {
    set i [interp create]
} -body {
    interp eval $i {
	proc readX {} {
	    global x
	    return $x
	}
    }
    $i set x "123 45"
    interp eval $i readX
} -result {123 45} -cleanup {
    interp delete $i
}

# cleanup
unset -nocomplain hidden_cmds
foreach i [interp children] {
    interp delete $i
}
rename _ms_limit_args {}
Changes to tests/registry.test.
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
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
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
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
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
# Copyright © 1997 Sun Microsystems, Inc.  All rights reserved.
# Copyright © 1998-1999 Scriptics Corporation.

if {"::tcltest" ni [namespace children]} {
    package require tcltest 2.5
    namespace import -force ::tcltest::*
}



testConstraint reg 0

if {[testConstraint win]} {
    if {![catch {
	    ::tcltest::loadTestedCommands
	    set ::regver [package require registry 1.4a1]
	}]} {
	testConstraint reg 1
    }
}
testConstraint notWine [expr {![info exists ::env(CI_USING_WINE)]}]

# determine the current locale
testConstraint english [expr {
    [llength [info commands testlocale]]
    && [string match "English*" [testlocale all ""]]
}]

test registry-1.0 {check if we are testing the right dll} {win reg} {
    set ::regver
} {1.4a1}
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?"}}

test registry-2.1 {DeleteKey: bad key} {win reg} {
    list [catch {registry delete foo} msg] $msg
} {1 {bad root name "foo": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}}
test registry-2.2 {DeleteKey: bad key} {win reg} {
    list [catch {registry delete HKEY_CLASSES_ROOT} msg] $msg
} {1 {bad key: cannot delete root keys}}
test registry-2.3 {DeleteKey: bad key} {win reg} {
    list [catch {registry delete HKEY_CLASSES_ROOT\\} msg] $msg
} {1 {bad key: cannot delete root keys}}
test registry-2.4 {DeleteKey: subkey at root level} {win reg} {
    registry set HKEY_CURRENT_USER\\TclFoobar
    registry delete HKEY_CURRENT_USER\\TclFoobar
    registry keys HKEY_CURRENT_USER TclFoobar
} {}
test registry-2.5 {DeleteKey: subkey below root level} {win reg} {
    registry set HKEY_CURRENT_USER\\TclFoobar\\test
    registry delete HKEY_CURRENT_USER\\TclFoobar\\test
    set result [registry keys HKEY_CURRENT_USER TclFoobar\\test]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} {}
test registry-2.6 {DeleteKey: recursive delete} {win reg} {
    registry set HKEY_CURRENT_USER\\TclFoobar\\test1
    registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3
    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result [registry keys HKEY_CURRENT_USER TclFoobar]
    set result
} {}
test registry-2.7 {DeleteKey: trailing backslashes} {win reg english} {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz
    list [catch {registry delete HKEY_CURRENT_USER\\TclFoobar\\} msg] $msg
} {1 {unable to delete key: The configuration registry key is invalid.}}
test registry-2.8 {DeleteKey: failure} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar
    registry delete HKEY_CURRENT_USER\\TclFoobar
} {}
test registry-2.9 {DeleteKey: unicode} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar\\a
    registry set HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar\\b
    registry delete HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar
    set result [registry keys HKEY_CURRENT_USER\\TclFoobar]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} {}

test registry-3.1 {DeleteValue} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar\\baz test1 blort
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz test2 blat
    registry delete HKEY_CURRENT_USER\\TclFoobar\\baz test1
    set result [registry values HKEY_CURRENT_USER\\TclFoobar\\baz]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} test2
test registry-3.2 {DeleteValue: bad key} {win reg english} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    list [catch {registry delete HKEY_CURRENT_USER\\TclFoobar test} msg] $msg
} {1 {unable to open key: The system cannot find the file specified.}}
test registry-3.3 {DeleteValue: bad value} {win reg english} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar\\baz test2 blort
    set result [list [catch {registry delete HKEY_CURRENT_USER\\TclFoobar test1} msg] $msg]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} {1 {unable to delete value "test1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}}
test registry-3.4 {DeleteValue: Unicode} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz \u00c7test1 blort
    registry set HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz test2 blat
    registry delete HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz \u00c7test1
    set result [registry values HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} test2

test registry-4.1 {GetKeyNames: bad key} {win reg english} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    list [catch {registry keys HKEY_CURRENT_USER\\TclFoobar} msg] $msg
} {1 {unable to open key: The system cannot find the file specified.}}
test registry-4.2 {GetKeyNames} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar\\baz
    set result [registry keys HKEY_CURRENT_USER\\TclFoobar]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} {baz}
test registry-4.3 {GetKeyNames: remote key} {win reg nonPortable english} {
    set hostname [info hostname]


    registry set \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar\\baz
    set result [registry keys \\\\gaspode\\HKEY_CURRENT_USER\\TclFoobar]

    registry delete \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar
    set result
} {baz}
test registry-4.4 {GetKeyNames: empty key} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar
    set result [registry keys HKEY_CURRENT_USER\\TclFoobar]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} {}
test registry-4.5 {GetKeyNames: patterns} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar\\baz
    registry set HKEY_CURRENT_USER\\TclFoobar\\blat
    registry set HKEY_CURRENT_USER\\TclFoobar\\foo
    set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} {baz blat}
test registry-4.6 {GetKeyNames: names with spaces} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar\\baz\ bar
    registry set HKEY_CURRENT_USER\\TclFoobar\\blat
    registry set HKEY_CURRENT_USER\\TclFoobar\\foo
    set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} {{baz bar} blat}
test registry-4.7 {GetKeyNames: Unicode} {win reg english} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar\\baz\u00c7bar
    registry set HKEY_CURRENT_USER\\TclFoobar\\blat
    registry set HKEY_CURRENT_USER\\TclFoobar\\foo
    set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} "baz\u00c7bar blat"
test registry-4.8 {GetKeyNames: Unicode} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar\\baz\u30b7bar
    registry set HKEY_CURRENT_USER\\TclFoobar\\blat
    registry set HKEY_CURRENT_USER\\TclFoobar\\foo
    set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} "baz\u30b7bar blat"
test registry-4.9 {GetKeyNames: very long key [Bug 1682211]} {*}{
    -constraints {win reg}
    -setup {
	registry set HKEY_CURRENT_USER\\TclFoobar\\a
	registry set HKEY_CURRENT_USER\\TclFoobar\\b[string repeat x 254]
	registry set HKEY_CURRENT_USER\\TclFoobar\\c
    }
    -body {
	lsort [registry keys HKEY_CURRENT_USER\\TclFoobar]
    }
    -cleanup {
	registry delete HKEY_CURRENT_USER\\TclFoobar
    }} \
    -result [list a b[string repeat x 254] c]

test registry-5.1 {GetType} {win reg english} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    list [catch {registry type HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg
} {1 {unable to open key: The system cannot find the file specified.}}
test registry-5.2 {GetType} {win reg english} {


    registry set HKEY_CURRENT_USER\\TclFoobar
    list [catch {registry type HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg


} {1 {unable to get type of value "val1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}}
test registry-5.3 {GetType} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar none
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]




    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} none
test registry-5.4 {GetType} {win reg} {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} sz
test registry-5.5 {GetType} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar sz
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} sz
test registry-5.6 {GetType} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar expand_sz
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} expand_sz
test registry-5.7 {GetType} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 binary
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result





} binary
test registry-5.8 {GetType} {win reg} {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 dword
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} dword
test registry-5.9 {GetType} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 dword_big_endian
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} dword_big_endian
test registry-5.10 {GetType} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 link
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} link
test registry-5.11 {GetType} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar multi_sz
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} multi_sz
test registry-5.12 {GetType} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 resource_list
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]




    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} resource_list
test registry-5.13 {GetType: unknown types} {win reg} {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 24
    set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} 24
test registry-5.14 {GetType: Unicode} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar va\u00c7l1 1 24
    set result [registry type HKEY_CURRENT_USER\\TclFoobar va\u00c7l1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} 24

test registry-6.1 {GetValue} {win reg english} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    list [catch {registry get HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg
} {1 {unable to open key: The system cannot find the file specified.}}
test registry-6.2 {GetValue} {win reg english} {


    registry set HKEY_CURRENT_USER\\TclFoobar
    list [catch {registry get HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg


} {1 {unable to get value "val1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}}
test registry-6.3 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar none
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} foobar
test registry-6.4 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} foobar
test registry-6.5 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} foobar
test registry-6.6 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar expand_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} foobar
test registry-6.7 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 binary
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} 1
test registry-6.8 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 0x20 dword
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} 32
test registry-6.9 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 0x20 dword_big_endian
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} 32
test registry-6.10 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 link
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} 1
test registry-6.11 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} foobar
test registry-6.12 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo\ bar baz} multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} {{foo bar} baz}
test registry-6.13 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 {} multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} {}
test registry-6.14 {GetValue: truncation of multivalues with null elements} \
	{win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 {a {} b} multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} a
test registry-6.15 {GetValue} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 resource_list
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} 1
test registry-6.16 {GetValue: unknown types} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 24
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} 1
test registry-6.17 {GetValue: Unicode value names} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val\u00c71 foobar multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val\u00c71]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} foobar
test registry-6.18 {GetValue: values with Unicode strings} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u30b7r baz} multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} "foo ba\u30b7r baz"
test registry-6.19 {GetValue: values with Unicode strings} {win reg english} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u00c7r baz} multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} "foo ba\u00c7r baz"
test registry-6.20 {GetValue: values with Unicode strings with embedded nulls} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u0000r baz} multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} "foo ba r baz"
test registry-6.21 {GetValue: very long value names and values} {win reg} {


    registry set HKEY_CURRENT_USER\\TclFoobar [string repeat k 16383] [string repeat x 16383] multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar [string repeat k 16383]]

    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} [string repeat x 16383]

test registry-7.1 {GetValueNames: bad key} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry values HKEY_CURRENT_USER\\TclFoobar
} -returnCodes error -result {unable to open key: The system cannot find the file specified.}
test registry-7.2 {GetValueNames} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
    registry set HKEY_CURRENT_USER\\TclFoobar baz foobar
} -body {

    registry values HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result baz
test registry-7.3 {GetValueNames} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar baz foobar1
    registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2
    registry set HKEY_CURRENT_USER\\TclFoobar {} foobar3
} -body {
    lsort [registry values HKEY_CURRENT_USER\\TclFoobar]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {{} baz blat}
test registry-7.4 {GetValueNames: remote key} -constraints {win reg nonPortable english} -body {
    set hostname [info hostname]


    registry set \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar baz blat
    set result [registry values \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar]

    registry delete \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar
    set result
} -result baz
test registry-7.5 {GetValueNames: empty key} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
    registry set HKEY_CURRENT_USER\\TclFoobar
} -body {

    registry values HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {}
test registry-7.6 {GetValueNames: patterns} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar baz foobar1
    registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2
    registry set HKEY_CURRENT_USER\\TclFoobar foo foobar3
} -body {
    lsort [registry values HKEY_CURRENT_USER\\TclFoobar b*]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {baz blat}
test registry-7.7 {GetValueNames: names with spaces} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar baz\ bar foobar1
    registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2
    registry set HKEY_CURRENT_USER\\TclFoobar foo foobar3
} -body {
    lsort [registry values HKEY_CURRENT_USER\\TclFoobar b*]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {{baz bar} blat}

test registry-8.1 {OpenSubKey} -constraints {win reg nonPortable english} \
    -body {
	# This test will only succeed if the current user does not have
	# registry access on the specified machine.
	registry keys {\\mom\HKEY_LOCAL_MACHINE}
    } -returnCodes error -result "unable to open key: Access is denied."
test registry-8.2 {OpenSubKey} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
    registry set HKEY_CURRENT_USER\\TclFoobar
} -body {

    registry keys HKEY_CURRENT_USER TclFoobar
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {TclFoobar}
test registry-8.3 {OpenSubKey} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {







>
>


>
|
<
<
|
<














|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|





|


|
>

|
<




|
<

|

|
|




|

>



|
>

|
<

|

>



|
>

|
<
|

>
|
|
|

>

|
>

<
|
|

>



|
>

|
<

|

>
|
|
|

>

|
>

|
<
|

>
>

|
>

|
<
|

>

|
>

|
<
|

>



|
>

<
|
|

>



|
>

<
|
|

>



|
>

<
|
|

>



|
>

<
|
|
<
<
|
|
|
<
|
|
<
|
|
<
|

|

>
|
|
|
>
>

|
>
>
|
|
>
>

|
>
>
>
>

<
|
<

|
>

|
<
|
>
>

|
>

|
<
|
>
>

|
>

<
|
|
>
>

|
>

|
>
>
>
>
>
|
<
<
<

|
<
|
>
>

|
>

<
|
|
>
>

|
>

|
<
|
>
>

|
>

<
|
|
>
>

|
>
>
>
>

<
|
<

|
>

|
<
|
>
>

|
>

|
<

|

>
|
|
|
>
>

|
>
>
|
|
>
>

|
>

<
|
|
>
>

|
>

<
|
|
>
>

|
>

<
|
|
>
>

|
>

<
|
|
>
>

|
>

|
<
|
>
>

|
>

|
<
|
>
>

|
>

|
<
|
>
>

|
>

|
<
|
>
>

|
>

<
|
|
>
>

|
>

<
|
|
>
>

|
>

|
<

|
>
>

|
>

|
<
|
>
>

|
>

|
<
|
>
>

|
>

|
<
|
>
>

|
>

<
|
|
>
>

|
>

<
|
|
>
>

|
>

<
|
|
>
>

|
>

<
|
|
>
>

|
>

<
|








<

>






>



<




|

>
>

|
>

<



<

>






>



<






>



<





|
<
|
|
|
|


<

>







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
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
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
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
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
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
# Copyright © 1997 Sun Microsystems, Inc.  All rights reserved.
# Copyright © 1998-1999 Scriptics Corporation.

if {"::tcltest" ni [namespace children]} {
    package require tcltest 2.5
    namespace import -force ::tcltest::*
}
::tcltest::loadTestedCommands
package require -exact tcl::test [info patchlevel]

testConstraint reg 0
catch {
    if {[testConstraint win]} {


	set ::regver [package require registry 1.4a1]

	testConstraint reg 1
    }
}
testConstraint notWine [expr {![info exists ::env(CI_USING_WINE)]}]

# determine the current locale
testConstraint english [expr {
    [llength [info commands testlocale]]
    && [string match "English*" [testlocale all ""]]
}]

test registry-1.0 {check if we are testing the right dll} {win reg} {
    set ::regver
} {1.4a1}
test registry-1.1 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry
} -result {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}
test registry-1.1a {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -32bit
} -result {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}
test registry-1.1b {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -64bit
} -result {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}
test registry-1.2 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry foo
} -result {bad option "foo": must be broadcast, delete, get, keys, set, type, or values}
test registry-1.2a {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -33bit foo
} -result {bad mode "-33bit": must be -32bit or -64bit}

test registry-1.3 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry d
} -result {wrong # args: should be "registry delete keyName ?valueName?"}
test registry-1.3a {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -32bit d
} -result {wrong # args: should be "registry -32bit delete keyName ?valueName?"}
test registry-1.3b {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -64bit d
} -result {wrong # args: should be "registry -64bit delete keyName ?valueName?"}
test registry-1.4 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry delete
} -result {wrong # args: should be "registry delete keyName ?valueName?"}
test registry-1.5 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry delete foo bar baz
} -result {wrong # args: should be "registry delete keyName ?valueName?"}

test registry-1.6 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry g
} -result {wrong # args: should be "registry get keyName valueName"}
test registry-1.6a {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -32bit g
} -result {wrong # args: should be "registry -32bit get keyName valueName"}
test registry-1.6b {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -64bit g
} -result {wrong # args: should be "registry -64bit get keyName valueName"}
test registry-1.7 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry get
} -result {wrong # args: should be "registry get keyName valueName"}
test registry-1.8 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry get foo
} -result {wrong # args: should be "registry get keyName valueName"}
test registry-1.9 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry get foo bar baz
} -result {wrong # args: should be "registry get keyName valueName"}

test registry-1.10 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry k
} -result {wrong # args: should be "registry keys keyName ?pattern?"}
test registry-1.10a {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -32bit k
} -result {wrong # args: should be "registry -32bit keys keyName ?pattern?"}
test registry-1.10b {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -64bit k
} -result {wrong # args: should be "registry -64bit keys keyName ?pattern?"}
test registry-1.11 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry keys
} -result {wrong # args: should be "registry keys keyName ?pattern?"}
test registry-1.12 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry keys foo bar baz
} -result {wrong # args: should be "registry keys keyName ?pattern?"}

test registry-1.13 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry s
} -result {wrong # args: should be "registry set keyName ?valueName data ?type??"}
test registry-1.13a {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -32bit s
} -result {wrong # args: should be "registry -32bit set keyName ?valueName data ?type??"}
test registry-1.13b {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -64bit s
} -result {wrong # args: should be "registry -64bit set keyName ?valueName data ?type??"}
test registry-1.14 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry set
} -result {wrong # args: should be "registry set keyName ?valueName data ?type??"}
test registry-1.15 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry set foo bar
} -result {wrong # args: should be "registry set keyName ?valueName data ?type??"}
test registry-1.16 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry set foo bar baz blat gorp
} -result {wrong # args: should be "registry set keyName ?valueName data ?type??"}

test registry-1.17 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry t
} -result {wrong # args: should be "registry type keyName valueName"}
test registry-1.17a {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -32bit t
} -result {wrong # args: should be "registry -32bit type keyName valueName"}
test registry-1.17b {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -64bit t
} -result {wrong # args: should be "registry -64bit type keyName valueName"}
test registry-1.18 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry type
} -result {wrong # args: should be "registry type keyName valueName"}
test registry-1.19 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry type foo
} -result {wrong # args: should be "registry type keyName valueName"}
test registry-1.20 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry type foo bar baz
} -result {wrong # args: should be "registry type keyName valueName"}

test registry-1.21 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry v
} -result {wrong # args: should be "registry values keyName ?pattern?"}
test registry-1.21a {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -32bit v
} -result {wrong # args: should be "registry -32bit values keyName ?pattern?"}
test registry-1.21b {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry -64bit v
} -result {wrong # args: should be "registry -64bit values keyName ?pattern?"}
test registry-1.22 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry values
} -result {wrong # args: should be "registry values keyName ?pattern?"}
test registry-1.23 {argument parsing for registry command} -constraints {win reg} -returnCodes error -body {
    registry values foo bar baz
} -result {wrong # args: should be "registry values keyName ?pattern?"}

test registry-2.1 {DeleteKey: bad key} -constraints {win reg} -returnCodes error -body {
    registry delete foo
} -result {bad root name "foo": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}
test registry-2.2 {DeleteKey: bad key} -constraints {win reg} -returnCodes error -body {
    registry delete HKEY_CLASSES_ROOT
} -result {bad key: cannot delete root keys}
test registry-2.3 {DeleteKey: bad key} -constraints {win reg} -returnCodes error -body {
    registry delete HKEY_CLASSES_ROOT\\
} -result {bad key: cannot delete root keys}
test registry-2.4 {DeleteKey: subkey at root level} {win reg} {
    registry set HKEY_CURRENT_USER\\TclFoobar
    registry delete HKEY_CURRENT_USER\\TclFoobar
    registry keys HKEY_CURRENT_USER TclFoobar
} {}
test registry-2.5 {DeleteKey: subkey below root level} -constraints {win reg} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\test
    registry delete HKEY_CURRENT_USER\\TclFoobar\\test
    registry keys HKEY_CURRENT_USER TclFoobar\\test
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {}

test registry-2.6 {DeleteKey: recursive delete} {win reg} {
    registry set HKEY_CURRENT_USER\\TclFoobar\\test1
    registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3
    registry delete HKEY_CURRENT_USER\\TclFoobar
    registry keys HKEY_CURRENT_USER TclFoobar

} {}
test registry-2.7 {DeleteKey: trailing backslashes} -constraints {win reg english} -returnCodes error -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz
    registry delete HKEY_CURRENT_USER\\TclFoobar\\
} -result {unable to delete key: The configuration registry key is invalid.}
test registry-2.8 {DeleteKey: failure} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar
    registry delete HKEY_CURRENT_USER\\TclFoobar
} {}
test registry-2.9 {DeleteKey: unicode} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar\\a
    registry set HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar\\b
    registry delete HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar
    registry keys HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {}


test registry-3.1 {DeleteValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz test1 blort
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz test2 blat
    registry delete HKEY_CURRENT_USER\\TclFoobar\\baz test1
    registry values HKEY_CURRENT_USER\\TclFoobar\\baz
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result test2

test registry-3.2 {DeleteValue: bad key} -constraints {win reg english} -returnCodes error -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry delete HKEY_CURRENT_USER\\TclFoobar test
} -result {unable to open key: The system cannot find the file specified.}
test registry-3.3 {DeleteValue: bad value} -constraints {win reg english} -returnCodes error -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz test2 blort
    registry delete HKEY_CURRENT_USER\\TclFoobar test1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result {unable to delete value "test1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}
test registry-3.4 {DeleteValue: Unicode} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz \u00c7test1 blort
    registry set HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz test2 blat
    registry delete HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz \u00c7test1
    registry values HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result test2


test registry-4.1 {GetKeyNames: bad key} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -returnCodes error -body {
    registry keys HKEY_CURRENT_USER\\TclFoobar
} -result {unable to open key: The system cannot find the file specified.}
test registry-4.2 {GetKeyNames} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz
    registry keys HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {baz}

test registry-4.3 {GetKeyNames: remote key} -constraints {win reg nonPortable english} -setup {
    set hostname [info hostname]
    registry delete \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar\\baz
    registry keys \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
    registry delete \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar
} -result {baz}

test registry-4.4 {GetKeyNames: empty key} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar
    registry keys HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {}

test registry-4.5 {GetKeyNames: patterns} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz
    registry set HKEY_CURRENT_USER\\TclFoobar\\blat
    registry set HKEY_CURRENT_USER\\TclFoobar\\foo
    lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result {baz blat}
test registry-4.6 {GetKeyNames: names with spaces} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz\ bar
    registry set HKEY_CURRENT_USER\\TclFoobar\\blat
    registry set HKEY_CURRENT_USER\\TclFoobar\\foo
    lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result {{baz bar} blat}
test registry-4.7 {GetKeyNames: Unicode} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz\u00c7bar
    registry set HKEY_CURRENT_USER\\TclFoobar\\blat
    registry set HKEY_CURRENT_USER\\TclFoobar\\foo
    lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result "baz\u00c7bar blat"
test registry-4.8 {GetKeyNames: Unicode} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz\u30b7bar
    registry set HKEY_CURRENT_USER\\TclFoobar\\blat
    registry set HKEY_CURRENT_USER\\TclFoobar\\foo
    lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result "baz\u30b7bar blat"
test registry-4.9 {GetKeyNames: very long key [Bug 1682211]} -constraints {win reg} -setup {


    registry set HKEY_CURRENT_USER\\TclFoobar\\a
    registry set HKEY_CURRENT_USER\\TclFoobar\\b[string repeat x 254]
    registry set HKEY_CURRENT_USER\\TclFoobar\\c

} -body {
    lsort [registry keys HKEY_CURRENT_USER\\TclFoobar]

} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result [list a b[string repeat x 254] c]

test registry-5.1 {GetType} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -returnCodes error -body {
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -result {unable to open key: The system cannot find the file specified.}
test registry-5.2 {GetType} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -returnCodes error -body {
    registry set HKEY_CURRENT_USER\\TclFoobar
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {unable to get type of value "val1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}
test registry-5.3 {GetType} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar none
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result none
test registry-5.4 {GetType} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -body {

    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result sz

test registry-5.5 {GetType} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar sz
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result sz

test registry-5.6 {GetType} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar expand_sz
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result expand_sz
test registry-5.7 {GetType} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 binary
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result binary
test registry-5.8 {GetType} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 dword
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {



    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result dword

test registry-5.9 {GetType} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 dword_big_endian
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result dword_big_endian
test registry-5.10 {GetType} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 link
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result link

test registry-5.11 {GetType} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar multi_sz
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result multi_sz
test registry-5.12 {GetType} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 resource_list
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result resource_list
test registry-5.13 {GetType: unknown types} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -body {

    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 24
    registry type HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result 24

test registry-5.14 {GetType: Unicode} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar va\u00c7l1 1 24
    registry type HKEY_CURRENT_USER\\TclFoobar va\u00c7l1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result 24


test registry-6.1 {GetValue} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -returnCodes error -body {
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -result {unable to open key: The system cannot find the file specified.}
test registry-6.2 {GetValue} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -returnCodes error -body {
    registry set HKEY_CURRENT_USER\\TclFoobar
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {unable to get value "val1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}
test registry-6.3 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar none
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result foobar
test registry-6.4 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result foobar
test registry-6.5 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar sz
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result foobar
test registry-6.6 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar expand_sz
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result foobar
test registry-6.7 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 binary
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result 1

test registry-6.8 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 0x20 dword
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result 32

test registry-6.9 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 0x20 dword_big_endian
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result 32

test registry-6.10 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 link
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result 1

test registry-6.11 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar multi_sz
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result foobar
test registry-6.12 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo\ bar baz} multi_sz
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result {{foo bar} baz}
test registry-6.13 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 {} multi_sz
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {}

test registry-6.14 {GetValue: truncation of multivalues with null elements} \
	-constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 {a {} b} multi_sz
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result a

test registry-6.15 {GetValue} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 resource_list
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result 1

test registry-6.16 {GetValue: unknown types} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 1 24
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result 1

test registry-6.17 {GetValue: Unicode value names} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val\u00c71 foobar multi_sz
    registry get HKEY_CURRENT_USER\\TclFoobar val\u00c71
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result foobar
test registry-6.18 {GetValue: values with Unicode strings} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u30b7r baz} multi_sz
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result "foo ba\u30b7r baz"
test registry-6.19 {GetValue: values with Unicode strings} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u00c7r baz} multi_sz
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result "foo ba\u00c7r baz"
test registry-6.20 {GetValue: values with Unicode strings with embedded nulls} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u0000r baz} multi_sz
    registry get HKEY_CURRENT_USER\\TclFoobar val1
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result "foo ba r baz"
test registry-6.21 {GetValue: very long value names and values} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar [string repeat k 16383] [string repeat x 16383] multi_sz
    registry get HKEY_CURRENT_USER\\TclFoobar [string repeat k 16383]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -result [string repeat x 16383]

test registry-7.1 {GetValueNames: bad key} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry values HKEY_CURRENT_USER\\TclFoobar
} -returnCodes error -result {unable to open key: The system cannot find the file specified.}
test registry-7.2 {GetValueNames} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar baz foobar
    registry values HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result baz
test registry-7.3 {GetValueNames} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar baz foobar1
    registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2
    registry set HKEY_CURRENT_USER\\TclFoobar {} foobar3

    lsort [registry values HKEY_CURRENT_USER\\TclFoobar]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {{} baz blat}
test registry-7.4 {GetValueNames: remote key} -constraints {win reg nonPortable english} -setup {
    set hostname [info hostname]
    registry delete \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar baz blat
    registry values \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
    registry delete \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar

} -result baz
test registry-7.5 {GetValueNames: empty key} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar
    registry values HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {}
test registry-7.6 {GetValueNames: patterns} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar baz foobar1
    registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2
    registry set HKEY_CURRENT_USER\\TclFoobar foo foobar3

    lsort [registry values HKEY_CURRENT_USER\\TclFoobar b*]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {baz blat}
test registry-7.7 {GetValueNames: names with spaces} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar baz\ bar foobar1
    registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2
    registry set HKEY_CURRENT_USER\\TclFoobar foo foobar3

    lsort [registry values HKEY_CURRENT_USER\\TclFoobar b*]
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {{baz bar} blat}

test registry-8.1 {OpenSubKey} -constraints {win reg nonPortable english} -body {

    # This test will only succeed if the current user does not have
    # registry access on the specified machine.
    registry keys {\\mom\HKEY_LOCAL_MACHINE}
} -returnCodes error -result "unable to open key: Access is denied."
test registry-8.2 {OpenSubKey} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar
    registry keys HKEY_CURRENT_USER TclFoobar
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {TclFoobar}
test registry-8.3 {OpenSubKey} -constraints {win reg english} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
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

test registry-10.1 {RecursiveDeleteKey} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\test1
    registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3
    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result [registry keys HKEY_CURRENT_USER TclFoobar]
    set result
} -result {}
test registry-10.2 {RecursiveDeleteKey} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar

    registry set HKEY_CURRENT_USER\\TclFoobar\\test1
    registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3
} -body {
    registry delete HKEY_CURRENT_USER\\TclFoobar\\test2\\test4
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {}

test registry-11.1 {SetValue: recursive creation} \
    -constraints {win reg} -setup {
	registry delete HKEY_CURRENT_USER\\TclFoobar
    } -body {
	registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat foobar
	set result [registry get HKEY_CURRENT_USER\\TclFoobar\\baz blat]


    } -result {foobar}
test registry-11.2 {SetValue: modification} -constraints {win reg} \
    -setup {
	registry delete HKEY_CURRENT_USER\\TclFoobar
    } -body {
	registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat foobar
	registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat frob
	set result [registry get HKEY_CURRENT_USER\\TclFoobar\\baz blat]


    } -result {frob}
test registry-11.3 {SetValue: failure} \
    -constraints {win reg nonPortable english} \
    -body {
	# 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?\""







|
<



>


<





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







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

test registry-10.1 {RecursiveDeleteKey} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\test1
    registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3
    registry delete HKEY_CURRENT_USER\\TclFoobar
    registry keys HKEY_CURRENT_USER TclFoobar

} -result {}
test registry-10.2 {RecursiveDeleteKey} -constraints {win reg} -setup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\test1
    registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3

    registry delete HKEY_CURRENT_USER\\TclFoobar\\test2\\test4
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {}

test registry-11.1 {SetValue: recursive creation} -constraints {win reg} -setup {

    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat foobar
    registry get HKEY_CURRENT_USER\\TclFoobar\\baz blat
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {foobar}
test registry-11.2 {SetValue: modification} -constraints {win reg} -setup {

    registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat foobar
    registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat frob
    registry get HKEY_CURRENT_USER\\TclFoobar\\baz blat
} -cleanup {
    registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {frob}
test registry-11.3 {SetValue: failure} -constraints {win reg nonPortable english} -body {


    # 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?\""
Changes to tests/switch.test.
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
	-*	{subst glob}
	-glob	{subst exact}
	default {subst none}
    }
} exact
test switch-3.6 {-exact vs. -glob vs. -regexp} -body {
    switch -foo a b c
} -returnCodes error -result {bad option "-foo": must be -exact, -glob, -indexvar, -matchvar, -nocase, -regexp, or --}
test switch-3.7 {-exact vs. -glob vs. -regexp with -nocase} {
    switch -exact -nocase aaaab {
	^a*b$	{subst regexp}
	*b	{subst glob}
	aaaab	{subst exact}
	default	{subst none}
    }







|







95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
	-*	{subst glob}
	-glob	{subst exact}
	default {subst none}
    }
} exact
test switch-3.6 {-exact vs. -glob vs. -regexp} -body {
    switch -foo a b c
} -returnCodes error -result {bad option "-foo": must be -exact, -glob, -indexvar, -integer, -matchvar, -nocase, -regexp, or --}
test switch-3.7 {-exact vs. -glob vs. -regexp with -nocase} {
    switch -exact -nocase aaaab {
	^a*b$	{subst regexp}
	*b	{subst glob}
	aaaab	{subst exact}
	default	{subst none}
    }
153
154
155
156
157
158
159









160
161
162
163
164
165
166
} -returnCodes error -result {bad option "-glob": -exact option already found}
test switch-3.17 {-exact vs. -glob vs. -regexp} -body {
    switch -glob -regexp Foo Foo {set result OK}
} -returnCodes error -result {bad option "-regexp": -glob option already found}
test switch-3.18 {-exact vs. -glob vs. -regexp} -body {
    switch -regexp -glob Foo Foo {set result OK}
} -returnCodes error -result {bad option "-glob": -regexp option already found}










test switch-4.1 {error in executed command} {
    list [catch {switch a a {error "Just a test"} default {subst 1}} msg] \
	    $msg $::errorInfo
} {1 {Just a test} {Just a test
    while executing
"error "Just a test""







>
>
>
>
>
>
>
>
>







153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
} -returnCodes error -result {bad option "-glob": -exact option already found}
test switch-3.17 {-exact vs. -glob vs. -regexp} -body {
    switch -glob -regexp Foo Foo {set result OK}
} -returnCodes error -result {bad option "-regexp": -glob option already found}
test switch-3.18 {-exact vs. -glob vs. -regexp} -body {
    switch -regexp -glob Foo Foo {set result OK}
} -returnCodes error -result {bad option "-glob": -regexp option already found}
test switch-3.19 {-exact vs. -glob vs. -regexp} -body {
    switch -glob -integer Foo Foo {set result OK}
} -returnCodes error -result {bad option "-integer": -glob option already found}
test switch-3.20 {-exact vs. -glob vs. -regexp} -body {
    switch -integer -glob Foo Foo {set result OK}
} -returnCodes error -result {bad option "-glob": -integer option already found}
test switch-3.21 {-exact vs. -glob vs. -regexp} -body {
    switch -integer -nocase Foo Foo {set result OK}
} -returnCodes error -result {-nocase option cannot be used with -integer option}

test switch-4.1 {error in executed command} {
    list [catch {switch a a {error "Just a test"} default {subst 1}} msg] \
	    $msg $::errorInfo
} {1 {Just a test} {Just a test
    while executing
"error "Just a test""
764
765
766
767
768
769
770
771
























































































772
773
774
775
776
777
778
779
	list [coroutine c coro] [c]
    }
    -result {ok1 ok2}
    -cleanup {
	rename coro {}
    }
}

























































































# cleanup
catch {rename foo {}}
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







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








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
	list [coroutine c coro] [c]
    }
    -result {ok1 ok2}
    -cleanup {
	rename coro {}
    }
}

test switch-16.1 {switch -integer: interp, polyarg} {
    switch -integer 0x1 01 {string cat ok}
} ok
test switch-16.2 {switch -integer: interp, polyarg} {
    switch -integer 0x1 0 {error early} 01 {string cat ok}
} ok
test switch-16.3 {switch -integer: interp, polyarg} {
    switch -integer 0x1 0 {error early} 01 {string cat ok} default {error late}
} ok
test switch-16.4 {switch -integer: interp, polyarg} {
    switch -integer 0x1 0 {error early} default {string cat ok}
} ok
test switch-16.5 {switch -integer: interp, polyarg} {
    switch -integer 0x1 0 {error body}
} {}
test switch-16.6 {switch -integer: interp, polyarg} -returnCodes error -body {
    switch -integer 0x1 gorp {error body}
} -result {expected integer but got "gorp"}
test switch-16.7 {switch -integer: interp, polyarg} -returnCodes error -body {
    switch -integer gorp 0 {error body}
} -result {expected integer but got "gorp"}

test switch-17.1 {switch -integer: interp, splitlist} {
    switch -integer 0x1 {01 {string cat ok}}
} ok
test switch-17.2 {switch -integer: interp, splitlist} {
    switch -integer 0x1 {0 {error early} 01 {string cat ok}}
} ok
test switch-17.3 {switch -integer: interp, splitlist} {
    switch -integer 0x1 {0 {error early} 01 {string cat ok} default {error late}}
} ok
test switch-17.4 {switch -integer: interp, splitlist} {
    switch -integer 0x1 {0 {error early} default {string cat ok}}
} ok
test switch-17.5 {switch -integer: interp, splitlist} {
    switch -integer 0x1 {0 {error body}}
} {}
test switch-17.6 {switch -integer: interp, splitlist} -returnCodes error -body {
    switch -integer 0x1 {gorp {error body}}
} -result {expected integer but got "gorp"}
test switch-17.7 {switch -integer: interp, splitlist} -returnCodes error -body {
    switch -integer gorp {0 {error body}}
} -result {expected integer but got "gorp"}

test switch-18.1 {switch -integer: compiled, polyarg} {
    switch -integer -- 0x1 01 {string cat ok}
} ok
test switch-18.2 {switch -integer: compiled, polyarg} {
    switch -integer -- 0x1 0 {error early} 01 {string cat ok}
} ok
test switch-18.3 {switch -integer: compiled, polyarg} {
    switch -integer -- 0x1 0 {error early} 01 {string cat ok} default {error late}
} ok
test switch-18.4 {switch -integer: compiled, polyarg} {
    switch -integer -- 0x1 0 {error early} default {string cat ok}
} ok
test switch-18.5 {switch -integer: compiled, polyarg} {
    switch -integer -- 0x1 0 {error body}
} {}
test switch-18.6 {switch -integer: compiled, polyarg} -returnCodes error -body {
    switch -integer -- 0x1 gorp {error body}
} -result {expected integer but got "gorp"}
test switch-18.7 {switch -integer: compiled, polyarg} -returnCodes error -body {
    switch -integer -- gorp 0 {error body}
} -result {expected integer but got "gorp"}

test switch-19.1 {switch -integer: compiled, splitlist} {
    switch -integer -- 0x1 {01 {string cat ok}}
} ok
test switch-19.2 {switch -integer: compiled, splitlist} {
    switch -integer -- 0x1 {0 {error early} 01 {string cat ok}}
} ok
test switch-19.3 {switch -integer: compiled, splitlist} {
    switch -integer -- 0x1 {0 {error early} 01 {string cat ok} default {error late}}
} ok
test switch-19.4 {switch -integer: compiled, splitlist} {
    switch -integer -- 0x1 {0 {error early} default {string cat ok}}
} ok
test switch-19.5 {switch -integer: compiled, splitlist} {
    switch -integer -- 0x1 {0 {error body}}
} {}
test switch-19.6 {switch -integer: compiled, splitlist} -returnCodes error -body {
    switch -integer -- 0x1 {gorp {error body}}
} -result {expected integer but got "gorp"}
test switch-19.7 {switch -integer: compiled, splitlist} -returnCodes error -body {
    switch -integer -- gorp {0 {error body}}
} -result {expected integer but got "gorp"}

# cleanup
catch {rename foo {}}
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to unix/configure.
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
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
1844
1845
1846
1847
1848
eval ac_res=\$$3
	       { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_func

# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR
# ------------------------------------------------------------------
# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR.
ac_fn_check_decl ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  as_decl_name=`echo $2|sed 's/ *(.*//'`
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
printf %s "checking whether $as_decl_name is declared... " >&6; }
if eval test \${$3+y}
then :
  printf %s "(cached) " >&6
else case e in #(
  e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
  eval ac_save_FLAGS=\$$6
  as_fn_append $6 " $5"
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
int
main (void)
{
#ifndef $as_decl_name
#ifdef __cplusplus
  (void) $as_decl_use;
#else
  (void) $as_decl_name;
#endif
#endif

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
  eval "$3=yes"
else case e in #(
  e) eval "$3=no" ;;
esac
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
  eval $6=\$ac_save_FLAGS
 ;;
esac
fi
eval ac_res=\$$3
	       { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_check_decl

# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
# -------------------------------------------
# Tests whether TYPE exists after having included INCLUDES, setting cache
# variable VAR accordingly.
ac_fn_c_check_type ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1781
1782
1783
1784
1785
1786
1787






















































1788
1789
1790
1791
1792
1793
1794
eval ac_res=\$$3
	       { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_func























































# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
# -------------------------------------------
# Tests whether TYPE exists after having included INCLUDES, setting cache
# variable VAR accordingly.
ac_fn_c_check_type ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
1937
1938
1939
1940
1941
1942
1943






















































1944
1945
1946
1947
1948
1949
1950
esac
fi
  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_run























































# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
# ----------------------------------------------------
# Tries to find if the field MEMBER exists in type AGGR, after including
# INCLUDES, setting cache variable VAR accordingly.
ac_fn_c_check_member ()
{







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







1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
esac
fi
  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_run

# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR
# ------------------------------------------------------------------
# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR.
ac_fn_check_decl ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  as_decl_name=`echo $2|sed 's/ *(.*//'`
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
printf %s "checking whether $as_decl_name is declared... " >&6; }
if eval test \${$3+y}
then :
  printf %s "(cached) " >&6
else case e in #(
  e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
  eval ac_save_FLAGS=\$$6
  as_fn_append $6 " $5"
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
int
main (void)
{
#ifndef $as_decl_name
#ifdef __cplusplus
  (void) $as_decl_use;
#else
  (void) $as_decl_name;
#endif
#endif

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
  eval "$3=yes"
else case e in #(
  e) eval "$3=no" ;;
esac
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
  eval $6=\$ac_save_FLAGS
 ;;
esac
fi
eval ac_res=\$$3
	       { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_check_decl

# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
# ----------------------------------------------------
# Tries to find if the field MEMBER exists in type AGGR, after including
# INCLUDES, setting cache variable VAR accordingly.
ac_fn_c_check_member ()
{
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
    fi


#--------------------------------------------------------------------
# Look for libraries that we will need when compiling the Tcl shell
#--------------------------------------------------------------------

{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5
printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; }
if test ${ac_cv_c_undeclared_builtin_options+y}
then :
  printf %s "(cached) " >&6
else case e in #(
  e) ac_save_CFLAGS=$CFLAGS
   ac_cv_c_undeclared_builtin_options='cannot detect'
   for ac_arg in '' -fno-builtin; do
     CFLAGS="$ac_save_CFLAGS $ac_arg"
     # This test program should *not* compile successfully.
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main (void)
{
(void) strchr;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :

else case e in #(
  e) # This test program should compile successfully.
        # No library function is consistently available on
        # freestanding implementations, so test against a dummy
        # declaration.  Include always-available headers on the
        # off chance that they somehow elicit warnings.
        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <float.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
extern void ac_decl (int, char *);

int
main (void)
{
(void) ac_decl (0, (char *) 0);
  (void) ac_decl;

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
  if test x"$ac_arg" = x
then :
  ac_cv_c_undeclared_builtin_options='none needed'
else case e in #(
  e) ac_cv_c_undeclared_builtin_options=$ac_arg ;;
esac
fi
          break
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
esac
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
    done
    CFLAGS=$ac_save_CFLAGS
   ;;
esac
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5
printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; }
  case $ac_cv_c_undeclared_builtin_options in #(
  'cannot detect') :
    { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
as_fn_error $? "cannot make $CC report undeclared builtins
See 'config.log' for more details" "$LINENO" 5; } ;; #(
  'none needed') :
    ac_c_undeclared_builtin_options='' ;; #(
  *) :
    ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;;
esac


    #--------------------------------------------------------------------
    # On a few very rare systems, all of the libm.a stuff is
    # already in libc.a.  Set compiler flags accordingly.
    #--------------------------------------------------------------------

    ac_fn_c_check_func "$LINENO" "sin" "ac_cv_func_sin"







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







4362
4363
4364
4365
4366
4367
4368



















































































4369
4370
4371
4372
4373
4374
4375
    fi


#--------------------------------------------------------------------
# Look for libraries that we will need when compiling the Tcl shell
#--------------------------------------------------------------------





















































































    #--------------------------------------------------------------------
    # On a few very rare systems, all of the libm.a stuff is
    # already in libc.a.  Set compiler flags accordingly.
    #--------------------------------------------------------------------

    ac_fn_c_check_func "$LINENO" "sin" "ac_cv_func_sin"
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008

5009
5010
5011
5012
5013
5014
5015
fi
ac_fn_c_check_func "$LINENO" "pthread_atfork" "ac_cv_func_pthread_atfork"
if test "x$ac_cv_func_pthread_atfork" = xyes
then :
  printf "%s\n" "#define HAVE_PTHREAD_ATFORK 1" >>confdefs.h

fi

    LIBS=$ac_saved_libs

    # TIP #509
    ac_fn_check_decl "$LINENO" "PTHREAD_MUTEX_RECURSIVE" "ac_cv_have_decl_PTHREAD_MUTEX_RECURSIVE" "#include <pthread.h>
" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_PTHREAD_MUTEX_RECURSIVE" = xyes
then :
  ac_have_decl=1
else case e in #(
  e) ac_have_decl=0 ;;
esac
fi
printf "%s\n" "#define HAVE_DECL_PTHREAD_MUTEX_RECURSIVE $ac_have_decl" >>confdefs.h
if test $ac_have_decl = 1
then :
  tcl_ok=yes
else case e in #(
  e) tcl_ok=no ;;
esac
fi




# Add the threads support libraries
LIBS="$LIBS$THREADS_LIBS"


    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5







|
<
|
<
<
<
<

<
<
<
<
<
|
|
<
<
<
<
<


>







4897
4898
4899
4900
4901
4902
4903
4904

4905




4906





4907
4908





4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
fi
ac_fn_c_check_func "$LINENO" "pthread_atfork" "ac_cv_func_pthread_atfork"
if test "x$ac_cv_func_pthread_atfork" = xyes
then :
  printf "%s\n" "#define HAVE_PTHREAD_ATFORK 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "pthread_spin_lock" "ac_cv_func_pthread_spin_lock"

if test "x$ac_cv_func_pthread_spin_lock" = xyes




then :





  printf "%s\n" "#define HAVE_PTHREAD_SPIN_LOCK 1" >>confdefs.h






fi

    LIBS=$ac_saved_libs


# Add the threads support libraries
LIBS="$LIBS$THREADS_LIBS"


    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_input_charset" >&5
printf "%s\n" "$tcl_cv_cc_input_charset" >&6; }
    if test $tcl_cv_cc_input_charset = yes; then
	CFLAGS="$CFLAGS -finput-charset=UTF-8"
    fi

    ac_fn_c_check_header_compile "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default"
if test "x$ac_cv_header_stdbool_h" = xyes
then :

printf "%s\n" "#define HAVE_STDBOOL_H 1" >>confdefs.h

fi


    # Check for vfork, posix_spawnp() and friends unconditionally
    ac_fn_c_check_func "$LINENO" "vfork" "ac_cv_func_vfork"
if test "x$ac_cv_func_vfork" = xyes







|
|


|







7439
7440
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451
7452
7453
7454
7455
7456
7457
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_input_charset" >&5
printf "%s\n" "$tcl_cv_cc_input_charset" >&6; }
    if test $tcl_cv_cc_input_charset = yes; then
	CFLAGS="$CFLAGS -finput-charset=UTF-8"
    fi

    ac_fn_c_check_header_compile "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default"
if test "x$ac_cv_header_stdatomic_h" = xyes
then :

printf "%s\n" "#define HAVE_STDATOMIC_H 1" >>confdefs.h

fi


    # Check for vfork, posix_spawnp() and friends unconditionally
    ac_fn_c_check_func "$LINENO" "vfork" "ac_cv_func_vfork"
if test "x$ac_cv_func_vfork" = xyes
9050
9051
9052
9053
9054
9055
9056



















































































9057
9058
9059
9060
9061
9062
9063
printf "%s\n" "#define HAVE_MTSAFE_GETHOSTBYNAME 1" >>confdefs.h


printf "%s\n" "#define HAVE_MTSAFE_GETHOSTBYADDR 1" >>confdefs.h


else




















































































    # Avoids picking hidden internal symbol from libc
    ac_fn_check_decl "$LINENO" "gethostbyname_r" "ac_cv_have_decl_gethostbyname_r" "#include <netdb.h>
" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_gethostbyname_r" = xyes
then :
  ac_have_decl=1







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







8953
8954
8955
8956
8957
8958
8959
8960
8961
8962
8963
8964
8965
8966
8967
8968
8969
8970
8971
8972
8973
8974
8975
8976
8977
8978
8979
8980
8981
8982
8983
8984
8985
8986
8987
8988
8989
8990
8991
8992
8993
8994
8995
8996
8997
8998
8999
9000
9001
9002
9003
9004
9005
9006
9007
9008
9009
9010
9011
9012
9013
9014
9015
9016
9017
9018
9019
9020
9021
9022
9023
9024
9025
9026
9027
9028
9029
9030
9031
9032
9033
9034
9035
9036
9037
9038
9039
9040
9041
9042
9043
9044
9045
9046
9047
9048
9049
printf "%s\n" "#define HAVE_MTSAFE_GETHOSTBYNAME 1" >>confdefs.h


printf "%s\n" "#define HAVE_MTSAFE_GETHOSTBYADDR 1" >>confdefs.h


else
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5
printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; }
if test ${ac_cv_c_undeclared_builtin_options+y}
then :
  printf %s "(cached) " >&6
else case e in #(
  e) ac_save_CFLAGS=$CFLAGS
   ac_cv_c_undeclared_builtin_options='cannot detect'
   for ac_arg in '' -fno-builtin; do
     CFLAGS="$ac_save_CFLAGS $ac_arg"
     # This test program should *not* compile successfully.
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main (void)
{
(void) strchr;
  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :

else case e in #(
  e) # This test program should compile successfully.
        # No library function is consistently available on
        # freestanding implementations, so test against a dummy
        # declaration.  Include always-available headers on the
        # off chance that they somehow elicit warnings.
        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <float.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
extern void ac_decl (int, char *);

int
main (void)
{
(void) ac_decl (0, (char *) 0);
  (void) ac_decl;

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
  if test x"$ac_arg" = x
then :
  ac_cv_c_undeclared_builtin_options='none needed'
else case e in #(
  e) ac_cv_c_undeclared_builtin_options=$ac_arg ;;
esac
fi
          break
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
esac
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
    done
    CFLAGS=$ac_save_CFLAGS
   ;;
esac
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5
printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; }
  case $ac_cv_c_undeclared_builtin_options in #(
  'cannot detect') :
    { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
as_fn_error $? "cannot make $CC report undeclared builtins
See 'config.log' for more details" "$LINENO" 5; } ;; #(
  'none needed') :
    ac_c_undeclared_builtin_options='' ;; #(
  *) :
    ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;;
esac


    # Avoids picking hidden internal symbol from libc
    ac_fn_check_decl "$LINENO" "gethostbyname_r" "ac_cv_have_decl_gethostbyname_r" "#include <netdb.h>
" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_gethostbyname_r" = xyes
then :
  ac_have_decl=1
Changes to unix/tcl.m4.
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
	hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -finput-charset=UTF-8"
	AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[tcl_cv_cc_input_charset=yes],[tcl_cv_cc_input_charset=no])
	CFLAGS=$hold_cflags])
    if test $tcl_cv_cc_input_charset = yes; then
	CFLAGS="$CFLAGS -finput-charset=UTF-8"
    fi

    AC_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have <stdbool.h>?])],)

    # Check for vfork, posix_spawnp() and friends unconditionally
    AC_CHECK_FUNCS(vfork posix_spawnp posix_spawn_file_actions_adddup2 posix_spawnattr_setflags)

    # FIXME: This subst was left in only because the TCL_DL_LIBS
    # entry in tclConfig.sh uses it. It is not clear why someone
    # would use TCL_DL_LIBS instead of TCL_LIBS.







|







1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
	hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -finput-charset=UTF-8"
	AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[tcl_cv_cc_input_charset=yes],[tcl_cv_cc_input_charset=no])
	CFLAGS=$hold_cflags])
    if test $tcl_cv_cc_input_charset = yes; then
	CFLAGS="$CFLAGS -finput-charset=UTF-8"
    fi

    AC_CHECK_HEADER(stdatomic.h, [AC_DEFINE(HAVE_STDATOMIC_H, 1, [Do we have <stdatomic.h>?])],)

    # Check for vfork, posix_spawnp() and friends unconditionally
    AC_CHECK_FUNCS(vfork posix_spawnp posix_spawn_file_actions_adddup2 posix_spawnattr_setflags)

    # FIXME: This subst was left in only because the TCL_DL_LIBS
    # entry in tclConfig.sh uses it. It is not clear why someone
    # would use TCL_DL_LIBS instead of TCL_LIBS.
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
    fi

    # Does the pthread-implementation provide
    # 'pthread_attr_setstacksize' ?

    ac_saved_libs=$LIBS
    LIBS="$LIBS $THREADS_LIBS"
    AC_CHECK_FUNCS(pthread_attr_setstacksize pthread_atfork)
    LIBS=$ac_saved_libs

    # TIP #509
    AC_CHECK_DECLS([PTHREAD_MUTEX_RECURSIVE],tcl_ok=yes,tcl_ok=no, [[#include <pthread.h>]])
])

#--------------------------------------------------------------------
# SC_TCL_EARLY_FLAGS
#
#	Check for what flags are needed to be passed so the correct OS
#	features are available.







|

<
<
<







2252
2253
2254
2255
2256
2257
2258
2259
2260



2261
2262
2263
2264
2265
2266
2267
    fi

    # Does the pthread-implementation provide
    # 'pthread_attr_setstacksize' ?

    ac_saved_libs=$LIBS
    LIBS="$LIBS $THREADS_LIBS"
    AC_CHECK_FUNCS(pthread_attr_setstacksize pthread_atfork pthread_spin_lock)
    LIBS=$ac_saved_libs



])

#--------------------------------------------------------------------
# SC_TCL_EARLY_FLAGS
#
#	Check for what flags are needed to be passed so the correct OS
#	features are available.
Changes to unix/tclConfig.h.in.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
   you don't. */
#undef HAVE_DECL_GETHOSTBYADDR_R

/* Define to 1 if you have the declaration of 'gethostbyname_r', and to 0 if
   you don't. */
#undef HAVE_DECL_GETHOSTBYNAME_R

/* Define to 1 if you have the declaration of 'PTHREAD_MUTEX_RECURSIVE', and
   to 0 if you don't. */
#undef HAVE_DECL_PTHREAD_MUTEX_RECURSIVE

/* Is 'DIR64' in <sys/types.h>? */
#undef HAVE_DIR64

/* Is eventfd(2) supported? */
#undef HAVE_EVENTFD

/* Define to 1 if you have the 'freeaddrinfo' function. */







<
<
<
<







35
36
37
38
39
40
41




42
43
44
45
46
47
48
   you don't. */
#undef HAVE_DECL_GETHOSTBYADDR_R

/* Define to 1 if you have the declaration of 'gethostbyname_r', and to 0 if
   you don't. */
#undef HAVE_DECL_GETHOSTBYNAME_R





/* Is 'DIR64' in <sys/types.h>? */
#undef HAVE_DIR64

/* Is eventfd(2) supported? */
#undef HAVE_EVENTFD

/* Define to 1 if you have the 'freeaddrinfo' function. */
185
186
187
188
189
190
191



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#undef HAVE_PSELECT

/* Define to 1 if you have the 'pthread_atfork' function. */
#undef HAVE_PTHREAD_ATFORK

/* Define to 1 if you have the 'pthread_attr_setstacksize' function. */
#undef HAVE_PTHREAD_ATTR_SETSTACKSIZE




/* Does putenv() copy strings or incorporate them by reference? */
#undef HAVE_PUTENV_THAT_COPIES

/* Are characters signed? */
#undef HAVE_SIGNED_CHAR

/* Do we have <stdbool.h>? */
#undef HAVE_STDBOOL_H

/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H

/* Define to 1 if you have the <stdio.h> header file. */
#undef HAVE_STDIO_H








>
>
>







|
|







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
#undef HAVE_PSELECT

/* Define to 1 if you have the 'pthread_atfork' function. */
#undef HAVE_PTHREAD_ATFORK

/* Define to 1 if you have the 'pthread_attr_setstacksize' function. */
#undef HAVE_PTHREAD_ATTR_SETSTACKSIZE

/* Define to 1 if you have the 'pthread_spin_lock' function. */
#undef HAVE_PTHREAD_SPIN_LOCK

/* Does putenv() copy strings or incorporate them by reference? */
#undef HAVE_PUTENV_THAT_COPIES

/* Are characters signed? */
#undef HAVE_SIGNED_CHAR

/* Do we have <stdatomic.h>? */
#undef HAVE_STDATOMIC_H

/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H

/* Define to 1 if you have the <stdio.h> header file. */
#undef HAVE_STDIO_H

Changes to unix/tclSelectNotfy.c.
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
    void *hIcon;
    void *hCursor;
    void *hbrBackground;
    const void *lpszMenuName;
    const void *lpszClassName;
} WNDCLASSW;

#ifdef __clang__
#pragma clang diagnostic ignored "-Wignored-attributes"
#endif
extern void __stdcall	CloseHandle(void *);
extern void *__stdcall	CreateEventW(void *, unsigned char, unsigned char,
			    void *);
extern void *__stdcall	CreateWindowExW(void *, const void *, const void *,
			    unsigned int, int, int, int, int, void *, void *,
			    void *, void *);
extern unsigned int __stdcall	DefWindowProcW(void *, int, void *, void *);
extern unsigned char __stdcall	DestroyWindow(void *);
extern int __stdcall	DispatchMessageW(const MSG *);
extern unsigned char __stdcall	GetMessageW(MSG *, void *, int, int);
extern void __stdcall	MsgWaitForMultipleObjects(unsigned int, void *,
			    unsigned char, unsigned int, unsigned int);
extern unsigned char __stdcall	PeekMessageW(MSG *, void *, int, int, int);
extern unsigned char __stdcall	PostMessageW(void *, unsigned int, void *,
				    void *);
extern void __stdcall	PostQuitMessage(int);
extern void *__stdcall	RegisterClassW(const WNDCLASSW *);
extern unsigned char __stdcall	ResetEvent(void *);
extern unsigned char __stdcall	TranslateMessage(const MSG *);

/*
 * Threaded-cygwin specific constants and functions in this file:
 */

#if TCL_THREADS && defined(__CYGWIN__)
static const wchar_t className[] = L"TclNotifier";
static unsigned int __stdcall	NotifierProc(void *hwnd, unsigned int message,
			    void *wParam, void *lParam);
#endif /* TCL_THREADS && defined(__CYGWIN__) */
#ifdef __cplusplus
}
#endif
#endif /* TCL_THREADS && __CYGWIN__ */








<
<
<
|
|

|


|
|
|
|
|

|
|

|
|
|
|







|







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
    void *hIcon;
    void *hCursor;
    void *hbrBackground;
    const void *lpszMenuName;
    const void *lpszClassName;
} WNDCLASSW;




extern void CloseHandle(void *);
extern void *CreateEventW(void *, unsigned char, unsigned char,
			    void *);
extern void *CreateWindowExW(void *, const void *, const void *,
			    unsigned int, int, int, int, int, void *, void *,
			    void *, void *);
extern unsigned int DefWindowProcW(void *, int, void *, void *);
extern unsigned char DestroyWindow(void *);
extern int DispatchMessageW(const MSG *);
extern unsigned char GetMessageW(MSG *, void *, int, int);
extern void MsgWaitForMultipleObjects(unsigned int, void *,
			    unsigned char, unsigned int, unsigned int);
extern unsigned char PeekMessageW(MSG *, void *, int, int, int);
extern unsigned char PostMessageW(void *, unsigned int, void *,
				    void *);
extern void PostQuitMessage(int);
extern void *RegisterClassW(const WNDCLASSW *);
extern unsigned char ResetEvent(void *);
extern unsigned char TranslateMessage(const MSG *);

/*
 * Threaded-cygwin specific constants and functions in this file:
 */

#if TCL_THREADS && defined(__CYGWIN__)
static const wchar_t className[] = L"TclNotifier";
static unsigned int NotifierProc(void *hwnd, unsigned int message,
			    void *wParam, void *lParam);
#endif /* TCL_THREADS && defined(__CYGWIN__) */
#ifdef __cplusplus
}
#endif
#endif /* TCL_THREADS && __CYGWIN__ */

595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
	prevPtr->nextPtr = filePtr->nextPtr;
    }
    Tcl_Free(filePtr);
}

#if TCL_THREADS && defined(__CYGWIN__)

static unsigned int __stdcall
NotifierProc(
    void *hwnd,
    unsigned int message,
    void *wParam,
    void *lParam)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);







|







592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
	prevPtr->nextPtr = filePtr->nextPtr;
    }
    Tcl_Free(filePtr);
}

#if TCL_THREADS && defined(__CYGWIN__)

static unsigned int
NotifierProc(
    void *hwnd,
    unsigned int message,
    void *wParam,
    void *lParam)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Changes to unix/tclUnixFCmd.c.
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
	Tcl_DecrRefCount(transPtr);
    }
    if (ret != TCL_OK) {
	*errorPtr = srcPathPtr;
    } else {
	transPtr = Tcl_FSGetTranslatedPath(NULL,destPathPtr);
	ret = Tcl_UtfToExternalDStringEx(NULL, NULL,
	    (transPtr != NULL ? TclGetString(transPtr) : NULL),
	    -1, TCL_ENCODING_PROFILE_TCL8, &dstString, NULL);
	if (transPtr != NULL) {
	    Tcl_DecrRefCount(transPtr);
	}
	if (ret != TCL_OK) {
	    *errorPtr = destPathPtr;
	} else {
	    ret = TraverseUnixTree(TraversalCopy, &srcString, &dstString, &ds, 0);







|
|







740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
	Tcl_DecrRefCount(transPtr);
    }
    if (ret != TCL_OK) {
	*errorPtr = srcPathPtr;
    } else {
	transPtr = Tcl_FSGetTranslatedPath(NULL,destPathPtr);
	ret = Tcl_UtfToExternalDStringEx(NULL, NULL,
		(transPtr != NULL ? TclGetString(transPtr) : NULL),
		-1, TCL_ENCODING_PROFILE_TCL8, &dstString, NULL);
	if (transPtr != NULL) {
	    Tcl_DecrRefCount(transPtr);
	}
	if (ret != TCL_OK) {
	    *errorPtr = destPathPtr;
	} else {
	    ret = TraverseUnixTree(TraversalCopy, &srcString, &dstString, &ds, 0);
Changes to unix/tclUnixInit.c.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#   endif
#endif

#ifdef __CYGWIN__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __clang__
#pragma clang diagnostic ignored "-Wignored-attributes"
#endif
DLLIMPORT extern __stdcall unsigned char GetVersionExW(void *);
DLLIMPORT extern __stdcall void *GetModuleHandleW(const void *);
DLLIMPORT extern __stdcall void FreeLibrary(void *);
DLLIMPORT extern __stdcall void *GetProcAddress(void *, const char *);
DLLIMPORT extern __stdcall void GetSystemInfo(void *);
#ifdef __cplusplus
}
#endif

#define NUMPROCESSORS 15
static const char *const processors[NUMPROCESSORS] = {
    "i686", "mips", "alpha", "ppc", "shx", "arm", "ia64", "alpha64", "msil",







<
<
<
|
|
|
|
|







23
24
25
26
27
28
29



30
31
32
33
34
35
36
37
38
39
40
41
#   endif
#endif

#ifdef __CYGWIN__
#ifdef __cplusplus
extern "C" {
#endif



DLLIMPORT extern unsigned char GetVersionExW(void *);
DLLIMPORT extern void *GetModuleHandleW(const void *);
DLLIMPORT extern void FreeLibrary(void *);
DLLIMPORT extern void *GetProcAddress(void *, const char *);
DLLIMPORT extern void GetSystemInfo(void *);
#ifdef __cplusplus
}
#endif

#define NUMPROCESSORS 15
static const char *const processors[NUMPROCESSORS] = {
    "i686", "mips", "alpha", "ppc", "shx", "arm", "ia64", "alpha64", "msil",
437
438
439
440
441
442
443

444
445
446



447
448
449
450
451
452
453
     * Look for the library relative to the TCL_LIBRARY env variable. If the
     * last dirname in the TCL_LIBRARY path does not match the last dirname in
     * the installLib variable, use the last dir name of installLib in
     * addition to the original TCL_LIBRARY path.
     */

    str = getenv("TCL_LIBRARY");			/* INTL: Native. */

    Tcl_ExternalToUtfDStringEx(NULL, NULL, str, TCL_INDEX_NONE,
	    TCL_ENCODING_PROFILE_TCL8, &buffer, NULL);
    str = Tcl_DStringValue(&buffer);




    if ((str != NULL) && (str[0] != '\0')) {
	Tcl_DString ds;
	Tcl_Size pathc;
	const char **pathv;
	char installLib[LIBRARY_SIZE];








>
|
|
|
>
>
>







434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
     * Look for the library relative to the TCL_LIBRARY env variable. If the
     * last dirname in the TCL_LIBRARY path does not match the last dirname in
     * the installLib variable, use the last dir name of installLib in
     * addition to the original TCL_LIBRARY path.
     */

    str = getenv("TCL_LIBRARY");			/* INTL: Native. */
    if (str != NULL) {
        Tcl_ExternalToUtfDStringEx(NULL, NULL, str, TCL_INDEX_NONE,
                                   TCL_ENCODING_PROFILE_TCL8, &buffer, NULL);
	str = Tcl_DStringValue(&buffer);
    } else {
        Tcl_DStringInit(&buffer);
    }

    if ((str != NULL) && (str[0] != '\0')) {
	Tcl_DString ds;
	Tcl_Size pathc;
	const char **pathv;
	char installLib[LIBRARY_SIZE];

856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
#endif

    unameOK = 0;
#ifdef __CYGWIN__
	unameOK = 1;
    if (!osInfoInitialized) {
	void *handle = GetModuleHandleW(L"NTDLL");
	int(__stdcall *getversion)(void *) =
		(int(__stdcall *)(void *))GetProcAddress(handle, "RtlGetVersion");
	osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
	if (!getversion || getversion(&osInfo)) {
	    GetVersionExW(&osInfo);
	}
	osInfoInitialized = 1;
    }








|
|







857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
#endif

    unameOK = 0;
#ifdef __CYGWIN__
	unameOK = 1;
    if (!osInfoInitialized) {
	void *handle = GetModuleHandleW(L"NTDLL");
	int(*getversion)(void *) =
		(int(*)(void *))GetProcAddress(handle, "RtlGetVersion");
	osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
	if (!getversion || getversion(&osInfo)) {
	    GetVersionExW(&osInfo);
	}
	osInfoInitialized = 1;
    }

Changes to unix/tclUnixPort.h.
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
#   define CP_UTF8 65001
#   define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004
#   define HMODULE void *
#   define MAX_PATH 260
#   define SOCKET unsigned int
#   define WSAEWOULDBLOCK 10035
    typedef unsigned short WCHAR;
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wignored-attributes"
#endif
    __declspec(dllimport) extern __stdcall int GetModuleHandleExW(unsigned int, const void *, void *);
    __declspec(dllimport) extern __stdcall int GetModuleFileNameW(void *, const void *, int);
    __declspec(dllimport) extern __stdcall int WideCharToMultiByte(int, int, const void *, int,
	    char *, int, const char *, void *);
    __declspec(dllimport) extern __stdcall int MultiByteToWideChar(int, int, const char *, int,
	    WCHAR *, int);
    __declspec(dllimport) extern __stdcall void OutputDebugStringW(const WCHAR *);
    __declspec(dllimport) extern __stdcall int IsDebuggerPresent(void);
    __declspec(dllimport) extern __stdcall int GetLastError(void);
    __declspec(dllimport) extern __stdcall int GetFileAttributesW(const WCHAR *);
    __declspec(dllimport) extern __stdcall int SetFileAttributesW(const WCHAR *, int);
    __declspec(dllimport) extern int cygwin_conv_path(int, const void *, void *, int);
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#   define timezone _timezone
    extern int TclOSfstat(int fd, void *statBuf);
    extern int TclOSstat(const char *name, void *statBuf);
    extern int TclOSlstat(const char *name, void *statBuf);
#ifdef __cplusplus
}
#endif







<
<
<
<
|
|
|

|

|
|
|
|
|

<
<
<







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
#   define CP_UTF8 65001
#   define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004
#   define HMODULE void *
#   define MAX_PATH 260
#   define SOCKET unsigned int
#   define WSAEWOULDBLOCK 10035
    typedef unsigned short WCHAR;




    __declspec(dllimport) extern int GetModuleHandleExW(unsigned int, const void *, void *);
    __declspec(dllimport) extern int GetModuleFileNameW(void *, const void *, int);
    __declspec(dllimport) extern int WideCharToMultiByte(int, int, const void *, int,
	    char *, int, const char *, void *);
    __declspec(dllimport) extern int MultiByteToWideChar(int, int, const char *, int,
	    WCHAR *, int);
    __declspec(dllimport) extern void OutputDebugStringW(const WCHAR *);
    __declspec(dllimport) extern int IsDebuggerPresent(void);
    __declspec(dllimport) extern int GetLastError(void);
    __declspec(dllimport) extern int GetFileAttributesW(const WCHAR *);
    __declspec(dllimport) extern int SetFileAttributesW(const WCHAR *, int);
    __declspec(dllimport) extern int cygwin_conv_path(int, const void *, void *, int);



#   define timezone _timezone
    extern int TclOSfstat(int fd, void *statBuf);
    extern int TclOSstat(const char *name, void *statBuf);
    extern int TclOSlstat(const char *name, void *statBuf);
#ifdef __cplusplus
}
#endif
Changes to unix/tclUnixThrd.c.
9
10
11
12
13
14
15




16
17
18
19
20
21
22
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tclInt.h"





#if TCL_THREADS

/*
 * TIP #509. Ensures that Tcl's mutexes are reentrant.
 *
 *----------------------------------------------------------------------
 *







>
>
>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tclInt.h"

#ifdef HAVE_STDATOMIC_H
#include <stdatomic.h>
#endif /* HAVE_STDATOMIC_H */

#if TCL_THREADS

/*
 * TIP #509. Ensures that Tcl's mutexes are reentrant.
 *
 *----------------------------------------------------------------------
 *
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








160

161
162
163
164
165
166
167
168
 *
 *	Waits for a limited amount of time on a condition variable linked to a
 *	recursive lock. (Similar to pthread_cond_timedwait)
 *
 *----------------------------------------------------------------------
 */

#ifndef HAVE_DECL_PTHREAD_MUTEX_RECURSIVE
#define HAVE_DECL_PTHREAD_MUTEX_RECURSIVE 0
#endif

#if HAVE_DECL_PTHREAD_MUTEX_RECURSIVE
/*
 * Pthread has native reentrant (AKA recursive) mutexes. Use them for
 * Tcl_Mutex.
 */

typedef pthread_mutex_t PMutex;

static void
PMutexInit(
    PMutex *pmutexPtr)
{
    pthread_mutexattr_t attr;

    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(pmutexPtr, &attr);
}

#define PMutexDestroy	pthread_mutex_destroy
#define PMutexLock	pthread_mutex_lock
#define PMutexUnlock	pthread_mutex_unlock
#define PCondWait	pthread_cond_wait
#define PCondTimedWait	pthread_cond_timedwait

#else /* !HAVE_PTHREAD_MUTEX_RECURSIVE */

/*
 * No native support for reentrant mutexes. Emulate them with regular mutexes
 * and thread-local counters.
 */

typedef struct PMutex {
    pthread_mutex_t mutex;



    pthread_t thread;
    int counter;
} PMutex;

static void
PMutexInit(
    PMutex *pmutexPtr)
{
    pthread_mutex_init(&pmutexPtr->mutex, NULL);



    pmutexPtr->thread = 0;
    pmutexPtr->counter = 0;
}

static void
PMutexDestroy(
    PMutex *pmutexPtr)
{












    pthread_mutex_destroy(&pmutexPtr->mutex);
}



static void
PMutexLock(
    PMutex *pmutexPtr)
{





















    if (pmutexPtr->thread != pthread_self() || pmutexPtr->counter == 0) {

































































	pthread_mutex_lock(&pmutexPtr->mutex);



	pmutexPtr->thread = pthread_self();

	pmutexPtr->counter = 0;

    }
    pmutexPtr->counter++;
}

static void
PMutexUnlock(
    PMutex *pmutexPtr)
{














    pmutexPtr->counter--;

    if (pmutexPtr->counter == 0) {




	pmutexPtr->thread = 0;



	pthread_mutex_unlock(&pmutexPtr->mutex);
    }
}

static void
PCondWait(
    pthread_cond_t *pcondPtr,
    PMutex *pmutexPtr)
{























    pthread_cond_wait(pcondPtr, &pmutexPtr->mutex);








}

static void
PCondTimedWait(
    pthread_cond_t *pcondPtr,
    PMutex *pmutexPtr,
    struct timespec *ptime)
{























    pthread_cond_timedwait(pcondPtr, &pmutexPtr->mutex, ptime);








}

#endif /* HAVE_PTHREAD_MUTEX_RECURSIVE */

/*
 * globalLock is used to serialize creation of mutexes, condition variables,
 * and thread local storage. This is the only place that can count on the
 * ability to statically initialize the mutex.
 */








<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|




>
>
>
|
|







>
>
>








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



>
>




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

>
>
>
|
>
|
>

<






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

>
>
>









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

>
>
>
>
>
>
>
>








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

>
>
>
>
>
>
>
>

>
|







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
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
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
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
 *
 *	Waits for a limited amount of time on a condition variable linked to a
 *	recursive lock. (Similar to pthread_cond_timedwait)
 *
 *----------------------------------------------------------------------
 */






/*


























 * No correct native support for reentrant mutexes. Emulate them with regular mutexes
 * and threadlocal counters.
 */

typedef struct PMutex {
    pthread_mutex_t mutex;
#if defined(HAVE_PTHREAD_SPIN_LOCK) && !defined(HAVE_STDATOMIC_H)
    pthread_spinlock_t lock;
#endif
    volatile pthread_t thread;
    int counter; // Number of additional locks in the same thread.
} PMutex;

static void
PMutexInit(
    PMutex *pmutexPtr)
{
    pthread_mutex_init(&pmutexPtr->mutex, NULL);
#if defined(HAVE_PTHREAD_SPIN_LOCK) && !defined(HAVE_STDATOMIC_H)
    pthread_spin_init(&pmutexPtr->lock, PTHREAD_PROCESS_PRIVATE);
#endif
    pmutexPtr->thread = 0;
    pmutexPtr->counter = 0;
}

static void
PMutexDestroy(
    PMutex *pmutexPtr)
{
#ifdef HAVE_STDATOMIC_H
    if (__atomic_load_n(&pmutexPtr->thread, __ATOMIC_SEQ_CST) != 0) {
	Tcl_Panic("mutex still owned");
    }
#else
    if (mutexPtr->thread != 0) {
	Tcl_Panic("mutex still owned");
    }
# if defined(HAVE_PTHREAD_SPIN_LOCK)
    pthread_spin_destroy(&pmutexPtr->lock);
# endif
#endif
    pthread_mutex_destroy(&pmutexPtr->mutex);
}

#ifdef HAVE_STDATOMIC_H

static void
PMutexLock(
    PMutex *pmutexPtr)
{
    pthread_t mythread = pthread_self();

    if (__atomic_load_n(&pmutexPtr->thread, __ATOMIC_SEQ_CST) == mythread) {
	// We own the lock already, so it's recursive.
	pmutexPtr->counter++;
    } else {
	// We don't owns the lock, so we have to lock it. Then we own it.
	pthread_mutex_lock(&pmutexPtr->mutex);
	__atomic_store_n(&pmutexPtr->thread, mythread, __ATOMIC_SEQ_CST);
    }
}

static void
PMutexUnlock(
    PMutex *pmutexPtr)
{
    pthread_t mythread = pthread_self();

    if (__atomic_load_n(&pmutexPtr->thread, __ATOMIC_SEQ_CST) != mythread) {
	Tcl_Panic("mutex not owned");
    }
    if (pmutexPtr->counter) {
	// It's recursive
	pmutexPtr->counter--;
    } else {
	__atomic_store_n(&pmutexPtr->thread, 0, __ATOMIC_SEQ_CST);
	pthread_mutex_unlock(&pmutexPtr->mutex);
    }
}

static void
PCondWait(
    pthread_cond_t *pcondPtr,
    PMutex *pmutexPtr)
{
    pthread_t mythread = pthread_self();

    if (__atomic_load_n(&pmutexPtr->thread, __ATOMIC_SEQ_CST) != mythread) {
	Tcl_Panic("mutex not owned");
    }
    int counter = pmutexPtr->counter;
    pmutexPtr->counter = 0;
    __atomic_store_n(&pmutexPtr->thread, 0, __ATOMIC_SEQ_CST);
    pthread_cond_wait(pcondPtr, &pmutexPtr->mutex);
    __atomic_store_n(&pmutexPtr->thread, mythread, __ATOMIC_SEQ_CST);
    pmutexPtr->counter = counter;
}

static void
PCondTimedWait(
    pthread_cond_t *pcondPtr,
    PMutex *pmutexPtr,
    struct timespec *ptime)
{
    pthread_t mythread = pthread_self();

    if (__atomic_load_n(&pmutexPtr->thread, __ATOMIC_SEQ_CST) != mythread) {
	Tcl_Panic("mutex not owned");
    }
    int counter = pmutexPtr->counter;
    pmutexPtr->counter = 0;
    __atomic_store_n(&pmutexPtr->thread, 0, __ATOMIC_SEQ_CST);
    pthread_cond_timedwait(pcondPtr, &pmutexPtr->mutex, ptime);
    __atomic_store_n(&pmutexPtr->thread, mythread, __ATOMIC_SEQ_CST);
    pmutexPtr->counter = counter;
}

#else /* HAVE_STDATOMIC_H */

static void
PMutexLock(
    PMutex *pmutexPtr)
{
    pthread_t mythread = pthread_self();
    pthread_t mutexthread;

#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_lock(&pmutexPtr->lock);
#endif
    mutexthread = pmutexPtr->thread;
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_unlock(&pmutexPtr->lock);
#endif
    if (mutexthread == mythread) {
	// We owned the lock already, so it's recursive.
	pmutexPtr->counter++;
    } else {
	pthread_mutex_lock(&pmutexPtr->mutex);
#ifdef HAVE_PTHREAD_SPIN_LOCK
	pthread_spin_lock(&pmutexPtr->lock);
#endif
	pmutexPtr->thread = mythread;
#ifdef HAVE_PTHREAD_SPIN_LOCK
	pthread_spin_unlock(&pmutexPtr->lock);
#endif
    }

}

static void
PMutexUnlock(
    PMutex *pmutexPtr)
{
    pthread_t mythread = pthread_self();
    pthread_t mutexthread;

#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_lock(&pmutexPtr->lock);
#endif
    mutexthread = pmutexPtr->thread;
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_unlock(&pmutexPtr->lock);
#endif

    if (mutexthread != mythread) {
	Tcl_Panic("mutex not owned");
    }
    if (pmutexPtr->counter) {
	// It's recursive
	pmutexPtr->counter--;
    } else {
#ifdef HAVE_PTHREAD_SPIN_LOCK
	pthread_spin_lock(&pmutexPtr->lock);
#endif
	pmutexPtr->thread = 0;
#ifdef HAVE_PTHREAD_SPIN_LOCK
	pthread_spin_unlock(&pmutexPtr->lock);
#endif
	pthread_mutex_unlock(&pmutexPtr->mutex);
    }
}

static void
PCondWait(
    pthread_cond_t *pcondPtr,
    PMutex *pmutexPtr)
{
    pthread_t mythread = pthread_self();
    pthread_t mutexthread;

#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_lock(&pmutexPtr->lock);
#endif
    mutexthread = pmutexPtr->thread;
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_unlock(&pmutexPtr->lock);
#endif

    if (mutexthread != mythread) {
	Tcl_Panic("mutex not owned");
    }
    int counter = pmutexPtr->counter;
    pmutexPtr->counter = 0;
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_lock(&pmutexPtr->lock);
#endif
    pmutexPtr->thread = 0;
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_unlock(&pmutexPtr->lock);
#endif
    pthread_cond_wait(pcondPtr, &pmutexPtr->mutex);
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_lock(&pmutexPtr->lock);
#endif
    pmutexPtr->thread = mythread;
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_unlock(&pmutexPtr->lock);
#endif
    pmutexPtr->counter = counter;
}

static void
PCondTimedWait(
    pthread_cond_t *pcondPtr,
    PMutex *pmutexPtr,
    struct timespec *ptime)
{
    pthread_t mythread = pthread_self();
    pthread_t mutexthread;

#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_lock(&pmutexPtr->lock);
#endif
    mutexthread = pmutexPtr->thread;
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_unlock(&pmutexPtr->lock);
#endif

    if (mutexthread != mythread) {
	Tcl_Panic("mutex not owned");
    }
    int counter = pmutexPtr->counter;
    pmutexPtr->counter = 0;
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_lock(&pmutexPtr->lock);
#endif
    pmutexPtr->thread = 0;
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_unlock(&pmutexPtr->lock);
#endif
    pthread_cond_timedwait(pcondPtr, &pmutexPtr->mutex, ptime);
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_lock(&pmutexPtr->lock);
#endif
    pmutexPtr->thread = mythread;
#ifdef HAVE_PTHREAD_SPIN_LOCK
    pthread_spin_unlock(&pmutexPtr->lock);
#endif
    pmutexPtr->counter = counter;
}

#endif /* HAVE_STDATOMIC_H */

/*
 * globalLock is used to serialize creation of mutexes, condition variables,
 * and thread local storage. This is the only place that can count on the
 * ability to statically initialize the mutex.
 */

528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
 *----------------------------------------------------------------------
 */

Tcl_Mutex *
Tcl_GetAllocMutex(void)
{
#if TCL_THREADS
    PMutex **allocLockPtrPtr = &allocLockPtr;

    pthread_once(&allocLockInitOnce, allocLockInit);
    return (Tcl_Mutex *) allocLockPtrPtr;
#else
    return NULL;
#endif
}

#if TCL_THREADS








<
<

|







696
697
698
699
700
701
702


703
704
705
706
707
708
709
710
711
 *----------------------------------------------------------------------
 */

Tcl_Mutex *
Tcl_GetAllocMutex(void)
{
#if TCL_THREADS


    pthread_once(&allocLockInitOnce, allocLockInit);
    return (Tcl_Mutex *) &allocLockPtr;
#else
    return NULL;
#endif
}

#if TCL_THREADS

633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
 *----------------------------------------------------------------------
 */

void
TclpFinalizeMutex(
    Tcl_Mutex *mutexPtr)
{
    PMutex *pmutexPtr = *(PMutex **) mutexPtr;

    if (pmutexPtr != NULL) {
	PMutexDestroy(pmutexPtr);
	Tcl_Free(pmutexPtr);
	*mutexPtr = NULL;
    }
}







|







799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
 *----------------------------------------------------------------------
 */

void
TclpFinalizeMutex(
    Tcl_Mutex *mutexPtr)
{
    PMutex *pmutexPtr = *(PMutex **)mutexPtr;

    if (pmutexPtr != NULL) {
	PMutexDestroy(pmutexPtr);
	Tcl_Free(pmutexPtr);
	*mutexPtr = NULL;
    }
}
Changes to utf8proc/utf8proc.h.
205
206
207
208
209
210
211
212

213
214
215
216
217
218
219
   *       @ref UTF8PROC_DECOMPOSE
   */
  UTF8PROC_STRIPMARK = (1<<13),
  /**
   * Strip unassigned codepoints.
   */
  UTF8PROC_STRIPNA    = (1<<14),
} utf8proc_option_t;


/** @name Error codes
 * Error codes being returned by almost all functions.
 */
/** @{ */
/** Memory could not be allocated. */
#define UTF8PROC_ERROR_NOMEM -1







|
>







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
   *       @ref UTF8PROC_DECOMPOSE
   */
  UTF8PROC_STRIPMARK = (1<<13),
  /**
   * Strip unassigned codepoints.
   */
  UTF8PROC_STRIPNA    = (1<<14),
} utf8proc_option_e;
typedef int utf8proc_option_t;

/** @name Error codes
 * Error codes being returned by almost all functions.
 */
/** @{ */
/** Memory could not be allocated. */
#define UTF8PROC_ERROR_NOMEM -1
Changes to win/configure.
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
PACKAGE_TARNAME='tcl'
PACKAGE_VERSION='9.1'
PACKAGE_STRING='tcl 9.1'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''

ac_unique_file="../generic/tcl.h"
# Factoring default headers for most tests.
ac_includes_default="\
#include <stddef.h>
#ifdef HAVE_STDIO_H
# include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif"

ac_header_c_list=
ac_subst_vars='LTLIBOBJS
LIBOBJS
RES
RC_DEFINES
RC_DEFINE
RC_INCLUDE
RC_TYPE







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







603
604
605
606
607
608
609
































610
611
612
613
614
615
616
PACKAGE_TARNAME='tcl'
PACKAGE_VERSION='9.1'
PACKAGE_STRING='tcl 9.1'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''

ac_unique_file="../generic/tcl.h"
































ac_subst_vars='LTLIBOBJS
LIBOBJS
RES
RC_DEFINES
RC_DEFINE
RC_INCLUDE
RC_TYPE
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
esac
fi
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_compile

# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists and can be compiled using the include files in
# INCLUDES, setting the cache variable VAR accordingly.
ac_fn_c_check_header_compile ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
printf %s "checking for $2... " >&6; }
if eval test \${$3+y}
then :
  printf %s "(cached) " >&6
else case e in #(
  e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
  eval "$3=yes"
else case e in #(
  e) eval "$3=no" ;;
esac
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
esac
fi
eval ac_res=\$$3
	       { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_header_compile

# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
# -------------------------------------------
# Tests whether TYPE exists after having included INCLUDES, setting cache
# variable VAR accordingly.
ac_fn_c_check_type ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1534
1535
1536
1537
1538
1539
1540



































1541
1542
1543
1544
1545
1546
1547
esac
fi
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_compile




































# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
# -------------------------------------------
# Tests whether TYPE exists after having included INCLUDES, setting cache
# variable VAR accordingly.
ac_fn_c_check_type ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
{
  int ok = 0;
  ${ac_c_conftest_c89_main}
  return ok;
}
"

as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H"
as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H"
as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H"
as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H"
as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H"
as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
# Check that the precious variables saved in the cache have kept the same
# value.
ac_cache_corrupted=false
for ac_var in $ac_precious_vars; do
  eval ac_old_set=\$ac_cv_env_${ac_var}_set
  eval ac_new_set=\$ac_env_${ac_var}_set
  eval ac_old_val=\$ac_cv_env_${ac_var}_value







<
<
<
<
<
<
<
<
<







2251
2252
2253
2254
2255
2256
2257









2258
2259
2260
2261
2262
2263
2264
{
  int ok = 0;
  ${ac_c_conftest_c89_main}
  return ok;
}
"










# Check that the precious variables saved in the cache have kept the same
# value.
ac_cache_corrupted=false
for ac_var in $ac_precious_vars; do
  eval ac_old_set=\$ac_cv_env_${ac_var}_set
  eval ac_new_set=\$ac_env_${ac_var}_set
  eval ac_old_val=\$ac_cv_env_${ac_var}_value
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982

#--------------------------------------------------------------------
# The statements below define a collection of compile flags.  This
# macro depends on the value of SHARED_BUILD, and should be called
# after SC_ENABLE_SHARED checks the configure switches.
#--------------------------------------------------------------------

ac_header= ac_cache=
for ac_item in $ac_header_c_list
do
  if test $ac_cache; then
    ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
    if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
      printf "%s\n" "#define $ac_item 1" >> confdefs.h
    fi
    ac_header= ac_cache=
  elif test $ac_header; then
    ac_cache=$ac_item
  else
    ac_header=$ac_item
  fi
done








if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
then :

printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h

fi


    # Step 0: Enable 64 bit support?

    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if 64bit support is requested" >&5
printf %s "checking if 64bit support is requested... " >&6; }
    # Check whether --enable-64bit was given.







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







3864
3865
3866
3867
3868
3869
3870





























3871
3872
3873
3874
3875
3876
3877

#--------------------------------------------------------------------
# The statements below define a collection of compile flags.  This
# macro depends on the value of SHARED_BUILD, and should be called
# after SC_ENABLE_SHARED checks the configure switches.
#--------------------------------------------------------------------
































    # Step 0: Enable 64 bit support?

    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if 64bit support is requested" >&5
printf %s "checking if 64bit support is requested... " >&6; }
    # Check whether --enable-64bit was given.
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
	LDFLAGS_OPTIMIZE=

	case "${CC}" in
	    *++)
		CFLAGS_WARNING="${CFLAGS_WARNING} -Wno-format"
		;;
	    *)
		CFLAGS_WARNING="${CFLAGS_WARNING} -Wc++-compat -fextended-identifiers"
		;;
	esac

	# Specify the CC output file names based on the target name
	CC_OBJNAME="-o \$@"
	CC_EXENAME="-o \$@"








|







4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
	LDFLAGS_OPTIMIZE=

	case "${CC}" in
	    *++)
		CFLAGS_WARNING="${CFLAGS_WARNING} -Wno-format"
		;;
	    *)
		CFLAGS_WARNING="${CFLAGS_WARNING} -Wc++-compat -Wno-c++-keyword -fextended-identifiers"
		;;
	esac

	# Specify the CC output file names based on the target name
	CC_OBJNAME="-o \$@"
	CC_EXENAME="-o \$@"

4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_eh_disposition" >&5
printf "%s\n" "$tcl_cv_eh_disposition" >&6; }
	if test "$tcl_cv_eh_disposition" = "no" ; then

printf "%s\n" "#define EXCEPTION_DISPOSITION int" >>confdefs.h

	fi

	ac_fn_c_check_header_compile "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default"
if test "x$ac_cv_header_stdbool_h" = xyes
then :

printf "%s\n" "#define HAVE_STDBOOL_H 1" >>confdefs.h

fi


	# See if the compiler supports casting to a union type.
	# This is used to stop gcc from printing a compiler
	# warning when initializing a union member.

	{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cast to union support" >&5
printf %s "checking for cast to union support... " >&6; }







<
<
<
<
<
<
<
<
<







4777
4778
4779
4780
4781
4782
4783









4784
4785
4786
4787
4788
4789
4790
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_eh_disposition" >&5
printf "%s\n" "$tcl_cv_eh_disposition" >&6; }
	if test "$tcl_cv_eh_disposition" = "no" ; then

printf "%s\n" "#define EXCEPTION_DISPOSITION int" >>confdefs.h

	fi










	# See if the compiler supports casting to a union type.
	# This is used to stop gcc from printing a compiler
	# warning when initializing a union member.

	{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cast to union support" >&5
printf %s "checking for cast to union support... " >&6; }
Changes to win/tcl.m4.
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
	LDFLAGS_OPTIMIZE=

	case "${CC}" in
	    *++)
		CFLAGS_WARNING="${CFLAGS_WARNING} -Wno-format"
		;;
	    *)
		CFLAGS_WARNING="${CFLAGS_WARNING} -Wc++-compat -fextended-identifiers"
		;;
	esac

	# Specify the CC output file names based on the target name
	CC_OBJNAME="-o \[$]@"
	CC_EXENAME="-o \[$]@"








|







719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
	LDFLAGS_OPTIMIZE=

	case "${CC}" in
	    *++)
		CFLAGS_WARNING="${CFLAGS_WARNING} -Wno-format"
		;;
	    *)
		CFLAGS_WARNING="${CFLAGS_WARNING} -Wc++-compat -Wno-c++-keyword -fextended-identifiers"
		;;
	esac

	# Specify the CC output file names based on the target name
	CC_OBJNAME="-o \[$]@"
	CC_EXENAME="-o \[$]@"

942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
		[tcl_cv_eh_disposition=no])
	)
	if test "$tcl_cv_eh_disposition" = "no" ; then
	AC_DEFINE(EXCEPTION_DISPOSITION, int,
		[Defined when cygwin/mingw does not support EXCEPTION DISPOSITION])
	fi

	AC_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have <stdbool.h>?])],)

	# See if the compiler supports casting to a union type.
	# This is used to stop gcc from printing a compiler
	# warning when initializing a union member.

	AC_CACHE_CHECK(for cast to union support,
	    tcl_cv_cast_to_union,
	    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[







<
<







942
943
944
945
946
947
948


949
950
951
952
953
954
955
		[tcl_cv_eh_disposition=no])
	)
	if test "$tcl_cv_eh_disposition" = "no" ; then
	AC_DEFINE(EXCEPTION_DISPOSITION, int,
		[Defined when cygwin/mingw does not support EXCEPTION DISPOSITION])
	fi



	# See if the compiler supports casting to a union type.
	# This is used to stop gcc from printing a compiler
	# warning when initializing a union member.

	AC_CACHE_CHECK(for cast to union support,
	    tcl_cv_cast_to_union,
	    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
Changes to win/tclWinInit.c.
327
328
329
330
331
332
333

334
335
336
337
338
339
340
static void
AppendEnvironment(
    Tcl_Obj *pathPtr,
    const char *lib)
{
    Tcl_Size pathc;
    WCHAR wBuf[MAX_PATH];

    char buf[MAX_PATH * 3];
    Tcl_Obj *objPtr;
    Tcl_DString ds;
    const char **pathv;
    char *shortlib;

    /*







>







327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
static void
AppendEnvironment(
    Tcl_Obj *pathPtr,
    const char *lib)
{
    Tcl_Size pathc;
    WCHAR wBuf[MAX_PATH];
    DWORD dw;
    char buf[MAX_PATH * 3];
    Tcl_Obj *objPtr;
    Tcl_DString ds;
    const char **pathv;
    char *shortlib;

    /*
351
352
353
354
355
356
357
358
359

360
361
362
363

364


365
366
367
368
369
370
371
	    break;
	}
    }
    if (shortlib == lib) {
	Tcl_Panic("no '/' character found in lib");
    }

    /*
     * The "L" preceding the TCL_LIBRARY string is used to tell VC++ that

     * this is a Unicode string.
     */

    GetEnvironmentVariableW(L"TCL_LIBRARY", wBuf, MAX_PATH);

    WideCharToMultiByte(CP_UTF8, 0, wBuf, -1, buf, MAX_PATH * 3, NULL, NULL);



    if (buf[0] != '\0') {
	objPtr = Tcl_NewStringObj(buf, TCL_INDEX_NONE);
	Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);

	TclWinNoBackslash(buf);
	Tcl_SplitPath(buf, &pathc, &pathv);







<
|
>
|
<
|
<
>
|
>
>







352
353
354
355
356
357
358

359
360
361

362

363
364
365
366
367
368
369
370
371
372
373
	    break;
	}
    }
    if (shortlib == lib) {
	Tcl_Panic("no '/' character found in lib");
    }


    dw = GetEnvironmentVariableW(L"TCL_LIBRARY", wBuf, MAX_PATH);
    if (dw <= 0 || dw >= MAX_PATH) {
	return;

    }

    if (WideCharToMultiByte(
	    CP_UTF8, 0, wBuf, -1, buf, MAX_PATH * 3, NULL, NULL) == 0) {
	return;
    }

    if (buf[0] != '\0') {
	objPtr = Tcl_NewStringObj(buf, TCL_INDEX_NONE);
	Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);

	TclWinNoBackslash(buf);
	Tcl_SplitPath(buf, &pathc, &pathv);
Changes to win/tclWinPipe.c.
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
    if (readFile != NULL) {
	/*
	 * Start the background reader thread.
	 */

	infoPtr->readable = CreateEventW(NULL, TRUE, TRUE, NULL);
	infoPtr->readThread = CreateThread(NULL, 256, PipeReaderThread,
	    TclPipeThreadCreateTI(&infoPtr->readTI, infoPtr), 0, NULL);
	SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
	infoPtr->validMask |= TCL_READABLE;
    } else {
	infoPtr->readTI = NULL;
	infoPtr->readThread = 0;
    }
    if (writeFile != NULL) {
	/*
	 * Start the background writer thread.
	 */

	infoPtr->writable = CreateEventW(NULL, TRUE, TRUE, NULL);
	infoPtr->writeThread = CreateThread(NULL, 256, PipeWriterThread,
	    TclPipeThreadCreateTI(&infoPtr->writeTI, infoPtr), 0, NULL);
	SetThreadPriority(infoPtr->writeThread, THREAD_PRIORITY_HIGHEST);
	infoPtr->validMask |= TCL_WRITABLE;
    } else {
	infoPtr->writeTI = NULL;
	infoPtr->writeThread = 0;
    }








|













|







1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
    if (readFile != NULL) {
	/*
	 * Start the background reader thread.
	 */

	infoPtr->readable = CreateEventW(NULL, TRUE, TRUE, NULL);
	infoPtr->readThread = CreateThread(NULL, 256, PipeReaderThread,
		TclPipeThreadCreateTI(&infoPtr->readTI, infoPtr), 0, NULL);
	SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
	infoPtr->validMask |= TCL_READABLE;
    } else {
	infoPtr->readTI = NULL;
	infoPtr->readThread = 0;
    }
    if (writeFile != NULL) {
	/*
	 * Start the background writer thread.
	 */

	infoPtr->writable = CreateEventW(NULL, TRUE, TRUE, NULL);
	infoPtr->writeThread = CreateThread(NULL, 256, PipeWriterThread,
		TclPipeThreadCreateTI(&infoPtr->writeTI, infoPtr), 0, NULL);
	SetThreadPriority(infoPtr->writeThread, THREAD_PRIORITY_HIGHEST);
	infoPtr->validMask |= TCL_WRITABLE;
    } else {
	infoPtr->writeTI = NULL;
	infoPtr->writeThread = 0;
    }

Changes to win/tclWinThrd.c.
39
40
41
42
43
44
45




46

47




48
49
50
51
52
53
54
55
56
/*
 * allocLock is used by Tcl's version of malloc for synchronization. For
 * obvious reasons, cannot use any dynamically allocated storage.
 */

#if TCL_THREADS





static struct Tcl_Mutex_ {

    CRITICAL_SECTION crit;




} allocLock;
static Tcl_Mutex allocLockPtr = &allocLock;
static int allocOnce = 0;

#endif /* TCL_THREADS */

/*
 * The joinLock serializes Create- and ExitThread. This is necessary to
 * prevent a race where a new joinable thread exits before the creating thread







>
>
>
>
|
>

>
>
>
>
|
|







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
/*
 * allocLock is used by Tcl's version of malloc for synchronization. For
 * obvious reasons, cannot use any dynamically allocated storage.
 */

#if TCL_THREADS

/*
 * Although CRITICAL_SECTIONs can be nested, we need to keep track
 * of their lock counts for condition variables.
 */

typedef struct WMutex {
    CRITICAL_SECTION crit;
    volatile LONG thread;
    int counter;
} WMutex;

static struct WMutex allocLock;
static WMutex *allocLockPtr = &allocLock;
static int allocOnce = 0;

#endif /* TCL_THREADS */

/*
 * The joinLock serializes Create- and ExitThread. This is necessary to
 * prevent a race where a new joinable thread exits before the creating thread
115
116
117
118
119
120
121
122
123
124



125
126
127
128
129
130
131
 */

#ifdef USE_THREAD_ALLOC
static DWORD tlsKey;

typedef struct {
    Tcl_Mutex tlock;
    CRITICAL_SECTION wlock;
} allocMutex;
#endif /* USE_THREAD_ALLOC */




/*
 * The per thread data passed from TclpThreadCreate
 * to TclWinThreadStart.
 */

typedef struct {







|


>
>
>







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
 */

#ifdef USE_THREAD_ALLOC
static DWORD tlsKey;

typedef struct {
    Tcl_Mutex tlock;
    WMutex wm;
} allocMutex;
#endif /* USE_THREAD_ALLOC */

static void WMutexInit(WMutex *);
static void WMutexDestroy(WMutex *);

/*
 * The per thread data passed from TclpThreadCreate
 * to TclWinThreadStart.
 */

typedef struct {
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
 */

Tcl_Mutex *
Tcl_GetAllocMutex(void)
{
#if TCL_THREADS
    if (!allocOnce) {
	InitializeCriticalSection(&allocLock.crit);
	allocOnce = 1;
    }
    return &allocLockPtr;
#else
    return NULL;
#endif
}

/*
 *----------------------------------------------------------------------







|


|







481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
 */

Tcl_Mutex *
Tcl_GetAllocMutex(void)
{
#if TCL_THREADS
    if (!allocOnce) {
	WMutexInit(&allocLock);
	allocOnce = 1;
    }
    return (Tcl_Mutex *) &allocLockPtr;
#else
    return NULL;
#endif
}

/*
 *----------------------------------------------------------------------
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
     */

    DeleteCriticalSection(&globalLock);
    initialized = 0;

#if TCL_THREADS
    if (allocOnce) {
	DeleteCriticalSection(&allocLock.crit);
	allocOnce = 0;
    }
#endif

    LeaveCriticalSection(&initLock);

    /*
     * Destroy the critical section that we were holding.
     */

    DeleteCriticalSection(&initLock);
}

#if TCL_THREADS






















































/* locally used prototype */
static void		FinalizeConditionEvent(void *data);

/*
 *----------------------------------------------------------------------
 *







|














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







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
     */

    DeleteCriticalSection(&globalLock);
    initialized = 0;

#if TCL_THREADS
    if (allocOnce) {
	WMutexDestroy(&allocLock);
	allocOnce = 0;
    }
#endif

    LeaveCriticalSection(&initLock);

    /*
     * Destroy the critical section that we were holding.
     */

    DeleteCriticalSection(&initLock);
}

#if TCL_THREADS

static void
WMutexInit(
    WMutex *wmPtr)
{
    InitializeCriticalSection(&wmPtr->crit);
    wmPtr->thread = 0;
    wmPtr->counter = 0;
}

static void
WMutexDestroy(
    WMutex *wmPtr)
{
    if (InterlockedOr(&wmPtr->thread, 0) != 0) {
	Tcl_Panic("mutex still owned");
    }
    DeleteCriticalSection(&wmPtr->crit);
}

static void
WMutexLock(
    WMutex *wmPtr)
{
    LONG mythread = GetCurrentThreadId();

    if (InterlockedOr(&wmPtr->thread, 0) == mythread) {
	// We owned the lock already, so it's recursive.
	wmPtr->counter++;
    } else {
	// We don't own the lock, so we can safely lock it. Then we own it.
	EnterCriticalSection(&wmPtr->crit);
	InterlockedExchange(&wmPtr->thread, mythread);
    }
}

static void
WMutexUnlock(
    WMutex *wmPtr)
{
    LONG mythread = GetCurrentThreadId();

    if (InterlockedOr(&wmPtr->thread, 0) != mythread) {
	Tcl_Panic("mutex not owned");
    }
    if (wmPtr->counter) {
	// It's recursive
	wmPtr->counter--;
    } else {
	InterlockedExchange(&wmPtr->thread, 0);
	LeaveCriticalSection(&wmPtr->crit);
    }
}

/* locally used prototype */
static void		FinalizeConditionEvent(void *data);

/*
 *----------------------------------------------------------------------
 *
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
 *	May block the current thread. The mutex is acquired when this returns.
 *
 *----------------------------------------------------------------------
 */

void
Tcl_MutexLock(
    Tcl_Mutex *mutexPtr)	/* The lock */
{
    CRITICAL_SECTION *csPtr;

    if (*mutexPtr == NULL) {
	TclpGlobalLock();

	/*
	 * Double inside global lock check to avoid a race.
	 */

	if (*mutexPtr == NULL) {
	    csPtr = (CRITICAL_SECTION *) Tcl_Alloc(sizeof(CRITICAL_SECTION));
	    InitializeCriticalSection(csPtr);
	    *mutexPtr = (Tcl_Mutex) csPtr;
	    TclRememberMutex(mutexPtr);
	}
	TclpGlobalUnlock();
    }
    csPtr = *((CRITICAL_SECTION **)mutexPtr);
    EnterCriticalSection(csPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_MutexUnlock --
 *
 *	This procedure is invoked to unlock a mutex.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The mutex is released when this returns.
 *
 *----------------------------------------------------------------------
 */

void
Tcl_MutexUnlock(
    Tcl_Mutex *mutexPtr)	/* The lock */
{
    CRITICAL_SECTION *csPtr = *((CRITICAL_SECTION **)mutexPtr);

    LeaveCriticalSection(csPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * TclpFinalizeMutex --
 *







|

|









|
|
|




|
|




















|

|
|
<







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
 *	May block the current thread. The mutex is acquired when this returns.
 *
 *----------------------------------------------------------------------
 */

void
Tcl_MutexLock(
    Tcl_Mutex *mutexPtr)	/* Really (WMutex **) */
{
    WMutex *wmPtr;

    if (*mutexPtr == NULL) {
	TclpGlobalLock();

	/*
	 * Double inside global lock check to avoid a race.
	 */

	if (*mutexPtr == NULL) {
	    wmPtr = (WMutex *) Tcl_Alloc(sizeof(WMutex));
	    WMutexInit(wmPtr);
	    *mutexPtr = (Tcl_Mutex) wmPtr;
	    TclRememberMutex(mutexPtr);
	}
	TclpGlobalUnlock();
    }
    wmPtr = *((WMutex **)mutexPtr);
    WMutexLock(wmPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_MutexUnlock --
 *
 *	This procedure is invoked to unlock a mutex.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The mutex is released when this returns.
 *
 *----------------------------------------------------------------------
 */

void
Tcl_MutexUnlock(
    Tcl_Mutex *mutexPtr)	/* Really (WMutex **) */
{
    WMutex *wmPtr = *((WMutex **)mutexPtr);
    WMutexUnlock(wmPtr);

}

/*
 *----------------------------------------------------------------------
 *
 * TclpFinalizeMutex --
 *
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
 *	The mutex list is deallocated.
 *
 *----------------------------------------------------------------------
 */

void
TclpFinalizeMutex(
    Tcl_Mutex *mutexPtr)
{
    CRITICAL_SECTION *csPtr = *(CRITICAL_SECTION **)mutexPtr;

    if (csPtr != NULL) {
	DeleteCriticalSection(csPtr);
	Tcl_Free(csPtr);
	*mutexPtr = NULL;
    }
}

/*
 *----------------------------------------------------------------------
 *







|

|

|
|
|







680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
 *	The mutex list is deallocated.
 *
 *----------------------------------------------------------------------
 */

void
TclpFinalizeMutex(
    Tcl_Mutex *mutexPtr)	/* Really (WMutex **) */
{
    WMutex *wmPtr = *(WMutex **)mutexPtr;

    if (wmPtr != NULL) {
	WMutexDestroy(wmPtr);
	Tcl_Free(wmPtr);
	*mutexPtr = NULL;
    }
}

/*
 *----------------------------------------------------------------------
 *
656
657
658
659
660
661
662
663
664
665

666
667
668
669
670
671
672
void
Tcl_ConditionWait(
    Tcl_Condition *condPtr,	/* Really (WinCondition **) */
    Tcl_Mutex *mutexPtr,	/* Really (CRITICAL_SECTION **) */
    const Tcl_Time *timePtr)	/* Timeout on waiting period */
{
    WinCondition *winCondPtr;	/* Per-condition queue head */
    CRITICAL_SECTION *csPtr;	/* Caller's Mutex, after casting */
    DWORD wtime;		/* Windows time value */
    int timeout;		/* True if we got a timeout */

    int doExit = 0;		/* True if we need to do exit setup */
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    /*
     * Self initialize the two parts of the condition. The per-condition and
     * per-thread parts need to be handled independently.
     */







|


>







720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
void
Tcl_ConditionWait(
    Tcl_Condition *condPtr,	/* Really (WinCondition **) */
    Tcl_Mutex *mutexPtr,	/* Really (CRITICAL_SECTION **) */
    const Tcl_Time *timePtr)	/* Timeout on waiting period */
{
    WinCondition *winCondPtr;	/* Per-condition queue head */
    WMutex *wmPtr;		/* Caller's Mutex, after casting */
    DWORD wtime;		/* Windows time value */
    int timeout;		/* True if we got a timeout */
    int counter;		/* Caller's Mutex counter */
    int doExit = 0;		/* True if we need to do exit setup */
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    /*
     * Self initialize the two parts of the condition. The per-condition and
     * per-thread parts need to be handled independently.
     */
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
	    winCondPtr->firstPtr = NULL;
	    winCondPtr->lastPtr = NULL;
	    *condPtr = (Tcl_Condition) winCondPtr;
	    TclRememberCondition(condPtr);
	}
	TclpGlobalUnlock();
    }
    csPtr = *((CRITICAL_SECTION **)mutexPtr);
    winCondPtr = *((WinCondition **)condPtr);
    if (timePtr == NULL) {
	wtime = INFINITE;
    } else {
	wtime = (DWORD)timePtr->sec * 1000 + (DWORD)timePtr->usec / 1000;
    }








|







778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
	    winCondPtr->firstPtr = NULL;
	    winCondPtr->lastPtr = NULL;
	    *condPtr = (Tcl_Condition) winCondPtr;
	    TclRememberCondition(condPtr);
	}
	TclpGlobalUnlock();
    }
    wmPtr = *((WMutex **)mutexPtr);
    winCondPtr = *((WinCondition **)condPtr);
    if (timePtr == NULL) {
	wtime = INFINITE;
    } else {
	wtime = (DWORD)timePtr->sec * 1000 + (DWORD)timePtr->usec / 1000;
    }

748
749
750
751
752
753
754



755
756
757
758
759
760
761
762
     * we get notified, but another thread grabs the condition before we do.
     * In that race condition we'll wait again for the full timeout. Timed
     * waits are dubious anyway. Either you have the locking protocol wrong
     * and are masking a deadlock, or you are using conditions to pause your
     * thread.
     */




    LeaveCriticalSection(csPtr);
    timeout = 0;
    while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) {
	ResetEvent(tsdPtr->condEvent);
	LeaveCriticalSection(&winCondPtr->condLock);
	if (WaitForSingleObjectEx(tsdPtr->condEvent, wtime,
		TRUE) == WAIT_TIMEOUT) {
	    timeout = 1;







>
>
>
|







813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
     * we get notified, but another thread grabs the condition before we do.
     * In that race condition we'll wait again for the full timeout. Timed
     * waits are dubious anyway. Either you have the locking protocol wrong
     * and are masking a deadlock, or you are using conditions to pause your
     * thread.
     */

    counter = wmPtr->counter;
    wmPtr->counter = 0;
    InterlockedExchange(&wmPtr->thread, 0);
    LeaveCriticalSection(&wmPtr->crit);
    timeout = 0;
    while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) {
	ResetEvent(tsdPtr->condEvent);
	LeaveCriticalSection(&winCondPtr->condLock);
	if (WaitForSingleObjectEx(tsdPtr->condEvent, wtime,
		TRUE) == WAIT_TIMEOUT) {
	    timeout = 1;
791
792
793
794
795
796
797
798


799
800
801
802
803
804
805
		tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
	    }
	    tsdPtr->flags = WIN_THREAD_RUNNING;
	}
    }

    LeaveCriticalSection(&winCondPtr->condLock);
    EnterCriticalSection(csPtr);


}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ConditionNotify --
 *







|
>
>







859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
		tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
	    }
	    tsdPtr->flags = WIN_THREAD_RUNNING;
	}
    }

    LeaveCriticalSection(&winCondPtr->condLock);
    EnterCriticalSection(&wmPtr->crit);
    wmPtr->counter = counter;
    InterlockedExchange(&wmPtr->thread, GetCurrentThreadId());
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ConditionNotify --
 *
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
{
    allocMutex *lockPtr;

    lockPtr = (allocMutex *)malloc(sizeof(allocMutex));
    if (lockPtr == NULL) {
	Tcl_Panic("could not allocate lock");
    }
    lockPtr->tlock = (Tcl_Mutex) &lockPtr->wlock;
    InitializeCriticalSection(&lockPtr->wlock);
    return &lockPtr->tlock;
}

void
TclpFreeAllocMutex(
    Tcl_Mutex *mutex)		/* The alloc mutex to free. */
{
    allocMutex *lockPtr = (allocMutex *) mutex;

    if (!lockPtr) {
	return;
    }

    DeleteCriticalSection(&lockPtr->wlock);
    free(lockPtr);
}

void
TclpInitAllocCache(void)
{
    /*







|
|









|


>
|







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
{
    allocMutex *lockPtr;

    lockPtr = (allocMutex *)malloc(sizeof(allocMutex));
    if (lockPtr == NULL) {
	Tcl_Panic("could not allocate lock");
    }
    lockPtr->tlock = (Tcl_Mutex)&lockPtr->wm;
    WMutexInit(&lockPtr->wm);
    return &lockPtr->tlock;
}

void
TclpFreeAllocMutex(
    Tcl_Mutex *mutex)		/* The alloc mutex to free. */
{
    allocMutex *lockPtr = (allocMutex *) mutex;

    if (!lockPtr || !lockPtr->tlock) {
	return;
    }
    lockPtr->tlock = NULL;
    WMutexDestroy(&lockPtr->wm);
    free(lockPtr);
}

void
TclpInitAllocCache(void)
{
    /*