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 086ca15865

2025-03-12
17:20
merge 9.0 (fix for `clock add` regression, relative time with TZ over DST-hole, see clock-30.34) Leaf check-in: c1e6ca3321 user: sebres tags: trunk, main
17:18
merge 8.7 (fix for `clock add` regression, relative time with TZ over DST-hole, see clock-30.34) Leaf check-in: 086ca15865 user: sebres tags: core-9-0-branch
17:00
clock: fixes regression for clock add (and potentially free-scan) for relative time units with TZ (b... Leaf check-in: b730bd6161 user: sebres tags: core-8-branch
2025-03-11
18:36
merge 8.7: fixes [482db1d796540e68], some minor optimizations and another corner cases for a compile... check-in: 57d18c0efc user: sebres 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
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
        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
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)
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>
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)
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
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.48.0
 - 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
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 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.
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
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
Tcl_Size
\fBTcl_Char16Len\fR(\fIutf16\fR)
.sp
int
Tcl_Size
\fBTcl_WCharLen\fR(\fIwcharStr\fR)
.sp
int
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
int
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
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
\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
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 m [expr {$n - 1}]
    set factor [factorial [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
Changes to generic/tclClock.c.
94
95
96
97
98
99
100
101


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

101
102
103
104
105
106
107
108
109







-
+
+







static Tcl_ObjCmdProc	ClockSecondsObjCmd;
static Tcl_ObjCmdProc	ClockFormatObjCmd;
static Tcl_ObjCmdProc	ClockScanObjCmd;
static int		ClockScanCommit(DateInfo *info,
			    ClockFmtScnCmdArgs *opts);
static int		ClockFreeScan(DateInfo *info,
			    Tcl_Obj *strObj, ClockFmtScnCmdArgs *opts);
static int		ClockCalcRelTime(DateInfo *info);
static int		ClockCalcRelTime(DateInfo *info,
			    ClockFmtScnCmdArgs *opts);
static Tcl_ObjCmdProc	ClockAddObjCmd;
static int		ClockValidDate(DateInfo *,
			    ClockFmtScnCmdArgs *, int stage);
static struct tm *	ThreadSafeLocalTime(const time_t *);
static size_t		TzsetIfNecessary(void);
static void		ClockDeleteCmdProc(void *);
static Tcl_ObjCmdProc	ClockSafeCatchCmd;
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3646
3647
3648
3649
3650
3651
3652













3653
3654
3655
3656
3657
3658
3659







-
-
-
-
-
-
-
-
-
-
-
-
-







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

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

    /*
     * If no GMT and not free-scan (where valid stage 1 is done in-between),
     * validate with stage 1 before local time conversion, otherwise it may
     * adjust date/time tokens to valid values
     */
    if ((opts.flags & CLF_VALIDATE_S1)
	    && info->flags & (CLF_ASSEMBLE_SECONDS|CLF_LOCALSEC)) {
	ret = ClockValidDate(&yy, &opts, CLF_VALIDATE_S1);
	if (ret != TCL_OK) {
	    goto done;
	}
    }

    /* Convert date info structure into UTC seconds */

    ret = ClockScanCommit(&yy, &opts);
    if (ret != TCL_OK) {
	goto done;
    }

3702
3703
3704
3705
3706
3707
3708












3709
3710
3711
3712
3713
3714
3715
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715







+
+
+
+
+
+
+
+
+
+
+
+







 */

static int
ClockScanCommit(
    DateInfo *info,		/* Clock scan info structure */
    ClockFmtScnCmdArgs *opts)	/* Format, locale, timezone and base */
{
    /*
     * If no GMT and not free-scan (where valid stage 1 is done in-between),
     * validate with stage 1 before local time conversion, otherwise it may
     * adjust date/time tokens to valid values
     */
    if ((opts->flags & CLF_VALIDATE_S1)
	    && info->flags & (CLF_ASSEMBLE_SECONDS|CLF_LOCALSEC)) {
	if (ClockValidDate(info, opts, CLF_VALIDATE_S1) != TCL_OK) {
	    return TCL_ERROR;
	}
    }

    /* If needed assemble julianDay using year, month, etc. */
    if (info->flags & CLF_ASSEMBLE_JULIANDAY) {
	if (info->flags & CLF_ISO8601WEEK) {
	    GetJulianDayFromEraYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE);
	} else if (!(info->flags & CLF_DAYOFYEAR) /* no day of year */
		|| (info->flags & (CLF_DAYOFMONTH|CLF_MONTH)) /* yymmdd over yyddd */
		== (CLF_DAYOFMONTH|CLF_MONTH)) {
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009

4010
4011
4012
4013
4014
4015
4016
3986
3987
3988
3989
3990
3991
3992

3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007

4008
4009
4010
4011
4012
4013
4014
4015







-















-
+







				 * simultaneously a yy-parse structure of the
				 * TclClockFreeScan */
    Tcl_Obj *strObj,		/* String containing the time to scan */
    ClockFmtScnCmdArgs *opts)	/* Command options */
{
    Tcl_Interp *interp = opts->interp;
    ClockClientData *dataPtr = opts->dataPtr;
    int ret = TCL_ERROR;

    /*
     * Parse the date. The parser will fill a structure "info" with date,
     * time, time zone, relative month/day/seconds, relative weekday, ordinal
     * month.
     * Notice that many yy-defines point to values in the "info" or "date"
     * structure, e. g. yySecondOfDay -> info->date.secondOfDay or
     *			yyMonth -> info->date.month (same as yydate.month)
     */
    yyInput = TclGetString(strObj);

    if (TclClockFreeScan(interp, info) != TCL_OK) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"unable to convert date-time string \"%s\": %s",
		TclGetString(strObj), Tcl_GetString(Tcl_GetObjResult(interp))));
	goto done;
	return TCL_ERROR;
    }

    /*
     * If the caller supplied a date in the string, update the date with
     * the value. If the caller didn't specify a time with the date, default to
     * midnight.
     */
4047
4048
4049
4050
4051
4052
4053
4054

4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068

4069
4070
4071
4072
4073
4074
4075
4046
4047
4048
4049
4050
4051
4052

4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066

4067
4068
4069
4070
4071
4072
4073
4074







-
+













-
+







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

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

	info->flags |= CLF_ASSEMBLE_SECONDS;
    }

    /*
     * For freescan apply validation rules (stage 1) before mixed with
     * relative time (otherwise always valid recalculated date & time).
     */
    if (opts->flags & CLF_VALIDATE) {
	if (ClockValidDate(info, opts, CLF_VALIDATE_S1) != TCL_OK) {
	    goto done;
	    return TCL_ERROR;
	}
    }

    /*
     * Assemble date, time, zone into seconds-from-epoch
     */

