Tcl Source Code

Changes On Branch core-9-0-branch
Login

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

Changes In Branch core-9-0-branch Excluding Merge-Ins

This is equivalent to a diff from 2ed32fc21a to 57d18c0efc

2025-03-11
18:37
merge 9.0 (fix for [482db1d796540e68]) Leaf check-in: 16f05b6fc9 user: sebres tags: trunk, main
18:36
merge 8.7: fixes [482db1d796540e68], some minor optimizations and another corner cases for a compile... Leaf check-in: 57d18c0efc user: sebres tags: core-9-0-branch
18:31
more cases for a compiler "fix" (signed-mod operation with potentially negative dividend) Leaf check-in: e33fcd57b0 user: sebres tags: core-8-branch
08:27
Update to appleboy/ssh-action@v1.2.2 check-in: 10c5cb8279 user: jan.nijtmans tags: core-9-0-branch
2025-02-19
08:36
Make a start with 9.1 development, as preparation for TIP #711 check-in: 0950b29f08 user: jan.nijtmans tags: trunk, main
08:29
Split off "9.0" branch, as preparation for TIP #711 check-in: 975a904f7f user: jan.nijtmans tags: core-9-0-branch
05:43
Fix [f5d0e75a49]. Correct tcl::process documentation for non-subprocesses check-in: 2ed32fc21a user: apnadkarni tags: trunk, main
2025-02-18
13:39
Be consistant in .VS/.VE tags in documentation: Just mention TIP number, nothing else. check-in: 9bab6a1ff0 user: jan.nijtmans tags: trunk, main
2025-02-11
17:09
Bug f5d0e75a49 - correct tcl::process documentation for non-subprocesses Closed-Leaf check-in: 7a71c8de17 user: apnadkarni tags: bug-f5d0e75a49

Changes to .github/workflows/onefiledist.yml.
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
          remote_path: ${{ env.REMOTE_PATH }}
          remote_host: ${{ vars.PUBLISH_HOST }}
          remote_user: ${{ vars.PUBLISH_USER }}
          remote_key: ${{ secrets.DEPLOY_HOST_KEY }}
          # MUST be a literal passwordless key
      - name: Publish files
        # https://github.com/marketplace/actions/ssh-remote-commands
        uses: appleboy/ssh-action@v1.2.0
        id: ssh
        if: steps.rsync.outcome == 'success'
        with:
          host: ${{ vars.PUBLISH_HOST }}
          username: ${{ vars.PUBLISH_USER }}
          key: ${{ secrets.DEPLOY_HOST_KEY }}
          script: |







|







215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
          remote_path: ${{ env.REMOTE_PATH }}
          remote_host: ${{ vars.PUBLISH_HOST }}
          remote_user: ${{ vars.PUBLISH_USER }}
          remote_key: ${{ secrets.DEPLOY_HOST_KEY }}
          # MUST be a literal passwordless key
      - name: Publish files
        # https://github.com/marketplace/actions/ssh-remote-commands
        uses: appleboy/ssh-action@v1.2.2
        id: ssh
        if: steps.rsync.outcome == 'success'
        with:
          host: ${{ vars.PUBLISH_HOST }}
          username: ${{ vars.PUBLISH_USER }}
          key: ${{ secrets.DEPLOY_HOST_KEY }}
          script: |
Changes to README.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# README:  Tcl

This is the **Tcl 9.0.2** source distribution.