4083
4084
4085
4086
4087
4088
4089



4090
4091
4092
4093

4094
4095

4096
4097



4098
4099
4100
4101




4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120


4121
4122
4123
4124
4125

4126

4127
4128
4129
4130
4131
4132
4133
4134
4135







4136
4137

4138
4139
4140


4141
4142
4143
4144
4145
4146
4147
4148







4149
4150
4151
4152
4153
4154
4155
4156








4157
4158
4159


4160
4161
4162
4163
4164
4165





4166
4167
4168


4169
4170
4171


4172
4173
4174
4175
4176
4177
4178
4179
4180








4181
4182
4183
4184
4185




4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206

4207
4208
4209
4210
4211
4212
4213
4214
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094

4095
4096
4097
4098


4099
4100
4101




4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123

4124
4125
4126
4127
4128
4129
4130
4131

4132
4133
4134







4135
4136
4137
4138
4139
4140
4141
4142

4143
4144


4145
4146
4147







4148
4149
4150
4151
4152
4153
4154
4155







4156
4157
4158
4159
4160
4161
4162
4163



4164
4165
4166





4167
4168
4169
4170
4171
4172


4173
4174
4175


4176
4177
4178








4179
4180
4181
4182
4183
4184
4185
4186
4187




4188
4189
4190
4191
4192




















4193

4194
4195
4196
4197
4198
4199
4200







+
+
+



-
+


+
-
-
+
+
+
-
-
-
-
+
+
+
+


















-
+
+





+
-
+


-
-
-
-
-
-
-
+
+
+
+
+
+
+

-
+

-
-
+
+

-
-
-
-
-
-
-
+
+
+
+
+
+
+

-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
+
+

-
-
-
-
-
+
+
+
+
+

-
-
+
+

-
-
+
+

-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+

-
-
-
-
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-







	    || (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
     * Do relative times if needed.
     */

    if (info->flags & CLF_RELCONV) {
    ret = ClockCalcRelTime(info);

	if (ClockCalcRelTime(info, opts) != TCL_OK) {
	    return TCL_ERROR;
	}
    /* Free scanning completed - date ready */

  done:
    return ret;
    }

    /* Free scanning completed - date ready */
    return TCL_OK;
}

/*----------------------------------------------------------------------
 *
 * ClockCalcRelTime --
 *
 *	Used for calculating of relative times.
 *
 * Results:
 *	Returns a standard Tcl result.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */
int
ClockCalcRelTime(
    DateInfo *info)		/* Date fields used for converting */
    DateInfo *info,		/* Date fields used for converting */
    ClockFmtScnCmdArgs *opts)	/* Command options */
{
    int prevDayOfWeek = yyDayOfWeek;	/* preserve unchanged day of week */

    /*
     * Because some calculations require in-between conversion of the
     * julian day, and fixed order due to tokens precedence,
     * julian day, we can repeat this processing multiple times
     * we can repeat this processing multiple times
     */
  repeat_rel:
    if (info->flags & CLF_RELCONV) {
	/*
	 * Relative conversion normally possible in UTC time only, because
	 * of possible wrong local time increment if ignores in-between DST-hole.
	 * (see test-cases clock-34.53, clock-34.54).
	 * So increment date in julianDay, but time inside day in UTC (seconds).
	 */

    /*
     * Relative conversion normally possible in UTC time only, because
     * of possible wrong local time increment if ignores in-between DST-hole.
     * (see tests clock-34.53, clock-34.54) or by jump across TZ (CET/CEST).
     * So increment date in julianDay, but time inside day in UTC (seconds).
     */

	/* add months (or years in months) */
    /* add relative months (or years in months) */

	if (yyRelMonth != 0) {
	    int m, h;
    if (yyRelMonth != 0) {
	int m, h;

	    /* if needed extract year, month, etc. again */
	    if (info->flags & CLF_ASSEMBLE_DATE) {
		GetGregorianEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);
		GetMonthDay(&yydate);
		GetYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE);
		info->flags &= ~CLF_ASSEMBLE_DATE;
	    }
	/* if needed extract year, month, etc. again */
	if (info->flags & CLF_ASSEMBLE_DATE) {
	    GetGregorianEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);
	    GetMonthDay(&yydate);
	    GetYearWeekDay(&yydate, GREGORIAN_CHANGE_DATE);
	    info->flags &= ~CLF_ASSEMBLE_DATE;
	}

	    /* add the requisite number of months */
	    yyMonth += yyRelMonth - 1;
	    yyYear += yyMonth / 12;
	    m = yyMonth % 12;
	    /* compiler fix for negative offs - wrap y, m = (0, -1) -> (-1, 11) */
	    if (m < 0) {
		yyYear--;
	/* 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--;
		m = 12 + m;
	    }
	    yyMonth = m + 1;
	}
	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;
	    }
	/* if the day doesn't exist in the current month, repair it */
	h = hath[IsGregorianLeapYear(&yydate)][m];
	if (yyDay > h) {
	    yyDay = h;
	}

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

	    yyRelMonth = 0;
	}
	yyRelMonth = 0;
    }

	/* add days (or other parts aligned to days) */
	if (yyRelDay) {
	    /* assemble julianDay using new year, month, etc. */
	    if (info->flags & CLF_ASSEMBLE_JULIANDAY) {
		GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
		info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
	    }
	    yydate.julianDay += yyRelDay;
    /* add relative days (or other parts aligned to days) */
    if (yyRelDay) {
	/* assemble julianDay using new year, month, etc. */
	if (info->flags & CLF_ASSEMBLE_JULIANDAY) {
	    GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
	    info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
	}
	yydate.julianDay += yyRelDay;

	    /* julianDay was changed, on demand (lazy) extract year, month, etc. again */
	    info->flags |= CLF_ASSEMBLE_DATE|CLF_ASSEMBLE_SECONDS;
	    yyRelDay = 0;
	}
	/* julianDay was changed, on demand (lazy) extract year, month, etc. again */
	info->flags |= CLF_ASSEMBLE_DATE | CLF_ASSEMBLE_SECONDS;
	yyRelDay = 0;
    }

	/* 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;
    }

    /*
     * Do relative (ordinal) month
    /* do relative (ordinal) month */
     */

    if (info->flags & CLF_ORDINALMONTH) {
	int monthDiff;

	/* if needed extract year, month, etc. again */
	if (info->flags & CLF_ASSEMBLE_DATE) {
	    GetGregorianEraYearDay(&yydate, GREGORIAN_CHANGE_DATE);
4231
4232
4233
4234
4235
4236
4237
4238

4239
4240
4241
4242
4243
4244

4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264























































4265
4266
4267
4268
4269
4270
4271
4217
4218
4219
4220
4221
4222
4223

4224
4225
4226
4227
4228


4229

4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310







-
+




-
-
+
-



















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	    yyMonthOrdinalIncr++;
	}

	/* process it further via relative times */
	yyYear += yyMonthOrdinalIncr;
	yyRelMonth += monthDiff;
	info->flags &= ~CLF_ORDINALMONTH;
	info->flags |= CLF_RELCONV|CLF_ASSEMBLE_JULIANDAY|CLF_ASSEMBLE_SECONDS;
	info->flags |= CLF_ASSEMBLE_JULIANDAY|CLF_ASSEMBLE_SECONDS;

	goto repeat_rel;
    }

    /*
     * Do relative weekday
    /* do relative weekday */
     */

    if ((info->flags & (CLF_DAYOFWEEK|CLF_HAVEDATE)) == CLF_DAYOFWEEK) {
	/* restore scanned day of week */
	yyDayOfWeek = prevDayOfWeek;

	/* if needed assemble julianDay now */
	if (info->flags & CLF_ASSEMBLE_JULIANDAY) {
	    GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
	    info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
	}

	yydate.isBce = 0;
	yydate.julianDay = WeekdayOnOrBefore(yyDayOfWeek, yydate.julianDay + 6)
		+ 7 * yyDayOrdinal;
	if (yyDayOrdinal > 0) {
	    yydate.julianDay -= 7;
	}
	info->flags |= CLF_ASSEMBLE_DATE|CLF_ASSEMBLE_SECONDS;
    }

    /* If relative time is there, adjust it in UTC as mentioned above. */
    if (yyRelSeconds) {
	/*
	 * If timezone is not GMT/UTC (due to DST-hole, local time offset),
	 * we shall do in-between conversion to UTC to append seconds there
	 * and hereafter convert back to TZ, otherwise apply it direct here.
	 */
	if (opts->timezoneObj != opts->dataPtr->literals[LIT_GMT]) {
	    /* 
	     * Convert date info structure into UTC seconds and add relative
	     * seconds (happens in commit).
	     */
	    if (ClockScanCommit(info, opts) != TCL_OK) {
		return TCL_ERROR;
	    }
	    yyRelSeconds = 0;
	    /* Convert it back */
	    if (ClockGetDateFields(opts->dataPtr, opts->interp, &yydate,
		  opts->timezoneObj, GREGORIAN_CHANGE_DATE) != TCL_OK) {
		/* TODO - GREGORIAN_CHANGE_DATE should be locale-dependent */
		return TCL_ERROR;
	    }
	    /* 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;
	    }
	    /* restore scanned day of week */
	    yyDayOfWeek = prevDayOfWeek;
	} else {
	    /* 
	     * GMT/UTC zone, so no DST and no offsets - apply it here, so that
	     * if time exceeds current date, do the day conversion and leave the
	     * rest of increment in yyRelSeconds (add it later in UTC by commit)
	     */
	    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;
	    }
	}
    }

    /* done, reset flag */
    info->flags &= ~CLF_RELCONV;

    return TCL_OK;
}