You can get any source release of Tcl from [our distribution
site](https://sourceforge.net/projects/tcl/files/Tcl/).

9.0 (production release, daily build)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/linux-build.yml/badge.svg?branch=main)](https://github.com/tcltk/tcl/actions/workflows/linux-build.yml?query=branch%3Amain)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/win-build.yml/badge.svg?branch=main)](https://github.com/tcltk/tcl/actions/workflows/win-build.yml?query=branch%3Amain)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/mac-build.yml/badge.svg?branch=main)](https://github.com/tcltk/tcl/actions/workflows/mac-build.yml?query=branch%3Amain)
<br>
8.7 (in development, daily build)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/linux-build.yml/badge.svg?branch=core-8-branch)](https://github.com/tcltk/tcl/actions/workflows/linux-build.yml?query=branch%3Acore-8-branch)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/win-build.yml/badge.svg?branch=core-8-branch)](https://github.com/tcltk/tcl/actions/workflows/win-build.yml?query=branch%3Acore-8-branch)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/mac-build.yml/badge.svg?branch=core-8-branch)](https://github.com/tcltk/tcl/actions/workflows/mac-build.yml?query=branch%3Acore-8-branch)

## Contents
 1. [Introduction](#intro)
 2. [Documentation](#doc)
 3. [Compiling and installing Tcl](#build)
 4. [Development tools](#devtools)
 5. [Tcl newsgroup](#complangtcl)







|




|
|
|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# README:  Tcl

This is the **Tcl 9.0.2** source distribution.

You can get any source release of Tcl from [our distribution
site](https://sourceforge.net/projects/tcl/files/Tcl/).

9.1 (in development, daily build)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/linux-build.yml/badge.svg?branch=main)](https://github.com/tcltk/tcl/actions/workflows/linux-build.yml?query=branch%3Amain)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/win-build.yml/badge.svg?branch=main)](https://github.com/tcltk/tcl/actions/workflows/win-build.yml?query=branch%3Amain)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/mac-build.yml/badge.svg?branch=main)](https://github.com/tcltk/tcl/actions/workflows/mac-build.yml?query=branch%3Amain)
<br>
9.0 (production release, daily build)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/linux-build.yml/badge.svg?branch=core-9-0-branch)](https://github.com/tcltk/tcl/actions/workflows/linux-build.yml?query=branch%3Acore-9-0-branch)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/win-build.yml/badge.svg?branch=core-9-0-branch)](https://github.com/tcltk/tcl/actions/workflows/win-build.yml?query=branch%3Acore-9-0-branch)
[![Build Status](https://github.com/tcltk/tcl/actions/workflows/mac-build.yml/badge.svg?branch=core-9-0-branch)](https://github.com/tcltk/tcl/actions/workflows/mac-build.yml?query=branch%3Acore-9-0-branch)

## Contents
 1. [Introduction](#intro)
 2. [Documentation](#doc)
 3. [Compiling and installing Tcl](#build)
 4. [Development tools](#devtools)
 5. [Tcl newsgroup](#complangtcl)
Changes to changes.md.
10
11
12
13
14
15
16





17
18
19
20
21
22
23
24
25
26
27
28
29
to the userbase.

# Bug fixes
 - [Better error-message than "interpreter uses an incompatible stubs mechanism"](https://core.tcl-lang.org/tcl/tktview/fc3509)
 - [$interp eval $lambda] after [eval $lambda] or vice versa fails](https://core.tcl-lang.org/tcl/tktview/98006f)
 - [tcl::mathfunc::isunordered inconsistency with some integer values](https://core.tcl-lang.org/tcl/tktview/67d5f7)
 - [test lseq hangs with -Os](https://core.tcl-lang.org/tcl/tktview/d2a3c5)






# Incompatibilities
 - No known incompatibilities with the Tcl 9.0.0 public interface.

# Updated bundled packages, libraries, standards, data
 - sqlite3 3.48.0
 - tzdata 2025a

Release Tcl 9.0.1 arises from the check-in with tag `core-9-0-1`.

Tcl patch releases have the primary purpose of delivering bug fixes
to the userbase.  As the first patch release in the Tcl 9.0.\* series,
Tcl 9.0.1 also includes a small number of interface changes that complete







>
>
>
>
>





|







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
to the userbase.

# Bug fixes
 - [Better error-message than "interpreter uses an incompatible stubs mechanism"](https://core.tcl-lang.org/tcl/tktview/fc3509)
 - [$interp eval $lambda] after [eval $lambda] or vice versa fails](https://core.tcl-lang.org/tcl/tktview/98006f)
 - [tcl::mathfunc::isunordered inconsistency with some integer values](https://core.tcl-lang.org/tcl/tktview/67d5f7)
 - [test lseq hangs with -Os](https://core.tcl-lang.org/tcl/tktview/d2a3c5)
 - [exec does not handle app execution aliases on Windows](https://core.tcl-lang.org/tcl/tktview/4f0b57)
 - [auto_execok does not find several built-in cmd commands](https://core.tcl-lang.org/tcl/tktview/4e2c8b)
 - [Panic "Buffer Underflow, BUFFER_PADDING not enough"](https://core.tcl-lang.org/tcl/tktview/73bb42)
 - [MS-VS build system: pckIndex.tcl when building for 9 misses "t" for TCL 8.6 part](https://core.tcl-lang.org/tcl/tktview/a77029)
 - [clock format -locale does not look up locale children if parent locale used first](https://core.tcl-lang.org/tcl/tktview/2c0f49)

# Incompatibilities
 - No known incompatibilities with the Tcl 9.0.0 public interface.

# Updated bundled packages, libraries, standards, data
 - sqlite3 3.49.1
 - tzdata 2025a

Release Tcl 9.0.1 arises from the check-in with tag `core-9-0-1`.

Tcl patch releases have the primary purpose of delivering bug fixes
to the userbase.  As the first patch release in the Tcl 9.0.\* series,
Tcl 9.0.1 also includes a small number of interface changes that complete
Changes to doc/StringObj.3.
206
207
208
209
210
211
212
213
214

215
216
217
218
219
220
221
222
223
224
225
representation.
.PP
\fBTcl_GetUniChar\fR returns the \fIindex\fR'th character in the
value's Unicode representation. If the index is out of range
it returns -1;
.PP
\fBTcl_GetRange\fR returns a newly created value comprised of the
characters between \fIfirst\fR and \fIlast\fR (inclusive) in the value's
Unicode representation.  If the value's Unicode representation

is invalid, the Unicode representation is regenerated from the value's
string representation.  If \fIfirst\fR is negative, then the returned
string starts at the beginning of the value. If \fIlast\fR is negative,
then the returned string ends at the end of the value.
.PP
\fBTcl_GetCharLength\fR returns the number of characters (as opposed
to bytes) in the string value.
.PP
\fBTcl_AppendToObj\fR appends the data given by \fIbytes\fR and
\fIlength\fR to the string representation of the value specified by
\fIobjPtr\fR.  If the value has an invalid string representation,







|
|
>
|
|
|
|







206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
representation.
.PP
\fBTcl_GetUniChar\fR returns the \fIindex\fR'th character in the
value's Unicode representation. If the index is out of range
it returns -1;
.PP
\fBTcl_GetRange\fR returns a newly created value comprised of the
characters between \fIfirst\fR and \fIlast\fR (inclusive) in the
value's Unicode or byte-array representation.  If the value is not
a byte-array and the values Unicode representation is invalid, the
Unicode representation is regenerated from the value's string
representation.  If \fIfirst\fR is negative, then the returned
string starts at the beginning of the value. If \fIlast\fR is
negative, then the returned string ends at the end of the value.
.PP
\fBTcl_GetCharLength\fR returns the number of characters (as opposed
to bytes) in the string value.
.PP
\fBTcl_AppendToObj\fR appends the data given by \fIbytes\fR and
\fIlength\fR to the string representation of the value specified by
\fIobjPtr\fR.  If the value has an invalid string representation,
Changes to doc/Utf.3.
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
.sp
unsigned short *
\fBTcl_UtfToChar16DString\fR(\fIsrc, numBytes, dsPtr\fR)
.sp
wchar_t *
\fBTcl_UtfToWCharDString\fR(\fIsrc, numBytes, dsPtr\fR)
.sp
int
\fBTcl_Char16Len\fR(\fIutf16\fR)
.sp
int
\fBTcl_WCharLen\fR(\fIwcharStr\fR)
.sp
int
\fBTcl_UniCharLen\fR(\fIuniStr\fR)
.sp
int
\fBTcl_UniCharNcmp\fR(\fIucs, uct, uniLength\fR)
.sp
int
\fBTcl_UniCharNcasecmp\fR(\fIucs, uct, uniLength\fR)
.sp
int
\fBTcl_UniCharCaseMatch\fR(\fIuniStr, uniPattern, nocase\fR)
.sp
int
\fBTcl_UtfNcmp\fR(\fIcs, ct, length\fR)
.sp
int
\fBTcl_UtfNcasecmp\fR(\fIcs, ct, length\fR)
.sp
int
\fBTcl_UtfCharComplete\fR(\fIsrc, numBytes\fR)
.sp
int
\fBTcl_NumUtfChars\fR(\fIsrc, numBytes\fR)
.sp
const char *
\fBTcl_UtfFindFirst\fR(\fIsrc, ch\fR)
.sp
const char *
\fBTcl_UtfFindLast\fR(\fIsrc, ch\fR)







|


|


|




















|







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
.sp
unsigned short *
\fBTcl_UtfToChar16DString\fR(\fIsrc, numBytes, dsPtr\fR)
.sp
wchar_t *
\fBTcl_UtfToWCharDString\fR(\fIsrc, numBytes, dsPtr\fR)
.sp
Tcl_Size
\fBTcl_Char16Len\fR(\fIutf16\fR)
.sp
Tcl_Size
\fBTcl_WCharLen\fR(\fIwcharStr\fR)
.sp
Tcl_Size
\fBTcl_UniCharLen\fR(\fIuniStr\fR)
.sp
int
\fBTcl_UniCharNcmp\fR(\fIucs, uct, uniLength\fR)
.sp
int
\fBTcl_UniCharNcasecmp\fR(\fIucs, uct, uniLength\fR)
.sp
int
\fBTcl_UniCharCaseMatch\fR(\fIuniStr, uniPattern, nocase\fR)
.sp
int
\fBTcl_UtfNcmp\fR(\fIcs, ct, length\fR)
.sp
int
\fBTcl_UtfNcasecmp\fR(\fIcs, ct, length\fR)
.sp
int
\fBTcl_UtfCharComplete\fR(\fIsrc, numBytes\fR)
.sp
Tcl_Size
\fBTcl_NumUtfChars\fR(\fIsrc, numBytes\fR)
.sp
const char *
\fBTcl_UtfFindFirst\fR(\fIsrc, ch\fR)
.sp
const char *
\fBTcl_UtfFindLast\fR(\fIsrc, ch\fR)
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
\fBTcl_UniCharToUtfDString\fR and \fBTcl_UtfToUniCharDString\fR except they
operate on sequences of \fBUTF-16\fR units instead of \fBTcl_UniChar\fR.
.PP
\fBTcl_Char16Len\fR corresponds to \fBstrlen\fR for UTF-16
characters.  It accepts a null-terminated UTF-16 sequence and returns
the number of UTF-16 units until the null.
.PP
\fBTcl_WCharLen\fR corresponds to \fBstrlen\fR for wchar_t
characters.  It accepts a null-terminated \fBwchar_t\fR sequence and returns
the number of \fBwchar_t\fR units until the null.
.PP
\fBTcl_UniCharLen\fR corresponds to \fBstrlen\fR for Unicode
characters.  It accepts a null-terminated Unicode string and returns
the number of Unicode characters (not bytes) in that string.
.PP







|







210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
\fBTcl_UniCharToUtfDString\fR and \fBTcl_UtfToUniCharDString\fR except they
operate on sequences of \fBUTF-16\fR units instead of \fBTcl_UniChar\fR.
.PP
\fBTcl_Char16Len\fR corresponds to \fBstrlen\fR for UTF-16
characters.  It accepts a null-terminated UTF-16 sequence and returns
the number of UTF-16 units until the null.
.PP
\fBTcl_WCharLen\fR corresponds to \fBstrlen\fR for \fBwchar_t\fR
characters.  It accepts a null-terminated \fBwchar_t\fR sequence and returns
the number of \fBwchar_t\fR units until the null.
.PP
\fBTcl_UniCharLen\fR corresponds to \fBstrlen\fR for Unicode
characters.  It accepts a null-terminated Unicode string and returns
the number of Unicode characters (not bytes) in that string.
.PP
Changes to doc/return.n.
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
        \fBreturn\fR -code error \e
                "expected non-negative integer,\e
                but got \e"$n\e""
    }
    if {$n < 2} {
        \fBreturn\fR 1
    }
    set m [expr {$n - 1}]
    set code [catch {factorial $m} factor]
    if {$code != 0} {
        \fBreturn\fR -code $code $factor
    }
    set product [expr {$n * $factor}]
    if {$product < 0} {
        \fBreturn\fR -code error \e
                "overflow computing factorial of $n"
    }
    \fBreturn\fR $product
}
.CE
.PP
Next, a procedure replacement for \fBbreak\fR.
.PP
.CS







|
<
<
<
<

<
<
<
<







261
262
263
264
265
266
267
268




269




270
271
272
273
274
275
276
        \fBreturn\fR -code error \e
                "expected non-negative integer,\e
                but got \e"$n\e""
    }
    if {$n < 2} {
        \fBreturn\fR 1
    }
    set factor [factorial [expr {$n - 1}]]




    set product [expr {$n * $factor}]




    \fBreturn\fR $product
}
.CE
.PP
Next, a procedure replacement for \fBbreak\fR.
.PP
.CS
Changes to generic/tclClock.c.
4083
4084
4085
4086
4087
4088
4089



4090
4091
4092
4093
4094
4095
4096
	    || (info->flags & CLF_ORDINALMONTH)
	    || ((info->flags & CLF_RELCONV)
	    && (yyRelMonth != 0 || yyRelDay != 0))) {
	yySecondOfDay = 0;
	info->flags |= CLF_ASSEMBLE_SECONDS;
    } else {
	yySecondOfDay = yydate.localSeconds % SECONDS_PER_DAY;



    }

    /*
     * Do relative times
     */

    ret = ClockCalcRelTime(info);







>
>
>







4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
	    || (info->flags & CLF_ORDINALMONTH)
	    || ((info->flags & CLF_RELCONV)
	    && (yyRelMonth != 0 || yyRelDay != 0))) {
	yySecondOfDay = 0;
	info->flags |= CLF_ASSEMBLE_SECONDS;
    } else {
	yySecondOfDay = yydate.localSeconds % SECONDS_PER_DAY;
	if (yySecondOfDay < 0) { /* compiler fix for signed-mod */
	    yySecondOfDay += SECONDS_PER_DAY;
	}
    }

    /*
     * Do relative times
     */

    ret = ClockCalcRelTime(info);
4147
4148
4149
4150
4151
4152
4153
4154
4155

4156
4157
4158
4159
4160
4161
4162
4163
4164
		info->flags &= ~CLF_ASSEMBLE_DATE;
	    }

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

		yyYear--;
		m = 12 + m;
	    }
	    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;







|

>

<







4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160

4161
4162
4163
4164
4165
4166
4167
		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;
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195


4196


4197
4198
4199
4200
4201
4202
4203

	/* relative time (seconds), if exceeds current date, do the day conversion and
	 * leave rest of the increment in yyRelSeconds to add it hereafter in UTC seconds */
	if (yyRelSeconds) {
	    Tcl_WideInt newSecs = yySecondOfDay + yyRelSeconds;

	    /* if seconds increment outside of current date, increment day */
	    if (newSecs / SECONDS_PER_DAY != yySecondOfDay / SECONDS_PER_DAY) {
		yyRelDay += newSecs / SECONDS_PER_DAY;
		yySecondOfDay = 0;


		yyRelSeconds = newSecs % SECONDS_PER_DAY;



		goto repeat_rel;
	    }
	}

	info->flags &= ~CLF_RELCONV;
    }







|


>
>
|
>
>







4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210

	/* relative time (seconds), if exceeds current date, do the day conversion and
	 * leave rest of the increment in yyRelSeconds to add it hereafter in UTC seconds */
	if (yyRelSeconds) {
	    Tcl_WideInt newSecs = yySecondOfDay + yyRelSeconds;

	    /* if seconds increment outside of current date, increment day */
            if (newSecs / SECONDS_PER_DAY != yySecondOfDay / SECONDS_PER_DAY) {
		yyRelDay += newSecs / SECONDS_PER_DAY;
		yySecondOfDay = 0;
		yyRelSeconds = (newSecs %= SECONDS_PER_DAY);
		if (newSecs < 0) { /* compiler fix for signed-mod */
		    yyRelSeconds += SECONDS_PER_DAY;
		    yyRelDay--;
		}

		goto repeat_rel;
	    }
	}

	info->flags &= ~CLF_RELCONV;
    }
4288
4289
4290
4291
4292
4293
4294

4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
    int weeks, resDayOfWeek;

    /* offset in days */
    weeks = offs / 5;
    offs = offs % 5;
    /* compiler fix for negative offs - wrap (0, -1) -> (-1, 4) */
    if (offs < 0) {

	weeks--;
	offs = 5 + offs;
    }
    offs += 7 * weeks;

    /* resulting day of week */
    {
	int day = (offs % 7);

	/* compiler fix for negative offs - wrap (0, -1) -> (-1, 6) */
	if (day < 0) {
	    day = 7 + day;
	}
	resDayOfWeek = dayOfWeek + day;
    }

    /* adjust if we start from a weekend */
    if (dayOfWeek > 5) {
	int adj = 5 - dayOfWeek;







>

<









|







4295
4296
4297
4298
4299
4300
4301
4302
4303

4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
    int weeks, resDayOfWeek;

    /* offset in days */
    weeks = offs / 5;
    offs = offs % 5;
    /* compiler fix for negative offs - wrap (0, -1) -> (-1, 4) */
    if (offs < 0) {
	offs += 5;
	weeks--;

    }
    offs += 7 * weeks;

    /* resulting day of week */
    {
	int day = (offs % 7);

	/* compiler fix for negative offs - wrap (0, -1) -> (-1, 6) */
	if (day < 0) {
	    day += 7;
	}
	resDayOfWeek = dayOfWeek + day;
    }

    /* adjust if we start from a weekend */
    if (dayOfWeek > 5) {
	int adj = 5 - dayOfWeek;
4414
4415
4416
4417
4418
4419
4420
4421




4422
4423
4424
4425
4426
4427
4428
    ret = ClockParseFmtScnArgs(&opts, &yy.date, objc, objv,
	    CLC_OP_ADD, "-gmt, -locale, or -timezone");
    if (ret != TCL_OK) {
	goto done;
    }

    /* time together as seconds of the day */
    yySecondOfDay = yySeconds = yydate.localSeconds % SECONDS_PER_DAY;




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

    ret = TCL_ERROR;








|
>
>
>
>







4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
    ret = ClockParseFmtScnArgs(&opts, &yy.date, objc, objv,
	    CLC_OP_ADD, "-gmt, -locale, or -timezone");
    if (ret != TCL_OK) {
	goto done;
    }

    /* time together as seconds of the day */
    yySecondOfDay = yydate.localSeconds % SECONDS_PER_DAY;
    if (yySecondOfDay < 0) { /* compiler fix for signed-mod */
	yySecondOfDay += SECONDS_PER_DAY;
    }
    yySeconds = yySecondOfDay;
    /* seconds are in localSeconds (relative base date), so reset time here */
    yyHour = 0;
    yyMinutes = 0;
    yyMeridian = MER24;

    ret = TCL_ERROR;

Changes to generic/tclCmdMZ.c.
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517

	    /*
	     * Calculate next threshold to check.
	     * Firstly check iteration time is not larger than remaining time,
	     * considering last known iteration growth factor.
	     */
	    threshold = (Tcl_WideUInt)(stop - middle) * TR_SCALE;
	     /* 
	      * Estimated count of iteration til the end of execution.
	      * Thereby 2.5% longer execution time would be OK.
	      */
	    if (threshold / estIterTm < 0.975) {
		/* estimated time for next iteration is too large */
		break;
	    }







|







4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517

	    /*
	     * Calculate next threshold to check.
	     * Firstly check iteration time is not larger than remaining time,
	     * considering last known iteration growth factor.
	     */
	    threshold = (Tcl_WideUInt)(stop - middle) * TR_SCALE;
	     /*
	      * Estimated count of iteration til the end of execution.
	      * Thereby 2.5% longer execution time would be OK.
	      */
	    if (threshold / estIterTm < 0.975) {
		/* estimated time for next iteration is too large */
		break;
	    }
Changes to generic/tclCompCmds.c.
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502

3503
3504
3505
3506
3507
3508
3509
3510
    CompileEnv *envPtr,		/* Holds resulting instructions. */
    int flags,			/* TCL_NO_LARGE_INDEX | TCL_NO_ELEMENT. */
    int *localIndexPtr,		/* Must not be NULL. */
    int *isScalarPtr)		/* Must not be NULL. */
{
    const char *p;
    const char *last, *name, *elName;
    size_t n;
    Tcl_Token *elemTokenPtr = NULL;
	size_t nameLen, elNameLen;
    int simpleVarName, localIndex;

    int elemTokenCount = 0, allocedTokens = 0, removedParen = 0;

    /*
     * Decide if we can use a frame slot for the var/array name or if we need
     * to emit code to compute and push the name at runtime. We use a frame
     * slot (entry in the array of local vars) if we are compiling a procedure
     * body and if the name is simple text that does not include namespace
     * qualifiers.







|



>
|







3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
    CompileEnv *envPtr,		/* Holds resulting instructions. */
    int flags,			/* TCL_NO_LARGE_INDEX | TCL_NO_ELEMENT. */
    int *localIndexPtr,		/* Must not be NULL. */
    int *isScalarPtr)		/* Must not be NULL. */
{
    const char *p;
    const char *last, *name, *elName;
    Tcl_Size n;
    Tcl_Token *elemTokenPtr = NULL;
	size_t nameLen, elNameLen;
    int simpleVarName, localIndex;
    Tcl_Size elemTokenCount = 0, removedParen = 0;
    int allocedTokens = 0;

    /*
     * Decide if we can use a frame slot for the var/array name or if we need
     * to emit code to compute and push the name at runtime. We use a frame
     * slot (entry in the array of local vars) if we are compiling a procedure
     * body and if the name is simple text that does not include namespace
     * qualifiers.
Changes to generic/tclCompile.c.
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
}

void
TclCompileTokens(
    Tcl_Interp *interp,		/* Used for error and status reporting. */
    Tcl_Token *tokenPtr,	/* Pointer to first in an array of tokens to
				 * compile. */
    size_t count1,		/* Number of tokens to consider at tokenPtr.
				 * Must be at least 1. */
    CompileEnv *envPtr)		/* Holds the resulting instructions. */
{
    Tcl_DString textBuffer;	/* Holds concatenated chars from adjacent
				 * TCL_TOKEN_TEXT, TCL_TOKEN_BS tokens. */
    char buffer[4] = "";
    Tcl_Size i, numObjsToConcat, adjust;
    size_t length;
    unsigned char *entryCodeNext = envPtr->codeNext;
#define NUM_STATIC_POS 20
    int isLiteral;
    Tcl_Size maxNumCL, numCL;
    Tcl_Size *clPosition = NULL;
    int depth = TclGetStackDepth(envPtr);
    int count = count1;

    /*
     * If this is actually a literal, handle continuation lines by
     * preallocating a small table to store the locations of any continuation
     * lines found in this literal.  The table is extended if needed.
     *
     * Note: In contrast with the analagous code in 'TclSubstTokens()' the







|







|






<







2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437

2438
2439
2440
2441
2442
2443
2444
}

void
TclCompileTokens(
    Tcl_Interp *interp,		/* Used for error and status reporting. */
    Tcl_Token *tokenPtr,	/* Pointer to first in an array of tokens to
				 * compile. */
    Tcl_Size count,		/* Number of tokens to consider at tokenPtr.
				 * Must be at least 1. */
    CompileEnv *envPtr)		/* Holds the resulting instructions. */
{
    Tcl_DString textBuffer;	/* Holds concatenated chars from adjacent
				 * TCL_TOKEN_TEXT, TCL_TOKEN_BS tokens. */
    char buffer[4] = "";
    Tcl_Size i, numObjsToConcat, adjust;
    int length;
    unsigned char *entryCodeNext = envPtr->codeNext;
#define NUM_STATIC_POS 20
    int isLiteral;
    Tcl_Size maxNumCL, numCL;
    Tcl_Size *clPosition = NULL;
    int depth = TclGetStackDepth(envPtr);


    /*
     * If this is actually a literal, handle continuation lines by
     * preallocating a small table to store the locations of any continuation
     * lines found in this literal.  The table is extended if needed.
     *
     * Note: In contrast with the analagous code in 'TclSubstTokens()' the
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
 */

void
TclCompileCmdWord(
    Tcl_Interp *interp,		/* Used for error and status reporting. */
    Tcl_Token *tokenPtr,	/* Pointer to first in an array of tokens for
				 * a command word to compile inline. */
    size_t count1,			/* Number of tokens to consider at tokenPtr.
				 * Must be at least 1. */
    CompileEnv *envPtr)		/* Holds the resulting instructions. */
{
    int count = count1;

    if ((count == 1) && (tokenPtr->type == TCL_TOKEN_TEXT)) {
	/*
	 * The common case that there is a single text token. Compile it
	 * into an inline sequence of instructions.
	 */








|



<







2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644

2645
2646
2647
2648
2649
2650
2651
 */

void
TclCompileCmdWord(
    Tcl_Interp *interp,		/* Used for error and status reporting. */
    Tcl_Token *tokenPtr,	/* Pointer to first in an array of tokens for
				 * a command word to compile inline. */
    Tcl_Size count,		/* Number of tokens to consider at tokenPtr.
				 * Must be at least 1. */
    CompileEnv *envPtr)		/* Holds the resulting instructions. */
{


    if ((count == 1) && (tokenPtr->type == TCL_TOKEN_TEXT)) {
	/*
	 * The common case that there is a single text token. Compile it
	 * into an inline sequence of instructions.
	 */

Changes to generic/tclCompile.h.
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

MODULE_SCOPE int	TclAttemptCompileProc(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Tcl_Size depth, Command *cmdPtr,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCleanupStackForBreakContinue(CompileEnv *envPtr,
			    ExceptionAux *auxPtr);
MODULE_SCOPE void	TclCompileCmdWord(Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, size_t count,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileExpr(Tcl_Interp *interp, const char *script,
			    Tcl_Size numBytes, CompileEnv *envPtr, int optimize);
MODULE_SCOPE void	TclCompileExprWords(Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, size_t numWords,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileInvocation(Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, Tcl_Obj *cmdObj, size_t numWords,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileScript(Tcl_Interp *interp,
			    const char *script, Tcl_Size numBytes,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileSyntaxError(Tcl_Interp *interp,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileTokens(Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, size_t count,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileVarSubst(Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, CompileEnv *envPtr);
MODULE_SCOPE Tcl_Size	TclCreateAuxData(void *clientData,
			    const AuxDataType *typePtr, CompileEnv *envPtr);
MODULE_SCOPE Tcl_Size	TclCreateExceptRange(ExceptionRangeType type,
			    CompileEnv *envPtr);







|















|







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

MODULE_SCOPE int	TclAttemptCompileProc(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Tcl_Size depth, Command *cmdPtr,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCleanupStackForBreakContinue(CompileEnv *envPtr,
			    ExceptionAux *auxPtr);
MODULE_SCOPE void	TclCompileCmdWord(Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, Tcl_Size count,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileExpr(Tcl_Interp *interp, const char *script,
			    Tcl_Size numBytes, CompileEnv *envPtr, int optimize);
MODULE_SCOPE void	TclCompileExprWords(Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, size_t numWords,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileInvocation(Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, Tcl_Obj *cmdObj, size_t numWords,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileScript(Tcl_Interp *interp,
			    const char *script, Tcl_Size numBytes,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileSyntaxError(Tcl_Interp *interp,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileTokens(Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, Tcl_Size count,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclCompileVarSubst(Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, CompileEnv *envPtr);
MODULE_SCOPE Tcl_Size	TclCreateAuxData(void *clientData,
			    const AuxDataType *typePtr, CompileEnv *envPtr);
MODULE_SCOPE Tcl_Size	TclCreateExceptRange(ExceptionRangeType type,
			    CompileEnv *envPtr);
Changes to generic/tclIO.c.
6059
6060
6061
6062
6063
6064
6065
6066

6067
6068
6069
6070
6071
6072
6073
		    && !GotFlag(statePtr, CHANNEL_STICKY_EOF)
		    && (!GotFlag(statePtr, CHANNEL_NONBLOCKING))) {
		goto finish;
	    }
	}

	if (copiedNow < 0) {
	    if (GotFlag(statePtr, CHANNEL_EOF)) {

		break;
	    }
	    if ((GotFlag(statePtr, CHANNEL_NONBLOCKING) || allowShortReads)
		    && GotFlag(statePtr, CHANNEL_BLOCKED)) {
		break;
	    }
	    result = GetInput(chanPtr);







|
>







6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
		    && !GotFlag(statePtr, CHANNEL_STICKY_EOF)
		    && (!GotFlag(statePtr, CHANNEL_NONBLOCKING))) {
		goto finish;
	    }
	}

	if (copiedNow < 0) {
	    if (GotFlag(statePtr, CHANNEL_EOF) || 
	        GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
		break;
	    }
	    if ((GotFlag(statePtr, CHANNEL_NONBLOCKING) || allowShortReads)
		    && GotFlag(statePtr, CHANNEL_BLOCKED)) {
		break;
	    }
	    result = GetInput(chanPtr);
Changes to generic/tclIOSock.c.
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
    const char *host,
    Tcl_TcpAcceptProc *acceptProc,
    void *callbackData)
{
    char portbuf[TCL_INTEGER_SPACE];

    TclFormatInt(portbuf, port);
    return Tcl_OpenTcpServerEx(interp, portbuf, host, -1,
	    TCL_TCPSERVER_REUSEADDR, acceptProc, callbackData);
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78







|
|







328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
    const char *host,
    Tcl_TcpAcceptProc *acceptProc,
    void *callbackData)
{
    char portbuf[TCL_INTEGER_SPACE];

    TclFormatInt(portbuf, port);
    return Tcl_OpenTcpServerEx(interp, portbuf, host, TCL_TCPSERVER_REUSEADDR,
	    -1, acceptProc, callbackData);
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
Changes to generic/tclObj.c.
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006

    if (uwideValue > WIDE_MAX) {
	mp_int bignumValue;
	if (mp_init_u64(&bignumValue, uwideValue) != MP_OKAY) {
	    Tcl_Panic("%s: memory overflow", "Tcl_SetWideUIntObj");
	}
	TclSetBignumInternalRep(objPtr, &bignumValue);
    } {
	TclSetIntObj(objPtr, (Tcl_WideInt)uwideValue);
    }
}

/*
 *----------------------------------------------------------------------
 *







|







2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006

    if (uwideValue > WIDE_MAX) {
	mp_int bignumValue;
	if (mp_init_u64(&bignumValue, uwideValue) != MP_OKAY) {
	    Tcl_Panic("%s: memory overflow", "Tcl_SetWideUIntObj");
	}
	TclSetBignumInternalRep(objPtr, &bignumValue);
    } else {
	TclSetIntObj(objPtr, (Tcl_WideInt)uwideValue);
    }
}

/*
 *----------------------------------------------------------------------
 *
Changes to generic/tclResult.c.
1029
1030
1031
1032
1033
1034
1035









1036
1037
1038
1039
1040
1041
1042
	Tcl_DictObjPut(NULL, options, keys[KEY_CODE],
		Tcl_NewWideIntObj(result));
	Tcl_DictObjPut(NULL, options, keys[KEY_LEVEL],
		Tcl_NewWideIntObj(0));
    }

    if (result == TCL_ERROR) {









	Tcl_AddErrorInfo(interp, "");
	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORSTACK], iPtr->errorStack);
    }
    if (iPtr->errorCode) {
	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORCODE], iPtr->errorCode);
    }
    if (iPtr->errorInfo) {







>
>
>
>
>
>
>
>
>







1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
	Tcl_DictObjPut(NULL, options, keys[KEY_CODE],
		Tcl_NewWideIntObj(result));
	Tcl_DictObjPut(NULL, options, keys[KEY_LEVEL],
		Tcl_NewWideIntObj(0));
    }

    if (result == TCL_ERROR) {
	if (!iPtr->errorInfo) {
	    /* 
	     * No errorLine without errorInfo, e. g. (re)thrown only message,
	     * this shall also avoid transfer of errorLine (if goes to child
	     * interp), because we have anyway nothing excepting message
	     * in the backtrace.
	     */
	    iPtr->errorLine = 1;
	}
	Tcl_AddErrorInfo(interp, "");
	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORSTACK], iPtr->errorStack);
    }
    if (iPtr->errorCode) {
	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORCODE], iPtr->errorCode);
    }
    if (iPtr->errorInfo) {
1170
1171
1172
1173
1174
1175
1176











1177
1178
1179
1180
1181
1182
1183
	if (tiPtr->returnOpts) {
	    Tcl_DecrRefCount(tiPtr->returnOpts);
	    tiPtr->returnOpts = NULL;
	}
    } else {
	Tcl_SetReturnOptions(targetInterp,
		Tcl_GetReturnOptions(sourceInterp, code));











	tiPtr->flags &= ~(ERR_ALREADY_LOGGED);
    }
    Tcl_SetObjResult(targetInterp, Tcl_GetObjResult(sourceInterp));
    Tcl_ResetResult(sourceInterp);
}

/*







>
>
>
>
>
>
>
>
>
>
>







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
	if (tiPtr->returnOpts) {
	    Tcl_DecrRefCount(tiPtr->returnOpts);
	    tiPtr->returnOpts = NULL;
	}
    } else {
	Tcl_SetReturnOptions(targetInterp,
		Tcl_GetReturnOptions(sourceInterp, code));
	/*
	 * Add line number if needed: not in line 1 and info contains no number
	 * yet at end of the stack (e. g. proc etc), to avoid double reporting
	 */
	if (tiPtr->errorLine > 1 && tiPtr->errorInfo &&
	    tiPtr->errorInfo->length &&
	    tiPtr->errorInfo->bytes[tiPtr->errorInfo->length-1] != ')'
	) {
	    Tcl_AppendObjToErrorInfo(targetInterp, Tcl_ObjPrintf(
		    "\n    (\"interp eval\" body line %d)", tiPtr->errorLine));
	}
	tiPtr->flags &= ~(ERR_ALREADY_LOGGED);
    }
    Tcl_SetObjResult(targetInterp, Tcl_GetObjResult(sourceInterp));
    Tcl_ResetResult(sourceInterp);
}

/*
Changes to generic/tclStringObj.c.
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405

    if ((objPtr->bytes) && (objPtr->length < 2)) {
	/* 0 bytes -> 0 chars; 1 byte -> 1 char */
	return objPtr->length;
    }

    /*
     * Optimize the case where we're really dealing with a bytearray object;
     * we don't need to convert to a string to perform the get-length operation.
     *
     * Starting in Tcl 8.7, we check for a "pure" bytearray, because the
     * machinery behind that test is using a proper bytearray ObjType.  We
     * could also compute length of an improper bytearray without shimmering
     * but there's no value in that. We *want* to shimmer an improper bytearray
     * because improper bytearrays have worthless internal reps.
     */

    if (TclIsPureByteArray(objPtr)) {
	(void) Tcl_GetBytesFromObj(NULL, objPtr, &numChars);
	return numChars;
    }








|


|
|
|
|
|







384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405

    if ((objPtr->bytes) && (objPtr->length < 2)) {
	/* 0 bytes -> 0 chars; 1 byte -> 1 char */
	return objPtr->length;
    }

    /*
     * Optimize the case where we're really dealing with a byte-array object;
     * we don't need to convert to a string to perform the get-length operation.
     *
     * Starting in Tcl 8.7, we check for a "pure" byte-array, because the
     * machinery behind that test is using a proper byte-array ObjType.  We
     * could also compute length of an improper byte-array without shimmering
     * but there's no value in that. We *want* to shimmer an improper byte-array
     * because improper byte-arrays have worthless internal reps.
     */

    if (TclIsPureByteArray(objPtr)) {
	(void) Tcl_GetBytesFromObj(NULL, objPtr, &numChars);
	return numChars;
    }

435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456

    if ((objPtr->bytes) && (objPtr->length < 2)) {
	/* 0 bytes -> 0 chars; 1 byte -> 1 char */
	return objPtr->length;
    }

    /*
     * Optimize the case where we're really dealing with a bytearray object;
     * we don't need to convert to a string to perform the get-length operation.
     *
     * Starting in Tcl 8.7, we check for a "pure" bytearray, because the
     * machinery behind that test is using a proper bytearray ObjType.  We
     * could also compute length of an improper bytearray without shimmering
     * but there's no value in that. We *want* to shimmer an improper bytearray
     * because improper bytearrays have worthless internal reps.
     */

    if (TclIsPureByteArray(objPtr)) {
	(void) Tcl_GetBytesFromObj(NULL, objPtr, &numChars);
    } else {
	TclGetString(objPtr);
	numChars = TclNumUtfChars(objPtr->bytes, objPtr->length);







|


|
|
|
|
|







435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456

    if ((objPtr->bytes) && (objPtr->length < 2)) {
	/* 0 bytes -> 0 chars; 1 byte -> 1 char */
	return objPtr->length;
    }

    /*
     * Optimize the case where we're really dealing with a byte-array object;
     * we don't need to convert to a string to perform the get-length operation.
     *
     * Starting in Tcl 8.7, we check for a "pure" byte-array, because the
     * machinery behind that test is using a proper byte-array ObjType.  We
     * could also compute length of an improper byte-array without shimmering
     * but there's no value in that. We *want* to shimmer an improper byte-array
     * because improper byte-arrays have worthless internal reps.
     */

    if (TclIsPureByteArray(objPtr)) {
	(void) Tcl_GetBytesFromObj(NULL, objPtr, &numChars);
    } else {
	TclGetString(objPtr);
	numChars = TclNumUtfChars(objPtr->bytes, objPtr->length);
696
697
698
699
700
701
702
703
704

705
706
707

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

725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetRange --
 *
 *	Create a Tcl Object that contains the chars between first and last of
 *	the object indicated by "objPtr". If the object is not already a

 *	String object, convert it to one.  If first is TCL_INDEX_NONE, the
 *	returned string start at the beginning of objPtr.  If last is
 *	TCL_INDEX_NONE, the returned string ends at the end of objPtr.

 *
 * Results:
 *	Returns a new Tcl Object of the String type.
 *
 * Side effects:
 *	Changes the internal rep of "objPtr" to the String type.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
Tcl_GetRange(
    Tcl_Obj *objPtr,		/* The Tcl object to find the range of. */
    Tcl_Size first,		/* First index of the range. */
    Tcl_Size last)		/* Last index of the range. */
{
    Tcl_Obj *newObjPtr;		/* The Tcl object to find the range of. */

    String *stringPtr;
    Tcl_Size length = 0;

    if (first < 0) {
	first = 0;
    }

    /*
     * Optimize the case where we're really dealing with a bytearray object
     * we don't need to convert to a string to perform the substring operation.
     */

    if (TclIsPureByteArray(objPtr)) {
	unsigned char *bytes = Tcl_GetBytesFromObj(NULL, objPtr, &length);

	if (last < 0 || last >= length) {







|
|
>
|
|
|
>


|













|
>








|







696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetRange --
 *
 *	Create a Tcl Object that contains the chars between first
 *	and last of the object indicated by "objPtr". If the object
 *	is not a byte-array object, and not already a String object,
 *	convert it to a String object. If first is TCL_INDEX_NONE,
 *	the returned string start at the beginning of objPtr. If
 *	last is TCL_INDEX_NONE, the returned string ends at the
 *	end of objPtr.
 *
 * Results:
 *	Returns a new Tcl Object of the String or byte-array type.
 *
 * Side effects:
 *	Changes the internal rep of "objPtr" to the String type.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
Tcl_GetRange(
    Tcl_Obj *objPtr,		/* The Tcl object to find the range of. */
    Tcl_Size first,		/* First index of the range. */
    Tcl_Size last)		/* Last index of the range. */
{
    Tcl_Obj *newObjPtr;		/* The Tcl object to return that is the new
					 * range. */
    String *stringPtr;
    Tcl_Size length = 0;

    if (first < 0) {
	first = 0;
    }

    /*
     * Optimize the case where we're really dealing with a byte-array object
     * we don't need to convert to a string to perform the substring operation.
     */

    if (TclIsPureByteArray(objPtr)) {
	unsigned char *bytes = Tcl_GetBytesFromObj(NULL, objPtr, &length);

	if (last < 0 || last >= length) {
796
797
798
799
800
801
802
803

804
805
806
807
808
809
810
811
812
813
814
815
816
817
818

Tcl_Obj *
TclGetRange(
    Tcl_Obj *objPtr,		/* The Tcl object to find the range of. */
    Tcl_Size first,		/* First index of the range. */
    Tcl_Size last)		/* Last index of the range. */
{
    Tcl_Obj *newObjPtr;		/* The Tcl object to find the range of. */

    Tcl_Size length = 0;

    if (first < 0) {
	first = TCL_INDEX_START;
    }

    /*
     * Optimize the case where we're really dealing with a bytearray object
     * we don't need to convert to a string to perform the substring operation.
     */

    if (TclIsPureByteArray(objPtr)) {
	unsigned char *bytes = Tcl_GetBytesFromObj(NULL, objPtr, &length);

	if (last < 0 || last >= length) {







|
>







|







799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822

Tcl_Obj *
TclGetRange(
    Tcl_Obj *objPtr,		/* The Tcl object to find the range of. */
    Tcl_Size first,		/* First index of the range. */
    Tcl_Size last)		/* Last index of the range. */
{
    Tcl_Obj *newObjPtr;	 	/* The Tcl object to return that is the new
					 * range. */
    Tcl_Size length = 0;

    if (first < 0) {
	first = TCL_INDEX_START;
    }

    /*
     * Optimize the case where we're really dealing with a byte-array object
     * we don't need to convert to a string to perform the substring operation.
     */

    if (TclIsPureByteArray(objPtr)) {
	unsigned char *bytes = Tcl_GetBytesFromObj(NULL, objPtr, &length);

	if (last < 0 || last >= length) {
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
	TclSetDuplicateObj(objPtr, appendObjPtr);
	return;
    }

    if (TclIsPureByteArray(appendObjPtr)
	    && (TclIsPureByteArray(objPtr) || objPtr->bytes == &tclEmptyString)) {
	/*
	 * Both bytearray objects are pure, so the second internal bytearray value
	 * can be appended to the first, with no need to modify the "bytes" field.
	 */

	/*
	 * One might expect the code here to be
	 *
	 *  bytes = Tcl_GetBytesFromObj(NULL, appendObjPtr, &length);







|







1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
	TclSetDuplicateObj(objPtr, appendObjPtr);
	return;
    }

    if (TclIsPureByteArray(appendObjPtr)
	    && (TclIsPureByteArray(objPtr) || objPtr->bytes == &tclEmptyString)) {
	/*
	 * Both byte-array objects are pure, so the second internal byte-array value
	 * can be appended to the first, with no need to modify the "bytes" field.
	 */

	/*
	 * One might expect the code here to be
	 *
	 *  bytes = Tcl_GetBytesFromObj(NULL, appendObjPtr, &length);
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
    Tcl_Size done = 1;
    int binary = TclIsPureByteArray(objPtr);
    Tcl_Size maxCount;

    /*
     * Analyze to determine what representation result should be.
     * GOALS:	Avoid shimmering & string rep generation.
     *		Produce pure bytearray when possible.
     *		Error on overflow.
     */

    if (!binary) {
	if (TclHasInternalRep(objPtr, &tclStringType)) {
	    String *stringPtr = GET_STRING(objPtr);
	    if (stringPtr->hasUnicode) {







|







3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
    Tcl_Size done = 1;
    int binary = TclIsPureByteArray(objPtr);
    Tcl_Size maxCount;

    /*
     * Analyze to determine what representation result should be.
     * GOALS:	Avoid shimmering & string rep generation.
     *		Produce pure byte-array when possible.
     *		Error on overflow.
     */

    if (!binary) {
	if (TclHasInternalRep(objPtr, &tclStringType)) {
	    String *stringPtr = GET_STRING(objPtr);
	    if (stringPtr->hasUnicode) {
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
	/* One object; return first */
	return objv[0];
    }

    /*
     * Analyze to determine what representation result should be.
     * GOALS:	Avoid shimmering & string rep generation.
     *		Produce pure bytearray when possible.
     *		Error on overflow.
     */

    ov = objv, oc = objc;
    do {
	Tcl_Obj *objPtr = *ov++;

	if (TclIsPureByteArray(objPtr)) {
	    allowUniChar = 0;
	} else if (objPtr->bytes) {
	    /* Value has a string rep. */
	    if (objPtr->length) {
		/*
		 * Non-empty string rep. Not a pure bytearray, so we won't
		 * create a pure bytearray.
		 */

		binary = 0;
		if (ov > objv+1 && ISCONTINUATION(TclGetString(objPtr))) {
		    forceUniChar = 1;
		} else if ((objPtr->typePtr) && !TclHasInternalRep(objPtr, &tclStringType)) {
		    /* Prevent shimmer of non-string types. */







|













|
|







3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
	/* One object; return first */
	return objv[0];
    }

    /*
     * Analyze to determine what representation result should be.
     * GOALS:	Avoid shimmering & string rep generation.
     *		Produce pure byte-array when possible.
     *		Error on overflow.
     */

    ov = objv, oc = objc;
    do {
	Tcl_Obj *objPtr = *ov++;

	if (TclIsPureByteArray(objPtr)) {
	    allowUniChar = 0;
	} else if (objPtr->bytes) {
	    /* Value has a string rep. */
	    if (objPtr->length) {
		/*
		 * Non-empty string rep. Not a pure byte-array, so we won't
		 * create a pure byte-array.
		 */

		binary = 0;
		if (ov > objv+1 && ISCONTINUATION(TclGetString(objPtr))) {
		    forceUniChar = 1;
		} else if ((objPtr->typePtr) && !TclHasInternalRep(objPtr, &tclStringType)) {
		    /* Prevent shimmer of non-string types. */
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
	Tcl_Size numBytes = 0;
	ov = objv;
	oc = objc;
	do {
	    Tcl_Obj *objPtr = *ov++;

	    /*
	     * Every argument is either a bytearray with a ("pure")
	     * value we know we can safely use, or it is an empty string.
	     * We don't need to count bytes for the empty strings.
	     */

	    if (TclIsPureByteArray(objPtr)) {
		(void)Tcl_GetBytesFromObj(NULL, objPtr, &numBytes); /* PANIC? */








|







3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
	Tcl_Size numBytes = 0;
	ov = objv;
	oc = objc;
	do {
	    Tcl_Obj *objPtr = *ov++;

	    /*
	     * Every argument is either a byte-array with a ("pure")
	     * value we know we can safely use, or it is an empty string.
	     * We don't need to count bytes for the empty strings.
	     */

	    if (TclIsPureByteArray(objPtr)) {
		(void)Tcl_GetBytesFromObj(NULL, objPtr, &numBytes); /* PANIC? */

3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
	    objResultPtr = Tcl_NewByteArrayObj(NULL, length);
	    dst = Tcl_SetByteArrayLength(objResultPtr, length);
	}
	while (objc--) {
	    Tcl_Obj *objPtr = *objv++;

	    /*
	     * Every argument is either a bytearray with a ("pure")
	     * value we know we can safely use, or it is an empty string.
	     * We don't need to copy bytes from the empty strings.
	     */

	    if (TclIsPureByteArray(objPtr)) {
		Tcl_Size more = 0;
		unsigned char *src = Tcl_GetBytesFromObj(NULL, objPtr, &more);







|







3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
	    objResultPtr = Tcl_NewByteArrayObj(NULL, length);
	    dst = Tcl_SetByteArrayLength(objResultPtr, length);
	}
	while (objc--) {
	    Tcl_Obj *objPtr = *objv++;

	    /*
	     * Every argument is either a byte-array with a ("pure")
	     * value we know we can safely use, or it is an empty string.
	     * We don't need to copy bytes from the empty strings.
	     */

	    if (TclIsPureByteArray(objPtr)) {
		Tcl_Size more = 0;
		unsigned char *src = Tcl_GetBytesFromObj(NULL, objPtr, &more);
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
    if (first < 0) {
	first = 0;
    }

    /*
     * The caller very likely had to call Tcl_GetCharLength() or similar
     * to be able to process index values.  This means it is likely that
     * objPtr is either a proper "bytearray" or a "string" or else it has
     * a known and short string rep.
     */

    if (TclIsPureByteArray(objPtr)) {
	Tcl_Size numBytes = 0;
	unsigned char *bytes = Tcl_GetBytesFromObj(NULL, objPtr, &numBytes);








|







4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
    if (first < 0) {
	first = 0;
    }

    /*
     * The caller very likely had to call Tcl_GetCharLength() or similar
     * to be able to process index values.  This means it is likely that
     * objPtr is either a proper "byte-array" or a "string" or else it has
     * a known and short string rep.
     */

    if (TclIsPureByteArray(objPtr)) {
	Tcl_Size numBytes = 0;
	unsigned char *bytes = Tcl_GetBytesFromObj(NULL, objPtr, &numBytes);

Changes to library/clock.tcl.
566
567
568
569
570
571
572






573
574
575
576
577
578
579
    set ns ::tcl::clock
    # Merge sequential locales (in reverse order, e. g. {} -> en -> en_en):
    if {[llength $locales] > 1} {
	set mrgcat [mcMerge [lrange $locales 1 end]]
	if {[dict exists $Msgs $ns $loc]} {
	    set mrgcat [dict merge $mrgcat [dict get $Msgs $ns $loc]]
	    dict set mrgcat L $loc






	} else {
	    # be sure a duplicate is created, don't overwrite {} (common) locale:
	    set mrgcat [dict merge $mrgcat [dict create L $loc]]
	}
    } else {
	if {[dict exists $Msgs $ns $loc]} {
	    set mrgcat [dict get $Msgs $ns $loc]







>
>
>
>
>
>







566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
    set ns ::tcl::clock
    # Merge sequential locales (in reverse order, e. g. {} -> en -> en_en):
    if {[llength $locales] > 1} {
	set mrgcat [mcMerge [lrange $locales 1 end]]
	if {[dict exists $Msgs $ns $loc]} {
	    set mrgcat [dict merge $mrgcat [dict get $Msgs $ns $loc]]
	    dict set mrgcat L $loc
	    # remove any previously localized formats (merged from parent
	    # locale and possibly cached in parent-mc by ClockLocalizeFormat),
	    # because they may depend on values which may vary in derivate:
	    foreach k [dict keys $mrgcat] {
		if {[string match FMT_* $k]} { dict unset mrgcat $k }
	    }
	} else {
	    # be sure a duplicate is created, don't overwrite {} (common) locale:
	    set mrgcat [dict merge $mrgcat [dict create L $loc]]
	}
    } else {
	if {[dict exists $Msgs $ns $loc]} {
	    set mrgcat [dict get $Msgs $ns $loc]
Changes to tests/appendComp.test.
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
    proc bar {} {
	trace add variable myvar read foo
	proc foo {args} {append ::result $args}
	lappend myvar a
	return $::result
    }
    bar
} -result {myvar {} read} -constraints {bug-3057639}
test appendComp-7.3 {lappend var triggers read trace, stack var} -setup {
    unset -nocomplain ::result
    unset -nocomplain ::myvar
} -body {
    proc bar {} {
	trace add variable ::myvar read foo
	proc foo {args} {append ::result $args}
	lappend ::myvar a
	return $::result
    }
    bar
} -result {::myvar {} r} -constraints {bug-3057639}
test appendComp-7.4 {lappend var triggers read trace, array var} -setup {
    unset -nocomplain ::result
} -body {
    # The behavior of read triggers on lappend changed in 8.0 to not trigger
    # them. Maybe not correct, but been there a while.
    proc bar {} {
	trace add variable myvar read foo
	proc foo {args} {append ::result $args}
	lappend myvar(b) a
	return $::result
    }
    bar
} -result {myvar b read} -constraints {bug-3057639}
test appendComp-7.5 {lappend var triggers read trace, array var} -setup {
    unset -nocomplain ::result
} -body {
    # The behavior of read triggers on lappend changed in 8.0 to not trigger
    # them. Maybe not correct, but been there a while.
    proc bar {} {
	trace add variable myvar read foo







|











|












|







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
    proc bar {} {
	trace add variable myvar read foo
	proc foo {args} {append ::result $args}
	lappend myvar a
	return $::result
    }
    bar
} -result {myvar {} read} -constraints {bug_3057639}
test appendComp-7.3 {lappend var triggers read trace, stack var} -setup {
    unset -nocomplain ::result
    unset -nocomplain ::myvar
} -body {
    proc bar {} {
	trace add variable ::myvar read foo
	proc foo {args} {append ::result $args}
	lappend ::myvar a
	return $::result
    }
    bar
} -result {::myvar {} r} -constraints {bug_3057639}
test appendComp-7.4 {lappend var triggers read trace, array var} -setup {
    unset -nocomplain ::result
} -body {
    # The behavior of read triggers on lappend changed in 8.0 to not trigger
    # them. Maybe not correct, but been there a while.
    proc bar {} {
	trace add variable myvar read foo
	proc foo {args} {append ::result $args}
	lappend myvar(b) a
	return $::result
    }
    bar
} -result {myvar b read} -constraints {bug_3057639}
test appendComp-7.5 {lappend var triggers read trace, array var} -setup {
    unset -nocomplain ::result
} -body {
    # The behavior of read triggers on lappend changed in 8.0 to not trigger
    # them. Maybe not correct, but been there a while.
    proc bar {} {
	trace add variable myvar read foo
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
	set myvar(0) 1
	trace add variable myvar read foo
	proc foo {args} {append ::result $args}
	lappend myvar(b) a
	return $::result
    }
    bar
} -result {myvar b read} -constraints {bug-3057639}
test appendComp-7.7 {lappend var triggers read trace, array stack var} -setup {
    unset -nocomplain ::myvar
    unset -nocomplain ::result
} -body {
    proc bar {} {
	trace add variable ::myvar read foo
	proc foo {args} {append ::result $args}
	lappend ::myvar(b) a
	return $::result
    }
    bar
} -result {::myvar b read} -constraints {bug-3057639}
test appendComp-7.8 {lappend var triggers read trace, array stack var} -setup {
    unset -nocomplain ::myvar
    unset -nocomplain ::result
} -body {
    proc bar {} {
	trace add variable ::myvar read foo
	proc foo {args} {append ::result $args}







|











|







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
	set myvar(0) 1
	trace add variable myvar read foo
	proc foo {args} {append ::result $args}
	lappend myvar(b) a
	return $::result
    }
    bar
} -result {myvar b read} -constraints {bug_3057639}
test appendComp-7.7 {lappend var triggers read trace, array stack var} -setup {
    unset -nocomplain ::myvar
    unset -nocomplain ::result
} -body {
    proc bar {} {
	trace add variable ::myvar read foo
	proc foo {args} {append ::result $args}
	lappend ::myvar(b) a
	return $::result
    }
    bar
} -result {::myvar b read} -constraints {bug_3057639}
test appendComp-7.8 {lappend var triggers read trace, array stack var} -setup {
    unset -nocomplain ::myvar
    unset -nocomplain ::result
} -body {
    proc bar {} {
	trace add variable ::myvar read foo
	proc foo {args} {append ::result $args}
Changes to tests/bigdata.test.
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
 } -result b
test script-bytecode-length-bigdata-1 {Test bytecode length limit} -body {
    # Note we need to exceed bytecode limit without exceeding script char limit
    set s [string repeat {{*}$x;} [expr 0x7fffffff/6]]
    catch $s r e
} -cleanup {
    bigClean
} -constraints panic-in-EnterCmdStartData

#
# string cat
bigtest string-cat-bigdata-1 "string cat large small result > INT_MAX" 1 -body {
    string equal \
	[string cat [bigString $::bigLengths(patlenmultiple)] [bigString]] \
	[bigString [expr {[bigPatLen]+$::bigLengths(patlenmultiple)}]]







|







135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
 } -result b
test script-bytecode-length-bigdata-1 {Test bytecode length limit} -body {
    # Note we need to exceed bytecode limit without exceeding script char limit
    set s [string repeat {{*}$x;} [expr 0x7fffffff/6]]
    catch $s r e
} -cleanup {
    bigClean
} -constraints panicInEnterCmdStartData

#
# string cat
bigtest string-cat-bigdata-1 "string cat large small result > INT_MAX" 1 -body {
    string equal \
	[string cat [bigString $::bigLengths(patlenmultiple)] [bigString]] \
	[bigString [expr {[bigPatLen]+$::bigLengths(patlenmultiple)}]]
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
	[string index $s2 5] \
	[string index $s2 end] \
	[string index $s2 end-5]
} -setup {
    set s [bigString 0x100000000]
} -cleanup {
    bigClean
} -constraints bug-takesTooLong

#
# string match
bigtestRO string-match-bigdata-1 {string match} {1 0 1} -body {
    list \
	[string match 0*5 $s] \
	[string match 0*4 $s] \







|







317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
	[string index $s2 5] \
	[string index $s2 end] \
	[string index $s2 end-5]
} -setup {
    set s [bigString 0x100000000]
} -cleanup {
    bigClean
} -constraints bugTakesTooLong

#
# string match
bigtestRO string-match-bigdata-1 {string match} {1 0 1} -body {
    list \
	[string match 0*5 $s] \
	[string match 0*4 $s] \
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
    puts B
    unset match; # Free up memory
    lappend result [string equal $digits [bigString 0x100000009]]
} -setup {
    set s [bigString 0x10000000a 0x100000009]
} -cleanup {
    bigClean digits match
} -constraints bug-takesTooLong

#
# regsub
bigtestRO regsub-bigdata-1 "regsub" X -body {
    regsub -all \\d $s {}
} -setup {
    set s [bigString 0x100000001 0x100000000]
} -cleanup {
    bigClean
} -constraints bug-takesTooLong
bigtestRO regsub-bigdata-2 "regsub" 1 -body {
    string equal [regsub -all \\d $s x] [string cat [string repeat x 0x100000000] X]
} -setup {
    set s [bigString 0x100000001 0x100000000]
} -cleanup {
    bigClean
} -constraints bug-takesTooLong

#
# subst
bigtestRO subst-bigdata-1 "subst" {1 1} -body {
    unset -nocomplain result
    lappend result [string equal [subst $s] $s]
    lappend result [string equal [subst {$s}] $s]







|









|






|







677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
    puts B
    unset match; # Free up memory
    lappend result [string equal $digits [bigString 0x100000009]]
} -setup {
    set s [bigString 0x10000000a 0x100000009]
} -cleanup {
    bigClean digits match
} -constraints bugTakesTooLong

#
# regsub
bigtestRO regsub-bigdata-1 "regsub" X -body {
    regsub -all \\d $s {}
} -setup {
    set s [bigString 0x100000001 0x100000000]
} -cleanup {
    bigClean
} -constraints bugTakesTooLong
bigtestRO regsub-bigdata-2 "regsub" 1 -body {
    string equal [regsub -all \\d $s x] [string cat [string repeat x 0x100000000] X]
} -setup {
    set s [bigString 0x100000001 0x100000000]
} -cleanup {
    bigClean
} -constraints bugTakesTooLong

#
# subst
bigtestRO subst-bigdata-1 "subst" {1 1} -body {
    unset -nocomplain result
    lappend result [string equal [subst $s] $s]
    lappend result [string equal [subst {$s}] $s]
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
    set l2 {a b c d e f g h i j}
    list [llength [ledit l2 2 3 {*}$l]] [llength $l2] [lrange $l2 0 7] [lrange $l2 end-7 end]
} -setup {
    # Note total number of arguments has to be less than INT_MAX
    set l [bigList 2147483642]
} -cleanup {
    bigClean
} -constraints memory-allocation-panic

#
# lindex
bigtestRO lindex-bigdata-1 "lindex" {6 7 5 {} 5 4 {} 9 {}} -body {
    list \
	[lindex $l 0x100000000] \
	[lindex $l 0x100000000+1] \







|







865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
    set l2 {a b c d e f g h i j}
    list [llength [ledit l2 2 3 {*}$l]] [llength $l2] [lrange $l2 0 7] [lrange $l2 end-7 end]
} -setup {
    # Note total number of arguments has to be less than INT_MAX
    set l [bigList 2147483642]
} -cleanup {
    bigClean
} -constraints memoryAllocationPanic

#
# lindex
bigtestRO lindex-bigdata-1 "lindex" {6 7 5 {} 5 4 {} 9 {}} -body {
    list \
	[lindex $l 0x100000000] \
	[lindex $l 0x100000000+1] \
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
    unset -nocomplain l2
    set l2 [lreplace [bigList 4294967296] 4294967290 0 a b c d e]
    lrange $l2 4294967290 end
} -setup {
    #set l [bigList 4294967296]
} -cleanup {
    bigClean
} -constraints bug-outofmemorypanic

#
# lsearch
bigtestRO lsearch-bigdata-1 "lsearch" {4294967300 4294967310 -1}  -body {
    list \
	[lsearch -exact $l X] \
	[lsearch -exact -start 4294967291 $l 0] \







|







1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
    unset -nocomplain l2
    set l2 [lreplace [bigList 4294967296] 4294967290 0 a b c d e]
    lrange $l2 4294967290 end
} -setup {
    #set l [bigList 4294967296]
} -cleanup {
    bigClean
} -constraints bugOutOfMemoryPanic

#
# lsearch
bigtestRO lsearch-bigdata-1 "lsearch" {4294967300 4294967310 -1}  -body {
    list \
	[lsearch -exact $l X] \
	[lsearch -exact -start 4294967291 $l 0] \
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
}
bigtest lseq-bigdata-2 "lseq" {9223372036854775807 9223372036854775799} -body {
    list [llength $l] [lindex $l 9223372036854775800]
} -setup {
    set l [lseq 0x7fffffffffffffff]; llength $l
} -cleanup {
    bigClean
} -constraints bug-fa00fbbbab

#
# lset
bigtest lset-bigdata-1 "lset" {4294967297 4294967297 {1 2 3 4 5 X}} -body {
    # Do NOT initialize l in a -setup block. That requires more memory and fails.
    set l [bigList 0x100000001]
    list [llength [lset l 0x100000000 X]] [llength $l] [lrange $l end-5 end]







|







1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
}
bigtest lseq-bigdata-2 "lseq" {9223372036854775807 9223372036854775799} -body {
    list [llength $l] [lindex $l 9223372036854775800]
} -setup {
    set l [lseq 0x7fffffffffffffff]; llength $l
} -cleanup {
    bigClean
} -constraints bug_fa00fbbbab

#
# lset
bigtest lset-bigdata-1 "lset" {4294967297 4294967297 {1 2 3 4 5 X}} -body {
    # Do NOT initialize l in a -setup block. That requires more memory and fails.
    set l [bigList 0x100000001]
    list [llength [lset l 0x100000000 X]] [llength $l] [lrange $l end-5 end]
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
    # Fill list compare needs too much memory
    set l [split $s ""]
    list [llength $l] [lrange 0 4] [lrange end-4 end]
} -setup {
    set s [bigString 0x100000000]
} -cleanup {
    bigClean
} -constraints bug-takesTooLong

bigtestRO concat-bigdata-1 "concat" {4294967296 {0 1 2 3 4} {6 7 0 1 2} {3 4 5 6 7}} -body {
    unset -nocomplain l2
    set l2 [concat $l $l]
    list [llength $l2] [lrange $l2 0 4] [lrange $l2 0x80000000-2 0x80000000+2] [lrange $l2 end-4 end]
} -setup {
    set l [bigList 0x80000000]







|







1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
    # Fill list compare needs too much memory
    set l [split $s ""]
    list [llength $l] [lrange 0 4] [lrange end-4 end]
} -setup {
    set s [bigString 0x100000000]
} -cleanup {
    bigClean
} -constraints bugTakesTooLong

bigtestRO concat-bigdata-1 "concat" {4294967296 {0 1 2 3 4} {6 7 0 1 2} {3 4 5 6 7}} -body {
    unset -nocomplain l2
    set l2 [concat $l $l]
    list [llength $l2] [lrange $l2 0 4] [lrange $l2 0x80000000-2 0x80000000+2] [lrange $l2 end-4 end]
} -setup {
    set l [bigList 0x80000000]
Changes to tests/chanio.test.
30
31
32
33
34
35
36

37
38
39
40
41
42
43
    variable f
    variable i
    variable n
    variable v
    variable msg
    variable expected


    catch {
	::tcltest::loadTestedCommands
	package require -exact tcl::test [info patchlevel]
	set ::tcltestlib [info loaded {} Tcltest]
    }
    source [file join [file dirname [info script]] tcltests.tcl]








>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    variable f
    variable i
    variable n
    variable v
    variable msg
    variable expected

    set ::tcltestlib {}
    catch {
	::tcltest::loadTestedCommands
	package require -exact tcl::test [info patchlevel]
	set ::tcltestlib [info loaded {} Tcltest]
    }
    source [file join [file dirname [info script]] tcltests.tcl]

Changes to tests/clock.test.
35517
35518
35519
35520
35521
35522
35523












35524
35525
35526
35527
35528
35529
35530
	    lappend res [clock scan \
	      [clock format 0 -format $fmt -locale $loc -gmt 1] \
	      -format $fmt -locale $loc -gmt 1]
	}
    }
    set res
} [lrepeat 12 0]












# END testcases29


# BEGIN testcases30

# Test [clock add]
test clock-30.1 {clock add years} {







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







35517
35518
35519
35520
35521
35522
35523
35524
35525
35526
35527
35528
35529
35530
35531
35532
35533
35534
35535
35536
35537
35538
35539
35540
35541
35542
	    lappend res [clock scan \
	      [clock format 0 -format $fmt -locale $loc -gmt 1] \
	      -format $fmt -locale $loc -gmt 1]
	}
    }
    set res
} [lrepeat 12 0]

test clock-29.1813 {cache consistency when deriving localized formats, bug [2c0f49e26c27847a]} {
    # ensure localized formats are not affected by mistaken merge of mc
    # from parent locale, so such formats got invalidated in child cache:
    namespace inscope ::tcl::clock {
	::msgcat::mcset en_US_roman_xx    DATE_FORMAT "%d.%m.%Y"
	::msgcat::mcset en_US_roman_xx_yy DATE_FORMAT "%Y|%m|%d"
    }
    list [clock format 86400 -format %x -gmt 1 -locale en_US_roman] \
         [clock format 86400 -format %x -gmt 1 -locale en_US_roman_xx] \
	 [clock format 86400 -format %x -gmt 1 -locale en_US_roman_xx_yy]
} {01/02/1970 02.01.1970 1970|01|02}
# END testcases29


# BEGIN testcases30

# Test [clock add]
test clock-30.1 {clock add years} {
35853
35854
35855
35856
35857
35858
35859



















35860
35861
35862
35863
35864
35865
35866
	[clock add 2177452800 -815 months -gmt 1] \
	[clock add 2177452800 -69 years -gmt 1] \
	[clock add 2177452800 -596524 hours -gmt 1] \
	[clock add 2177452800 -35791395 minutes -gmt 1] \
	[clock add 2177452800 -0x7fffffff seconds -gmt 1]
      ]
} [lrepeat 2 {29894400 34214400 0 29966400 29969100 29969153}]




















# END testcases30


test clock-31.1 {system locale} \
    -constraints win \
    -setup {







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







35865
35866
35867
35868
35869
35870
35871
35872
35873
35874
35875
35876
35877
35878
35879
35880
35881
35882
35883
35884
35885
35886
35887
35888
35889
35890
35891
35892
35893
35894
35895
35896
35897
	[clock add 2177452800 -815 months -gmt 1] \
	[clock add 2177452800 -69 years -gmt 1] \
	[clock add 2177452800 -596524 hours -gmt 1] \
	[clock add 2177452800 -35791395 minutes -gmt 1] \
	[clock add 2177452800 -0x7fffffff seconds -gmt 1]
      ]
} [lrepeat 2 {29894400 34214400 0 29966400 29969100 29969153}]
test clock-30.33 {regression test - add with negative base (local seconds of the day, bug [482db1d796540e68])} {
    list \
      [list \
	[clock add -631152000 27463 days 3000 seconds -timezone :CET] \
	[clock add -631152000 902 months 10 days 3000 seconds -timezone :CET] \
	[clock add -631152000 75 years 69 days 3000 seconds -timezone :CET] \
	[clock add -631152000 659112 hours 3000 seconds -timezone :CET] \
	[clock add -631152000 39546720 minutes 3000 seconds -timezone :CET] \
	[clock add -631152000 2372806200 seconds -timezone :CET]
      ] \
      [list \
	[clock add -631152000 27463 days 3000 seconds -gmt 1] \
	[clock add -631152000 902 months 10 days 3000 seconds -gmt 1] \
	[clock add -631152000 75 years 69 days 3000 seconds -gmt 1] \
	[clock add -631152000 659112 hours 3000 seconds -gmt 1] \
	[clock add -631152000 39546720 minutes 3000 seconds -gmt 1] \
	[clock add -631152000 2372806200 seconds -gmt 1]
      ]
} [lrepeat 2 [lrepeat 6 [expr {-631152000 + 2372806200}]]]

# END testcases30


test clock-31.1 {system locale} \
    -constraints win \
    -setup {
Changes to tests/cmdMZ.test.
21
22
23
24
25
26
27


28
29
30
31
32
33
34
    namespace import ::tcltest::customMatch
    namespace import ::tcltest::makeFile
    namespace import ::tcltest::removeFile
    namespace import ::tcltest::temporaryDirectory
    namespace import ::tcltest::testConstraint
    namespace import ::tcltest::test



    proc ListGlobMatch {expected actual} {
	if {[llength $expected] != [llength $actual]} {
	    return 0
	}
	foreach e $expected a $actual {
	    if {![string match $e $a]} {
		return 0







>
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    namespace import ::tcltest::customMatch
    namespace import ::tcltest::makeFile
    namespace import ::tcltest::removeFile
    namespace import ::tcltest::temporaryDirectory
    namespace import ::tcltest::testConstraint
    namespace import ::tcltest::test

    testConstraint memory [llength [info commands memory]]

    proc ListGlobMatch {expected actual} {
	if {[llength $expected] != [llength $actual]} {
	    return 0
	}
	foreach e $expected a $actual {
	    if {![string match $e $a]} {
		return 0
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
	    if {![string is integer -strict [eval $m1]]} {error unexpected}
	}
	# increase again (no "continue" from nested call):
	incr x
    }
    list [lindex [timerate $m1 1000 5] 2] $x
} {5 20}
test cmdMZ-6.13 {Tcl_TimeRateObjCmd: stability by O(n**2), avoid long execution time on growing iteration time} {


    set result {}
    # test the function with quadratic complexity (iteration growth 2x, 10x, 100x):
    foreach e {2 10 100} {
	set x 1
	set m1 [timerate {
	    apply {x {
		while {[incr x -1]} {}
	    }} [set x [expr {$x*$e}]]
	} 50]
	lappend result "${e}x"
	# check it was too slow (it is OK to use factor 2 to prevent sporadic
	# errors on some slow systems or time issues, because if it is not fixed,
	# the execution time may grow hundreds and thousand times):
	if {[lindex $m1 6] > 50 * 2} {
	    lappend result "unexpected long: $m1"
	}
    }
    set result
} {2x 10x 100x}

test cmdMZ-try-1.0 {







|
>
>










|
|

|







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
	    if {![string is integer -strict [eval $m1]]} {error unexpected}
	}
	# increase again (no "continue" from nested call):
	incr x
    }
    list [lindex [timerate $m1 1000 5] 2] $x
} {5 20}
test cmdMZ-6.13 {Tcl_TimeRateObjCmd: stability by O(n**2), avoid long execution time on growing iteration time} {!memory} {
    # don't run this test on memory-debug builds - it seems to be very time-consuming there,
    # what may led to an unexpectedly high increase by such complexity and it'd fail...
    set result {}
    # test the function with quadratic complexity (iteration growth 2x, 10x, 100x):
    foreach e {2 10 100} {
	set x 1
	set m1 [timerate {
	    apply {x {
		while {[incr x -1]} {}
	    }} [set x [expr {$x*$e}]]
	} 50]
	lappend result "${e}x"
	# check it was too slow (it is OK to use factor 10 to prevent sporadic
	# errors on some slow systems or timing issues, because if it is not fixed,
	# the execution time may grow hundreds and thousand times):
	if {[lindex $m1 6] > 50 * 10} {
	    lappend result "unexpected long: $m1"
	}
    }
    set result
} {2x 10x 100x}

test cmdMZ-try-1.0 {
Changes to tests/exec.test.
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
} -result [list 1 a\uFFFDb]

test exec-bug-4f0b5767ac {exec App Execution Alias} -constraints haveWinget -body {
    exec winget --info
} -result "Windows Package Manager*" -match glob

foreach cmdBuiltin {
    assoc call cd cls color copy date del dir echo 
    erase exit ftype for if md mkdir mklink move path 
    pause prompt rd ren rename rmdir set start time 
    title type ver vol
} {
    test auto_execok-$cmdBuiltin-1.0 "auto_execok $cmdBuiltin" \
        -constraints win \
        -body {
            string equal [auto_execok $cmdBuiltin] \
                "[file normalize $::env(COMSPEC)] /c $cmdBuiltin"







|
|
|







748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
} -result [list 1 a\uFFFDb]

test exec-bug-4f0b5767ac {exec App Execution Alias} -constraints haveWinget -body {
    exec winget --info
} -result "Windows Package Manager*" -match glob

foreach cmdBuiltin {
    assoc call cd cls color copy date del dir echo
    erase exit ftype for if md mkdir mklink move path
    pause prompt rd ren rename rmdir set start time
    title type ver vol
} {
    test auto_execok-$cmdBuiltin-1.0 "auto_execok $cmdBuiltin" \
        -constraints win \
        -body {
            string equal [auto_execok $cmdBuiltin] \
                "[file normalize $::env(COMSPEC)] /c $cmdBuiltin"
Changes to tests/expr.test.
7318
7319
7320
7321
7322
7323
7324

7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
          1e308**1e10	infinite
                  Inf	infinite
              -1e5555	infinite
     -1e308**(1e10+1)	infinite
                 -Inf	infinite
                  NaN	nan
} {

    if {[regexp {[/\*]} $v]} { set v [expr $v] }
    test expr-58.1($v)=$r "float classification: fpclassify($v) eq $r" {
	fpclassify $v
    } $r
    test expr-58.2($v) "float classification: isfinite($v)" {
	expr {isfinite($v)}
    } [expr {$r ni {"infinite" "nan"}}]
    test expr-58.3($v) "float classification: isinf($v)" {
	expr {isinf($v)}
    } [expr {$r eq "infinite"}]
    test expr-58.4($v) "float classification: isnan($v)" {
	expr {isnan($v)}
    } [expr {$r eq "nan"}]
    test expr-58.5($v) "float classification: isnormal($v)" {
	expr {isnormal($v)}
    } [expr {$r eq "normal"}]
    test expr-58.6($v) "float classification: issubnormal($v)" {
	expr {issubnormal($v)}
    } [expr {$r eq "subnormal"}]
    test expr-58.7($v) "float classification: isunordered(0 and $v)" {
	expr {isunordered(0,$v) + isunordered($v,0)}
    } [expr {$r eq "nan" ? 2 : 0}]
    test expr-58.9($v) "float classification: isunordered(NaN and $v)" {
	expr {isunordered(NaN,$v) + isunordered($v,NaN)}
    } 2
}
unset -nocomplain v r

test expr-59.10 {float classification: fpclassify} -returnCodes error -body {
    fpclassify







>
|
|


|


|


|


|


|


|


|







7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
          1e308**1e10	infinite
                  Inf	infinite
              -1e5555	infinite
     -1e308**(1e10+1)	infinite
                 -Inf	infinite
                  NaN	nan
} {
    set changed 0
    if {[regexp {[/\*]} $v]} { set v [expr $v]; set changed 1 }
    test expr-58.1($v)=$r-$changed "float classification: fpclassify($v) eq $r" {
	fpclassify $v
    } $r
    test expr-58.2($v)-$changed "float classification: isfinite($v)" {
	expr {isfinite($v)}
    } [expr {$r ni {"infinite" "nan"}}]
    test expr-58.3($v)-$changed "float classification: isinf($v)" {
	expr {isinf($v)}
    } [expr {$r eq "infinite"}]
    test expr-58.4($v)-$changed "float classification: isnan($v)" {
	expr {isnan($v)}
    } [expr {$r eq "nan"}]
    test expr-58.5($v)-$changed "float classification: isnormal($v)" {
	expr {isnormal($v)}
    } [expr {$r eq "normal"}]
    test expr-58.6($v)-$changed "float classification: issubnormal($v)" {
	expr {issubnormal($v)}
    } [expr {$r eq "subnormal"}]
    test expr-58.7($v)-$changed "float classification: isunordered(0 and $v)" {
	expr {isunordered(0,$v) + isunordered($v,0)}
    } [expr {$r eq "nan" ? 2 : 0}]
    test expr-58.8($v)-$changed "float classification: isunordered(NaN and $v)" {
	expr {isunordered(NaN,$v) + isunordered($v,NaN)}
    } 2
}
unset -nocomplain v r

test expr-59.10 {float classification: fpclassify} -returnCodes error -body {
    fpclassify
Changes to tests/interp.test.
2217
2218
2219
2220
2221
2222
2223
















2224
2225
2226
2227
2228
2229
2230
    interp alias $interp test {} MyTestAlias $interp
    interp eval $interp {catch test;set ::errorInfo}
} -cleanup {
    interp delete $interp
} -result {msg
    while executing
"test"}

















# Interps & Namespaces
test interp-27.1 {interp aliases & namespaces} -setup {
    set i [interp create]
} -body {
    set aliasTrace {}
    proc tstAlias {args} {







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







2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
    interp alias $interp test {} MyTestAlias $interp
    interp eval $interp {catch test;set ::errorInfo}
} -cleanup {
    interp delete $interp
} -result {msg
    while executing
"test"}
test interp-26.9 {error transmission: body line number in info similar to eval-cmd, bug [ba68d1e9484a3a92]} -setup {
    set interp [interp create]
} -body {
    # eval body with multiline code (error in line 3):
    catch {
	$interp eval "#1st line\n#2nd line\nexpr {1/0}"
    } msg res
    dict get $res -errorinfo
} -cleanup {
    interp delete $interp
} -result {divide by zero
    invoked from within
"expr {1/0}"
    ("interp eval" body line 3)
    invoked from within
"$interp eval "#1st line\n#2nd line\nexpr {1/0}""}

# Interps & Namespaces
test interp-27.1 {interp aliases & namespaces} -setup {
    set i [interp create]
} -body {
    set aliasTrace {}
    proc tstAlias {args} {
Changes to tests/io.test.
25
26
27
28
29
30
31

32
33
34
35
36
37
38
    variable f
    variable i
    variable n
    variable v
    variable msg
    variable expected


    catch {
	::tcltest::loadTestedCommands
	package require -exact tcl::test [info patchlevel]
	set ::tcltestlib [info loaded {} Tcltest]
    }
    source [file join [file dirname [info script]] tcltests.tcl]








>







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    variable f
    variable i
    variable n
    variable v
    variable msg
    variable expected

    set ::tcltestlib {}
    catch {
	::tcltest::loadTestedCommands
	package require -exact tcl::test [info patchlevel]
	set ::tcltestlib [info loaded {} Tcltest]
    }
    source [file join [file dirname [info script]] tcltests.tcl]

9945
9946
9947
9948
9949
9950
9951















































































9952
9953
9954
9955
9956
9957
9958
9959
9960
9961
    removeFile $scriptFile
} -body {
    set fd [open |[list [info nameofexecutable] $scriptFile r+]]
    fconfigure $fd -encoding utf-8 -profile replace
    read $fd
} -result a\uFFFDb

















































































# cleanup
foreach file [list fooBar longfile script2 output test1 pipe my_script \
	test2 test3 cat stdout kyrillic.txt utf8-fcopy.txt utf8-rp.txt] {
    removeFile $file
}
cleanupTests
}
namespace delete ::tcl::test::io
return







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










9946
9947
9948
9949
9950
9951
9952
9953
9954
9955
9956
9957
9958
9959
9960
9961
9962
9963
9964
9965
9966
9967
9968
9969
9970
9971
9972
9973
9974
9975
9976
9977
9978
9979
9980
9981
9982
9983
9984
9985
9986
9987
9988
9989
9990
9991
9992
9993
9994
9995
9996
9997
9998
9999
10000
10001
10002
10003
10004
10005
10006
10007
10008
10009
10010
10011
10012
10013
10014
10015
10016
10017
10018
10019
10020
10021
10022
10023
10024
10025
10026
10027
10028
10029
10030
10031
10032
10033
10034
10035
10036
10037
10038
10039
10040
10041
    removeFile $scriptFile
} -body {
    set fd [open |[list [info nameofexecutable] $scriptFile r+]]
    fconfigure $fd -encoding utf-8 -profile replace
    read $fd
} -result a\uFFFDb

proc read_blocked {args} {
    global e
    set timer [after 10000 {set ::e timeout}]
    set e ""
    set l 1; if {[llength $args] > 1} {set l [lindex $args 1]}
    try {
	while {[string length $e] < $l} {
	    append e [read {*}$args]
	    after 10; update
	}
	set e
    } finally {
	after cancel $timer
	unset -nocomplain e
    }
}
test io-bug-73bb42fb-1 {
    Non-blocking+buffer size+encoding error panic - TCL bug 73bb42fb.
    Verify error at offset 0.
} -setup {
    writeFile $path(test1) binary \xD6[string repeat _ 20]
} -body {
    set fd [open $path(test1)]
    fconfigure $fd -encoding utf-8 -profile strict -blocking 0 -buffersize 10 -translation lf -eofchar {}
    list [catch {read_blocked $fd 1} e d] $e [dict getd $d -code ""] [dict getd $d -errorcode ""] [tell $fd]
} -cleanup {
    close $fd
} -match glob -result {1 {error reading *} 1 {POSIX EILSEQ {invalid or incomplete multibyte or wide character}} 0}

test io-bug-73bb43fb-2 {
    Non-blocking+buffer size+encoding error panic - TCL bug 73bb42fb.
    Verify valid data returned before error generated.
} -setup {
    writeFile $path(test1) binary X\xD6[string repeat _ 20]
} -body {
    set fd [open $path(test1)]
    fconfigure $fd -encoding utf-8 -profile strict -blocking 0 -buffersize 10 -translation lf -eofchar {}
    set result {}
    lappend result [read_blocked $fd]
    lappend result [tell $fd]
    lappend result [catch {read_blocked $fd} e d] $e [dict getd $d -code ""] [dict getd $d -errorcode ""] [tell $fd]
} -cleanup {
    close $fd
} -match glob -result {X 1 1 {error reading *} 1 {POSIX EILSEQ {invalid or incomplete multibyte or wide character}} 1}

test io-bug-73bb43fb-3 {
    Non-blocking+buffer size+encoding error panic - TCL bug 73bb42fb.
    Modified Sergey's repro script from ticket. Check no crash / error.
} -setup {
    set f ""
} -body {
    set f [open [list | [info nameofexecutable] << {fconfigure stdout -translation binary; puts \xD6[string repeat _ 20]}]]
    fconfigure $f -encoding utf-8 -profile strict -blocking 0 -buffersize 10 -translation lf -eofchar {}
    list [catch { read_blocked $f } e d] $e [dict getd $d -code ""] [dict getd $d -errorcode ""]
} -cleanup {
    if {$f ne ""} {close $f}
} -match glob -result {1 {error reading *} 1 {POSIX EILSEQ {invalid or incomplete multibyte or wide character}}}

test io-bug-73bb43fb-4 {
    Non-blocking+buffer size+encoding error panic - TCL bug 73bb42fb.
    (PoC) Delay between bytes of single utf-8 char doesn't cause encoding error with profile strict.
} -setup {
    set f ""
} -body {
    set f [open [list | [info nameofexecutable] << {
      fconfigure stdout -translation binary
      puts -nonewline "START-"; flush stdout
      foreach {ch} [split [encoding convertto utf-8 \u30B3] ""] {; # 3 bytes E3 82 B3
        puts -nonewline $ch; flush stdout; if {$ch ne "\xB3"} {after 100}
      }
      puts -nonewline "-DONE"; flush stdout
    }]]
    fconfigure $f -encoding utf-8 -profile strict -blocking 0 -buffersize 10 -translation lf -eofchar {}
    list [catch { read_blocked $f 12 } e d] $e [dict getd $d -code ""] [dict getd $d -errorcode ""]
} -cleanup {
    if {$f ne ""} {close $f}
} -result "0 START-\u30B3-DONE 0 {}"

rename read_blocked {}

# cleanup
foreach file [list fooBar longfile script2 output test1 pipe my_script \
	test2 test3 cat stdout kyrillic.txt utf8-fcopy.txt utf8-rp.txt] {
    removeFile $file
}
cleanupTests
}
namespace delete ::tcl::test::io
return
Changes to tests/listObj.test.
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
    testobj set 1 [testlistrep new 1000 100 100]
} -cleanup {
    testobj freeallvars
} -body {
    list [testlistobj index 1 -1] [testlistobj index 1 1000]
} -result {null null}

test listobj-14.3 {Tcl_ListObjIndex out-of-bounds index for lseq} -constraints {bug-30e4e9102f testobj} -setup {
    testobj set 1 [lseq 3]
} -cleanup {
    testobj freeallvars
} -body {
    list [testlistobj index 1 -1] [testlistobj index 1 3]
} -result {null null}








|







315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
    testobj set 1 [testlistrep new 1000 100 100]
} -cleanup {
    testobj freeallvars
} -body {
    list [testlistobj index 1 -1] [testlistobj index 1 1000]
} -result {null null}

test listobj-14.3 {Tcl_ListObjIndex out-of-bounds index for lseq} -constraints {bug_30e4e9102f testobj} -setup {
    testobj set 1 [lseq 3]
} -cleanup {
    testobj freeallvars
} -body {
    list [testlistobj index 1 -1] [testlistobj index 1 3]
} -result {null null}

Changes to tests/zipfs.test.
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
	    [readbin [file join $newmount test2]]
    } -result {{} {test2 test3} test2-overlay}

    test zipfs-unmount-nested-2 "unmount parent of nested mount on existing directory should not affect nested mount" -setup {
	mount [zippath test.zip]
	set newmount [file join [zipfs root] test testdir]
	mount [zippath test-overlay.zip] $newmount
    } -constraints bug-4ae42446ab -cleanup {
	cleanup
    } -body {
	# KNOWN BUG. The test2 file is also present in parent mount.
	# After the unmount, the test2 in the nested mount is not
	# made available.
	zipfs unmount $defMountPt
	list \







|







665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
	    [readbin [file join $newmount test2]]
    } -result {{} {test2 test3} test2-overlay}

    test zipfs-unmount-nested-2 "unmount parent of nested mount on existing directory should not affect nested mount" -setup {
	mount [zippath test.zip]
	set newmount [file join [zipfs root] test testdir]
	mount [zippath test-overlay.zip] $newmount
    } -constraints bug_4ae42446ab -cleanup {
	cleanup
    } -body {
	# KNOWN BUG. The test2 file is also present in parent mount.
	# After the unmount, the test2 in the nested mount is not
	# made available.
	zipfs unmount $defMountPt
	list \
Changes to win/Makefile.in.
1053
1054
1055
1056
1057
1058
1059



1060
1061
1062
1063
1064
1065
1066

cleanhelp:
	$(RM) *.hlp *.cnt *.GID

clean: cleanhelp clean-packages
	$(RM) *.lib *.a *.exp *.dll *.$(RES) *.${OBJEXT} *~ \#* TAGS a.out
	$(RM) $(TCLSH) $(CAT32) $(TEST_EXE_FILE) $(TEST_DLL_FILE) tcltest.cmd tcltest.sh



	$(RM) *.pch *.ilk *.pdb *.zip
	$(RM) minizip${HOST_EXEEXT} *.${HOST_OBJEXT}
	$(RMDIR) *.vfs

distclean: distclean-packages clean
	$(RM) Makefile config.status config.cache config.log tclConfig.sh \
		config.status.lineno tclsh.exe.manifest tclUuid.h







>
>
>







1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069

cleanhelp:
	$(RM) *.hlp *.cnt *.GID

clean: cleanhelp clean-packages
	$(RM) *.lib *.a *.exp *.dll *.$(RES) *.${OBJEXT} *~ \#* TAGS a.out
	$(RM) $(TCLSH) $(CAT32) $(TEST_EXE_FILE) $(TEST_DLL_FILE) tcltest.cmd tcltest.sh
	# remaining binaries (inclusive manifests) by version/branch switch, but retain tclsh.exe.manifest (that created on configure phase)
	find . -maxdepth 1 -type f -regex '\./tcl\(sh[^.]+\|test\|[^.]+.dll\)\.[^.]*\(\.manifest\)?' \
		-a -not -name 'tclsh.exe.manifest' -exec rm {} \;
	$(RM) *.pch *.ilk *.pdb *.zip
	$(RM) minizip${HOST_EXEEXT} *.${HOST_OBJEXT}
	$(RMDIR) *.vfs

distclean: distclean-packages clean
	$(RM) Makefile config.status config.cache config.log tclConfig.sh \
		config.status.lineno tclsh.exe.manifest tclUuid.h
Changes to win/rules.vc.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
!ifndef _RULES_VC
_RULES_VC = 1

# The following macros define the version of the rules.vc nmake build system
# For modifications that are not backward-compatible, you *must* change
# the major version.
RULES_VERSION_MAJOR = 1
RULES_VERSION_MINOR = 13

# The PROJECT macro must be defined by parent makefile.
!if "$(PROJECT)" == ""
!error *** Error: Macro PROJECT not defined! Please define it before including rules.vc
!endif

!if "$(PRJ_PACKAGE_TCLNAME)" == ""







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
!ifndef _RULES_VC
_RULES_VC = 1

# The following macros define the version of the rules.vc nmake build system
# For modifications that are not backward-compatible, you *must* change
# the major version.
RULES_VERSION_MAJOR = 1
RULES_VERSION_MINOR = 14

# The PROJECT macro must be defined by parent makefile.
!if "$(PROJECT)" == ""
!error *** Error: Macro PROJECT not defined! Please define it before including rules.vc
!endif

!if "$(PRJ_PACKAGE_TCLNAME)" == ""
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707

!if [echo REM = This file is generated from rules.vc > versions.vc]
!endif
!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \
   && [nmakehlp -V "$(_TCL_H)" "define TCL_MAJOR_VERSION" >> versions.vc]
!endif
!if [echo TCL_MINOR_VERSION = \>> versions.vc] \
   && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc]
!endif
!if [echo TCL_RELEASE_SERIAL = \>> versions.vc] \
   && [nmakehlp -V "$(_TCL_H)" TCL_RELEASE_SERIAL >> versions.vc]
!endif
!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \
   && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc]
!endif







|







693
694
695
696
697
698
699
700
701
702
703
704
705
706
707

!if [echo REM = This file is generated from rules.vc > versions.vc]
!endif
!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \
   && [nmakehlp -V "$(_TCL_H)" "define TCL_MAJOR_VERSION" >> versions.vc]
!endif
!if [echo TCL_MINOR_VERSION = \>> versions.vc] \
   && [nmakehlp -V "$(_TCL_H)" "define TCL_MINOR_VERSION" >> versions.vc]
!endif
!if [echo TCL_RELEASE_SERIAL = \>> versions.vc] \
   && [nmakehlp -V "$(_TCL_H)" TCL_RELEASE_SERIAL >> versions.vc]
!endif
!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \
   && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc]
!endif
1293
1294
1295
1296
1297
1298
1299

1300
1301
1302
1303
1304
1305
1306
1307
tklibs = "$(TKSTUBLIB)" "$(TKIMPLIB)"

!endif # $(DOING_TK)
!endif # $(DOING_TK) || $(NEED_TK)

# Various output paths
PRJIMPLIB	= $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib

PRJLIBNAME8	= $(PROJECT)$(VERSION)$(SUFX).$(EXT)
# Even when building against Tcl 8, PRJLIBNAME9 must not have "t"
PRJLIBNAME9	= tcl9$(PROJECT)$(VERSION)$(SUFX:t=).$(EXT)
!if $(TCL_MAJOR_VERSION) == 8 || "$(TCL_BUILD_FOR)" == "8"
PRJLIBNAME	= $(PRJLIBNAME8)
!else
PRJLIBNAME	= $(PRJLIBNAME9)
!endif







>
|







1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
tklibs = "$(TKSTUBLIB)" "$(TKIMPLIB)"

!endif # $(DOING_TK)
!endif # $(DOING_TK) || $(NEED_TK)

# Various output paths
PRJIMPLIB	= $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
# Even when building against Tcl 9, PRJLIBNAME8 must have "t"
PRJLIBNAME8	= $(PROJECT)$(VERSION)t$(SUFX:t=).$(EXT)
# Even when building against Tcl 8, PRJLIBNAME9 must not have "t"
PRJLIBNAME9	= tcl9$(PROJECT)$(VERSION)$(SUFX:t=).$(EXT)
!if $(TCL_MAJOR_VERSION) == 8 || "$(TCL_BUILD_FOR)" == "8"
PRJLIBNAME	= $(PRJLIBNAME8)
!else
PRJLIBNAME	= $(PRJLIBNAME9)
!endif