/*----------------------------------------------------------------------
 *
 * ClockWeekdaysOffs --
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
4327
4328
4329
4330
4331
4332
4333
4334
4335

4336
4337
4338
4339
4340
4341
4342
4343
4344

4345
4346
4347
4348
4349
4350
4351
4352







+

-









-
+







    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 = 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;
	    day += 7;
	}
	resDayOfWeek = dayOfWeek + day;
    }

    /* adjust if we start from a weekend */
    if (dayOfWeek > 5) {
	int adj = 5 - dayOfWeek;
4389
4390
4391
4392
4393
4394
4395
4396

4397
4398
4399
4400
4401
4402
4403
4428
4429
4430
4431
4432
4433
4434

4435
4436
4437
4438
4439
4440
4441
4442







-
+







	NULL
    };
    enum unitInd {
	CLC_ADD_YEARS,	CLC_ADD_MONTHS,	    CLC_ADD_WEEK,   CLC_ADD_WEEKS,
	CLC_ADD_DAYS,	CLC_ADD_WEEKDAYS,
	CLC_ADD_HOURS,	CLC_ADD_MINUTES,    CLC_ADD_SECONDS
    };
    int unitIndex;		/* Index of an option. */
    int unitIndex = CLC_ADD_SECONDS;	/* Index of an option. */
    Tcl_Size i;
    Tcl_WideInt offs;

    /* even number of arguments */
    if ((objc & 1) == 1) {
	Tcl_WrongNumArgs(interp, 0, objv, syntax);
	Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", (char *)NULL);
4414
4415
4416
4417
4418
4419
4420
4421





4422
4423
4424
4425
4426
4427
4428
4453
4454
4455
4456
4457
4458
4459

4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471







-
+
+
+
+
+







    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;
    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;

4449
4450
4451
4452
4453
4454
4455
4456
4457


4458
4459

4460
4461
4462
4463
4464
4465
4466



4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4492
4493
4494
4495
4496
4497
4498


4499
4500
4501

4502







4503
4504
4505
4506
4507
4508
4509
4510

4511
4512
4513
4514
4515
4516
4517







-
-
+
+

-
+
-
-
-
-
-
-
-
+
+
+





-








	/* nothing to do if zero quantity */
	if (!offs) {
	    continue;
	}

	/* if in-between conversion needed (already have relative date/time),
	 * correct date info, because the date may be changed,
	 * so refresh it now */
	 * correct date info, because the local date/time may be changed, so
	 * refresh it now (see test clock-30.34 "clock add jump over DST hole") */

	if ((info->flags & CLF_RELCONV)
	if ((info->flags & CLF_RELCONV) ||
		&& (unitIndex == CLC_ADD_WEEKDAYS
		/* some months can be shorter as another */
		|| yyRelMonth || yyRelDay
		/* day changed */
		|| yySeconds + yyRelSeconds > SECONDS_PER_DAY
		|| yySeconds + yyRelSeconds < 0)) {
	    if (ClockCalcRelTime(info) != TCL_OK) {
	    (yyRelSeconds && unitIndex < CLC_ADD_HOURS)
	) {
	    if (ClockCalcRelTime(info, &opts) != TCL_OK) {
		goto done;
	    }
	}

	/* process increment by offset + unit */
	info->flags |= CLF_RELCONV;
	switch (unitIndex) {
	case CLC_ADD_YEARS:
	    yyRelMonth += offs * 12;
	    break;
	case CLC_ADD_MONTHS:
	    yyRelMonth += offs;
	    break;
4496
4497
4498
4499
4500
4501
4502



4503
4504
4505
4506


4507
4508
4509
4510

4511
4512
4513
4514
4515
4516
4517
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546

4547
4548
4549
4550
4551

4552
4553
4554
4555
4556
4557
4558
4559







+
+
+



-
+
+



-
+







	case CLC_ADD_MINUTES:
	    yyRelSeconds += offs * 60;
	    break;
	case CLC_ADD_SECONDS:
	    yyRelSeconds += offs;
	    break;
	}
	if (unitIndex != CLC_ADD_SECONDS) {
	    info->flags |= CLF_RELCONV;
	}
    }

    /*
     * Do relative times (if not yet already processed interim):
     * Do relative times (if not yet already processed interim),
     * thereby ignore relative time (it can be processed within commit).
     */

    if (info->flags & CLF_RELCONV) {
	if (ClockCalcRelTime(info) != TCL_OK) {
	if (ClockCalcRelTime(info, &opts) != TCL_OK) {
	    goto done;
	}
    }

    /* Convert date info structure into UTC seconds */

    ret = ClockScanCommit(&yy, &opts);
Changes to generic/tclCmdMZ.c.
4503
4504
4505
4506
4507
4508
4509
4510

4511
4512
4513
4514
4515
4516
4517
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
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;
    size_t n;
    Tcl_Size n;
    Tcl_Token *elemTokenPtr = NULL;
	size_t nameLen, elNameLen;
    int simpleVarName, localIndex;
    Tcl_Size elemTokenCount = 0, removedParen = 0;
    int elemTokenCount = 0, allocedTokens = 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
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. */
    size_t count1,		/* Number of tokens to consider at tokenPtr.
    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;
    size_t length;
    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);
    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
2635
2636
2637
2638
2639
2640
2641
2642

2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
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. */
    size_t count1,			/* Number of tokens to consider at tokenPtr.
    Tcl_Size count,		/* 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.
	 */

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
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,
			    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, size_t count,
			    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/tclDate.c.
1493
1494
1495
1496
1497
1498
1499

1500
1501
1502
1503
1504
1505

1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524

1525
1526
1527
1528
1529
1530
1531
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525

1526
1527
1528
1529
1530
1531
1532
1533







+






+


















-
+







	    yyIncrFlags(CLF_HAVEDATE);
	}
    break;

  case 7: /* item: ordMonth  */
                   {
	    yyIncrFlags(CLF_ORDINALMONTH);
	    info->flags |= CLF_RELCONV;
	}
    break;

  case 8: /* item: day  */
              {
	    yyIncrFlags(CLF_DAYOFWEEK);
	    info->flags |= CLF_RELCONV;
	}
    break;

  case 9: /* item: relspec  */
                  {
	    info->flags |= CLF_RELCONV;
	}
    break;

  case 10: /* item: iso  */
              {
	    yyIncrFlags(CLF_TIME|CLF_HAVEDATE);
	}
    break;

  case 11: /* item: trek  */
               {
	    yyIncrFlags(CLF_TIME|CLF_HAVEDATE);
	    info->flags |= CLF_RELCONV;
	    info->flags |= CLF_TREK;
	}
    break;

  case 13: /* iextime: tUNUMBER ':' tUNUMBER ':' tUNUMBER  */
                                             {
	    yyHour = (yyvsp[-4].Number);
	    yyMinutes = (yyvsp[-2].Number);
1778
1779
1780
1781
1782
1783
1784

1785
1786
1787
1788
1789
1790
1791
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794







+







	     */

	    yyYear = (yyvsp[-2].Number)/1000 + 2323 - 377;
	    yyDay  = 1;
	    yyMonth = 1;
	    yyRelDay += (((yyvsp[-2].Number)%1000)*(365 + IsLeapYear(yyYear)))/1000;
	    yyRelSeconds += (yyvsp[0].Number) * (144LL * 60LL);
	    info->flags |= CLF_RELCONV;
	}
    break;

  case 54: /* relspec: relunits tAGO  */
                        {
	    yyRelSeconds *= -1;
	    yyRelMonth *= -1;
1841
1842
1843
1844
1845
1846
1847

1848
1849
1850
1851
1852
1853
1854

1855
1856
1857
1858
1859
1860
1861

1862
1863
1864
1865
1866
1867
1868
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874







+







+







+







	}
    break;

  case 64: /* unit: tSEC_UNIT  */
                    {
	    (yyval.Number) = (yyvsp[0].Number);
	    yyRelPointer = &yyRelSeconds;
	    /* no flag CLF_RELCONV needed by seconds */
	}
    break;

  case 65: /* unit: tDAY_UNIT  */
                    {
	    (yyval.Number) = (yyvsp[0].Number);
	    yyRelPointer = &yyRelDay;
	    info->flags |= CLF_RELCONV;
	}
    break;

  case 66: /* unit: tMONTH_UNIT  */
                      {
	    (yyval.Number) = (yyvsp[0].Number);
	    yyRelPointer = &yyRelMonth;
	    info->flags |= CLF_RELCONV;
	}
    break;

  case 67: /* INTNUM: tUNUMBER  */
                   {
	    (yyval.Number) = (yyvsp[0].Number);
	}
1878
1879
1880
1881
1882
1883
1884
1885

1886
1887
1888
1889
1890
1891
1892
1884
1885
1886
1887
1888
1889
1890

1891
1892
1893
1894
1895
1896
1897
1898







-
+







                   {
	    (yyval.Number) = (yyvsp[0].Number);
	}
    break;

  case 70: /* numitem: tUNUMBER  */
                   {
	    if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_RELCONV)) == (CLF_TIME|CLF_HAVEDATE)) {
	    if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_TREK)) == (CLF_TIME|CLF_HAVEDATE)) {
		yyYear = (yyvsp[0].Number);
	    } else {
		yyIncrFlags(CLF_TIME);
		if (yyDigitCount <= 2) {
		    yyHour = (yyvsp[0].Number);
		    yyMinutes = 0;
		} else {
Changes to generic/tclDate.h.
59
60
61
62
63
64
65

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







+








    /*
     * Extra flags used outside of scan/format-tokens too (int, not a short).
     */

    CLF_RELCONV = 1 << 17,
    CLF_ORDINALMONTH = 1 << 18,
    CLF_TREK = 1 << 19,

    /* On demand (lazy) assemble flags */

    CLF_ASSEMBLE_DATE = 1 << 28,/* assemble year, month, etc. using julianDay */
    CLF_ASSEMBLE_JULIANDAY = 1 << 29,
				/* assemble julianDay using year, month, etc. */
    CLF_ASSEMBLE_SECONDS = 1 << 30
Changes to generic/tclGetDate.y.
182
183
184
185
186
187
188

189
190
191

192
193
194
195
196
197
198
199
200
201

202
203
204
205
206
207
208
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

203
204
205
206
207
208
209
210







+



+









-
+







	    yyIncrFlags(CLF_ZONE);
	}
	| date {
	    yyIncrFlags(CLF_HAVEDATE);
	}
	| ordMonth {
	    yyIncrFlags(CLF_ORDINALMONTH);
	    info->flags |= CLF_RELCONV;
	}
	| day {
	    yyIncrFlags(CLF_DAYOFWEEK);
	    info->flags |= CLF_RELCONV;
	}
	| relspec {
	    info->flags |= CLF_RELCONV;
	}
	| iso {
	    yyIncrFlags(CLF_TIME|CLF_HAVEDATE);
	}
	| trek {
	    yyIncrFlags(CLF_TIME|CLF_HAVEDATE);
	    info->flags |= CLF_RELCONV;
	    info->flags |= CLF_TREK;
	}
	| numitem
	;

iextime : tUNUMBER ':' tUNUMBER ':' tUNUMBER {
	    yyHour = $1;
	    yyMinutes = $3;
385
386
387
388
389
390
391

392
393
394
395
396
397
398
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401







+







	     */

	    yyYear = $2/1000 + 2323 - 377;
	    yyDay  = 1;
	    yyMonth = 1;
	    yyRelDay += (($2%1000)*(365 + IsLeapYear(yyYear)))/1000;
	    yyRelSeconds += $4 * (144LL * 60LL);
	    info->flags |= CLF_RELCONV;
	}
	;

relspec : relunits tAGO {
	    yyRelSeconds *= -1;
	    yyRelMonth *= -1;
	    yyRelDay *= -1;
427
428
429
430
431
432
433

434
435
436
437

438
439
440
441

442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457

458
459
460
461
462
463
464
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462

463
464
465
466
467
468
469
470







+




+




+















-
+







	    $$ =  1;
	}
	;

unit	: tSEC_UNIT {
	    $$ = $1;
	    yyRelPointer = &yyRelSeconds;
	    /* no flag CLF_RELCONV needed by seconds */
	}
	| tDAY_UNIT {
	    $$ = $1;
	    yyRelPointer = &yyRelDay;
	    info->flags |= CLF_RELCONV;
	}
	| tMONTH_UNIT {
	    $$ = $1;
	    yyRelPointer = &yyRelMonth;
	    info->flags |= CLF_RELCONV;
	}
	;

INTNUM	: tUNUMBER {
	    $$ = $1;
	}
	| tISOBAS6 {
	    $$ = $1;
	}
	| tISOBAS8 {
	    $$ = $1;
	}
	;

numitem	: tUNUMBER {
	    if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_RELCONV)) == (CLF_TIME|CLF_HAVEDATE)) {
	    if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_TREK)) == (CLF_TIME|CLF_HAVEDATE)) {
		yyYear = $1;
	    } else {
		yyIncrFlags(CLF_TIME);
		if (yyDigitCount <= 2) {
		    yyHour = $1;
		    yyMinutes = 0;
		} else {
Changes to generic/tclIO.c.
6059
6060
6061
6062
6063
6064
6065
6066


6067
6068
6069
6070
6071
6072
6073
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)) {
	    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
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);
    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
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
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
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
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;
     * 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" 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.
     * 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
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;
     * 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" 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.
     * 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
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 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.
 *	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 type.
 *	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 find the range of. */
    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 bytearray object
     * 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
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 find the range of. */
    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 bytearray object
     * 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
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 bytearray objects are pure, so the second internal bytearray value
	 * 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
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 bytearray when possible.
     *		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
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 bytearray when possible.
     *		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 bytearray, so we won't
		 * create a pure bytearray.
		 * 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
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 bytearray with a ("pure")
	     * 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
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 bytearray with a ("pure")
	     * 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
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 "bytearray" or a "string" or else it has
     * 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
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
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}
} -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}
} -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}
} -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
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}
} -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}
} -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
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
} -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
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
} -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
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
} -constraints bugTakesTooLong

#
# regsub
bigtestRO regsub-bigdata-1 "regsub" X -body {
    regsub -all \\d $s {}
} -setup {
    set s [bigString 0x100000001 0x100000000]
} -cleanup {
    bigClean
} -constraints bug-takesTooLong
} -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 bug-takesTooLong
} -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
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
} -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
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
} -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
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
} -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
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
} -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
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
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
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
35898
35899
35900
35901
35902
35903
35904
35905
35906
35907
35908
35909
35910
35911
35912
35913
35914
35915
35916
35917
35918
35919
35920
35921
35922
35923
35924
35925
35926
35927
35928
35929
35930
35931
35932
35933
35934
35935
35936
35937
35938
35939
35940
35941
35942
35943
35944
35945
35946
35947







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	[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}]]]
test clock-30.34 {regression test - clock add jump over DST hole with TZ (1 day != 24 hours, etc)} -body {
    # time units (in opposite to date units) have to ignore DST hole (affects UTC only, so remain relative time),
    # however date units have to jump over the DST hole with retaining of current local time.
    proc test_add_dst {t args} {
	set exp [lindex $args end]; set args [lreplace $args end end]
	set tz [lindex $args end]
	set v [clock format [clock add $t {*}$args] -format "%Y-%m-%d %H:%M:%S %Z" -timezone $tz]
	if {$v ne $exp} {
	    list "\"$v\" ne \"$exp\"" "    while testing \[clock format \[clock add $t $args\] -format \"%Y-%m-%d %H:%M:%S %Z\" -timezone $tz\]"
	}
    }
    set t [clock scan "2024-03-31 01:59:59" -timezone :CET]; # 1 second before time switch CET/CEST
    join [list \
	{*}[test_add_dst $t -timezone :CET                         {2024-03-31 01:59:59 CET}] \
	{*}[test_add_dst $t -1 month -timezone :CET                {2024-02-29 01:59:59 CET}] \
	{*}[test_add_dst $t 1 second -1 month -timezone :CET       {2024-02-29 03:00:00 CET}] \
	{*}[test_add_dst $t -1 day -timezone :CET                  {2024-03-30 01:59:59 CET}] \
	{*}[test_add_dst $t 1 second -1 day -timezone :CET         {2024-03-30 03:00:00 CET}] \
	{*}[test_add_dst $t 1 second -timezone :CET                {2024-03-31 03:00:00 CEST}] \
	{*}[test_add_dst $t 1 day -timezone :CET                   {2024-04-01 01:59:59 CEST}] \
	{*}[test_add_dst $t 24 hours -timezone :CET                {2024-04-01 02:59:59 CEST}] \
	{*}[test_add_dst $t 1440 minutes -timezone :CET            {2024-04-01 02:59:59 CEST}] \
	{*}[test_add_dst $t 86400 seconds -timezone :CET           {2024-04-01 02:59:59 CEST}] \
	{*}[test_add_dst $t 1 second 1 day -timezone :CET          {2024-04-01 03:00:00 CEST}] \
	{*}[test_add_dst $t 1 second 24 hours -timezone :CET       {2024-04-01 03:00:00 CEST}] \
	{*}[test_add_dst $t 1 second 1440 minutes -timezone :CET   {2024-04-01 03:00:00 CEST}] \
	{*}[test_add_dst $t 1 second 86400 seconds -timezone :CET  {2024-04-01 03:00:00 CEST}] \
	{*}[test_add_dst $t 1 month -timezone :CET                 {2024-04-30 01:59:59 CEST}] \
	{*}[test_add_dst $t 1 second 1 month -timezone :CET        {2024-04-30 03:00:00 CEST}] \
	\
	{*}[test_add_dst $t -timezone :GMT                         {2024-03-31 00:59:59 GMT}] \
	{*}[test_add_dst $t -1 month -timezone :GMT                {2024-02-29 00:59:59 GMT}] \
	{*}[test_add_dst $t 1 second -1 month -timezone :GMT       {2024-02-29 01:00:00 GMT}] \
	{*}[test_add_dst $t -1 day -timezone :GMT                  {2024-03-30 00:59:59 GMT}] \
	{*}[test_add_dst $t 1 second -1 day -timezone :GMT         {2024-03-30 01:00:00 GMT}] \
	{*}[test_add_dst $t 1 second -timezone :GMT                {2024-03-31 01:00:00 GMT}] \
	{*}[test_add_dst $t 1 day -timezone :GMT                   {2024-04-01 00:59:59 GMT}] \
	{*}[test_add_dst $t 24 hours -timezone :GMT                {2024-04-01 00:59:59 GMT}] \
	{*}[test_add_dst $t 1440 minutes -timezone :GMT            {2024-04-01 00:59:59 GMT}] \
	{*}[test_add_dst $t 86400 seconds -timezone :GMT           {2024-04-01 00:59:59 GMT}] \
	{*}[test_add_dst $t 1 second 1 day -timezone :GMT          {2024-04-01 01:00:00 GMT}] \
	{*}[test_add_dst $t 1 second 24 hours -timezone :GMT       {2024-04-01 01:00:00 GMT}] \
	{*}[test_add_dst $t 1 second 1440 minutes -timezone :GMT   {2024-04-01 01:00:00 GMT}] \
	{*}[test_add_dst $t 1 second 86400 seconds -timezone :GMT  {2024-04-01 01:00:00 GMT}] \
	{*}[test_add_dst $t 1 month -timezone :GMT                 {2024-04-30 00:59:59 GMT}] \
	{*}[test_add_dst $t 1 second 1 month -timezone :GMT        {2024-04-30 01:00:00 GMT}] \
      ] \n
} -cleanup {
    rename test_add_dst {}
} -result {}

# 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
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
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} {
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 2 to prevent sporadic
	# errors on some slow systems or time issues, because if it is not fixed,
	# 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 * 2} {
	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
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 
    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
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] }
    test expr-58.1($v)=$r "float classification: fpclassify($v) eq $r" {
    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) "float classification: isfinite($v)" {
    test expr-58.2($v)-$changed "float classification: isfinite($v)" {
	expr {isfinite($v)}
    } [expr {$r ni {"infinite" "nan"}}]
    test expr-58.3($v) "float classification: isinf($v)" {
    test expr-58.3($v)-$changed "float classification: isinf($v)" {
	expr {isinf($v)}
    } [expr {$r eq "infinite"}]
    test expr-58.4($v) "float classification: isnan($v)" {
    test expr-58.4($v)-$changed "float classification: isnan($v)" {
	expr {isnan($v)}
    } [expr {$r eq "nan"}]
    test expr-58.5($v) "float classification: isnormal($v)" {
    test expr-58.5($v)-$changed "float classification: isnormal($v)" {
	expr {isnormal($v)}
    } [expr {$r eq "normal"}]
    test expr-58.6($v) "float classification: issubnormal($v)" {
    test expr-58.6($v)-$changed "float classification: issubnormal($v)" {
	expr {issubnormal($v)}
    } [expr {$r eq "subnormal"}]
    test expr-58.7($v) "float classification: isunordered(0 and $v)" {
    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.9($v) "float classification: isunordered(NaN and $v)" {
    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
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
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
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
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 {
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
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 {
    } -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
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
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
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
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]
   && [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
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)$(SUFX).$(EXT)
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