Tcl Source Code

Check-in [9a863e9399]
Login
EuroTcl/OpenACS 11 - 12 JULY 2024, VIENNA

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

Overview
Comment:Merge trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | apn-icu
Files: files | file ages | folders
SHA3-256: 9a863e93994746bee8c111abf1a6930f971ddc065d77297165229b50711e856e
User & Date: apnadkarni 2024-06-20 07:44:32
Context
2024-06-21
10:52
Fix test constraint check-in: 4aa775e938 user: apnadkarni tags: apn-icu
2024-06-20
07:44
Merge trunk check-in: 9a863e9399 user: apnadkarni tags: apn-icu
07:42
Add basic tests check-in: 0562381402 user: apnadkarni tags: apn-icu
2024-06-19
16:39
Fix [7be97a6859]: Reviewing chan.n changes check-in: 9453353b55 user: jan.nijtmans tags: trunk, main
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to changes.md.

32
33
34
35
36
37
38

39
40
41
42
43
44
45
 - Ended interpretation of ~ as home directory in pathnames
 - Removed the "identity" encoding
 - $::tcl_precision no longer controls string generation of doubles
 - Removed Tcl 7 legacies: [case], [puts] [read] variant syntaxes
 - Removed subcommands [trace variable|vdelete|vinfo]
 - No -eofchar option for channels anymore for writing.
 - On Windows 10+ (Version 1903 or higher), system encoding is always utf-8.


## Incompatibilities in C public interface
 - Many arguments expanded type from int to Tcl_Size
 - Ended support for Tcl_ChannelTypeVersion less than 5
 - Introduced versioning of the Tcl_ObjType struct
 - Removed macros CONST*: Tcl 9 support means dropping Tcl 8.3 support
 - Removed routines:







>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 - Ended interpretation of ~ as home directory in pathnames
 - Removed the "identity" encoding
 - $::tcl_precision no longer controls string generation of doubles
 - Removed Tcl 7 legacies: [case], [puts] [read] variant syntaxes
 - Removed subcommands [trace variable|vdelete|vinfo]
 - No -eofchar option for channels anymore for writing.
 - On Windows 10+ (Version 1903 or higher), system encoding is always utf-8.
 - Removed command ::tcl::unsupported::inject.

## Incompatibilities in C public interface
 - Many arguments expanded type from int to Tcl_Size
 - Ended support for Tcl_ChannelTypeVersion less than 5
 - Introduced versioning of the Tcl_ObjType struct
 - Removed macros CONST*: Tcl 9 support means dropping Tcl 8.3 support
 - Removed routines:

Changes to doc/CrtCommand.3.

98
99
100
101
102
103
104
105

106


107
108
109
110
111
112
113
114
point to constant strings or may be shared with other parts of the
interpreter.
Note also that the argument strings are encoded in normalized UTF-8 since
version 8.1 of Tcl.
.PP
\fIProc\fR must return an integer code that is expected to be one of
\fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or
\fBTCL_CONTINUE\fR.  See the Tcl overview man page

for details on what these codes mean.  Most normal commands will only


return \fBTCL_OK\fR or \fBTCL_ERROR\fR.  In addition, \fIproc\fR must set
the interpreter result;
in the case of a \fBTCL_OK\fR return code this gives the result
of the command, and in the case of \fBTCL_ERROR\fR it gives an error message.
The \fBTcl_SetResult\fR procedure provides an easy interface for setting
the return value;  for complete details on how the interpreter result
field is managed, see the \fBTcl_Interp\fR man page.
Before invoking a command procedure,







|
>
|
>
>
|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
point to constant strings or may be shared with other parts of the
interpreter.
Note also that the argument strings are encoded in normalized UTF-8 since
version 8.1 of Tcl.
.PP
\fIProc\fR must return an integer code that is expected to be one of
\fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or
\fBTCL_CONTINUE\fR. See the \fBreturn\fR man page for details on
what these codes mean and the use of extended values for an extension's
private use. Most normal commands will only return \fBTCL_OK\fR
or \fBTCL_ERROR\fR.
.PP
In addition, \fIproc\fR must set
the interpreter result;
in the case of a \fBTCL_OK\fR return code this gives the result
of the command, and in the case of \fBTCL_ERROR\fR it gives an error message.
The \fBTcl_SetResult\fR procedure provides an easy interface for setting
the return value;  for complete details on how the interpreter result
field is managed, see the \fBTcl_Interp\fR man page.
Before invoking a command procedure,

Changes to doc/CrtObjCmd.3.

128
129
130
131
132
133
134
135
136

137

138
139
140
141
142
143
144
\fBTcl_GetIntFromObj\fR on \fIobjv\fR[\fB2\fR] to obtain the integer
representation of that value; that call may change the type of the value
that \fIobjv\fR[\fB2\fR] points at, but will not change where
\fIobjv\fR[\fB2\fR] points.
.PP
\fIproc\fR must return an integer code that is either \fBTCL_OK\fR,
\fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR.
See the Tcl overview man page
for details on what these codes mean.  Most normal commands will only

return \fBTCL_OK\fR or \fBTCL_ERROR\fR.

In addition, if \fIproc\fR needs to return a non-empty result,
it can call \fBTcl_SetObjResult\fR to set the interpreter's result.
In the case of a \fBTCL_OK\fR return code this gives the result
of the command,
and in the case of \fBTCL_ERROR\fR this gives an error message.
Before invoking a command procedure,
\fBTcl_EvalObjEx\fR sets interpreter's result to







<
|
>
|
>







128
129
130
131
132
133
134

135
136
137
138
139
140
141
142
143
144
145
\fBTcl_GetIntFromObj\fR on \fIobjv\fR[\fB2\fR] to obtain the integer
representation of that value; that call may change the type of the value
that \fIobjv\fR[\fB2\fR] points at, but will not change where
\fIobjv\fR[\fB2\fR] points.
.PP
\fIproc\fR must return an integer code that is either \fBTCL_OK\fR,
\fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR.

See the \fBreturn\fR man page for details on what these codes mean and the
use of extended values for an extension's private use. Most normal commands
will only return \fBTCL_OK\fR or \fBTCL_ERROR\fR.
.PP
In addition, if \fIproc\fR needs to return a non-empty result,
it can call \fBTcl_SetObjResult\fR to set the interpreter's result.
In the case of a \fBTCL_OK\fR return code this gives the result
of the command,
and in the case of \fBTCL_ERROR\fR this gives an error message.
Before invoking a command procedure,
\fBTcl_EvalObjEx\fR sets interpreter's result to

Changes to doc/catch.n.

26
27
28
29
30
31
32
33
34
35


36
37
38
39
40
41
42
43
value corresponding to the exceptional return code returned by evaluation
of \fIscript\fR.  Tcl defines the normal return code from script
evaluation to be zero (0), or \fBTCL_OK\fR.  Tcl also defines four exceptional
return codes: 1 (\fBTCL_ERROR\fR), 2 (\fBTCL_RETURN\fR), 3 (\fBTCL_BREAK\fR),
and 4 (\fBTCL_CONTINUE\fR).  Errors during evaluation of a script are indicated
by a return code of \fBTCL_ERROR\fR.  The other exceptional return codes are
returned by the \fBreturn\fR, \fBbreak\fR, and \fBcontinue\fR commands
and in other special situations as documented.  Tcl packages can define
new commands that return other integer values as return codes as well,
and scripts that make use of the \fBreturn \-code\fR command can also


have return codes other than the five defined by Tcl.
.PP
If the \fIresultVarName\fR argument is given, then the variable it names is
set to the result of the script evaluation.  When the return code from the
script is 1 (\fBTCL_ERROR\fR), the value stored in \fIresultVarName\fR is an
error message.  When the return code from the script is 0 (\fBTCL_OK\fR), the
value stored in \fIresultVarName\fR is the value returned from \fIscript\fR.
.PP







|
|
|
>
>
|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
value corresponding to the exceptional return code returned by evaluation
of \fIscript\fR.  Tcl defines the normal return code from script
evaluation to be zero (0), or \fBTCL_OK\fR.  Tcl also defines four exceptional
return codes: 1 (\fBTCL_ERROR\fR), 2 (\fBTCL_RETURN\fR), 3 (\fBTCL_BREAK\fR),
and 4 (\fBTCL_CONTINUE\fR).  Errors during evaluation of a script are indicated
by a return code of \fBTCL_ERROR\fR.  The other exceptional return codes are
returned by the \fBreturn\fR, \fBbreak\fR, and \fBcontinue\fR commands
and in other special situations as documented.
New commands defined by Tcl packages as well as scripts that make
use of the \fBreturn \-code\fR  command can return other integer
values as the return code. These must however lie outside the range
reserved for Tcl as documented for the \fBreturn\fR command.

.PP
If the \fIresultVarName\fR argument is given, then the variable it names is
set to the result of the script evaluation.  When the return code from the
script is 1 (\fBTCL_ERROR\fR), the value stored in \fIresultVarName\fR is an
error message.  When the return code from the script is 0 (\fBTCL_OK\fR), the
value stored in \fIresultVarName\fR is the value returned from \fIscript\fR.
.PP

Changes to doc/chan.n.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
with the \fBopen\fR and \fBsocket\fR commands, or the default named
channels \fBstdin\fR, \fBstdout\fR or \fBstderr\fR which correspond to
the process's standard input, output and error streams respectively).
\fIOption\fR indicates what to do with the channel; any unique
abbreviation for \fIoption\fR is acceptable. Valid options are:
.\" METHOD: blocked
.TP
\fBchan blocked \fIchannelId\fR
.
This tests whether the last input operation on the channel called
\fIchannelId\fR failed because it would have otherwise caused the
process to block, and returns 1 if that was the case. It returns 0
otherwise. Note that this only ever returns 1 when the channel has
been configured to be non-blocking; all Tcl channels have blocking
turned on by default.
.\" METHOD: close
.TP
\fBchan close \fIchannelId\fR ?\fIdirection\fR?
.
Close and destroy the channel called \fIchannelId\fR. Note that this
deletes all existing file-events registered on the channel.
If the \fIdirection\fR argument (which must be \fBread\fR or \fBwrite\fR or
any unique abbreviation of them) is present, the channel will only be
half-closed, so that it can go from being read-write to write-only or
read-only respectively. If a read-only channel is closed for reading, it is
the same as if the channel is fully closed, and respectively similar for
write-only channels. Without the \fIdirection\fR argument, the channel is
closed for both reading and writing (but only if those directions are
currently open). It is an error to close a read-only channel for writing, or a
write-only channel for reading.
.RS
.PP
As part of closing the channel, all buffered output is flushed to the
channel's output device (only if the channel is ceasing to be writable), any
buffered input is discarded (only if the channel is ceasing to be readable),
the underlying operating system resource is closed and \fIchannelId\fR becomes
unavailable for future use (both only if the channel is being completely
closed).
.PP
If the channel is blocking and the channel is ceasing to be writable, the
command does not return until all output is flushed.  If the channel is
non-blocking and there is unflushed output, the channel remains open and the
command returns immediately; output will be flushed in the background and the
channel will be closed when all the flushing is complete.
.PP
If \fIchannelId\fR is a blocking channel for a command pipeline then
\fBchan close\fR waits for the child processes to complete.
.PP
If the channel is shared between interpreters, then \fBchan close\fR
makes \fIchannelId\fR unavailable in the invoking interpreter but has
no other effect until all of the sharing interpreters have closed the
channel. When the last interpreter in which the channel is registered
invokes \fBchan close\fR (or \fBclose\fR), the cleanup actions
described above occur. With half-closing, the half-close of the channel only
applies to the current interpreter's view of the channel until all channels
have closed it in that direction (or completely).
See the \fBinterp\fR command for a description of channel sharing.







|


|






|

|















|









|



|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
with the \fBopen\fR and \fBsocket\fR commands, or the default named
channels \fBstdin\fR, \fBstdout\fR or \fBstderr\fR which correspond to
the process's standard input, output and error streams respectively).
\fIOption\fR indicates what to do with the channel; any unique
abbreviation for \fIoption\fR is acceptable. Valid options are:
.\" METHOD: blocked
.TP
\fBchan blocked \fIchannel\fR
.
This tests whether the last input operation on the channel called
\fIchannel\fR failed because it would have otherwise caused the
process to block, and returns 1 if that was the case. It returns 0
otherwise. Note that this only ever returns 1 when the channel has
been configured to be non-blocking; all Tcl channels have blocking
turned on by default.
.\" METHOD: close
.TP
\fBchan close \fIchannel\fR ?\fIdirection\fR?
.
Close and destroy the channel called \fIchannel\fR. Note that this
deletes all existing file-events registered on the channel.
If the \fIdirection\fR argument (which must be \fBread\fR or \fBwrite\fR or
any unique abbreviation of them) is present, the channel will only be
half-closed, so that it can go from being read-write to write-only or
read-only respectively. If a read-only channel is closed for reading, it is
the same as if the channel is fully closed, and respectively similar for
write-only channels. Without the \fIdirection\fR argument, the channel is
closed for both reading and writing (but only if those directions are
currently open). It is an error to close a read-only channel for writing, or a
write-only channel for reading.
.RS
.PP
As part of closing the channel, all buffered output is flushed to the
channel's output device (only if the channel is ceasing to be writable), any
buffered input is discarded (only if the channel is ceasing to be readable),
the underlying operating system resource is closed and \fIchannel\fR becomes
unavailable for future use (both only if the channel is being completely
closed).
.PP
If the channel is blocking and the channel is ceasing to be writable, the
command does not return until all output is flushed.  If the channel is
non-blocking and there is unflushed output, the channel remains open and the
command returns immediately; output will be flushed in the background and the
channel will be closed when all the flushing is complete.
.PP
If \fIchannel\fR is a blocking channel for a command pipeline then
\fBchan close\fR waits for the child processes to complete.
.PP
If the channel is shared between interpreters, then \fBchan close\fR
makes \fIchannel\fR unavailable in the invoking interpreter but has
no other effect until all of the sharing interpreters have closed the
channel. When the last interpreter in which the channel is registered
invokes \fBchan close\fR (or \fBclose\fR), the cleanup actions
described above occur. With half-closing, the half-close of the channel only
applies to the current interpreter's view of the channel until all channels
have closed it in that direction (or completely).
See the \fBinterp\fR command for a description of channel sharing.
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
switch them back to blocking or (b) use the environment variable
\fBTCL_FLUSH_NONBLOCKING_ON_EXIT\fR, which when set and not equal to
.QW \fB0\fR
restores the previous behavior.
.RE
.\" METHOD: configure
.TP
\fBchan configure \fIchannelId\fR ?\fIoptionName\fR? ?\fIvalue\fR? ?\fIoptionName value\fR?...
.
Query or set the configuration options of the channel named
\fIchannelId\fR.
.RS
.PP
If no \fIoptionName\fR or \fIvalue\fR arguments are supplied, the
command returns a list containing alternating option names and values
for the channel.  If \fIoptionName\fR is supplied but no \fIvalue\fR
then the command returns the current value of the given option.  If
one or more pairs of \fIoptionName\fR and \fIvalue\fR are supplied,







|


|







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
switch them back to blocking or (b) use the environment variable
\fBTCL_FLUSH_NONBLOCKING_ON_EXIT\fR, which when set and not equal to
.QW \fB0\fR
restores the previous behavior.
.RE
.\" METHOD: configure
.TP
\fBchan configure \fIchannel\fR ?\fIoptionName\fR? ?\fIvalue\fR? ?\fIoptionName value\fR?...
.
Query or set the configuration options of the channel named
\fIchannel\fR.
.RS
.PP
If no \fIoptionName\fR or \fIvalue\fR arguments are supplied, the
command returns a list containing alternating option names and values
for the channel.  If \fIoptionName\fR is supplied but no \fIvalue\fR
then the command returns the current value of the given option.  If
one or more pairs of \fIoptionName\fR and \fIvalue\fR are supplied,
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
This subcommand is \fBsafe\fR and made accessible to safe
interpreters.  While it arranges for the execution of arbitrary Tcl
code the system also makes sure that the code is always executed
within the safe interpreter.
.RE
.\" METHOD: eof
.TP
\fBchan eof \fIchannelId\fR
.
Test whether the last input operation on the channel called
\fIchannelId\fR failed because the end of the data stream was reached,
returning 1 if end-of-file was reached, and 0 otherwise.
.\" METHOD: event
.TP
\fBchan event \fIchannelId event\fR ?\fIscript\fR?
.
Arrange for the Tcl script \fIscript\fR to be installed as a \fIfile
event handler\fR to be called whenever the channel called
\fIchannelId\fR enters the state described by \fIevent\fR (which must
be either \fBreadable\fR or \fBwritable\fR); only one such handler may
be installed per event per channel at a time.  If \fIscript\fR is the
empty string, the current handler is deleted (this also happens if the
channel is closed or the interpreter deleted).  If \fIscript\fR is
omitted, the currently installed script is returned (or an empty
string if no such handler is installed).  The callback is only
performed if the event loop is being serviced (e.g. via \fBvwait\fR or







|


|



|



|







387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
This subcommand is \fBsafe\fR and made accessible to safe
interpreters.  While it arranges for the execution of arbitrary Tcl
code the system also makes sure that the code is always executed
within the safe interpreter.
.RE
.\" METHOD: eof
.TP
\fBchan eof \fIchannel\fR
.
Test whether the last input operation on the channel called
\fIchannel\fR failed because the end of the data stream was reached,
returning 1 if end-of-file was reached, and 0 otherwise.
.\" METHOD: event
.TP
\fBchan event \fIchannel event\fR ?\fIscript\fR?
.
Arrange for the Tcl script \fIscript\fR to be installed as a \fIfile
event handler\fR to be called whenever the channel called
\fIchannel\fR enters the state described by \fIevent\fR (which must
be either \fBreadable\fR or \fBwritable\fR); only one such handler may
be installed per event per channel at a time.  If \fIscript\fR is the
empty string, the current handler is deleted (this also happens if the
channel is closed or the interpreter deleted).  If \fIscript\fR is
omitted, the currently installed script is returned (or an empty
string if no such handler is installed).  The callback is only
performed if the event loop is being serviced (e.g. via \fBvwait\fR or
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
script then the command registered with \fBinterp bgerror\fR is used
to report the error.  In addition, the file event handler is deleted
if it ever returns an error; this is done in order to prevent infinite
loops due to buggy handlers.
.RE
.\" METHOD: flush
.TP
\fBchan flush \fIchannelId\fR
.
Ensures that all pending output for the channel called \fIchannelId\fR
is written.
.RS
.PP
If the channel is in blocking mode the command does not return until
all the buffered output has been flushed to the channel. If the
channel is in non-blocking mode, the command may return before all
buffered output has been flushed; the remainder will be flushed in the
background as fast as the underlying file or device is able to absorb
it.
.RE
.\" METHOD: gets
.TP
\fBchan gets \fIchannelId\fR ?\fIvarName\fR?
.
Reads a line from the channel consisting of all characters up to the next
end-of-line sequence or until end of file is seen. The line feed character
corresponding to end-of-line sequence is not included as part of the line.
If the \fIvarName\fR argument is specified, the line is stored in the variable
of that name and the command returns the length of the line. If \fIvarName\fR
is not specified, the command returns the line itself as the result of the command.







|

|












|







464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
script then the command registered with \fBinterp bgerror\fR is used
to report the error.  In addition, the file event handler is deleted
if it ever returns an error; this is done in order to prevent infinite
loops due to buggy handlers.
.RE
.\" METHOD: flush
.TP
\fBchan flush \fIchannel\fR
.
Ensures that all pending output for the channel called \fIchannel\fR
is written.
.RS
.PP
If the channel is in blocking mode the command does not return until
all the buffered output has been flushed to the channel. If the
channel is in non-blocking mode, the command may return before all
buffered output has been flushed; the remainder will be flushed in the
background as fast as the underlying file or device is able to absorb
it.
.RE
.\" METHOD: gets
.TP
\fBchan gets \fIchannel\fR ?\fIvarName\fR?
.
Reads a line from the channel consisting of all characters up to the next
end-of-line sequence or until end of file is seen. The line feed character
corresponding to end-of-line sequence is not included as part of the line.
If the \fIvarName\fR argument is specified, the line is stored in the variable
of that name and the command returns the length of the line. If \fIvarName\fR
is not specified, the command returns the line itself as the result of the command.
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
\fBchan names\fR ?\fIpattern\fR?
.
Produces a list of all channel names. If \fIpattern\fR is specified,
only those channel names that match it (according to the rules of
\fBstring match\fR) will be returned.
.\" METHOD: pending
.TP
\fBchan pending \fImode channelId\fR
.
Depending on whether \fImode\fR is \fBinput\fR or \fBoutput\fR,
returns the number of
bytes of input or output (respectively) currently buffered
internally for \fIchannelId\fR (especially useful in a readable event
callback to impose application-specific limits on input line lengths to avoid
a potential denial-of-service attack where a hostile user crafts
an extremely long line that exceeds the available memory to buffer it).
Returns -1 if the channel was not opened for the mode in question.
.\" METHOD: pipe
.TP
\fBchan pipe\fR







|




|







532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
\fBchan names\fR ?\fIpattern\fR?
.
Produces a list of all channel names. If \fIpattern\fR is specified,
only those channel names that match it (according to the rules of
\fBstring match\fR) will be returned.
.\" METHOD: pending
.TP
\fBchan pending \fImode channel\fR
.
Depending on whether \fImode\fR is \fBinput\fR or \fBoutput\fR,
returns the number of
bytes of input or output (respectively) currently buffered
internally for \fIchannel\fR (especially useful in a readable event
callback to impose application-specific limits on input line lengths to avoid
a potential denial-of-service attack where a hostile user crafts
an extremely long line that exceeds the available memory to buffer it).
Returns -1 if the channel was not opened for the mode in question.
.\" METHOD: pipe
.TP
\fBchan pipe\fR
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
differences, but the details of what exactly gets written when are not. This
is most likely to show up when using pipelines for testing; care should be
taken to ensure that deadlocks do not occur and that potential short reads are
allowed for.
.RE
.\" METHOD: pop
.TP
\fBchan pop \fIchannelId\fR
.
Removes the topmost transformation from the channel \fIchannelId\fR, if there
is any. If there are no transformations added to \fIchannelId\fR, this is
equivalent to \fBchan close\fR of that channel. The result is normally the
empty string, but can be an error in some situations (i.e. where the
underlying system stream is closed and that results in an error).
.\" METHOD: postevent
.TP
\fBchan postevent \fIchannelId eventSpec\fR
.
This subcommand is used by command handlers specified with \fBchan
create\fR. It notifies the channel represented by the handle
\fIchannelId\fR that the event(s) listed in the \fIeventSpec\fR have
occurred. The argument has to be a list containing any of the strings
\fBread\fR and \fBwrite\fR. The list must contain at least one
element as it does not make sense to invoke the command if there are
no events to post.
.RS
.PP
Note that this subcommand can only be used with channel handles that







|

|
|





|



|







568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
differences, but the details of what exactly gets written when are not. This
is most likely to show up when using pipelines for testing; care should be
taken to ensure that deadlocks do not occur and that potential short reads are
allowed for.
.RE
.\" METHOD: pop
.TP
\fBchan pop \fIchannel\fR
.
Removes the topmost transformation from the channel \fIchannel\fR, if there
is any. If there are no transformations added to \fIchannel\fR, this is
equivalent to \fBchan close\fR of that channel. The result is normally the
empty string, but can be an error in some situations (i.e. where the
underlying system stream is closed and that results in an error).
.\" METHOD: postevent
.TP
\fBchan postevent \fIchannel eventSpec\fR
.
This subcommand is used by command handlers specified with \fBchan
create\fR. It notifies the channel represented by the handle
\fIchannel\fR that the event(s) listed in the \fIeventSpec\fR have
occurred. The argument has to be a list containing any of the strings
\fBread\fR and \fBwrite\fR. The list must contain at least one
element as it does not make sense to invoke the command if there are
no events to post.
.RS
.PP
Note that this subcommand can only be used with channel handles that
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
current interpreter or in other interpreters or other threads, even
where the event is posted from a safe interpreter and listened for by
a trusted interpreter. \fBChan event\fR handlers are \fIalways\fR
executed in the interpreter that set them up.
.RE
.\" METHOD: push
.TP
\fBchan push \fIchannelId cmdPrefix\fR
.
Adds a new transformation on top of the channel \fIchannelId\fR. The
\fIcmdPrefix\fR argument describes a list of one or more words which represent
a handler that will be used to implement the transformation. The command
prefix must provide the API described in the \fBtranschan\fR manual page.
The result of this subcommand is a handle to the transformation. Note that it
is important to make sure that the transformation is capable of supporting the
channel mode that it is used with or this can make the channel neither
readable nor writable.
.\" METHOD: puts
.TP
\fBchan puts\fR ?\fB\-nonewline\fR? ?\fIchannelId\fR? \fIstring\fR
.
Writes \fIstring\fR to the channel named \fIchannelId\fR followed by a
newline character. A trailing newline character is written unless the
optional flag \fB\-nonewline\fR is given. If \fIchannelId\fR is
omitted, the string is written to the standard output channel,
\fBstdout\fR.
.RS
.PP
Newline characters in the output are translated by \fBchan puts\fR to
platform-specific end-of-line sequences according to the currently
configured value of the \fB\-translation\fR option for the channel
(for example, on PCs newlines are normally replaced with
carriage-return-linefeed sequences; see \fBchan configure\fR above for
details).
.PP
Tcl buffers output internally, so characters written with \fBchan
puts\fR may not appear immediately on the output file or device; Tcl
will normally delay output until the buffer is full or the channel is
closed.  You can force output to appear immediately with the \fBchan
flush\fR command.
.PP
When the output buffer fills up, the \fBchan puts\fR command will
normally block until all the buffered data has been accepted for
output by the operating system.  If \fIchannelId\fR is in non-blocking
mode then the \fBchan puts\fR command will not block even if the
operating system cannot accept the data.  Instead, Tcl continues to
buffer the data and writes it in the background as fast as the
underlying file or device can accept it.  The application must use the
Tcl event loop for non-blocking output to work; otherwise Tcl never
finds out that the file or device is ready for more output data.  It
is possible for an arbitrarily large amount of data to be buffered for
a channel in non-blocking mode, which could consume a large amount of
memory.  To avoid wasting memory, non-blocking I/O should normally be
used in an event-driven fashion with the \fBchan event\fR command
(do not invoke \fBchan puts\fR unless you have recently been notified
via a file event that the channel is ready for more output data).
.PP
The command will raise an error exception with POSIX error code \fBEILSEQ\fR if
the encoding profile \fBstrict\fR is in effect for the channel and the output
data cannot be encoded in the encoding configured for the channel. Data
may be partially written to the channel in this case.
.RE
.\" METHOD: read
.TP
\fBchan read \fIchannelId\fR ?\fInumChars\fR?
.TP
\fBchan read \fR?\fB\-nonewline\fR? \fIchannelId\fR
.
In the first form, the result will be the next \fInumChars\fR
characters read from the channel named \fIchannelId\fR; if
\fInumChars\fR is omitted, all characters up to the point when the
channel would signal a failure (whether an end-of-file, blocked or
other error condition) are read. In the second form (i.e. when
\fInumChars\fR has been omitted) the flag \fB\-nonewline\fR may be
given to indicate that any trailing newline in the string that has
been read should be trimmed.
.RS
.PP
If \fIchannelId\fR is in non-blocking mode, \fBchan read\fR may not
read as many characters as requested: once all available input has
been read, the command will return the data that is available rather
than blocking for more input.  If the channel is configured to use a
multi-byte encoding, then there may actually be some bytes remaining
in the internal buffers that do not form a complete character.  These
bytes will not be returned until a complete character is available or
end-of-file is reached.  The \fB\-nonewline\fR switch is ignored if
the command returns before reaching the end of the file.
.PP
\fBChan read\fR translates end-of-line sequences in the input into
newline characters according to the \fB\-translation\fR option for the
channel (see \fBchan configure\fR above for a discussion on the ways
in which \fBchan configure\fR will alter input).
.PP
When reading from a serial port, most applications should configure
the serial port channel to be non-blocking, like this:
.PP
.CS
\fBchan configure \fIchannelId \fB\-blocking \fI0\fR.
.CE
.PP
Then \fBchan read\fR behaves much like described above.  Note that
most serial ports are comparatively slow; it is entirely possible to
get a \fBreadable\fR event for each character read from them. Care
must be taken when using \fBchan read\fR on blocking serial ports:
.TP
\fBchan read \fIchannelId numChars\fR
.
In this form \fBchan read\fR blocks until \fInumChars\fR have been
received from the serial port.
.TP
\fBchan read \fIchannelId\fR
.
In this form \fBchan read\fR blocks until the reception of the
end-of-file character, see \fBchan configure -eofchar\fR. If there no
end-of-file character has been configured for the channel, then
\fBchan read\fR will block forever.
.PP
If the encoding profile \fBstrict\fR is in effect for the channel, the command







|

|









|

|

|



















|




















|

|


|








|


















|







|




|







614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
current interpreter or in other interpreters or other threads, even
where the event is posted from a safe interpreter and listened for by
a trusted interpreter. \fBChan event\fR handlers are \fIalways\fR
executed in the interpreter that set them up.
.RE
.\" METHOD: push
.TP
\fBchan push \fIchannel cmdPrefix\fR
.
Adds a new transformation on top of the channel \fIchannel\fR. The
\fIcmdPrefix\fR argument describes a list of one or more words which represent
a handler that will be used to implement the transformation. The command
prefix must provide the API described in the \fBtranschan\fR manual page.
The result of this subcommand is a handle to the transformation. Note that it
is important to make sure that the transformation is capable of supporting the
channel mode that it is used with or this can make the channel neither
readable nor writable.
.\" METHOD: puts
.TP
\fBchan puts\fR ?\fB\-nonewline\fR? ?\fIchannel\fR? \fIstring\fR
.
Writes \fIstring\fR to the channel named \fIchannel\fR followed by a
newline character. A trailing newline character is written unless the
optional flag \fB\-nonewline\fR is given. If \fIchannel\fR is
omitted, the string is written to the standard output channel,
\fBstdout\fR.
.RS
.PP
Newline characters in the output are translated by \fBchan puts\fR to
platform-specific end-of-line sequences according to the currently
configured value of the \fB\-translation\fR option for the channel
(for example, on PCs newlines are normally replaced with
carriage-return-linefeed sequences; see \fBchan configure\fR above for
details).
.PP
Tcl buffers output internally, so characters written with \fBchan
puts\fR may not appear immediately on the output file or device; Tcl
will normally delay output until the buffer is full or the channel is
closed.  You can force output to appear immediately with the \fBchan
flush\fR command.
.PP
When the output buffer fills up, the \fBchan puts\fR command will
normally block until all the buffered data has been accepted for
output by the operating system.  If \fIchannel\fR is in non-blocking
mode then the \fBchan puts\fR command will not block even if the
operating system cannot accept the data.  Instead, Tcl continues to
buffer the data and writes it in the background as fast as the
underlying file or device can accept it.  The application must use the
Tcl event loop for non-blocking output to work; otherwise Tcl never
finds out that the file or device is ready for more output data.  It
is possible for an arbitrarily large amount of data to be buffered for
a channel in non-blocking mode, which could consume a large amount of
memory.  To avoid wasting memory, non-blocking I/O should normally be
used in an event-driven fashion with the \fBchan event\fR command
(do not invoke \fBchan puts\fR unless you have recently been notified
via a file event that the channel is ready for more output data).
.PP
The command will raise an error exception with POSIX error code \fBEILSEQ\fR if
the encoding profile \fBstrict\fR is in effect for the channel and the output
data cannot be encoded in the encoding configured for the channel. Data
may be partially written to the channel in this case.
.RE
.\" METHOD: read
.TP
\fBchan read \fIchannel\fR ?\fInumChars\fR?
.TP
\fBchan read \fR?\fB\-nonewline\fR? \fIchannel\fR
.
In the first form, the result will be the next \fInumChars\fR
characters read from the channel named \fIchannel\fR; if
\fInumChars\fR is omitted, all characters up to the point when the
channel would signal a failure (whether an end-of-file, blocked or
other error condition) are read. In the second form (i.e. when
\fInumChars\fR has been omitted) the flag \fB\-nonewline\fR may be
given to indicate that any trailing newline in the string that has
been read should be trimmed.
.RS
.PP
If \fIchannel\fR is in non-blocking mode, \fBchan read\fR may not
read as many characters as requested: once all available input has
been read, the command will return the data that is available rather
than blocking for more input.  If the channel is configured to use a
multi-byte encoding, then there may actually be some bytes remaining
in the internal buffers that do not form a complete character.  These
bytes will not be returned until a complete character is available or
end-of-file is reached.  The \fB\-nonewline\fR switch is ignored if
the command returns before reaching the end of the file.
.PP
\fBChan read\fR translates end-of-line sequences in the input into
newline characters according to the \fB\-translation\fR option for the
channel (see \fBchan configure\fR above for a discussion on the ways
in which \fBchan configure\fR will alter input).
.PP
When reading from a serial port, most applications should configure
the serial port channel to be non-blocking, like this:
.PP
.CS
\fBchan configure \fIchannel \fB\-blocking \fI0\fR.
.CE
.PP
Then \fBchan read\fR behaves much like described above.  Note that
most serial ports are comparatively slow; it is entirely possible to
get a \fBreadable\fR event for each character read from them. Care
must be taken when using \fBchan read\fR on blocking serial ports:
.TP
\fBchan read \fIchannel numChars\fR
.
In this form \fBchan read\fR blocks until \fInumChars\fR have been
received from the serial port.
.TP
\fBchan read \fIchannel\fR
.
In this form \fBchan read\fR blocks until the reception of the
end-of-file character, see \fBchan configure -eofchar\fR. If there no
end-of-file character has been configured for the channel, then
\fBchan read\fR will block forever.
.PP
If the encoding profile \fBstrict\fR is in effect for the channel, the command
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
blocking channel case, the \fB\-data\fR key is not present in the
error option dictionary. In the case of exception thrown due to encoding
errors, it is possible to introspect, and in some cases recover, by
changing the encoding in use. See \fBENCODING ERROR EXAMPLES\fR later.
.RE
.\" METHOD: seek
.TP
\fBchan seek \fIchannelId offset\fR ?\fIorigin\fR?
.
Sets the current access position within the underlying data stream for
the channel named \fIchannelId\fR to be \fIoffset\fR bytes relative to
\fIorigin\fR. \fIOffset\fR must be an integer (which may be negative)
and \fIorigin\fR must be one of the following:
.RS
.IP \fBstart\fR
The new access position will be \fIoffset\fR bytes from the start
of the underlying file or device.
.IP \fBcurrent\fR







|


|







741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
blocking channel case, the \fB\-data\fR key is not present in the
error option dictionary. In the case of exception thrown due to encoding
errors, it is possible to introspect, and in some cases recover, by
changing the encoding in use. See \fBENCODING ERROR EXAMPLES\fR later.
.RE
.\" METHOD: seek
.TP
\fBchan seek \fIchannel offset\fR ?\fIorigin\fR?
.
Sets the current access position within the underlying data stream for
the channel named \fIchannel\fR to be \fIoffset\fR bytes relative to
\fIorigin\fR. \fIOffset\fR must be an integer (which may be negative)
and \fIorigin\fR must be one of the following:
.RS
.IP \fBstart\fR
The new access position will be \fIoffset\fR bytes from the start
of the underlying file or device.
.IP \fBcurrent\fR
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
.PP
Note that \fIoffset\fR values are byte offsets, not character offsets.
Both \fBchan seek\fR and \fBchan tell\fR operate in terms of bytes,
not characters, unlike \fBchan read\fR.
.RE
.\" METHOD: tell
.TP
\fBchan tell \fIchannelId\fR
.
Returns a number giving the current access position within the
underlying data stream for the channel named \fIchannelId\fR. This
value returned is a byte offset that can be passed to \fBchan seek\fR
in order to set the channel to a particular position.  Note that this
value is in terms of bytes, not characters like \fBchan read\fR.  The
value returned is -1 for channels that do not support seeking.
.\" METHOD: truncate
.TP
\fBchan truncate \fIchannelId\fR ?\fIlength\fR?
.
Sets the byte length of the underlying data stream for the channel
named \fIchannelId\fR to be \fIlength\fR (or to the current byte
offset within the underlying data stream if \fIlength\fR is
omitted). The channel is flushed before truncation.
.
.SH EXAMPLES
.SS "SIMPLE CHANNEL OPERATION EXAMPLES"
.PP
Instruct Tcl to always send output to \fBstdout\fR immediately,







|


|






|


|







775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
.PP
Note that \fIoffset\fR values are byte offsets, not character offsets.
Both \fBchan seek\fR and \fBchan tell\fR operate in terms of bytes,
not characters, unlike \fBchan read\fR.
.RE
.\" METHOD: tell
.TP
\fBchan tell \fIchannel\fR
.
Returns a number giving the current access position within the
underlying data stream for the channel named \fIchannel\fR. This
value returned is a byte offset that can be passed to \fBchan seek\fR
in order to set the channel to a particular position.  Note that this
value is in terms of bytes, not characters like \fBchan read\fR.  The
value returned is -1 for channels that do not support seeking.
.\" METHOD: truncate
.TP
\fBchan truncate \fIchannel\fR ?\fIlength\fR?
.
Sets the byte length of the underlying data stream for the channel
named \fIchannel\fR to be \fIlength\fR (or to the current byte
offset within the underlying data stream if \fIlength\fR is
omitted). The channel is flushed before truncation.
.
.SH EXAMPLES
.SS "SIMPLE CHANNEL OPERATION EXAMPLES"
.PP
Instruct Tcl to always send output to \fBstdout\fR immediately,

Changes to doc/close.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH close n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
close \- Close an open channel
.SH SYNOPSIS
\fBclose \fIchannelId\fR ?\fBr\fR(\fBead\fR)|\fBw\fR(\fBrite\fR)?
.BE
.SH DESCRIPTION
.PP
The \fBclose\fR command has been superceded by the \fBchan close\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH close n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
close \- Close an open channel
.SH SYNOPSIS
\fBclose \fIchannel\fR ?\fBr\fR(\fBead\fR)|\fBw\fR(\fBrite\fR)?
.BE
.SH DESCRIPTION
.PP
The \fBclose\fR command has been superceded by the \fBchan close\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)

Changes to doc/eof.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH eof n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
eof \- Check for end of file condition on channel
.SH SYNOPSIS
\fBeof \fIchannelId\fR
.BE
.SH DESCRIPTION
.PP
The \fBeof\fR command has been superceded by the \fBchan eof\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH eof n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
eof \- Check for end of file condition on channel
.SH SYNOPSIS
\fBeof \fIchannel\fR
.BE
.SH DESCRIPTION
.PP
The \fBeof\fR command has been superceded by the \fBchan eof\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)

Changes to doc/fblocked.n.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
'\"
'\" Copyright (c) 1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH fblocked n 7.5 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
fblocked \- Test whether the last input operation exhausted all available input
.SH SYNOPSIS
\fBfblocked \fIchannelId\fR
.BE
.SH DESCRIPTION
.PP
The \fBfblocked\fR command has been superceded by the \fBchan blocked\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
'\"
'\" Copyright (c) 1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH fblocked n 7.5 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
fblocked \- Test whether the last input operation exhausted all available input
.SH SYNOPSIS
\fBfblocked \fIchannel\fR
.BE
.SH DESCRIPTION
.PP
The \fBfblocked\fR command has been superceded by the \fBchan blocked\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)

Changes to doc/fconfigure.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
fconfigure \- Set and get options on a channel
.SH SYNOPSIS
.nf
\fBfconfigure \fIchannelId\fR
\fBfconfigure \fIchannelId name\fR
\fBfconfigure \fIchannelId name value \fR?\fIname value ...\fR?
.fi
.BE
.SH DESCRIPTION
.PP
The \fBfconfigure\fR command has been superceded by the \fBchan configure\fR
command which supports the same syntax and options.
.SH "SEE ALSO"







|
|
|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
fconfigure \- Set and get options on a channel
.SH SYNOPSIS
.nf
\fBfconfigure \fIchannel\fR
\fBfconfigure \fIchannel name\fR
\fBfconfigure \fIchannel name value \fR?\fIname value ...\fR?
.fi
.BE
.SH DESCRIPTION
.PP
The \fBfconfigure\fR command has been superceded by the \fBchan configure\fR
command which supports the same syntax and options.
.SH "SEE ALSO"

Changes to doc/fileevent.n.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.TH fileevent n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
fileevent \- Execute a script when a channel becomes readable or writable
.SH SYNOPSIS
\fBfileevent \fIchannelId \fBreadable \fR?\fIscript\fR?
.sp
\fBfileevent \fIchannelId \fBwritable \fR?\fIscript\fR?
.BE
.SH DESCRIPTION
.PP
The \fBfileevent\fR command has been superceded by the \fBchan event\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)







|

|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.TH fileevent n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
fileevent \- Execute a script when a channel becomes readable or writable
.SH SYNOPSIS
\fBfileevent \fIchannel \fBreadable \fR?\fIscript\fR?
.sp
\fBfileevent \fIchannel \fBwritable \fR?\fIscript\fR?
.BE
.SH DESCRIPTION
.PP
The \fBfileevent\fR command has been superceded by the \fBchan event\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)

Changes to doc/flush.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH flush n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
flush \- Flush buffered output for a channel
.SH SYNOPSIS
\fBflush \fIchannelId\fR
.BE
.SH DESCRIPTION
.PP
The \fBflush\fR command has been superceded by the \fBchan flush\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH flush n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
flush \- Flush buffered output for a channel
.SH SYNOPSIS
\fBflush \fIchannel\fR
.BE
.SH DESCRIPTION
.PP
The \fBflush\fR command has been superceded by the \fBchan flush\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)

Changes to doc/format.n.

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
function of the \fBexpr\fR command (at least a 64-bit range).
If it is \fBz\fR or \fBt\fR it specifies that the integer value is
truncated to the range determined by the value of the \fBpointerSize\fR
element of the \fBtcl_platform\fR array.
If it is \fBL\fR it specifies that an integer or double value is taken
without truncation for conversion to a formatted substring.
If neither of those are present, the integer value is
truncated to the range determined by the value of the
\fBwordSize\fR element of the \fBtcl_platform\fR array).
.SS "MANDATORY CONVERSION TYPE"
.PP
The last thing in a conversion specifier is an alphabetic character
that determines what kind of conversion to perform.
The following conversion characters are currently supported:
.IP \fBd\fR 10
Convert integer to signed decimal string.







|
<







137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
function of the \fBexpr\fR command (at least a 64-bit range).
If it is \fBz\fR or \fBt\fR it specifies that the integer value is
truncated to the range determined by the value of the \fBpointerSize\fR
element of the \fBtcl_platform\fR array.
If it is \fBL\fR it specifies that an integer or double value is taken
without truncation for conversion to a formatted substring.
If neither of those are present, the integer value is
truncated to a 32-bit range.

.SS "MANDATORY CONVERSION TYPE"
.PP
The last thing in a conversion specifier is an alphabetic character
that determines what kind of conversion to perform.
The following conversion characters are currently supported:
.IP \fBd\fR 10
Convert integer to signed decimal string.

Changes to doc/gets.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH gets n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
gets \- Read a line from a channel
.SH SYNOPSIS
\fBgets \fIchannelId\fR ?\fIvarName\fR?
.BE
.SH DESCRIPTION
.PP
The \fBgets\fR command has been superceded by the \fBchan gets\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH gets n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
gets \- Read a line from a channel
.SH SYNOPSIS
\fBgets \fIchannel\fR ?\fIvarName\fR?
.BE
.SH DESCRIPTION
.PP
The \fBgets\fR command has been superceded by the \fBchan gets\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)

Changes to doc/interp.n.

388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
application. If your machine has a limit on the size of the C stack, you
may get stack overflows before reaching the limit set by the command. If
this happens, see if there is a mechanism in your system for increasing
the maximum size of the C stack.
.RE
.\" METHOD: share
.TP
\fBinterp share\fI srcPath channelId destPath\fR
.
Causes the IO channel identified by \fIchannelId\fR to become shared
between the interpreter identified by \fIsrcPath\fR and the interpreter
identified by \fIdestPath\fR. Both interpreters have the same permissions
on the IO channel.
Both interpreters must close it to close the underlying IO channel; IO
channels accessible in an interpreter are automatically closed when an
interpreter is destroyed.
.\" METHOD: target
.TP
\fBinterp target\fI path alias\fR
.
Returns a Tcl list describing the target interpreter for an alias. The
alias is specified with an interpreter path and source command name, just
as in \fBinterp alias\fR above. The name of the target interpreter is
returned as an interpreter path, relative to the invoking interpreter.
If the target interpreter for the alias is the invoking interpreter then an
empty list is returned. If the target interpreter for the alias is not the
invoking interpreter or one of its descendants then an error is generated.
The target command does not have to be defined at the time of this invocation.
.\" METHOD: transfer
.TP
\fBinterp transfer\fI srcPath channelId destPath\fR
.
Causes the IO channel identified by \fIchannelId\fR to become available in
the interpreter identified by \fIdestPath\fR and unavailable in the
interpreter identified by \fIsrcPath\fR.
.SH "CHILD COMMAND"
.PP
For each child interpreter created with the \fBinterp\fR command, a
new Tcl command is created in the parent interpreter with the same
name as the new interpreter. This command may be used to invoke







|

|




















|

|







388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
application. If your machine has a limit on the size of the C stack, you
may get stack overflows before reaching the limit set by the command. If
this happens, see if there is a mechanism in your system for increasing
the maximum size of the C stack.
.RE
.\" METHOD: share
.TP
\fBinterp share\fI srcPath channel destPath\fR
.
Causes the IO channel identified by \fIchannel\fR to become shared
between the interpreter identified by \fIsrcPath\fR and the interpreter
identified by \fIdestPath\fR. Both interpreters have the same permissions
on the IO channel.
Both interpreters must close it to close the underlying IO channel; IO
channels accessible in an interpreter are automatically closed when an
interpreter is destroyed.
.\" METHOD: target
.TP
\fBinterp target\fI path alias\fR
.
Returns a Tcl list describing the target interpreter for an alias. The
alias is specified with an interpreter path and source command name, just
as in \fBinterp alias\fR above. The name of the target interpreter is
returned as an interpreter path, relative to the invoking interpreter.
If the target interpreter for the alias is the invoking interpreter then an
empty list is returned. If the target interpreter for the alias is not the
invoking interpreter or one of its descendants then an error is generated.
The target command does not have to be defined at the time of this invocation.
.\" METHOD: transfer
.TP
\fBinterp transfer\fI srcPath channel destPath\fR
.
Causes the IO channel identified by \fIchannel\fR to become available in
the interpreter identified by \fIdestPath\fR and unavailable in the
interpreter identified by \fIsrcPath\fR.
.SH "CHILD COMMAND"
.PP
For each child interpreter created with the \fBinterp\fR command, a
new Tcl command is created in the parent interpreter with the same
name as the new interpreter. This command may be used to invoke

Changes to doc/namespace.n.

491
492
493
494
495
496
497
498
499


500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
If you provide a fully-qualified name that starts with a \fB::\fR,
there is no question about what command, variable, or namespace
you mean.
However, if the name does not start with a \fB::\fR
(i.e., is \fIrelative\fR),
Tcl follows basic rules for looking it up:
.IP \(bu
\fBVariable names\fR are always resolved by looking first in the current
namespace, and then in the global namespace.


.IP \(bu
\fBCommand names\fR are always resolved by looking in the current namespace
first. If not found there, they are searched for in every namespace on the
current namespace's command path (which is empty by default). If not found
there, command names are looked up in the global namespace (or, failing that,
are processed by the appropriate \fBnamespace unknown\fR handler.)
.IP \(bu
\fBNamespace names\fR are always resolved by looking in only the current
namespace.
.PP
In the following example,
.PP
.CS
set traceLevel 0
\fBnamespace eval\fR Debug {
    printTrace $traceLevel
}
.CE
.PP
Tcl looks for \fBtraceLevel\fR in the namespace \fBDebug\fR
and then in the global namespace.
It looks up the command \fBprintTrace\fR in the same way.
If a variable or command name is not found in either context,
the name is undefined.
To make this point absolutely clear, consider the following example:
.PP
.CS
set traceLevel 0
\fBnamespace eval\fR Foo {
    variable traceLevel 3

    \fBnamespace eval\fR Debug {
        printTrace $traceLevel
    }
}
.CE
.PP
Here Tcl looks for \fBtraceLevel\fR first in the namespace \fBFoo::Debug\fR.
Since it is not found there, Tcl then looks for it
in the global namespace.
The variable \fBFoo::traceLevel\fR is completely ignored
during the name resolution process.
.PP
You can use the \fBnamespace which\fR command to clear up any question
about name resolution.
For example, the command:
.PP
.CS
\fBnamespace eval\fR Foo::Debug {\fBnamespace which\fR -variable traceLevel}
.CE
.PP
returns \fB::traceLevel\fR.
On the other hand, the command,
.PP
.CS
\fBnamespace eval\fR Foo {\fBnamespace which\fR -variable traceLevel}
.CE
.PP
returns \fB::Foo::traceLevel\fR.
.PP
As mentioned above,
namespace names are looked up differently
than the names of variables and commands.
Namespace names are always resolved in the current namespace.
This means, for example,
that a \fBnamespace eval\fR command that creates a new namespace
always creates a child of the current namespace
unless the new namespace name begins with \fB::\fR.
.PP
Tcl has no access control to limit what variables, commands,
or namespaces you can reference.







|
|
>
>



















|
<

|














|
<
<
|
|









|
|





|


|
|
|







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

522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538


539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
If you provide a fully-qualified name that starts with a \fB::\fR,
there is no question about what command, variable, or namespace
you mean.
However, if the name does not start with a \fB::\fR
(i.e., is \fIrelative\fR),
Tcl follows basic rules for looking it up:
.IP \(bu
\fBVariable names\fR are always resolved starting in the current
namespace. In the absence of special resolvers, foo::bar::baz refers to
a variable named "baz" in a namespace named "bar" that is a child of a
namespace named "foo" that is a child of the current namespace of the interpreter.
.IP \(bu
\fBCommand names\fR are always resolved by looking in the current namespace
first. If not found there, they are searched for in every namespace on the
current namespace's command path (which is empty by default). If not found
there, command names are looked up in the global namespace (or, failing that,
are processed by the appropriate \fBnamespace unknown\fR handler.)
.IP \(bu
\fBNamespace names\fR are always resolved by looking in only the current
namespace.
.PP
In the following example,
.PP
.CS
set traceLevel 0
\fBnamespace eval\fR Debug {
    printTrace $traceLevel
}
.CE
.PP
Tcl looks for \fBtraceLevel\fR in the namespace \fBDebug\fR.

It looks up the command \fBprintTrace\fR in the same way.
If a variable or command name is not found,
the name is undefined.
To make this point absolutely clear, consider the following example:
.PP
.CS
set traceLevel 0
\fBnamespace eval\fR Foo {
    variable traceLevel 3

    \fBnamespace eval\fR Debug {
        printTrace $traceLevel
    }
}
.CE
.PP
Here Tcl looks for \fBtraceLevel\fR in the namespace \fBFoo::Debug\fR.


The variables \fBFoo::traceLevel\fR and \fBFoo::Debug::traceLevel\fR
are completely ignored during the name resolution process.
.PP
You can use the \fBnamespace which\fR command to clear up any question
about name resolution.
For example, the command:
.PP
.CS
\fBnamespace eval\fR Foo::Debug {\fBnamespace which\fR -variable traceLevel}
.CE
.PP
returns the empty string.
The command,
.PP
.CS
\fBnamespace eval\fR Foo {\fBnamespace which\fR -variable traceLevel}
.CE
.PP
returns the empty string as well.
.PP
As mentioned above,
namespace names and variables are looked up differently
than the names of commands.
Namespace names and variables are always resolved in the current namespace.
This means, for example,
that a \fBnamespace eval\fR command that creates a new namespace
always creates a child of the current namespace
unless the new namespace name begins with \fB::\fR.
.PP
Tcl has no access control to limit what variables, commands,
or namespaces you can reference.

Changes to doc/puts.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH puts n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
puts \- Write to a channel
.SH SYNOPSIS
\fBputs \fR?\fB\-nonewline\fR? ?\fIchannelId\fR? \fIstring\fR
.BE
.SH DESCRIPTION
.PP
The \fBputs\fR command has been superceded by the \fBchan puts\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH puts n 7.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
puts \- Write to a channel
.SH SYNOPSIS
\fBputs \fR?\fB\-nonewline\fR? ?\fIchannel\fR? \fIstring\fR
.BE
.SH DESCRIPTION
.PP
The \fBputs\fR command has been superceded by the \fBchan puts\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)

Changes to doc/read.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.TH read n 8.1 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
read \- Read from a channel
.SH SYNOPSIS
\fBread \fR?\fB\-nonewline\fR? \fIchannelId\fR
.sp
\fBread \fIchannelId numChars\fR
.BE
.SH DESCRIPTION
.PP
The \fBread\fR command has been superceded by the \fBchan read\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)







|

|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.TH read n 8.1 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
read \- Read from a channel
.SH SYNOPSIS
\fBread \fR?\fB\-nonewline\fR? \fIchannel\fR
.sp
\fBread \fIchannel numChars\fR
.BE
.SH DESCRIPTION
.PP
The \fBread\fR command has been superceded by the \fBchan read\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)

Changes to doc/refchan.n.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
.\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
refchan \- command handler API of reflected channels
.SH SYNOPSIS
.nf
\fBchan create \fImode cmdPrefix\fR

\fIcmdPrefix \fBblocking\fI channelId mode\fR
\fIcmdPrefix \fBcget\fI channelId option\fR
\fIcmdPrefix \fBcgetall\fI channelId\fR
\fIcmdPrefix \fBconfigure\fI channelId option value\fR
\fIcmdPrefix \fBfinalize\fI channelId\fR
\fIcmdPrefix \fBinitialize\fI channelId mode\fR
\fIcmdPrefix \fBread\fI channelId count\fR
\fIcmdPrefix \fBseek\fI channelId offset base\fR
\fIcmdPrefix \fBwatch\fI channelId eventspec\fR
\fIcmdPrefix \fBwrite\fI channelId data\fR
.fi
.BE
.SH DESCRIPTION
.PP
The Tcl-level handler for a reflected channel has to be a command with
subcommands (termed an \fIensemble\fR, as it is a command such as that
created by \fBnamespace ensemble\fR \fBcreate\fR, though the implementation
of handlers for reflected channel \fIis not\fR tied to \fBnamespace
ensemble\fRs in any way; see \fBEXAMPLE\fR below for how to build an
\fBoo::class\fR that supports the API). Note that \fIcmdPrefix\fR is whatever was
specified in the call to \fBchan create\fR, and may consist of
multiple arguments; this will be expanded to multiple words in place
of the prefix.
.PP
Of all the possible subcommands, the handler \fImust\fR support
\fBinitialize\fR, \fBfinalize\fR, and \fBwatch\fR. Support for the
other subcommands is optional.
.SS "MANDATORY SUBCOMMANDS"
.\" METHOD: initialize
.TP
\fIcmdPrefix \fBinitialize \fIchannelId mode\fR
.
An invocation of this subcommand will be the first call the
\fIcmdPrefix\fR will receive for the specified new \fIchannelId\fR. It
is the responsibility of this subcommand to set up any internal data
structures required to keep track of the channel and its state.
.RS
.PP
The return value of the method has to be a list containing the names
of all subcommands supported by the \fIcmdPrefix\fR. This also tells
the Tcl core which version of the API for reflected channels is used by







|
|
|
|
|
|
|
|
|
|




















|


|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
.\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
refchan \- command handler API of reflected channels
.SH SYNOPSIS
.nf
\fBchan create \fImode cmdPrefix\fR

\fIcmdPrefix \fBblocking\fI channel mode\fR
\fIcmdPrefix \fBcget\fI channel option\fR
\fIcmdPrefix \fBcgetall\fI channel\fR
\fIcmdPrefix \fBconfigure\fI channel option value\fR
\fIcmdPrefix \fBfinalize\fI channel\fR
\fIcmdPrefix \fBinitialize\fI channel mode\fR
\fIcmdPrefix \fBread\fI channel count\fR
\fIcmdPrefix \fBseek\fI channel offset base\fR
\fIcmdPrefix \fBwatch\fI channel eventspec\fR
\fIcmdPrefix \fBwrite\fI channel data\fR
.fi
.BE
.SH DESCRIPTION
.PP
The Tcl-level handler for a reflected channel has to be a command with
subcommands (termed an \fIensemble\fR, as it is a command such as that
created by \fBnamespace ensemble\fR \fBcreate\fR, though the implementation
of handlers for reflected channel \fIis not\fR tied to \fBnamespace
ensemble\fRs in any way; see \fBEXAMPLE\fR below for how to build an
\fBoo::class\fR that supports the API). Note that \fIcmdPrefix\fR is whatever was
specified in the call to \fBchan create\fR, and may consist of
multiple arguments; this will be expanded to multiple words in place
of the prefix.
.PP
Of all the possible subcommands, the handler \fImust\fR support
\fBinitialize\fR, \fBfinalize\fR, and \fBwatch\fR. Support for the
other subcommands is optional.
.SS "MANDATORY SUBCOMMANDS"
.\" METHOD: initialize
.TP
\fIcmdPrefix \fBinitialize \fIchannel mode\fR
.
An invocation of this subcommand will be the first call the
\fIcmdPrefix\fR will receive for the specified new \fIchannel\fR. It
is the responsibility of this subcommand to set up any internal data
structures required to keep track of the channel and its state.
.RS
.PP
The return value of the method has to be a list containing the names
of all subcommands supported by the \fIcmdPrefix\fR. This also tells
the Tcl core which version of the API for reflected channels is used by
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
will usually contain at least one element.
.PP
The subcommand must throw an error if the chosen mode is not
supported by the \fIcmdPrefix\fR.
.RE
.\" METHOD: finalize
.TP
\fIcmdPrefix \fBfinalize \fIchannelId\fR
.
An invocation of this subcommand will be the last call the
\fIcmdPrefix\fR will receive for the specified \fIchannelId\fR. It will
be generated just before the destruction of the data structures of the
channel held by the Tcl core. The command handler \fImust not\fR
access the \fIchannelId\fR anymore in no way. Upon this subcommand being
called, any internal resources allocated to this channel must be
cleaned up.
.RS
.PP
The return value of this subcommand is ignored.
.PP
If the subcommand throws an error the command which caused its
invocation (usually \fBchan close\fR) will appear to have thrown this
error. Any exception beyond \fBerror\fR (e.g.,\ \fBbreak\fR, etc.) is
treated as (and converted to) an error.
.PP
This subcommand is not invoked if the creation of the channel was
aborted during \fBinitialize\fR (See above).
.RE
.\" METHOD: watch
.TP
\fIcmdPrefix \fBwatch \fIchannelId eventspec\fR
.
This subcommand notifies the \fIcmdPrefix\fR that the specified
\fIchannelId\fR is interested in the events listed in the
\fIeventspec\fR. This argument is a list containing any of \fBread\fR
and \fBwrite\fR. The list may be empty, which signals that the
channel does not wish to be notified of any events. In that situation,
the handler should disable event generation completely.
.RS
.PP
\fBWarning:\fR Any return value of the subcommand is ignored. This
includes all errors thrown by the subcommand, \fBbreak\fR, \fBcontinue\fR, and
custom return codes.
.PP
This subcommand interacts with \fBchan postevent\fR. Trying to post an
event which was not listed in the last call to \fBwatch\fR will cause
\fBchan postevent\fR to throw an error.
.RE
.SS "OPTIONAL SUBCOMMANDS"
.\" METHOD: read
.TP
\fIcmdPrefix \fBread \fIchannelId count\fR
.
This \fIoptional\fR subcommand is called when the user requests data from the
channel \fIchannelId\fR. \fIcount\fR specifies how many \fIbytes\fR have been
requested. If the subcommand is not supported then it is not possible to read
from the channel handled by the command.
.RS
.PP
The return value of this subcommand is taken as the requested data
\fIbytes\fR. If the returned data contains more bytes than requested,
an error will be signaled and later thrown by the command which







|


|


|
















|


|

















|


|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
will usually contain at least one element.
.PP
The subcommand must throw an error if the chosen mode is not
supported by the \fIcmdPrefix\fR.
.RE
.\" METHOD: finalize
.TP
\fIcmdPrefix \fBfinalize \fIchannel\fR
.
An invocation of this subcommand will be the last call the
\fIcmdPrefix\fR will receive for the specified \fIchannel\fR. It will
be generated just before the destruction of the data structures of the
channel held by the Tcl core. The command handler \fImust not\fR
access the \fIchannel\fR anymore in no way. Upon this subcommand being
called, any internal resources allocated to this channel must be
cleaned up.
.RS
.PP
The return value of this subcommand is ignored.
.PP
If the subcommand throws an error the command which caused its
invocation (usually \fBchan close\fR) will appear to have thrown this
error. Any exception beyond \fBerror\fR (e.g.,\ \fBbreak\fR, etc.) is
treated as (and converted to) an error.
.PP
This subcommand is not invoked if the creation of the channel was
aborted during \fBinitialize\fR (See above).
.RE
.\" METHOD: watch
.TP
\fIcmdPrefix \fBwatch \fIchannel eventspec\fR
.
This subcommand notifies the \fIcmdPrefix\fR that the specified
\fIchannel\fR is interested in the events listed in the
\fIeventspec\fR. This argument is a list containing any of \fBread\fR
and \fBwrite\fR. The list may be empty, which signals that the
channel does not wish to be notified of any events. In that situation,
the handler should disable event generation completely.
.RS
.PP
\fBWarning:\fR Any return value of the subcommand is ignored. This
includes all errors thrown by the subcommand, \fBbreak\fR, \fBcontinue\fR, and
custom return codes.
.PP
This subcommand interacts with \fBchan postevent\fR. Trying to post an
event which was not listed in the last call to \fBwatch\fR will cause
\fBchan postevent\fR to throw an error.
.RE
.SS "OPTIONAL SUBCOMMANDS"
.\" METHOD: read
.TP
\fIcmdPrefix \fBread \fIchannel count\fR
.
This \fIoptional\fR subcommand is called when the user requests data from the
channel \fIchannel\fR. \fIcount\fR specifies how many \fIbytes\fR have been
requested. If the subcommand is not supported then it is not possible to read
from the channel handled by the command.
.RS
.PP
The return value of this subcommand is taken as the requested data
\fIbytes\fR. If the returned data contains more bytes than requested,
an error will be signaled and later thrown by the command which
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
If the subcommand throws any other error, the command which caused its
invocation (usually \fBgets\fR, or \fBread\fR) will appear to have
thrown this error. Any exception beyond \fBerror\fR, (e.g.,\ \fBbreak\fR,
etc.) is treated as and converted to an error.
.RE
.\" METHOD: write
.TP
\fIcmdPrefix \fBwrite \fIchannelId data\fR
.
This \fIoptional\fR subcommand is called when the user writes data to
the channel \fIchannelId\fR. The \fIdata\fR argument contains \fIbytes\fR, not
characters. Any type of transformation (EOL, encoding) configured for
the channel has already been applied at this point. If this subcommand
is not supported then it is not possible to write to the channel
handled by the command.
.RS
.PP
The return value of the subcommand is taken as the number of bytes







|


|







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
If the subcommand throws any other error, the command which caused its
invocation (usually \fBgets\fR, or \fBread\fR) will appear to have
thrown this error. Any exception beyond \fBerror\fR, (e.g.,\ \fBbreak\fR,
etc.) is treated as and converted to an error.
.RE
.\" METHOD: write
.TP
\fIcmdPrefix \fBwrite \fIchannel data\fR
.
This \fIoptional\fR subcommand is called when the user writes data to
the channel \fIchannel\fR. The \fIdata\fR argument contains \fIbytes\fR, not
characters. Any type of transformation (EOL, encoding) configured for
the channel has already been applied at this point. If this subcommand
is not supported then it is not possible to write to the channel
handled by the command.
.RS
.PP
The return value of the subcommand is taken as the number of bytes
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
If the subcommand throws any other error the command which caused its
invocation (usually \fBputs\fR) will appear to have thrown this error.
Any exception beyond \fBerror\fR (e.g.,\ \fBbreak\fR, etc.) is treated
as and converted to an error.
.RE
.\" METHOD: seek
.TP
\fIcmdPrefix \fBseek \fIchannelId offset base\fR
.
This \fIoptional\fR subcommand is responsible for the handling of
\fBchan seek\fR and \fBchan tell\fR requests on the channel
\fIchannelId\fR. If it is not supported then seeking will not be possible for
the channel.
.RS
.PP
The \fIbase\fR argument is the same as the equivalent argument of the
builtin \fBchan seek\fR, namely:
.IP \fBstart\fR 10
Seeking is relative to the beginning of the channel.







|



|







230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
If the subcommand throws any other error the command which caused its
invocation (usually \fBputs\fR) will appear to have thrown this error.
Any exception beyond \fBerror\fR (e.g.,\ \fBbreak\fR, etc.) is treated
as and converted to an error.
.RE
.\" METHOD: seek
.TP
\fIcmdPrefix \fBseek \fIchannel offset base\fR
.
This \fIoptional\fR subcommand is responsible for the handling of
\fBchan seek\fR and \fBchan tell\fR requests on the channel
\fIchannel\fR. If it is not supported then seeking will not be possible for
the channel.
.RS
.PP
The \fIbase\fR argument is the same as the equivalent argument of the
builtin \fBchan seek\fR, namely:
.IP \fBstart\fR 10
Seeking is relative to the beginning of the channel.
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
.PP
The offset/base combination of 0/\fBcurrent\fR signals a \fBchan tell\fR
request, i.e.,\ seek nothing relative to the current location, making
the new location identical to the current one, which is then returned.
.RE
.\" METHOD: configure
.TP
\fIcmdPrefix \fBconfigure \fIchannelId option value\fR
.
This \fIoptional\fR subcommand is for setting the type-specific options of
channel \fIchannelId\fR. The \fIoption\fR argument indicates the option to be
written, and the \fIvalue\fR argument indicates the value to set the option to.
.RS
.PP
This subcommand will never try to update more than one option at a
time; that is behavior implemented in the Tcl channel core.
.PP
The return value of the subcommand is ignored.
.PP
If the subcommand throws an error the command which performed the
(re)configuration or query (usually \fBfconfigure\fR or
\fBchan configure\fR) will appear to have thrown this error. Any exception
beyond \fBerror\fR (e.g.,\ \fBbreak\fR, etc.) is treated as and
converted to an error.
.RE
.\" METHOD: cget
.TP
\fIcmdPrefix \fBcget \fIchannelId option\fR
.
This \fIoptional\fR subcommand is used when reading a single type-specific
option of channel \fIchannelId\fR. If this subcommand is supported then the
subcommand \fBcgetall\fR must be supported as well.
.RS
.PP
The subcommand should return the value of the specified \fIoption\fR.
.PP
If the subcommand throws an error, the command which performed the
(re)configuration or query (usually \fBfconfigure\fR or \fBchan configure\fR)
will appear to have thrown this error. Any exception beyond \fIerror\fR
(e.g.,\ \fBbreak\fR, etc.) is treated as and converted to an error.
.RE
.\" METHOD: cgetall
.TP
\fIcmdPrefix \fBcgetall \fIchannelId\fR
.
This \fIoptional\fR subcommand is used for reading all type-specific options
of channel \fIchannelId\fR. If this subcommand is supported then the
subcommand \fBcget\fR has to be supported as well.
.RS
.PP
The subcommand should return a list of all options and their values.
This list must have an even number of elements.
.PP
If the subcommand throws an error the command which performed the
(re)configuration or query (usually \fBfconfigure\fR or \fBchan configure\fR)
will appear to have thrown this error. Any exception beyond \fBerror\fR
(e.g.,\ \fBbreak\fR, etc.) is treated as and converted to an error.
.RE
.\" METHOD: blocking
.TP
\fIcmdPrefix \fBblocking \fIchannelId mode\fR
.
This \fIoptional\fR subcommand handles changes to the blocking mode of the
channel \fIchannelId\fR. The \fImode\fR is a boolean flag. A true value means
that the channel has to be set to blocking, and a false value means that the
channel should be non-blocking.
.RS
.PP
The return value of the subcommand is ignored.
.PP
If the subcommand throws an error the command which caused its
invocation (usually \fBfconfigure\fR or \fBchan configure\fR) will appear to
have thrown this error. Any exception beyond \fBerror\fR (e.g.,\ \fBbreak\fR,
etc.) is treated as and converted to an error.
.RE
.\" METHOD: truncate
.TP
\fIcmdPrefix \fBtruncate\fI channelId length\fR
.
This \fIoptional\fR subcommand handles changing the length of the
underlying data stream for the channel \fIchannelId\fR. Its length
gets set to \fIlength\fR.
.RS
.PP
If the subcommand throws an error the command which caused its
invocation (usually \fBchan truncate\fR) will appear to have thrown
this error. Any exception beyond \fBerror\fR (e.g.,\ \fBbreak\fR,
etc.) is treated as and converted to an error.







|


|
















|


|












|


|













|


|













|


|







267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
.PP
The offset/base combination of 0/\fBcurrent\fR signals a \fBchan tell\fR
request, i.e.,\ seek nothing relative to the current location, making
the new location identical to the current one, which is then returned.
.RE
.\" METHOD: configure
.TP
\fIcmdPrefix \fBconfigure \fIchannel option value\fR
.
This \fIoptional\fR subcommand is for setting the type-specific options of
channel \fIchannel\fR. The \fIoption\fR argument indicates the option to be
written, and the \fIvalue\fR argument indicates the value to set the option to.
.RS
.PP
This subcommand will never try to update more than one option at a
time; that is behavior implemented in the Tcl channel core.
.PP
The return value of the subcommand is ignored.
.PP
If the subcommand throws an error the command which performed the
(re)configuration or query (usually \fBfconfigure\fR or
\fBchan configure\fR) will appear to have thrown this error. Any exception
beyond \fBerror\fR (e.g.,\ \fBbreak\fR, etc.) is treated as and
converted to an error.
.RE
.\" METHOD: cget
.TP
\fIcmdPrefix \fBcget \fIchannel option\fR
.
This \fIoptional\fR subcommand is used when reading a single type-specific
option of channel \fIchannel\fR. If this subcommand is supported then the
subcommand \fBcgetall\fR must be supported as well.
.RS
.PP
The subcommand should return the value of the specified \fIoption\fR.
.PP
If the subcommand throws an error, the command which performed the
(re)configuration or query (usually \fBfconfigure\fR or \fBchan configure\fR)
will appear to have thrown this error. Any exception beyond \fIerror\fR
(e.g.,\ \fBbreak\fR, etc.) is treated as and converted to an error.
.RE
.\" METHOD: cgetall
.TP
\fIcmdPrefix \fBcgetall \fIchannel\fR
.
This \fIoptional\fR subcommand is used for reading all type-specific options
of channel \fIchannel\fR. If this subcommand is supported then the
subcommand \fBcget\fR has to be supported as well.
.RS
.PP
The subcommand should return a list of all options and their values.
This list must have an even number of elements.
.PP
If the subcommand throws an error the command which performed the
(re)configuration or query (usually \fBfconfigure\fR or \fBchan configure\fR)
will appear to have thrown this error. Any exception beyond \fBerror\fR
(e.g.,\ \fBbreak\fR, etc.) is treated as and converted to an error.
.RE
.\" METHOD: blocking
.TP
\fIcmdPrefix \fBblocking \fIchannel mode\fR
.
This \fIoptional\fR subcommand handles changes to the blocking mode of the
channel \fIchannel\fR. The \fImode\fR is a boolean flag. A true value means
that the channel has to be set to blocking, and a false value means that the
channel should be non-blocking.
.RS
.PP
The return value of the subcommand is ignored.
.PP
If the subcommand throws an error the command which caused its
invocation (usually \fBfconfigure\fR or \fBchan configure\fR) will appear to
have thrown this error. Any exception beyond \fBerror\fR (e.g.,\ \fBbreak\fR,
etc.) is treated as and converted to an error.
.RE
.\" METHOD: truncate
.TP
\fIcmdPrefix \fBtruncate\fI channel length\fR
.
This \fIoptional\fR subcommand handles changing the length of the
underlying data stream for the channel \fIchannel\fR. Its length
gets set to \fIlength\fR.
.RS
.PP
If the subcommand throws an error the command which caused its
invocation (usually \fBchan truncate\fR) will appear to have thrown
this error. Any exception beyond \fBerror\fR (e.g.,\ \fBbreak\fR,
etc.) is treated as and converted to an error.

Changes to doc/return.n.

74
75
76
77
78
79
80
81



82
83
84
85
86
87
88
The return code of the procedure is 4 (\fBTCL_CONTINUE\fR).  The
procedure command behaves in its calling context as if it
were the command \fBcontinue\fR.
.TP 13
\fIvalue\fR
.
\fIValue\fR must be an integer;  it will be returned as the
return code for the current procedure.



.LP
When a procedure wants to signal that it has received invalid
arguments from its caller, it may use \fBreturn -code error\fR
with \fIresult\fR set to a suitable error message.  Otherwise
usage of the \fBreturn -code\fR option is mostly limited to
procedures that implement a new control structure.
.PP







|
>
>
>







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
The return code of the procedure is 4 (\fBTCL_CONTINUE\fR).  The
procedure command behaves in its calling context as if it
were the command \fBcontinue\fR.
.TP 13
\fIvalue\fR
.
\fIValue\fR must be an integer;  it will be returned as the
return code for the current procedure. Applications
and packages should use values in the range 5 to 1073741823 (0x3fffffff)
for their own purposes. Values outside this range are reserved
for use by Tcl.
.LP
When a procedure wants to signal that it has received invalid
arguments from its caller, it may use \fBreturn -code error\fR
with \fIresult\fR set to a suitable error message.  Otherwise
usage of the \fBreturn -code\fR option is mostly limited to
procedures that implement a new control structure.
.PP

Changes to doc/scan.n.

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

84
85
86

87
88
89
90
91
92
93
at most once and the empty positions will be filled in with empty strings.
.SS "OPTIONAL SIZE MODIFIER"
.PP
The size modifier field is used only when scanning a substring into
one of Tcl's integer values.  The size modifier field dictates the
integer range acceptable to be stored in a variable, or, for the inline
case, in a position in the result list.
The syntactically valid values for the size modifier are \fBh\fR, \fBL\fR,
\fBl\fR, \fBz\fR, \fBt\fR, and \fBll\fR.  The \fBh\fR size
modifier value is equivalent
to the absence of a size modifier in the the conversion specifier.
Either one indicates the integer range to be stored is limited to the range
determined by the value of the \fBwordSize\fR element of the \fBtcl_platform\fR
array).  The \fBL\fR, \fBq\fR or \fBj\fR size modifiers are equivalent to the
\fBl\fR size modifier. Either of them indicates the integer range to be stored is

limited to the same range produced by the \fBwide()\fR function of
the \fBexpr\fR command.  The \fBll\fR size modifier indicates that
the integer range to be stored is unlimited.

.SS "MANDATORY CONVERSION CHARACTER"
.PP
The following conversion characters are supported:
.IP \fBd\fR
The input substring must be a decimal integer.
It is read in and the integer value is stored in the variable,
truncated as required by the size modifier value.







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







69
70
71
72
73
74
75
76
77
78
79
80

81
82
83
84
85
86
87
88
89
90
91
92
93
94
at most once and the empty positions will be filled in with empty strings.
.SS "OPTIONAL SIZE MODIFIER"
.PP
The size modifier field is used only when scanning a substring into
one of Tcl's integer values.  The size modifier field dictates the
integer range acceptable to be stored in a variable, or, for the inline
case, in a position in the result list.
The syntactically valid values for the size modifier are \fBh\fR,
\fBl\fR, \fBz\fR, \fBt\fR, \fBq\fR, \fBj\fR, \fBll\fR, and \fBL\fR.
The \fBh\fR size modifier value is equivalent to the absence of a size
modifier in the the conversion specifier.  Either one indicates the
integer range to be stored is limited to the 32-bit range.  The \fBL\fR

size modifier is equivalent to the \fBll\fR size modifier.  Either one
indicates the integer range to be stored is unlimited.  The \fBl\fR (or
\fBq\fR or \fBj\fR) size modifier indicates that the integer range to be
stored is limited to the same range produced by the \fBwide()\fR function
of the \fBexpr\fR command. The \fBz\fR and \fBt\fR modifiers indicate the
integer range to be the same as for either \fBh\fR or \fBl\fR, depending
on the value of the \fBpointerSize\fR element of the \fBtcl_platform\fR array.
.SS "MANDATORY CONVERSION CHARACTER"
.PP
The following conversion characters are supported:
.IP \fBd\fR
The input substring must be a decimal integer.
It is read in and the integer value is stored in the variable,
truncated as required by the size modifier value.
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
puts "X=$x, Y=$y"
.CE
.PP
An interactive session demonstrating the truncation of integer
values determined by size modifiers:
.PP
.CS
\fI%\fR set tcl_platform(wordSize)
4
\fI%\fR scan 20000000000000000000 %d
2147483647
\fI%\fR scan 20000000000000000000 %ld
9223372036854775807
\fI%\fR scan 20000000000000000000 %lld
20000000000000000000
.CE







<
<







245
246
247
248
249
250
251


252
253
254
255
256
257
258
puts "X=$x, Y=$y"
.CE
.PP
An interactive session demonstrating the truncation of integer
values determined by size modifiers:
.PP
.CS


\fI%\fR scan 20000000000000000000 %d
2147483647
\fI%\fR scan 20000000000000000000 %ld
9223372036854775807
\fI%\fR scan 20000000000000000000 %lld
20000000000000000000
.CE

Changes to doc/seek.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH seek n 8.1 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
seek \- Change the access position for an open channel
.SH SYNOPSIS
\fBseek \fIchannelId offset \fR?\fIorigin\fR?
.BE
.SH DESCRIPTION
.PP
The \fBseek\fR command has been superceded by the \fBchan seek\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH seek n 8.1 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
seek \- Change the access position for an open channel
.SH SYNOPSIS
\fBseek \fIchannel offset \fR?\fIorigin\fR?
.BE
.SH DESCRIPTION
.PP
The \fBseek\fR command has been superceded by the \fBchan seek\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)

Changes to doc/tell.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH tell n 8.1 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
tell \- Return current access position for an open channel
.SH SYNOPSIS
\fBtell \fIchannelId\fR
.BE
.SH DESCRIPTION
.PP
The \fBtell\fR command has been superceded by the \fBchan tell\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH tell n 8.1 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
tell \- Return current access position for an open channel
.SH SYNOPSIS
\fBtell \fIchannel\fR
.BE
.SH DESCRIPTION
.PP
The \fBtell\fR command has been superceded by the \fBchan tell\fR
command which supports the same syntax and options.
.SH "SEE ALSO"
chan(n)

Changes to doc/transchan.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
transchan \- command handler API of channel transforms
.SH SYNOPSIS
.nf
\fBchan push \fIchannelId cmdPrefix\fR

\fIcmdPrefix \fBclear \fIhandle\fR
\fIcmdPrefix \fBdrain \fIhandle\fR
\fIcmdPrefix \fBfinalize \fIhandle\fR
\fIcmdPrefix \fBflush \fIhandle\fR
\fIcmdPrefix \fBinitialize \fIhandle mode\fR
\fIcmdPrefix \fBlimit? \fIhandle\fR







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
transchan \- command handler API of channel transforms
.SH SYNOPSIS
.nf
\fBchan push \fIchannel cmdPrefix\fR

\fIcmdPrefix \fBclear \fIhandle\fR
\fIcmdPrefix \fBdrain \fIhandle\fR
\fIcmdPrefix \fBfinalize \fIhandle\fR
\fIcmdPrefix \fBflush \fIhandle\fR
\fIcmdPrefix \fBinitialize \fIhandle mode\fR
\fIcmdPrefix \fBlimit? \fIhandle\fR

Changes to generic/tcl.h.

511
512
513
514
515
516
517


518
519
520
521
522
523
524


525
526
527
528
529
530
531
 * TCL_RETURN		The command requests that the current function return;
 *			the interpreter's result contains the function's
 *			return value.
 * TCL_BREAK		The command requests that the innermost loop be
 *			exited; the interpreter's result is meaningless.
 * TCL_CONTINUE		Go on to the next iteration of the current loop; the
 *			interpreter's result is meaningless.


 */

#define TCL_OK			0
#define TCL_ERROR		1
#define TCL_RETURN		2
#define TCL_BREAK		3
#define TCL_CONTINUE		4



/*
 *----------------------------------------------------------------------------
 * Flags to control what substitutions are performed by Tcl_SubstObj():
 */

#define TCL_SUBST_COMMANDS	001







>
>







>
>







511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
 * TCL_RETURN		The command requests that the current function return;
 *			the interpreter's result contains the function's
 *			return value.
 * TCL_BREAK		The command requests that the innermost loop be
 *			exited; the interpreter's result is meaningless.
 * TCL_CONTINUE		Go on to the next iteration of the current loop; the
 *			interpreter's result is meaningless.
 * Integer return codes in the range TCL_CODE_USER_MIN to TCL_CODE_USER_MAX are
 * reserved for the use of packages.
 */

#define TCL_OK			0
#define TCL_ERROR		1
#define TCL_RETURN		2
#define TCL_BREAK		3
#define TCL_CONTINUE		4
#define TCL_CODE_USER_MIN	5
#define TCL_CODE_USER_MAX	0x3fffffff /*  1073741823 */

/*
 *----------------------------------------------------------------------------
 * Flags to control what substitutions are performed by Tcl_SubstObj():
 */

#define TCL_SUBST_COMMANDS	001

Changes to generic/tclArithSeries.c.

508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
    Tcl_WideInt *intNumberPtr,
    double *dblNumberPtr,
    Tcl_Obj *numberObj)
{
    void *clientData;
    int tcl_number_type;

    if (Tcl_GetNumberFromObj(interp, numberObj, &clientData, 
		&tcl_number_type) != TCL_OK) {
    	return TCL_ERROR;
    }
    if (tcl_number_type == TCL_NUMBER_BIG) {
    	/* bignum is not supported yet. */
    	Tcl_WideInt w;
	(void)Tcl_GetWideIntFromObj(interp, numberObj, &w);







|







508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
    Tcl_WideInt *intNumberPtr,
    double *dblNumberPtr,
    Tcl_Obj *numberObj)
{
    void *clientData;
    int tcl_number_type;

    if (Tcl_GetNumberFromObj(interp, numberObj, &clientData,
		&tcl_number_type) != TCL_OK) {
    	return TCL_ERROR;
    }
    if (tcl_number_type == TCL_NUMBER_BIG) {
    	/* bignum is not supported yet. */
    	Tcl_WideInt w;
	(void)Tcl_GetWideIntFromObj(interp, numberObj, &w);

Changes to generic/tclBasic.c.

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
static Tcl_NRPostProc	TEOV_Exception;
static Tcl_NRPostProc	TEOV_NotFoundCallback;
static Tcl_NRPostProc	TEOV_RestoreVarFrame;
static Tcl_NRPostProc	TEOV_RunLeaveTraces;
static Tcl_NRPostProc	EvalObjvCore;
static Tcl_NRPostProc	Dispatch;

static Tcl_ObjCmdProc NRInjectObjCmd;
static Tcl_NRPostProc NRPostInvoke;
static Tcl_ObjCmdProc CoroTypeObjCmd;
static Tcl_ObjCmdProc TclNRCoroInjectObjCmd;
static Tcl_ObjCmdProc TclNRCoroProbeObjCmd;
static Tcl_NRPostProc InjectHandler;
static Tcl_NRPostProc InjectHandlerPostCall;








<







233
234
235
236
237
238
239

240
241
242
243
244
245
246
static Tcl_NRPostProc	TEOV_Exception;
static Tcl_NRPostProc	TEOV_NotFoundCallback;
static Tcl_NRPostProc	TEOV_RestoreVarFrame;
static Tcl_NRPostProc	TEOV_RunLeaveTraces;
static Tcl_NRPostProc	EvalObjvCore;
static Tcl_NRPostProc	Dispatch;


static Tcl_NRPostProc NRPostInvoke;
static Tcl_ObjCmdProc CoroTypeObjCmd;
static Tcl_ObjCmdProc TclNRCoroInjectObjCmd;
static Tcl_ObjCmdProc TclNRCoroProbeObjCmd;
static Tcl_NRPostProc InjectHandler;
static Tcl_NRPostProc InjectHandlerPostCall;

1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
    /* Adding the bytecode assembler command */
    cmdPtr = (Command *) Tcl_NRCreateCommand(interp,
	    "::tcl::unsupported::assemble", Tcl_AssembleObjCmd,
	    TclNRAssembleObjCmd, NULL, NULL);
    cmdPtr->compileProc = &TclCompileAssembleCmd;

    /* Coroutine monkeybusiness */
    Tcl_NRCreateCommand(interp, "::tcl::unsupported::inject", NULL,
	    NRInjectObjCmd, NULL, NULL);
    Tcl_CreateObjCommand(interp, "::tcl::unsupported::corotype",
	    CoroTypeObjCmd, NULL, NULL);

    /* Load and intialize ICU */
    Tcl_CreateObjCommand(interp, "::tcl::unsupported::loadIcu",
	    TclLoadIcuObjCmd, NULL, NULL);








<
<







1191
1192
1193
1194
1195
1196
1197


1198
1199
1200
1201
1202
1203
1204
    /* Adding the bytecode assembler command */
    cmdPtr = (Command *) Tcl_NRCreateCommand(interp,
	    "::tcl::unsupported::assemble", Tcl_AssembleObjCmd,
	    TclNRAssembleObjCmd, NULL, NULL);
    cmdPtr->compileProc = &TclCompileAssembleCmd;

    /* Coroutine monkeybusiness */


    Tcl_CreateObjCommand(interp, "::tcl::unsupported::corotype",
	    CoroTypeObjCmd, NULL, NULL);

    /* Load and intialize ICU */
    Tcl_CreateObjCommand(interp, "::tcl::unsupported::loadIcu",
	    TclLoadIcuObjCmd, NULL, NULL);

9306
9307
9308
9309
9310
9311
9312
9313
9314
9315
9316
9317
9318
9319
9320
9321
9322
9323
9324
9325
9326
9327
9328
9329
9330
9331
9332
9333
9334
9335
9336
9337
9338
9339
9340
9341
9342
9343
9344
9345
9346
9347
9348

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclNREvalList --
 *
 *	Callback to invoke command as list, used in order to delayed
 *	processing of canonical list command in sane environment.
 *
 *----------------------------------------------------------------------
 */

static int
TclNREvalList(
    void *data[],
    Tcl_Interp *interp,
    TCL_UNUSED(int) /*result*/)
{
    Tcl_Size objc;
    Tcl_Obj **objv;
    Tcl_Obj *listPtr = (Tcl_Obj *)data[0];

    Tcl_IncrRefCount(listPtr);

    TclMarkTailcall(interp);
    TclNRAddCallback(interp, TclNRReleaseValues, listPtr, NULL, NULL,NULL);
    TclListObjGetElements(NULL, listPtr, &objc, &objv);
    return TclNREvalObjv(interp, objc, objv, 0, NULL);
}

/*
 *----------------------------------------------------------------------
 *
 * CoroTypeObjCmd --
 *
 *	Implementation of [::tcl::unsupported::corotype] command.
 *
 *----------------------------------------------------------------------
 */








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







9303
9304
9305
9306
9307
9308
9309





























9310
9311
9312
9313
9314
9315
9316

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *





























 * CoroTypeObjCmd --
 *
 *	Implementation of [::tcl::unsupported::corotype] command.
 *
 *----------------------------------------------------------------------
 */

9657
9658
9659
9660
9661
9662
9663
9664
9665
9666
9667
9668
9669
9670
9671
9672
9673
9674
9675
9676
9677
9678
9679
9680
9681
9682
9683
9684
9685
9686
9687
9688
9689
9690
9691
9692
9693
9694
9695
9696
9697
9698
9699
9700
9701
9702
9703
9704
9705
9706
9707
9708
9709
9710
9711
9712
9713
9714
9715
9716
9717
9718
9719
9720
9721
9722
9723
9724
9725
	Tcl_Size numLevels = iPtr->numLevels;
	iPtr->numLevels = corPtr->auxNumLevels;
	corPtr->auxNumLevels = numLevels - corPtr->auxNumLevels;
	iPtr->execEnvPtr = corPtr->callerEEPtr;
    }
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * NRInjectObjCmd --
 *
 *	Implementation of [::tcl::unsupported::inject] command.
 *
 *----------------------------------------------------------------------
 */

static int
NRInjectObjCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{
    CoroutineData *corPtr;
    ExecEnv *savedEEPtr = iPtr->execEnvPtr;

    /*
     * Usage more or less like tailcall:
     *   inject coroName cmd ?arg1 arg2 ...?
     */

    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "coroName cmd ?arg1 arg2 ...?");
	return TCL_ERROR;
    }

    corPtr = GetCoroutineFromObj(interp, objv[1],
	    "can only inject a command into a coroutine");
    if (!corPtr) {
	return TCL_ERROR;
    }
    if (!COR_IS_SUSPENDED(corPtr)) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(
		"can only inject a command into a suspended coroutine", TCL_INDEX_NONE));
	Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ACTIVE", (char *)NULL);
	return TCL_ERROR;
    }

    /*
     * Add the callback to the coro's execEnv, so that it is the first thing
     * to happen when the coro is resumed.
     */

    iPtr->execEnvPtr = corPtr->eePtr;
    TclNRAddCallback(interp, TclNREvalList, Tcl_NewListObj(objc - 2, objv + 2),
	    NULL, NULL, NULL);
    iPtr->execEnvPtr = savedEEPtr;

    return TCL_OK;
}

int
TclNRInterpCoroutine(
    void *clientData,
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */







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







9625
9626
9627
9628
9629
9630
9631























































9632
9633
9634
9635
9636
9637
9638
	Tcl_Size numLevels = iPtr->numLevels;
	iPtr->numLevels = corPtr->auxNumLevels;
	corPtr->auxNumLevels = numLevels - corPtr->auxNumLevels;
	iPtr->execEnvPtr = corPtr->callerEEPtr;
    }
    return result;
}
























































int
TclNRInterpCoroutine(
    void *clientData,
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */

Changes to generic/tclEnsemble.c.

273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
 *
 * Side effects:
 *	Creates the ensemble for the namespace if one did not previously
 *	exist.
 *
 * Note:
 *	Can't use SetEnsembleConfigOptions() here. Different (but overlapping)
 *	options are supported. 
 *
 *----------------------------------------------------------------------
 */
static Tcl_Command
InitEnsembleFromOptions(
    Tcl_Interp *interp,
    int objc,







|







273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
 *
 * Side effects:
 *	Creates the ensemble for the namespace if one did not previously
 *	exist.
 *
 * Note:
 *	Can't use SetEnsembleConfigOptions() here. Different (but overlapping)
 *	options are supported.
 *
 *----------------------------------------------------------------------
 */
static Tcl_Command
InitEnsembleFromOptions(
    Tcl_Interp *interp,
    int objc,
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
 *	Reports an error in the interpreter (if non-NULL) if the command is
 *	not an ensemble.
 *
 *----------------------------------------------------------------------
 */
static inline EnsembleConfig *
GetEnsembleFromCommand(
    Tcl_Interp *interp,		/* Where to report an error. May be NULL. */	
    Tcl_Command token)		/* What to check for ensemble-ness. */
{
    Command *cmdPtr = (Command *) token;

    if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
	if (interp != NULL) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(







|







882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
 *	Reports an error in the interpreter (if non-NULL) if the command is
 *	not an ensemble.
 *
 *----------------------------------------------------------------------
 */
static inline EnsembleConfig *
GetEnsembleFromCommand(
    Tcl_Interp *interp,		/* Where to report an error. May be NULL. */
    Tcl_Command token)		/* What to check for ensemble-ness. */
{
    Command *cmdPtr = (Command *) token;

    if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
	if (interp != NULL) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
1700
1701
1702
1703
1704
1705
1706


1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717

1718
1719
1720
1721
1722
1723
1724
			    map[i].nreProc, map[i].clientData, NULL);
		    Tcl_DStringSetLength(&hiddenBuf, hiddenLen);
		    if (Tcl_HideCommand(interp, "___tmp",
			    Tcl_DStringAppend(&hiddenBuf, map[i].name,
				    TCL_AUTO_LENGTH))) {
			Tcl_Panic("%s", Tcl_GetStringResult(interp));
		    }


		} else {
		    /*
		     * Not hidden, so just create it. Yay!
		     */

		    cmdPtr = (Command *)
			    Tcl_NRCreateCommand(interp, TclGetString(toObj),
			    map[i].proc, map[i].nreProc, map[i].clientData,
			    NULL);
		}
		cmdPtr->compileProc = map[i].compileProc;

	    }
	}
	Tcl_SetEnsembleMappingDict(interp, ensemble, mapDict);
    }

    Tcl_DStringFree(&buf);
    Tcl_DStringFree(&hiddenBuf);







>
>









<
|
>







1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717

1718
1719
1720
1721
1722
1723
1724
1725
1726
			    map[i].nreProc, map[i].clientData, NULL);
		    Tcl_DStringSetLength(&hiddenBuf, hiddenLen);
		    if (Tcl_HideCommand(interp, "___tmp",
			    Tcl_DStringAppend(&hiddenBuf, map[i].name,
				    TCL_AUTO_LENGTH))) {
			Tcl_Panic("%s", Tcl_GetStringResult(interp));
		    }
		    /* don't compile unsafe subcommands in safe interp */
		    cmdPtr->compileProc = NULL;
		} else {
		    /*
		     * Not hidden, so just create it. Yay!
		     */

		    cmdPtr = (Command *)
			    Tcl_NRCreateCommand(interp, TclGetString(toObj),
			    map[i].proc, map[i].nreProc, map[i].clientData,
			    NULL);

		    cmdPtr->compileProc = map[i].compileProc;
		}
	    }
	}
	Tcl_SetEnsembleMappingDict(interp, ensemble, mapDict);
    }

    Tcl_DStringFree(&buf);
    Tcl_DStringFree(&hiddenBuf);
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
    }
    targetCmdObj = elems[0];

    oldCmdPtr = cmdPtr;
    Tcl_IncrRefCount(targetCmdObj);
    newCmdPtr = (Command *) Tcl_GetCommandFromObj(interp, targetCmdObj);
    TclDecrRefCount(targetCmdObj);
    if (newCmdPtr == NULL || Tcl_IsSafe(interp)
	    || newCmdPtr->nsPtr->flags & NS_SUPPRESS_COMPILATION
	    || newCmdPtr->flags & CMD_HAS_EXEC_TRACES
	    || ((Interp *) interp)->flags & DONT_COMPILE_CMDS_INLINE) {
	/*
	 * Maps to an undefined command or a command without a compiler.
	 * Cannot compile.
	 */

	goto cleanup;
    }
    cmdPtr = newCmdPtr;
    depth++;

    /*
     * See whether we have a nested ensemble. If we do, we can go round the







|







<







3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234

3235
3236
3237
3238
3239
3240
3241
    }
    targetCmdObj = elems[0];

    oldCmdPtr = cmdPtr;
    Tcl_IncrRefCount(targetCmdObj);
    newCmdPtr = (Command *) Tcl_GetCommandFromObj(interp, targetCmdObj);
    TclDecrRefCount(targetCmdObj);
    if (newCmdPtr == NULL || (Tcl_IsSafe(interp) && !cmdPtr->compileProc)
	    || newCmdPtr->nsPtr->flags & NS_SUPPRESS_COMPILATION
	    || newCmdPtr->flags & CMD_HAS_EXEC_TRACES
	    || ((Interp *) interp)->flags & DONT_COMPILE_CMDS_INLINE) {
	/*
	 * Maps to an undefined command or a command without a compiler.
	 * Cannot compile.
	 */

	goto cleanup;
    }
    cmdPtr = newCmdPtr;
    depth++;

    /*
     * See whether we have a nested ensemble. If we do, we can go round the

Changes to generic/tclIO.c.

9191
9192
9193
9194
9195
9196
9197
9198
9199
9200
9201
9202
9203
9204
9205
    const char *chanName;
    int modeIndex;		/* Index of mode argument. */
    int mask;
    static const char *const modeOptions[] = {"readable", "writable", NULL};
    static const int maskArray[] = {TCL_READABLE, TCL_WRITABLE};

    if ((objc != 3) && (objc != 4)) {
	Tcl_WrongNumArgs(interp, 1, objv, "channelId event ?script?");
	return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[2], modeOptions, "event name", 0,
	    &modeIndex) != TCL_OK) {
	return TCL_ERROR;
    }
    mask = maskArray[modeIndex];







|







9191
9192
9193
9194
9195
9196
9197
9198
9199
9200
9201
9202
9203
9204
9205
    const char *chanName;
    int modeIndex;		/* Index of mode argument. */
    int mask;
    static const char *const modeOptions[] = {"readable", "writable", NULL};
    static const int maskArray[] = {TCL_READABLE, TCL_WRITABLE};

    if ((objc != 3) && (objc != 4)) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel event ?script?");
	return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[2], modeOptions, "event name", 0,
	    &modeIndex) != TCL_OK) {
	return TCL_ERROR;
    }
    mask = maskArray[modeIndex];

Changes to generic/tclIOCmd.c.

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
	    chanObjPtr = objv[2];
	    string = objv[3];
	    break;
	}
	/* Fall through */
    default:			/* [puts] or
				 * [puts some bad number of arguments...] */
	Tcl_WrongNumArgs(interp, 1, objv, "?-nonewline? ?channelId? string");
	return TCL_ERROR;
    }

    if (chanObjPtr == NULL) {
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

	if (!tsdPtr->initialized) {







|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
	    chanObjPtr = objv[2];
	    string = objv[3];
	    break;
	}
	/* Fall through */
    default:			/* [puts] or
				 * [puts some bad number of arguments...] */
	Tcl_WrongNumArgs(interp, 1, objv, "?-nonewline? ?channel? string");
	return TCL_ERROR;
    }

    if (chanObjPtr == NULL) {
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

	if (!tsdPtr->initialized) {
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Obj *chanObjPtr;
    Tcl_Channel chan;		/* The channel to flush on. */
    int mode;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "channelId");
	return TCL_ERROR;
    }
    chanObjPtr = objv[1];
    if (TclGetChannelFromObj(interp, chanObjPtr, &chan, &mode, 0) != TCL_OK) {
	return TCL_ERROR;
    }
    if (!(mode & TCL_WRITABLE)) {







|







218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Obj *chanObjPtr;
    Tcl_Channel chan;		/* The channel to flush on. */
    int mode;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel");
	return TCL_ERROR;
    }
    chanObjPtr = objv[1];
    if (TclGetChannelFromObj(interp, chanObjPtr, &chan, &mode, 0) != TCL_OK) {
	return TCL_ERROR;
    }
    if (!(mode & TCL_WRITABLE)) {
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
    Tcl_Channel chan;		/* The channel to read from. */
    Tcl_Size lineLen;		/* Length of line just read. */
    int mode;			/* Mode in which channel is opened. */
    Tcl_Obj *linePtr, *chanObjPtr;
    int code = TCL_OK;

    if ((objc != 2) && (objc != 3)) {
	Tcl_WrongNumArgs(interp, 1, objv, "channelId ?varName?");
	return TCL_ERROR;
    }
    chanObjPtr = objv[1];
    if (TclGetChannelFromObj(interp, chanObjPtr, &chan, &mode, 0) != TCL_OK) {
	return TCL_ERROR;
    }
    if (!(mode & TCL_READABLE)) {







|







284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
    Tcl_Channel chan;		/* The channel to read from. */
    Tcl_Size lineLen;		/* Length of line just read. */
    int mode;			/* Mode in which channel is opened. */
    Tcl_Obj *linePtr, *chanObjPtr;
    int code = TCL_OK;

    if ((objc != 2) && (objc != 3)) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel ?varName?");
	return TCL_ERROR;
    }
    chanObjPtr = objv[1];
    if (TclGetChannelFromObj(interp, chanObjPtr, &chan, &mode, 0) != TCL_OK) {
	return TCL_ERROR;
    }
    if (!(mode & TCL_READABLE)) {
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
    Tcl_Obj *resultPtr, *chanObjPtr;

    if ((objc != 2) && (objc != 3)) {
	Interp *iPtr;

    argerror:
	iPtr = (Interp *) interp;
	Tcl_WrongNumArgs(interp, 1, objv, "channelId ?numChars?");

	/*
	 * Do not append directly; that makes ensembles using this command as
	 * a subcommand produce the wrong message.
	 */

	iPtr->flags |= INTERP_ALTERNATE_WRONG_ARGS;
	Tcl_WrongNumArgs(interp, 1, objv, "?-nonewline? channelId");
	return TCL_ERROR;
    }

    i = 1;
    newline = 0;
    if (strcmp(TclGetString(objv[1]), "-nonewline") == 0) {
	newline = 1;







|







|







375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
    Tcl_Obj *resultPtr, *chanObjPtr;

    if ((objc != 2) && (objc != 3)) {
	Interp *iPtr;

    argerror:
	iPtr = (Interp *) interp;
	Tcl_WrongNumArgs(interp, 1, objv, "channel ?numChars?");

	/*
	 * Do not append directly; that makes ensembles using this command as
	 * a subcommand produce the wrong message.
	 */

	iPtr->flags |= INTERP_ALTERNATE_WRONG_ARGS;
	Tcl_WrongNumArgs(interp, 1, objv, "?-nonewline? channel");
	return TCL_ERROR;
    }

    i = 1;
    newline = 0;
    if (strcmp(TclGetString(objv[1]), "-nonewline") == 0) {
	newline = 1;
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
    int optionIndex;
    static const char *const originOptions[] = {
	"start", "current", "end", NULL
    };
    static const int modeArray[] = {SEEK_SET, SEEK_CUR, SEEK_END};

    if ((objc != 3) && (objc != 4)) {
	Tcl_WrongNumArgs(interp, 1, objv, "channelId offset ?origin?");
	return TCL_ERROR;
    }
    if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
	return TCL_ERROR;
    }
    if (TclGetWideIntFromObj(interp, objv[2], &offset) != TCL_OK) {
	return TCL_ERROR;







|







511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
    int optionIndex;
    static const char *const originOptions[] = {
	"start", "current", "end", NULL
    };
    static const int modeArray[] = {SEEK_SET, SEEK_CUR, SEEK_END};

    if ((objc != 3) && (objc != 4)) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel offset ?origin?");
	return TCL_ERROR;
    }
    if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
	return TCL_ERROR;
    }
    if (TclGetWideIntFromObj(interp, objv[2], &offset) != TCL_OK) {
	return TCL_ERROR;
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Channel chan;		/* The channel to tell on. */
    Tcl_WideInt newLoc;
    int code;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "channelId");
	return TCL_ERROR;
    }

    /*
     * Try to find a channel with the right name and permissions in the IO
     * channel table of this interpreter.
     */







|







580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Channel chan;		/* The channel to tell on. */
    Tcl_WideInt newLoc;
    int code;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel");
	return TCL_ERROR;
    }

    /*
     * Try to find a channel with the right name and permissions in the IO
     * channel table of this interpreter.
     */
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
    Tcl_Channel chan;		/* The channel to close. */
    static const char *const dirOptions[] = {
	"read", "write", NULL
    };
    static const int dirArray[] = {TCL_CLOSE_READ, TCL_CLOSE_WRITE};

    if ((objc != 2) && (objc != 3)) {
	Tcl_WrongNumArgs(interp, 1, objv, "channelId ?direction?");
	return TCL_ERROR;
    }

    if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
	return TCL_ERROR;
    }








|







643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
    Tcl_Channel chan;		/* The channel to close. */
    static const char *const dirOptions[] = {
	"read", "write", NULL
    };
    static const int dirArray[] = {TCL_CLOSE_READ, TCL_CLOSE_WRITE};

    if ((objc != 2) && (objc != 3)) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel ?direction?");
	return TCL_ERROR;
    }

    if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
	return TCL_ERROR;
    }

749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    const char *optionName, *valueName;
    Tcl_Channel chan;		/* The channel to set a mode on. */
    int i;			/* Iterate over arg-value pairs. */

    if ((objc < 2) || (((objc % 2) == 1) && (objc != 3))) {
	Tcl_WrongNumArgs(interp, 1, objv, "channelId ?-option value ...?");
	return TCL_ERROR;
    }

    if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
	return TCL_ERROR;
    }








|







749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    const char *optionName, *valueName;
    Tcl_Channel chan;		/* The channel to set a mode on. */
    int i;			/* Iterate over arg-value pairs. */

    if ((objc < 2) || (((objc % 2) == 1) && (objc != 3))) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel ?-option value ...?");
	return TCL_ERROR;
    }

    if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
	return TCL_ERROR;
    }

822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Channel chan;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "channelId");
	return TCL_ERROR;
    }

    if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
	return TCL_ERROR;
    }








|







822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Channel chan;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel");
	return TCL_ERROR;
    }

    if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
	return TCL_ERROR;
    }

1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Channel chan;
    int mode;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "channelId");
	return TCL_ERROR;
    }

    if (TclGetChannelFromObj(interp, objv[1], &chan, &mode, 0) != TCL_OK) {
	return TCL_ERROR;
    }
    if (!(mode & TCL_READABLE)) {







|







1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Channel chan;
    int mode;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel");
	return TCL_ERROR;
    }

    if (TclGetChannelFromObj(interp, objv[1], &chan, &mode, 0) != TCL_OK) {
	return TCL_ERROR;
    }
    if (!(mode & TCL_READABLE)) {
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
{
    Tcl_Channel chan;
    static const char *const options[] = {"input", "output", NULL};
    enum pendingOptionsEnum {PENDING_INPUT, PENDING_OUTPUT} index;
    int mode;

    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "mode channelId");
	return TCL_ERROR;
    }

    if (Tcl_GetIndexFromObj(interp, objv[1], options, "mode", 0,
	    &index) != TCL_OK) {
	return TCL_ERROR;
    }







|







1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
{
    Tcl_Channel chan;
    static const char *const options[] = {"input", "output", NULL};
    enum pendingOptionsEnum {PENDING_INPUT, PENDING_OUTPUT} index;
    int mode;

    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "mode channel");
	return TCL_ERROR;
    }

    if (Tcl_GetIndexFromObj(interp, objv[1], options, "mode", 0,
	    &index) != TCL_OK) {
	return TCL_ERROR;
    }
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Channel chan;
    Tcl_WideInt length;

    if ((objc < 2) || (objc > 3)) {
	Tcl_WrongNumArgs(interp, 1, objv, "channelId ?length?");
	return TCL_ERROR;
    }
    if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
	return TCL_ERROR;
    }

    if (objc == 3) {







|







1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Channel chan;
    Tcl_WideInt length;

    if ((objc < 2) || (objc > 3)) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel ?length?");
	return TCL_ERROR;
    }
    if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
	return TCL_ERROR;
    }

    if (objc == 3) {

Changes to generic/tclInterp.c.

1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
    }
    case OPT_TRANSFER:
    case OPT_SHARE: {
	Tcl_Interp *parentInterp;	/* The parent of the child. */
	Tcl_Channel chan;

	if (objc != 5) {
	    Tcl_WrongNumArgs(interp, 2, objv, "srcPath channelId destPath");
	    return TCL_ERROR;
	}
	parentInterp = GetInterp(interp, objv[2]);
	if (parentInterp == NULL) {
	    return TCL_ERROR;
	}
	chan = Tcl_GetChannel(parentInterp, TclGetString(objv[3]), NULL);







|







1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
    }
    case OPT_TRANSFER:
    case OPT_SHARE: {
	Tcl_Interp *parentInterp;	/* The parent of the child. */
	Tcl_Channel chan;

	if (objc != 5) {
	    Tcl_WrongNumArgs(interp, 2, objv, "srcPath channel destPath");
	    return TCL_ERROR;
	}
	parentInterp = GetInterp(interp, objv[2]);
	if (parentInterp == NULL) {
	    return TCL_ERROR;
	}
	chan = Tcl_GetChannel(parentInterp, TclGetString(objv[3]), NULL);

Changes to generic/tclScan.c.

381
382
383
384
385
386
387




388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
	case 'z':
	case 't':
	    if (sizeof(void *) > sizeof(int)) {
		flags |= SCAN_LONGER;
	    }
	    format += TclUtfToUniChar(format, &ch);
	    break;




	case 'l':
	    if (*format == 'l') {
		flags |= SCAN_BIG;
		format += 1;
		format += TclUtfToUniChar(format, &ch);
		break;
	    }
	    /* FALLTHRU */
	case 'L':
	case 'j':
	case 'q':
	    flags |= SCAN_LONGER;
	    /* FALLTHRU */
	case 'h':
	    format += TclUtfToUniChar(format, &ch);
	}







>
>
>
>








<







381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399

400
401
402
403
404
405
406
	case 'z':
	case 't':
	    if (sizeof(void *) > sizeof(int)) {
		flags |= SCAN_LONGER;
	    }
	    format += TclUtfToUniChar(format, &ch);
	    break;
	case 'L':
	    flags |= SCAN_BIG;
	    format += TclUtfToUniChar(format, &ch);
	    break;
	case 'l':
	    if (*format == 'l') {
		flags |= SCAN_BIG;
		format += 1;
		format += TclUtfToUniChar(format, &ch);
		break;
	    }
	    /* FALLTHRU */

	case 'j':
	case 'q':
	    flags |= SCAN_LONGER;
	    /* FALLTHRU */
	case 'h':
	    format += TclUtfToUniChar(format, &ch);
	}
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    const char *format;
    int numVars, nconversions, totalVars = -1;
    int objIndex, offset, i, result, code;
    long value;
    const char *string, *end, *baseString;
    char op = 0;
    int underflow = 0;
    Tcl_Size width;
    Tcl_WideInt wideValue;
    Tcl_UniChar ch = 0, sch = 0;
    Tcl_Obj **objs = NULL, *objPtr = NULL;







|







600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    const char *format;
    int numVars, nconversions, totalVars = -1;
    int objIndex, offset, i, result, code;
    int value;
    const char *string, *end, *baseString;
    char op = 0;
    int underflow = 0;
    Tcl_Size width;
    Tcl_WideInt wideValue;
    Tcl_UniChar ch = 0, sch = 0;
    Tcl_Obj **objs = NULL, *objPtr = NULL;
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
				"unsigned bignum scans are invalid", -1));
			Tcl_SetErrorCode(interp, "TCL", "FORMAT",
				"BADUNSIGNED", (char *)NULL);
			return TCL_ERROR;
		    }
		}
	    } else {
		if (TclGetLongFromObj(NULL, objPtr, &value) != TCL_OK) {
		    if (TclGetString(objPtr)[0] == '-') {
			value = LONG_MIN;
		    } else {
			value = LONG_MAX;
		    }
		}
		if ((flags & SCAN_UNSIGNED) && (value < 0)) {
#ifdef TCL_WIDE_INT_IS_LONG
		    mp_int big;
		    if (mp_init_u64(&big, (unsigned long)value) != MP_OKAY) {
			Tcl_SetObjResult(interp, Tcl_NewStringObj(







|

|

|







993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
				"unsigned bignum scans are invalid", -1));
			Tcl_SetErrorCode(interp, "TCL", "FORMAT",
				"BADUNSIGNED", (char *)NULL);
			return TCL_ERROR;
		    }
		}
	    } else {
		if (TclGetIntFromObj(NULL, objPtr, &value) != TCL_OK) {
		    if (TclGetString(objPtr)[0] == '-') {
			value = INT_MIN;
		    } else {
			value = INT_MAX;
		    }
		}
		if ((flags & SCAN_UNSIGNED) && (value < 0)) {
#ifdef TCL_WIDE_INT_IS_LONG
		    mp_int big;
		    if (mp_init_u64(&big, (unsigned long)value) != MP_OKAY) {
			Tcl_SetObjResult(interp, Tcl_NewStringObj(

Changes to generic/tclStringObj.c.

1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
     */

    while (*format != '\0') {
	char *end;
	int gotMinus = 0, gotHash = 0, gotZero = 0, gotSpace = 0, gotPlus = 0;
	int gotPrecision, sawFlag, useShort = 0, useBig = 0;
	Tcl_WideInt width, precision;
#ifndef TCL_WIDE_INT_IS_LONG
	int useWide = 0;
#endif
	int newXpg, allocSegment = 0;
	Tcl_Size numChars, segmentLimit, segmentNumBytes;
	Tcl_Obj *segment;
	int step = TclUtfToUniChar(format, &ch);

	format += step;
	if (ch != '%') {







<

<







1871
1872
1873
1874
1875
1876
1877

1878

1879
1880
1881
1882
1883
1884
1885
     */

    while (*format != '\0') {
	char *end;
	int gotMinus = 0, gotHash = 0, gotZero = 0, gotSpace = 0, gotPlus = 0;
	int gotPrecision, sawFlag, useShort = 0, useBig = 0;
	Tcl_WideInt width, precision;

	int useWide = 0;

	int newXpg, allocSegment = 0;
	Tcl_Size numChars, segmentLimit, segmentNumBytes;
	Tcl_Obj *segment;
	int step = TclUtfToUniChar(format, &ch);

	format += step;
	if (ch != '%') {
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
	} else if (ch == 'l') {
	    format += step;
	    step = TclUtfToUniChar(format, &ch);
	    if (ch == 'l') {
		useBig = 1;
		format += step;
		step = TclUtfToUniChar(format, &ch);
#ifndef TCL_WIDE_INT_IS_LONG
	    } else {
		useWide = 1;
#endif
	    }
	} else if (ch == 'I') {
	    if ((format[1] == '6') && (format[2] == '4')) {
		format += (step + 2);
		step = TclUtfToUniChar(format, &ch);
#ifndef TCL_WIDE_INT_IS_LONG
		useWide = 1;
#endif
	    } else if ((format[1] == '3') && (format[2] == '2')) {
		format += (step + 2);
		step = TclUtfToUniChar(format, &ch);
	    } else {
		format += step;
		step = TclUtfToUniChar(format, &ch);
	    }
	} else if ((ch == 'q') || (ch == 'j')) {
	    format += step;
	    step = TclUtfToUniChar(format, &ch);
#ifndef TCL_WIDE_INT_IS_LONG
	    useWide = 1;
#endif
	} else if ((ch == 't') || (ch == 'z')) {
	    format += step;
	    step = TclUtfToUniChar(format, &ch);
#ifndef TCL_WIDE_INT_IS_LONG
	    if (sizeof(void *) > sizeof(int)) {
		useWide = 1;
	    }
#endif
	} else if (ch == 'L') {
	    format += step;
	    step = TclUtfToUniChar(format, &ch);
	    useBig = 1;
	}

	format += step;







<


<





<

<










<

<



<



<







2076
2077
2078
2079
2080
2081
2082

2083
2084

2085
2086
2087
2088
2089

2090

2091
2092
2093
2094
2095
2096
2097
2098
2099
2100

2101

2102
2103
2104

2105
2106
2107

2108
2109
2110
2111
2112
2113
2114
	} else if (ch == 'l') {
	    format += step;
	    step = TclUtfToUniChar(format, &ch);
	    if (ch == 'l') {
		useBig = 1;
		format += step;
		step = TclUtfToUniChar(format, &ch);

	    } else {
		useWide = 1;

	    }
	} else if (ch == 'I') {
	    if ((format[1] == '6') && (format[2] == '4')) {
		format += (step + 2);
		step = TclUtfToUniChar(format, &ch);

		useWide = 1;

	    } else if ((format[1] == '3') && (format[2] == '2')) {
		format += (step + 2);
		step = TclUtfToUniChar(format, &ch);
	    } else {
		format += step;
		step = TclUtfToUniChar(format, &ch);
	    }
	} else if ((ch == 'q') || (ch == 'j')) {
	    format += step;
	    step = TclUtfToUniChar(format, &ch);

	    useWide = 1;

	} else if ((ch == 't') || (ch == 'z')) {
	    format += step;
	    step = TclUtfToUniChar(format, &ch);

	    if (sizeof(void *) > sizeof(int)) {
		useWide = 1;
	    }

	} else if (ch == 'L') {
	    format += step;
	    step = TclUtfToUniChar(format, &ch);
	    useBig = 1;
	}

	format += step;
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
	case 'o':
	case 'p':
	case 'x':
	case 'X':
	case 'b': {
	    short s = 0;	/* Silence compiler warning; only defined and
				 * used when useShort is true. */
	    long l;
	    Tcl_WideInt w;
	    mp_int big;
	    int isNegative = 0;
	    Tcl_Size toAppend;

#ifndef TCL_WIDE_INT_IS_LONG
	    if ((ch == 'p') && (sizeof(void *) > sizeof(int))) {
		useWide = 1;
	    }
#endif
	    if (useBig) {
		int cmpResult;
		if (Tcl_GetBignumFromObj(interp, segment, &big) != TCL_OK) {
		    goto error;
		}
		cmpResult = mp_cmp_d(&big, 0);
		isNegative = (cmpResult == MP_LT);
		if (cmpResult == MP_EQ) {
		    gotHash = 0;
		}
		if (ch == 'u') {
		    if (isNegative) {
			mp_clear(&big);
			msg = "unsigned bignum format is invalid";
			errCode = "BADUNSIGNED";
			goto errorMsg;
		    } else {
			ch = 'd';
		    }
		}
#ifndef TCL_WIDE_INT_IS_LONG
	    } else if (useWide) {
		if (TclGetWideBitsFromObj(interp, segment, &w) != TCL_OK) {
		    goto error;
		}
		isNegative = (w < (Tcl_WideInt) 0);
		if (w == (Tcl_WideInt) 0) {
		    gotHash = 0;
		}
#endif
	    } else if (TclGetLongFromObj(NULL, segment, &l) != TCL_OK) {
		if (TclGetWideBitsFromObj(interp, segment, &w) != TCL_OK) {
		    goto error;
		} else {
		    l = (long) w;
		}
		if (useShort) {
		    s = (short) l;
		    isNegative = (s < (short) 0);
		    if (s == (short) 0) {
			gotHash = 0;
		    }
		} else {
		    isNegative = (l < (long) 0);
		    if (l == (long) 0) {
			gotHash = 0;
		    }
		}
	    } else if (useShort) {
		s = (short) l;
		isNegative = (s < (short) 0);
		if (s == (short) 0) {
		    gotHash = 0;
		}
	    } else {
		isNegative = (l < (long) 0);
		if (l == (long) 0) {
		    gotHash = 0;
		}
	    }

	    TclNewObj(segment);
	    allocSegment = 1;
	    segmentLimit = TCL_SIZE_MAX;







|





<



<




















<








<
|



|








|
|










|
|







2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178

2179
2180
2181

2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201

2202
2203
2204
2205
2206
2207
2208
2209

2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
	case 'o':
	case 'p':
	case 'x':
	case 'X':
	case 'b': {
	    short s = 0;	/* Silence compiler warning; only defined and
				 * used when useShort is true. */
	    int l;
	    Tcl_WideInt w;
	    mp_int big;
	    int isNegative = 0;
	    Tcl_Size toAppend;


	    if ((ch == 'p') && (sizeof(void *) > sizeof(int))) {
		useWide = 1;
	    }

	    if (useBig) {
		int cmpResult;
		if (Tcl_GetBignumFromObj(interp, segment, &big) != TCL_OK) {
		    goto error;
		}
		cmpResult = mp_cmp_d(&big, 0);
		isNegative = (cmpResult == MP_LT);
		if (cmpResult == MP_EQ) {
		    gotHash = 0;
		}
		if (ch == 'u') {
		    if (isNegative) {
			mp_clear(&big);
			msg = "unsigned bignum format is invalid";
			errCode = "BADUNSIGNED";
			goto errorMsg;
		    } else {
			ch = 'd';
		    }
		}

	    } else if (useWide) {
		if (TclGetWideBitsFromObj(interp, segment, &w) != TCL_OK) {
		    goto error;
		}
		isNegative = (w < (Tcl_WideInt) 0);
		if (w == (Tcl_WideInt) 0) {
		    gotHash = 0;
		}

	    } else if (TclGetIntFromObj(NULL, segment, &l) != TCL_OK) {
		if (TclGetWideBitsFromObj(interp, segment, &w) != TCL_OK) {
		    goto error;
		} else {
		    l = (int) w;
		}
		if (useShort) {
		    s = (short) l;
		    isNegative = (s < (short) 0);
		    if (s == (short) 0) {
			gotHash = 0;
		    }
		} else {
		    isNegative = (l < (int) 0);
		    if (l == (int) 0) {
			gotHash = 0;
		    }
		}
	    } else if (useShort) {
		s = (short) l;
		isNegative = (s < (short) 0);
		if (s == (short) 0) {
		    gotHash = 0;
		}
	    } else {
		isNegative = (l < (int) 0);
		if (l == (int) 0) {
		    gotHash = 0;
		}
	    }

	    TclNewObj(segment);
	    allocSegment = 1;
	    segmentLimit = TCL_SIZE_MAX;
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
	    case 'd': {
		Tcl_Size length;
		Tcl_Obj *pure;
		const char *bytes;

		if (useShort) {
		    TclNewIntObj(pure, s);
#ifndef TCL_WIDE_INT_IS_LONG
		} else if (useWide) {
		    TclNewIntObj(pure, w);
#endif
		} else if (useBig) {
		    pure = Tcl_NewBignumObj(&big);
		} else {
		    TclNewIntObj(pure, l);
		}
		Tcl_IncrRefCount(pure);
		bytes = TclGetStringFromObj(pure, &length);







<


<







2276
2277
2278
2279
2280
2281
2282

2283
2284

2285
2286
2287
2288
2289
2290
2291
	    case 'd': {
		Tcl_Size length;
		Tcl_Obj *pure;
		const char *bytes;

		if (useShort) {
		    TclNewIntObj(pure, s);

		} else if (useWide) {
		    TclNewIntObj(pure, w);

		} else if (useBig) {
		    pure = Tcl_NewBignumObj(&big);
		} else {
		    TclNewIntObj(pure, l);
		}
		Tcl_IncrRefCount(pure);
		bytes = TclGetStringFromObj(pure, &length);
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
		    unsigned short us = (unsigned short) s;

		    bits = (Tcl_WideUInt) us;
		    while (us) {
			numDigits++;
			us /= base;
		    }
#ifndef TCL_WIDE_INT_IS_LONG
		} else if (useWide) {
		    Tcl_WideUInt uw = (Tcl_WideUInt) w;

		    bits = uw;
		    while (uw) {
			numDigits++;
			uw /= base;
		    }
#endif
		} else if (useBig && !mp_iszero(&big)) {
		    int leftover = (big.used * MP_DIGIT_BIT) % numBits;
		    mp_digit mask = (~(mp_digit)0) << (MP_DIGIT_BIT-leftover);

		    numDigits = 1 +
			    (((Tcl_WideInt) big.used * MP_DIGIT_BIT) / numBits);
		    while ((mask & big.dp[big.used-1]) == 0) {
			numDigits--;
			mask >>= numBits;
		    }
		    if (numDigits > INT_MAX) {
			msg = overflow;
			errCode = "OVERFLOW";
			goto errorMsg;
		    }
		} else if (!useBig) {
		    unsigned long ul = (unsigned long) l;

		    bits = (Tcl_WideUInt) ul;
		    while (ul) {
			numDigits++;
			ul /= base;
		    }
		}







<








<
















|







2362
2363
2364
2365
2366
2367
2368

2369
2370
2371
2372
2373
2374
2375
2376

2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
		    unsigned short us = (unsigned short) s;

		    bits = (Tcl_WideUInt) us;
		    while (us) {
			numDigits++;
			us /= base;
		    }

		} else if (useWide) {
		    Tcl_WideUInt uw = (Tcl_WideUInt) w;

		    bits = uw;
		    while (uw) {
			numDigits++;
			uw /= base;
		    }

		} else if (useBig && !mp_iszero(&big)) {
		    int leftover = (big.used * MP_DIGIT_BIT) % numBits;
		    mp_digit mask = (~(mp_digit)0) << (MP_DIGIT_BIT-leftover);

		    numDigits = 1 +
			    (((Tcl_WideInt) big.used * MP_DIGIT_BIT) / numBits);
		    while ((mask & big.dp[big.used-1]) == 0) {
			numDigits--;
			mask >>= numBits;
		    }
		    if (numDigits > INT_MAX) {
			msg = overflow;
			errCode = "OVERFLOW";
			goto errorMsg;
		    }
		} else if (!useBig) {
		    unsigned ul = (unsigned) l;

		    bits = (Tcl_WideUInt) ul;
		    while (ul) {
			numDigits++;
			ul /= base;
		    }
		}

Changes to generic/tclTest.c.

6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
    if ((cmdName[0] == 't') && (strncmp(cmdName, "transform", len) == 0)) {
	/*
	 * Syntax: transform channel -command command
	 */

	if (argc != 5) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		    " transform channelId -command cmd\"", (char *)NULL);
	    return TCL_ERROR;
	}
	if (strcmp(argv[3], "-command") != 0) {
	    Tcl_AppendResult(interp, "bad argument \"", argv[3],
		    "\": should be \"-command\"", (char *)NULL);
	    return TCL_ERROR;
	}







|







6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
    if ((cmdName[0] == 't') && (strncmp(cmdName, "transform", len) == 0)) {
	/*
	 * Syntax: transform channel -command command
	 */

	if (argc != 5) {
	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
		    " transform channel -command cmd\"", (char *)NULL);
	    return TCL_ERROR;
	}
	if (strcmp(argv[3], "-command") != 0) {
	    Tcl_AppendResult(interp, "bad argument \"", argv[3],
		    "\": should be \"-command\"", (char *)NULL);
	    return TCL_ERROR;
	}

Changes to library/tcltest/tcltest.tcl.

1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
	1 {
	    # Only the string to be printed is specified
	    append outData [lindex $args 0]\n
	    return
	    # return [Puts [lindex $args 0]]
	}
	2 {
	    # Either -nonewline or channelId has been specified
	    if {[lindex $args 0] eq "-nonewline"} {
		append outData [lindex $args end]
		return
		# return [Puts -nonewline [lindex $args end]]
	    } else {
		set channel [lindex $args 0]
		set newline \n
	    }
	}
	3 {
	    if {[lindex $args 0] eq "-nonewline"} {
		# Both -nonewline and channelId are specified, unless
		# it's an error.  -nonewline is supposed to be argv[0].
		set channel [lindex $args 1]
		set newline ""
	    }
	}
    }








|











|







1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
	1 {
	    # Only the string to be printed is specified
	    append outData [lindex $args 0]\n
	    return
	    # return [Puts [lindex $args 0]]
	}
	2 {
	    # Either -nonewline or channel has been specified
	    if {[lindex $args 0] eq "-nonewline"} {
		append outData [lindex $args end]
		return
		# return [Puts -nonewline [lindex $args end]]
	    } else {
		set channel [lindex $args 0]
		set newline \n
	    }
	}
	3 {
	    if {[lindex $args 0] eq "-nonewline"} {
		# Both -nonewline and channel are specified, unless
		# it's an error.  -nonewline is supposed to be argv[0].
		set channel [lindex $args 1]
		set newline ""
	    }
	}
    }

Changes to tests/chan.test.

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
} -returnCodes error -result "wrong # args: should be \"chan subcommand ?arg ...?\""
test chan-1.2 {chan command general syntax} -body {
    chan FOOBAR
} -returnCodes error -match glob -result "unknown or ambiguous subcommand \"FOOBAR\": must be *"

test chan-2.1 {chan command: blocked subcommand} -body {
    chan blocked foo bar
} -returnCodes error -result "wrong # args: should be \"chan blocked channelId\""
test chan-3.1 {chan command: close subcommand} -body {
    chan close foo bar zet
} -returnCodes error -result "wrong # args: should be \"chan close channelId ?direction?\""
test chan-3.2 {chan command: close subcommand} -setup {
    set chan [open [info script] r]
} -body {
    chan close $chan bar
} -cleanup {
    close $chan
} -returnCodes error -result "bad direction \"bar\": must be read or write"
test chan-3.3 {chan command: close subcommand} -setup {
    set chan [open [info script] r]
} -body {
    chan close $chan write
} -cleanup {
    close $chan
} -returnCodes error -result "Half-close of write-side not possible, side not opened or already closed"
test chan-4.1 {chan command: configure subcommand} -body {
    chan configure
} -returnCodes error -result "wrong # args: should be \"chan configure channelId ?-option value ...?\""
test chan-4.2 {chan command: [Bug 800753]} -body {
    chan configure stdout -eofchar Ā
} -returnCodes error -result {bad value for -eofchar: must be non-NUL ASCII character}
test chan-4.3 {chan command: [Bug 800753]} -body {
    chan configure stdout -eofchar \x00
} -returnCodes error -result {bad value for -eofchar: must be non-NUL ASCII character}
test chan-4.4 {chan command: check valid inValue, no outValue} -constraints deprecated -body {







|


|
















|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
} -returnCodes error -result "wrong # args: should be \"chan subcommand ?arg ...?\""
test chan-1.2 {chan command general syntax} -body {
    chan FOOBAR
} -returnCodes error -match glob -result "unknown or ambiguous subcommand \"FOOBAR\": must be *"

test chan-2.1 {chan command: blocked subcommand} -body {
    chan blocked foo bar
} -returnCodes error -result "wrong # args: should be \"chan blocked channel\""
test chan-3.1 {chan command: close subcommand} -body {
    chan close foo bar zet
} -returnCodes error -result "wrong # args: should be \"chan close channel ?direction?\""
test chan-3.2 {chan command: close subcommand} -setup {
    set chan [open [info script] r]
} -body {
    chan close $chan bar
} -cleanup {
    close $chan
} -returnCodes error -result "bad direction \"bar\": must be read or write"
test chan-3.3 {chan command: close subcommand} -setup {
    set chan [open [info script] r]
} -body {
    chan close $chan write
} -cleanup {
    close $chan
} -returnCodes error -result "Half-close of write-side not possible, side not opened or already closed"
test chan-4.1 {chan command: configure subcommand} -body {
    chan configure
} -returnCodes error -result "wrong # args: should be \"chan configure channel ?-option value ...?\""
test chan-4.2 {chan command: [Bug 800753]} -body {
    chan configure stdout -eofchar Ā
} -returnCodes error -result {bad value for -eofchar: must be non-NUL ASCII character}
test chan-4.3 {chan command: [Bug 800753]} -body {
    chan configure stdout -eofchar \x00
} -returnCodes error -result {bad value for -eofchar: must be non-NUL ASCII character}
test chan-4.4 {chan command: check valid inValue, no outValue} -constraints deprecated -body {
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

test chan-5.1 {chan command: copy subcommand} -body {
    chan copy foo
} -returnCodes error -result "wrong # args: should be \"chan copy input output ?-size size? ?-command callback?\""

test chan-6.1 {chan command: eof subcommand} -body {
    chan eof foo bar
} -returnCodes error -result "wrong # args: should be \"chan eof channelId\""

test chan-7.1 {chan command: event subcommand} -body {
    chan event foo
} -returnCodes error -result "wrong # args: should be \"chan event channelId event ?script?\""

test chan-8.1 {chan command: flush subcommand} -body {
    chan flush foo bar
} -returnCodes error -result "wrong # args: should be \"chan flush channelId\""

test chan-9.1 {chan command: gets subcommand} -body {
    chan gets
} -returnCodes error -result "wrong # args: should be \"chan gets channelId ?varName?\""

test chan-10.1 {chan command: names subcommand} -body {
    chan names foo bar
} -returnCodes error -result "wrong # args: should be \"chan names ?pattern?\""

test chan-11.1 {chan command: puts subcommand} -body {
    chan puts foo bar foo bar
} -returnCodes error -result "wrong # args: should be \"chan puts ?-nonewline? ?channelId? string\""

test chan-12.1 {chan command: read subcommand} -body {
    chan read
} -returnCodes error -result "wrong # args: should be \"chan read channelId ?numChars?\" or \"chan read ?-nonewline? channelId\""

test chan-13.1 {chan command: seek subcommand} -body {
    chan seek foo bar foo bar
} -returnCodes error -result "wrong # args: should be \"chan seek channelId offset ?origin?\""

test chan-14.1 {chan command: tell subcommand} -body {
    chan tell foo bar
} -returnCodes error -result "wrong # args: should be \"chan tell channelId\""

test chan-15.1 {chan command: truncate subcommand} -body {
    chan truncate foo bar foo bar
} -returnCodes error -result "wrong \# args: should be \"chan truncate channelId ?length?\""
test chan-15.2 {chan command: truncate subcommand} -setup {
    set file [makeFile {} testTruncate]
    set f [open $file w+]
    fconfigure $f -translation binary
} -body {
    seek $f 0
    puts -nonewline $f 12345
    seek $f 0
    chan truncate $f 2
    read $f
} -result 12 -cleanup {
    catch {close $f}
    catch {removeFile $file}
}

# TIP 287: chan pending
test chan-16.1 {chan command: pending subcommand} -body {
    chan pending
} -returnCodes error -result "wrong # args: should be \"chan pending mode channelId\""
test chan-16.2 {chan command: pending subcommand} -body {
    chan pending stdin
} -returnCodes error -result "wrong # args: should be \"chan pending mode channelId\""
test chan-16.3 {chan command: pending subcommand} -body {
    chan pending stdin stdout stderr
} -returnCodes error -result "wrong # args: should be \"chan pending mode channelId\""
test chan-16.4 {chan command: pending subcommand} -body {
    chan pending {input output} stdout
} -returnCodes error -result "bad mode \"input output\": must be input or output"
test chan-16.5 {chan command: pending input subcommand} -body {
    chan pending input stdout
} -result -1
test chan-16.6 {chan command: pending input subcommand} -body {







|



|



|



|







|



|



|



|



|


















|


|


|







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

test chan-5.1 {chan command: copy subcommand} -body {
    chan copy foo
} -returnCodes error -result "wrong # args: should be \"chan copy input output ?-size size? ?-command callback?\""

test chan-6.1 {chan command: eof subcommand} -body {
    chan eof foo bar
} -returnCodes error -result "wrong # args: should be \"chan eof channel\""

test chan-7.1 {chan command: event subcommand} -body {
    chan event foo
} -returnCodes error -result "wrong # args: should be \"chan event channel event ?script?\""

test chan-8.1 {chan command: flush subcommand} -body {
    chan flush foo bar
} -returnCodes error -result "wrong # args: should be \"chan flush channel\""

test chan-9.1 {chan command: gets subcommand} -body {
    chan gets
} -returnCodes error -result "wrong # args: should be \"chan gets channel ?varName?\""

test chan-10.1 {chan command: names subcommand} -body {
    chan names foo bar
} -returnCodes error -result "wrong # args: should be \"chan names ?pattern?\""

test chan-11.1 {chan command: puts subcommand} -body {
    chan puts foo bar foo bar
} -returnCodes error -result "wrong # args: should be \"chan puts ?-nonewline? ?channel? string\""

test chan-12.1 {chan command: read subcommand} -body {
    chan read
} -returnCodes error -result "wrong # args: should be \"chan read channel ?numChars?\" or \"chan read ?-nonewline? channel\""

test chan-13.1 {chan command: seek subcommand} -body {
    chan seek foo bar foo bar
} -returnCodes error -result "wrong # args: should be \"chan seek channel offset ?origin?\""

test chan-14.1 {chan command: tell subcommand} -body {
    chan tell foo bar
} -returnCodes error -result "wrong # args: should be \"chan tell channel\""

test chan-15.1 {chan command: truncate subcommand} -body {
    chan truncate foo bar foo bar
} -returnCodes error -result "wrong \# args: should be \"chan truncate channel ?length?\""
test chan-15.2 {chan command: truncate subcommand} -setup {
    set file [makeFile {} testTruncate]
    set f [open $file w+]
    fconfigure $f -translation binary
} -body {
    seek $f 0
    puts -nonewline $f 12345
    seek $f 0
    chan truncate $f 2
    read $f
} -result 12 -cleanup {
    catch {close $f}
    catch {removeFile $file}
}

# TIP 287: chan pending
test chan-16.1 {chan command: pending subcommand} -body {
    chan pending
} -returnCodes error -result "wrong # args: should be \"chan pending mode channel\""
test chan-16.2 {chan command: pending subcommand} -body {
    chan pending stdin
} -returnCodes error -result "wrong # args: should be \"chan pending mode channel\""
test chan-16.3 {chan command: pending subcommand} -body {
    chan pending stdin stdout stderr
} -returnCodes error -result "wrong # args: should be \"chan pending mode channel\""
test chan-16.4 {chan command: pending subcommand} -body {
    chan pending {input output} stdout
} -returnCodes error -result "bad mode \"input output\": must be input or output"
test chan-16.5 {chan command: pending input subcommand} -body {
    chan pending input stdout
} -result -1
test chan-16.6 {chan command: pending input subcommand} -body {

Changes to tests/chanio.test.

5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
} -cleanup {
    file delete ./~ ;# ./ because don't want to delete home in case of bugs!
    cd $curdir
} -result 1

test chan-io-41.1 {Tcl_FileeventCmd: errors} -constraints fileevent -body {
    chan event foo
} -returnCodes error -result {wrong # args: should be "chan event channelId event ?script?"}
test chan-io-41.2 {Tcl_FileeventCmd: errors} -constraints fileevent -body {
    chan event foo bar baz q
} -returnCodes error -result {wrong # args: should be "chan event channelId event ?script?"}
test chan-io-41.3 {Tcl_FileeventCmd: errors} -constraints fileevent -body {
    chan event gorp readable
} -returnCodes error -result {can not find channel named "gorp"}
test chan-io-41.4 {Tcl_FileeventCmd: errors} -constraints fileevent -body {
    chan event gorp writable
} -returnCodes error -result {can not find channel named "gorp"}
test chan-io-41.5 {Tcl_FileeventCmd: errors} -constraints fileevent -body {







|


|







5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
} -cleanup {
    file delete ./~ ;# ./ because don't want to delete home in case of bugs!
    cd $curdir
} -result 1

test chan-io-41.1 {Tcl_FileeventCmd: errors} -constraints fileevent -body {
    chan event foo
} -returnCodes error -result {wrong # args: should be "chan event channel event ?script?"}
test chan-io-41.2 {Tcl_FileeventCmd: errors} -constraints fileevent -body {
    chan event foo bar baz q
} -returnCodes error -result {wrong # args: should be "chan event channel event ?script?"}
test chan-io-41.3 {Tcl_FileeventCmd: errors} -constraints fileevent -body {
    chan event gorp readable
} -returnCodes error -result {can not find channel named "gorp"}
test chan-io-41.4 {Tcl_FileeventCmd: errors} -constraints fileevent -body {
    chan event gorp writable
} -returnCodes error -result {can not find channel named "gorp"}
test chan-io-41.5 {Tcl_FileeventCmd: errors} -constraints fileevent -body {

Changes to tests/coroutine.test.

821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865

866
867
868
869
870
871
872
		# c1.  After the fix, that doesn't happen, so if c1 still exists call it
		# one final time to allow it to finish and clean up
		rename c1 {}
	}
	return [list $done0 $done1]
} -result {failure failure}


test coroutine-8.0.0 {coro inject executed} -body {
    coroutine demo apply {{} { foreach i {1 2} yield }}
    demo
    set ::result none
    tcl::unsupported::inject demo set ::result inject-executed
    demo
    set ::result
} -result {inject-executed}
test coroutine-8.0.1 {coro inject after error} -body {
    coroutine demo apply {{} { foreach i {1 2} yield; error test }}
    demo
    set ::result none
    tcl::unsupported::inject demo set ::result inject-executed
    lappend ::result [catch {demo} err] $err
} -result {inject-executed 1 test}
test coroutine-8.1.1 {coro inject, ticket 42202ba1e5ff566e} -body {
    interp create child
    child eval {
	coroutine demo apply {{} { while {1} yield }}
	demo
	tcl::unsupported::inject demo set ::result inject-executed
    }
    interp delete child
} -result {}
test coroutine-8.1.2 {coro inject with result, ticket 42202ba1e5ff566e} -body {
    interp create child
    child eval {
	coroutine demo apply {{} { while {1} yield }}
	demo
	tcl::unsupported::inject demo set ::result inject-executed
    }
    child eval demo
    set result [child eval {set ::result}]

    interp delete child
    set result
} -result {inject-executed}


test coroutine-9.1 {coroprobe with yield} -body {
    coroutine demo apply {{} { foreach i {1 2} yield }}
    list [coroprobe demo set i] [demo] [coroprobe demo set i] [demo]
} -cleanup {
    catch {rename demo {}}
} -result {1 {} 2 {}}







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





|








|






|
>







821
822
823
824
825
826
827
















828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
		# c1.  After the fix, that doesn't happen, so if c1 still exists call it
		# one final time to allow it to finish and clean up
		rename c1 {}
	}
	return [list $done0 $done1]
} -result {failure failure}

















test coroutine-8.1.1 {coro inject, ticket 42202ba1e5ff566e} -body {
    interp create child
    child eval {
	coroutine demo apply {{} { while {1} yield }}
	demo
	coroinject demo set ::result inject-executed
    }
    interp delete child
} -result {}
test coroutine-8.1.2 {coro inject with result, ticket 42202ba1e5ff566e} -body {
    interp create child
    child eval {
	coroutine demo apply {{} { while {1} yield }}
	demo
	coroinject demo lappend ::result inject-executed
    }
    child eval demo
    set result [child eval {set ::result}]

    interp delete child
    set result
} -result {inject-executed yield {}}


test coroutine-9.1 {coroprobe with yield} -body {
    coroutine demo apply {{} { foreach i {1 2} yield }}
    list [coroprobe demo set i] [demo] [coroprobe demo set i] [demo]
} -cleanup {
    catch {rename demo {}}
} -result {1 {} 2 {}}
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059

test coroutine-12.1 {coroutine general introspection} -setup {
    set i [interp create]
} -body {
    $i eval {
	# Make the introspection code
	namespace path tcl::unsupported
	proc probe {type var} {
	    upvar 1 $var v
	    set f [info frame]
	    incr f -1
	    set result [list $v [dict get [info frame $f] proc]]
	    if {$type eq "yield"} {
		tailcall yield $result
	    } else {
		tailcall yieldto string cat $result
	    }
	}
	proc pokecoro {c var} {
	    inject $c probe [corotype $c] $var
	    $c
	}

	# Coroutine implementations
	proc cbody1 {} {
	    set val [info coroutine]
	    set accum {}







|











|







1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044

test coroutine-12.1 {coroutine general introspection} -setup {
    set i [interp create]
} -body {
    $i eval {
	# Make the introspection code
	namespace path tcl::unsupported
	proc probe {var type args} {
	    upvar 1 $var v
	    set f [info frame]
	    incr f -1
	    set result [list $v [dict get [info frame $f] proc]]
	    if {$type eq "yield"} {
		tailcall yield $result
	    } else {
		tailcall yieldto string cat $result
	    }
	}
	proc pokecoro {c var} {
	    coroinject $c probe $var
	    $c
	}

	# Coroutine implementations
	proc cbody1 {} {
	    set val [info coroutine]
	    set accum {}

Changes to tests/expr.test.

5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
        [expr {$max_long_str + 0}] \
        [expr {$max_long + 0}] \
        [expr {2147483647 + 0}] \
        [expr {$max_long == $max_long_hex}] \
        [expr {int(2147483647 + 1) > 0}] \

} {2147483647 2147483647 2147483647 2147483647 1 1}
test expr-33.2 {parse smallest long value} longIs32bit {
    set min_long_str -2147483648
    set min_long_hex "-0x80000000 "

    set min_long -2147483648
    # This will convert to integer (not wide) internal rep
    string is integer $min_long








|







5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
        [expr {$max_long_str + 0}] \
        [expr {$max_long + 0}] \
        [expr {2147483647 + 0}] \
        [expr {$max_long == $max_long_hex}] \
        [expr {int(2147483647 + 1) > 0}] \

} {2147483647 2147483647 2147483647 2147483647 1 1}
test expr-33.2 {parse smallest long value} {
    set min_long_str -2147483648
    set min_long_hex "-0x80000000 "

    set min_long -2147483648
    # This will convert to integer (not wide) internal rep
    string is integer $min_long

Changes to tests/format.test.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

if {"::tcltest" ni [namespace children]} {
    package require tcltest 2.5
    namespace import -force ::tcltest::*
}

# %u output depends on word length, so this test is not portable.
testConstraint longIs32bit [expr {$tcl_platform(wordSize) == 4}]
testConstraint longIs64bit [expr {$tcl_platform(wordSize) == 8}]
testConstraint wideIs64bit [expr {wide(0x8000000000000000) < 0}]
testConstraint pointerIs64bit [expr {$tcl_platform(pointerSize) >= 8}]
# MSVC uses a broken libc that gets sprintf("%g") wrong. This is a pain
# particularly in Continuous Integration, and there isn't anything much we can
# do about it.
testConstraint knownMsvcBug [expr {![string match msvc-* [tcl::build-info compiler]]}]

test format-1.1 {integer formatting} {
    format "%*d %d %d %d" 6 34 16923 -12 -1
} {    34 16923 -12 -1}
test format-1.2 {integer formatting} {
    format "%4d %4d %4d %4d %d %#x %#X" 6 34 16923 -12 -1 14 12
} {   6   34 16923  -12 -1 0xe 0xC}
test format-1.3 {integer formatting} longIs32bit {
    format "%4u %4u %4u %4u %d %#o" 6 34 16923 -12 -1 0
} {   6   34 16923 4294967284 -1 0}
test format-1.3.1 {integer formatting} longIs64bit {
    format "%4u %4u %4u %4u %d %#o" 6 34 16923 -12 -1 0
} {   6   34 16923 18446744073709551604 -1 0}
test format-1.4 {integer formatting} {
    format "%-4d %-4i %-4d %-4ld" 6 34 16923 -12 -1
} {6    34   16923 -12 }
test format-1.5 {integer formatting} {
    format "%04d %04d %04d %04i" 6 34 16923 -12 -1
} {0006 0034 16923 -012}
test format-1.6 {integer formatting} {
    format "%00*d" 6 34
} {000034}
# Printing negative numbers in hex or octal format depends on word
# length, so these tests are not portable.
test format-1.7 {integer formatting} longIs32bit {
    format "%4x %4x %4x %4x" 6 34 16923 -12 -1
} {   6   22 421b fffffff4}
test format-1.7.1 {integer formatting} longIs64bit {
    format "%4x %4x %4x %4x" 6 34 16923 -12 -1
} {   6   22 421b fffffffffffffff4}
test format-1.8 {integer formatting} longIs32bit {
    format "%#x %#x %#X %#X %#x" 0 6 34 16923 -12 -1
} {0 0x6 0x22 0x421B 0xfffffff4}
test format-1.8.1 {integer formatting} longIs64bit {
    format "%#x %#x %#X %#X %#x" 0 6 34 16923 -12 -1
} {0 0x6 0x22 0x421B 0xfffffffffffffff4}
test format-1.9 {integer formatting} longIs32bit {
    format "%#5x %#20x %#20x %#20x %#20x" 0 6 34 16923 -12 -1
} {    0                  0x6                 0x22               0x421b           0xfffffff4}
test format-1.9.1 {integer formatting} longIs64bit {
    format "%#5x %#20x %#20x %#20x %#20x" 0 6 34 16923 -12 -1
} {    0                  0x6                 0x22               0x421b   0xfffffffffffffff4}
test format-1.10 {integer formatting} longIs32bit {
    format "%-#5x %-#20x %-#20x %-#20x %-#20x" 0 6 34 16923 -12 -1
} {0     0x6                  0x22                 0x421b               0xfffffff4          }
test format-1.10.1 {integer formatting} longIs64bit {
    format "%-#5x %-#20x %-#20x %-#20x %-#20x" 0 6 34 16923 -12 -1
} {0     0x6                  0x22                 0x421b               0xfffffffffffffff4  }
test format-1.11 {integer formatting} longIs32bit {
    format "%-#5o %-#20o %#-20o %#-20o %#-20o" 0 6 34 16923 -12 -1
} {0     0o6                  0o42                 0o41033              0o37777777764       }
test format-1.11.1 {integer formatting} longIs64bit {
    format "%-#5o %-#20o %#-20o %#-20o %#-20o" 0 6 34 16923 -12 -1
} {0     0o6                  0o42                 0o41033              0o1777777777777777777764}
test format-1.12 {integer formatting} {
    format "%b %#b %#b %llb" 5 0 5 [expr {2**100}]
} {101 0 0b101 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000}
test format-1.13 {integer formatting} {
    format "%#0d %#0d %#0d %#0d %#0d" 0 6 34 16923 -12 -1
} {0 0d6 0d34 0d16923 -0d12}
test format-1.14 {integer formatting} {







|
<
<
<












|


<
<
<











|


<
<
<
|


<
<
<
|


<
<
<
|


<
<
<
|


<
<
<







11
12
13
14
15
16
17
18



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



34
35
36
37
38
39
40
41
42
43
44
45
46
47



48
49
50



51
52
53



54
55
56



57
58
59



60
61
62
63
64
65
66
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

if {"::tcltest" ni [namespace children]} {
    package require tcltest 2.5
    namespace import -force ::tcltest::*
}

# %z/%t/%p output depends on pointerSize, so some tests are not portable.



testConstraint pointerIs64bit [expr {$tcl_platform(pointerSize) >= 8}]
# MSVC uses a broken libc that gets sprintf("%g") wrong. This is a pain
# particularly in Continuous Integration, and there isn't anything much we can
# do about it.
testConstraint knownMsvcBug [expr {![string match msvc-* [tcl::build-info compiler]]}]

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



test format-1.4 {integer formatting} {
    format "%-4d %-4i %-4d %-4ld" 6 34 16923 -12 -1
} {6    34   16923 -12 }
test format-1.5 {integer formatting} {
    format "%04d %04d %04d %04i" 6 34 16923 -12 -1
} {0006 0034 16923 -012}
test format-1.6 {integer formatting} {
    format "%00*d" 6 34
} {000034}
# Printing negative numbers in hex or octal format depends on word
# length, so these tests are not portable.
test format-1.7 {integer formatting} {
    format "%4x %4x %4x %4x" 6 34 16923 -12 -1
} {   6   22 421b fffffff4}



test format-1.8 {integer formatting} {
    format "%#x %#x %#X %#X %#x" 0 6 34 16923 -12 -1
} {0 0x6 0x22 0x421B 0xfffffff4}



test format-1.9 {integer formatting} {
    format "%#5x %#20x %#20x %#20x %#20x" 0 6 34 16923 -12 -1
} {    0                  0x6                 0x22               0x421b           0xfffffff4}



test format-1.10 {integer formatting} {
    format "%-#5x %-#20x %-#20x %-#20x %-#20x" 0 6 34 16923 -12 -1
} {0     0x6                  0x22                 0x421b               0xfffffff4          }



test format-1.11 {integer formatting} {
    format "%-#5o %-#20o %#-20o %#-20o %#-20o" 0 6 34 16923 -12 -1
} {0     0o6                  0o42                 0o41033              0o37777777764       }



test format-1.12 {integer formatting} {
    format "%b %#b %#b %llb" 5 0 5 [expr {2**100}]
} {101 0 0b101 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000}
test format-1.13 {integer formatting} {
    format "%#0d %#0d %#0d %#0d %#0d" 0 6 34 16923 -12 -1
} {0 0d6 0d34 0d16923 -0d12}
test format-1.14 {integer formatting} {
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
for {set i 290} {$i < 400} {incr i} {
    test format-16.[expr {$i -289}] {testing MAX_FLOAT_SIZE} {
        format {%s} $b
    } $b
    append b "x"
}

test format-17.1 {testing %d with wide} {longIs32bit wideIs64bit} {
    format %d 7810179016327718216
} 1819043144
test format-17.2 {testing %ld with wide} {wideIs64bit} {
    format %ld 7810179016327718216
} 7810179016327718216
test format-17.3 {testing %ld with non-wide} {wideIs64bit} {
    format %ld 42
} 42
test format-17.4 {testing %l with non-integer} {
    format %lf 1
} 1.000000
test format-17.5 {testing %llu with positive bignum} -body {
    format %llu 0xabcdef0123456789abcdef







|


|


|







531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
for {set i 290} {$i < 400} {incr i} {
    test format-16.[expr {$i -289}] {testing MAX_FLOAT_SIZE} {
        format {%s} $b
    } $b
    append b "x"
}

test format-17.1 {testing %d with wide} {
    format %d 7810179016327718216
} 1819043144
test format-17.2 {testing %ld with wide} {
    format %ld 7810179016327718216
} 7810179016327718216
test format-17.3 {testing %ld with non-wide} {
    format %ld 42
} 42
test format-17.4 {testing %l with non-integer} {
    format %lf 1
} 1.000000
test format-17.5 {testing %llu with positive bignum} -body {
    format %llu 0xabcdef0123456789abcdef
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
    lappend result [expr {$a == $b}]
    set b 0xaaaa
    append b aaaa
    lappend result [expr {$a == $b}]
    format %08x $b
    lappend result [expr {$a == $b}]
} {1 1 1 1}
test format-18.2 {do not demote existing numeric values} {longIs32bit wideIs64bit} {
    set a [expr {0xaaaaaaaaaa + 1}]
    set b 0xaaaaaaaaab
    list [format %08x $a] [expr {$a == $b}]
} {aaaaaaab 1}

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

test format-19.4.1 {Bug d498578df4: width overflow should cause limit exceeded} \
-constraints {longIs32bit} -body {
    # in case of overflow into negative, it produces width -2 (and limit exceeded),
    # in case of width will be unsigned, it will be outside limit (2GB for 32bit)...
    # and it don't throw an error in case the bug is not fixed (and probably no segfault).
    format %[expr {0xffffffff - 1}]g 0
} -returnCodes error -result "max size for a Tcl value exceeded"

test format-19.4.2 {Bug d498578df4: width overflow should cause limit exceeded} -body {







|
















|
<







564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588

589
590
591
592
593
594
595
    lappend result [expr {$a == $b}]
    set b 0xaaaa
    append b aaaa
    lappend result [expr {$a == $b}]
    format %08x $b
    lappend result [expr {$a == $b}]
} {1 1 1 1}
test format-18.2 {do not demote existing numeric values} {
    set a [expr {0xaaaaaaaaaa + 1}]
    set b 0xaaaaaaaaab
    list [format %08x $a] [expr {$a == $b}]
} {aaaaaaab 1}

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

test format-19.4.1 {Bug d498578df4: width overflow should cause limit exceeded} -body {

    # in case of overflow into negative, it produces width -2 (and limit exceeded),
    # in case of width will be unsigned, it will be outside limit (2GB for 32bit)...
    # and it don't throw an error in case the bug is not fixed (and probably no segfault).
    format %[expr {0xffffffff - 1}]g 0
} -returnCodes error -result "max size for a Tcl value exceeded"

test format-19.4.2 {Bug d498578df4: width overflow should cause limit exceeded} -body {

Changes to tests/io.test.

6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
    set x [list [catch {open ~/foo} msg] $msg]
    set ::env(HOME) $home
    set x
} {1 {couldn't open "~/foo": no such file or directory}}

test io-41.1 {Tcl_FileeventCmd: errors} {fileevent} {
    list [catch {fileevent foo} msg] $msg
} {1 {wrong # args: should be "fileevent channelId event ?script?"}}
test io-41.2 {Tcl_FileeventCmd: errors} {fileevent} {
    list [catch {fileevent foo bar baz q} msg] $msg
} {1 {wrong # args: should be "fileevent channelId event ?script?"}}
test io-41.3 {Tcl_FileeventCmd: errors} {fileevent} {
    list [catch {fileevent gorp readable} msg] $msg
} {1 {can not find channel named "gorp"}}
test io-41.4 {Tcl_FileeventCmd: errors} {fileevent} {
    list [catch {fileevent gorp writable} msg] $msg
} {1 {can not find channel named "gorp"}}
test io-41.5 {Tcl_FileeventCmd: errors} {fileevent} {







|


|







6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
    set x [list [catch {open ~/foo} msg] $msg]
    set ::env(HOME) $home
    set x
} {1 {couldn't open "~/foo": no such file or directory}}

test io-41.1 {Tcl_FileeventCmd: errors} {fileevent} {
    list [catch {fileevent foo} msg] $msg
} {1 {wrong # args: should be "fileevent channel event ?script?"}}
test io-41.2 {Tcl_FileeventCmd: errors} {fileevent} {
    list [catch {fileevent foo bar baz q} msg] $msg
} {1 {wrong # args: should be "fileevent channel event ?script?"}}
test io-41.3 {Tcl_FileeventCmd: errors} {fileevent} {
    list [catch {fileevent gorp readable} msg] $msg
} {1 {can not find channel named "gorp"}}
test io-41.4 {Tcl_FileeventCmd: errors} {fileevent} {
    list [catch {fileevent gorp writable} msg] $msg
} {1 {can not find channel named "gorp"}}
test io-41.5 {Tcl_FileeventCmd: errors} {fileevent} {

Changes to tests/ioCmd.test.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Custom constraints used in this file
testConstraint testchannel	[llength [info commands testchannel]]

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

test iocmd-1.1 {puts command} {
   list [catch {puts} msg] $msg
} {1 {wrong # args: should be "puts ?-nonewline? ?channelId? string"}}
test iocmd-1.2 {puts command} {
   list [catch {puts a b c d e f g} msg] $msg
} {1 {wrong # args: should be "puts ?-nonewline? ?channelId? string"}}
test iocmd-1.3 {puts command} {
   list [catch {puts froboz -nonewline kablooie} msg] $msg
} {1 {wrong # args: should be "puts ?-nonewline? ?channelId? string"}}
test iocmd-1.4 {puts command} {
   list [catch {puts froboz hello} msg] $msg
} {1 {can not find channel named "froboz"}}
test iocmd-1.5 {puts command} {
   list [catch {puts stdin hello} msg] $msg
} {1 {channel "stdin" wasn't opened for writing}}








|


|


|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Custom constraints used in this file
testConstraint testchannel	[llength [info commands testchannel]]

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

test iocmd-1.1 {puts command} {
   list [catch {puts} msg] $msg
} {1 {wrong # args: should be "puts ?-nonewline? ?channel? string"}}
test iocmd-1.2 {puts command} {
   list [catch {puts a b c d e f g} msg] $msg
} {1 {wrong # args: should be "puts ?-nonewline? ?channel? string"}}
test iocmd-1.3 {puts command} {
   list [catch {puts froboz -nonewline kablooie} msg] $msg
} {1 {wrong # args: should be "puts ?-nonewline? ?channel? string"}}
test iocmd-1.4 {puts command} {
   list [catch {puts froboz hello} msg] $msg
} {1 {can not find channel named "froboz"}}
test iocmd-1.5 {puts command} {
   list [catch {puts stdin hello} msg] $msg
} {1 {channel "stdin" wasn't opened for writing}}

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    puts -nonewline $f [binary format a4a5 foo bar]
    close $f
    file size $path(test1)
} 9

test iocmd-2.1 {flush command} {
   list [catch {flush} msg] $msg
} {1 {wrong # args: should be "flush channelId"}}
test iocmd-2.2 {flush command} {
   list [catch {flush a b c d e} msg] $msg
} {1 {wrong # args: should be "flush channelId"}}
test iocmd-2.3 {flush command} {
   list [catch {flush foo} msg] $msg
} {1 {can not find channel named "foo"}}
test iocmd-2.4 {flush command} {
   list [catch {flush stdin} msg] $msg
} {1 {channel "stdin" wasn't opened for writing}}

test iocmd-3.1 {gets command} {
   list [catch {gets} msg] $msg
} {1 {wrong # args: should be "gets channelId ?varName?"}}
test iocmd-3.2 {gets command} {
   list [catch {gets a b c d e f g} msg] $msg
} {1 {wrong # args: should be "gets channelId ?varName?"}}
test iocmd-3.3 {gets command} {
   list [catch {gets aaa} msg] $msg
} {1 {can not find channel named "aaa"}}
test iocmd-3.4 {gets command} {
   list [catch {gets stdout} msg] $msg
} {1 {channel "stdout" wasn't opened for reading}}
test iocmd-3.5 {gets command} {
    set f [open $path(test1) w]
    puts $f [binary format a4a5 foo bar]
    close $f
    set f [open $path(test1) r]
    set result [gets $f]
    close $f
    set x foo\x00
    set x "${x}bar\x00\x00"
    string compare $x $result
} 0

test iocmd-4.1 {read command} {
   list [catch {read} msg] $msg
} {1 {wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"}}
test iocmd-4.2 {read command} {
   list [catch {read a b c d e f g h} msg] $msg
} {1 {wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"}}
test iocmd-4.3 {read command} {
   list [catch {read aaa} msg] $msg
} {1 {can not find channel named "aaa"}}
test iocmd-4.4 {read command} {
   list [catch {read -nonewline} msg] $msg
} {1 {wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"}}
test iocmd-4.5 {read command} {
   list [catch {read -nonew file4} msg] $msg $::errorCode
} {1 {can not find channel named "-nonew"} {TCL LOOKUP CHANNEL -nonew}}
test iocmd-4.6 {read command} {
   list [catch {read stdout} msg] $msg
} {1 {channel "stdout" wasn't opened for reading}}
test iocmd-4.7 {read command} {
   list [catch {read -nonewline stdout} msg] $msg
} {1 {channel "stdout" wasn't opened for reading}}
test iocmd-4.8 {read command with incorrect combination of arguments} {
    file delete $path(test1)
    set f [open $path(test1) w]
    puts $f "Two lines: this one"
    puts $f "and this one"
    close $f
    set f [open $path(test1)]
    set x [list [catch {read -nonewline $f 20 z} msg] $msg $::errorCode]
    close $f
    set x
} {1 {wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"} {TCL WRONGARGS}}
test iocmd-4.9 {read command} {
    list [catch {read stdin foo} msg] $msg $::errorCode
} {1 {expected non-negative integer but got "foo"} {TCL VALUE NUMBER}}
test iocmd-4.10 {read command} {
    list [catch {read file107} msg] $msg $::errorCode
} {1 {can not find channel named "file107"} {TCL LOOKUP CHANNEL file107}}
set path(test3) [makeFile {} test3]







|


|









|


|




















|


|





|



















|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    puts -nonewline $f [binary format a4a5 foo bar]
    close $f
    file size $path(test1)
} 9

test iocmd-2.1 {flush command} {
   list [catch {flush} msg] $msg
} {1 {wrong # args: should be "flush channel"}}
test iocmd-2.2 {flush command} {
   list [catch {flush a b c d e} msg] $msg
} {1 {wrong # args: should be "flush channel"}}
test iocmd-2.3 {flush command} {
   list [catch {flush foo} msg] $msg
} {1 {can not find channel named "foo"}}
test iocmd-2.4 {flush command} {
   list [catch {flush stdin} msg] $msg
} {1 {channel "stdin" wasn't opened for writing}}

test iocmd-3.1 {gets command} {
   list [catch {gets} msg] $msg
} {1 {wrong # args: should be "gets channel ?varName?"}}
test iocmd-3.2 {gets command} {
   list [catch {gets a b c d e f g} msg] $msg
} {1 {wrong # args: should be "gets channel ?varName?"}}
test iocmd-3.3 {gets command} {
   list [catch {gets aaa} msg] $msg
} {1 {can not find channel named "aaa"}}
test iocmd-3.4 {gets command} {
   list [catch {gets stdout} msg] $msg
} {1 {channel "stdout" wasn't opened for reading}}
test iocmd-3.5 {gets command} {
    set f [open $path(test1) w]
    puts $f [binary format a4a5 foo bar]
    close $f
    set f [open $path(test1) r]
    set result [gets $f]
    close $f
    set x foo\x00
    set x "${x}bar\x00\x00"
    string compare $x $result
} 0

test iocmd-4.1 {read command} {
   list [catch {read} msg] $msg
} {1 {wrong # args: should be "read channel ?numChars?" or "read ?-nonewline? channel"}}
test iocmd-4.2 {read command} {
   list [catch {read a b c d e f g h} msg] $msg
} {1 {wrong # args: should be "read channel ?numChars?" or "read ?-nonewline? channel"}}
test iocmd-4.3 {read command} {
   list [catch {read aaa} msg] $msg
} {1 {can not find channel named "aaa"}}
test iocmd-4.4 {read command} {
   list [catch {read -nonewline} msg] $msg
} {1 {wrong # args: should be "read channel ?numChars?" or "read ?-nonewline? channel"}}
test iocmd-4.5 {read command} {
   list [catch {read -nonew file4} msg] $msg $::errorCode
} {1 {can not find channel named "-nonew"} {TCL LOOKUP CHANNEL -nonew}}
test iocmd-4.6 {read command} {
   list [catch {read stdout} msg] $msg
} {1 {channel "stdout" wasn't opened for reading}}
test iocmd-4.7 {read command} {
   list [catch {read -nonewline stdout} msg] $msg
} {1 {channel "stdout" wasn't opened for reading}}
test iocmd-4.8 {read command with incorrect combination of arguments} {
    file delete $path(test1)
    set f [open $path(test1) w]
    puts $f "Two lines: this one"
    puts $f "and this one"
    close $f
    set f [open $path(test1)]
    set x [list [catch {read -nonewline $f 20 z} msg] $msg $::errorCode]
    close $f
    set x
} {1 {wrong # args: should be "read channel ?numChars?" or "read ?-nonewline? channel"} {TCL WRONGARGS}}
test iocmd-4.9 {read command} {
    list [catch {read stdin foo} msg] $msg $::errorCode
} {1 {expected non-negative integer but got "foo"} {TCL VALUE NUMBER}}
test iocmd-4.10 {read command} {
    list [catch {read file107} msg] $msg $::errorCode
} {1 {can not find channel named "file107"} {TCL LOOKUP CHANNEL file107}}
set path(test3) [makeFile {} test3]
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    read $f 12z
} -cleanup {
    close $f
} -result {expected non-negative integer but got "12z"} -errorCode {TCL VALUE NUMBER}

test iocmd-5.1 {seek command} -returnCodes error -body {
    seek
} -result {wrong # args: should be "seek channelId offset ?origin?"}
test iocmd-5.2 {seek command} -returnCodes error -body {
    seek a b c d e f g
} -result {wrong # args: should be "seek channelId offset ?origin?"}
test iocmd-5.3 {seek command} -returnCodes error -body {
    seek stdin gugu
} -result {expected integer but got "gugu"}
test iocmd-5.4 {seek command} -returnCodes error -body {
    seek stdin 100 gugu
} -result {bad origin "gugu": must be start, current, or end}

test iocmd-6.1 {tell command} {
    list [catch {tell} msg] $msg
} {1 {wrong # args: should be "tell channelId"}}
test iocmd-6.2 {tell command} {
    list [catch {tell a b c d e} msg] $msg
} {1 {wrong # args: should be "tell channelId"}}
test iocmd-6.3 {tell command} {
    list [catch {tell aaa} msg] $msg
} {1 {can not find channel named "aaa"}}

test iocmd-7.1 {close command} {
    list [catch {close} msg] $msg
} {1 {wrong # args: should be "close channelId ?direction?"}}
test iocmd-7.2 {close command} {
    list [catch {close a b c d e} msg] $msg
} {1 {wrong # args: should be "close channelId ?direction?"}}
test iocmd-7.3 {close command} {
    list [catch {close aaa} msg] $msg
} {1 {can not find channel named "aaa"}}
test iocmd-7.4 {close command} -setup {
    set chan [open [info script] r]
} -body {
    chan close $chan bar







|


|









|


|






|


|







157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    read $f 12z
} -cleanup {
    close $f
} -result {expected non-negative integer but got "12z"} -errorCode {TCL VALUE NUMBER}

test iocmd-5.1 {seek command} -returnCodes error -body {
    seek
} -result {wrong # args: should be "seek channel offset ?origin?"}
test iocmd-5.2 {seek command} -returnCodes error -body {
    seek a b c d e f g
} -result {wrong # args: should be "seek channel offset ?origin?"}
test iocmd-5.3 {seek command} -returnCodes error -body {
    seek stdin gugu
} -result {expected integer but got "gugu"}
test iocmd-5.4 {seek command} -returnCodes error -body {
    seek stdin 100 gugu
} -result {bad origin "gugu": must be start, current, or end}

test iocmd-6.1 {tell command} {
    list [catch {tell} msg] $msg
} {1 {wrong # args: should be "tell channel"}}
test iocmd-6.2 {tell command} {
    list [catch {tell a b c d e} msg] $msg
} {1 {wrong # args: should be "tell channel"}}
test iocmd-6.3 {tell command} {
    list [catch {tell aaa} msg] $msg
} {1 {can not find channel named "aaa"}}

test iocmd-7.1 {close command} {
    list [catch {close} msg] $msg
} {1 {wrong # args: should be "close channel ?direction?"}}
test iocmd-7.2 {close command} {
    list [catch {close a b c d e} msg] $msg
} {1 {wrong # args: should be "close channel ?direction?"}}
test iocmd-7.3 {close command} {
    list [catch {close aaa} msg] $msg
} {1 {can not find channel named "aaa"}}
test iocmd-7.4 {close command} -setup {
    set chan [open [info script] r]
} -body {
    chan close $chan bar
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    }
    set opts [list {*}$basicOpts {*}$extra]
    lset opts end [string cat "or " [lindex $opts end]]
    return [format {bad option "%s": should be one of %s} $got [join $opts ", "]]
}
test iocmd-8.1 {fconfigure command} -returnCodes error -body {
    fconfigure
} -result {wrong # args: should be "fconfigure channelId ?-option value ...?"}
test iocmd-8.2 {fconfigure command} -returnCodes error -body {
    fconfigure a b c d e f
} -result {wrong # args: should be "fconfigure channelId ?-option value ...?"}
test iocmd-8.3 {fconfigure command} -returnCodes error -body {
    fconfigure a b
} -result {can not find channel named "a"}
test iocmd-8.4 {fconfigure command} -setup {
    file delete $path(test1)
    set f1 [open $path(test1) w]
} -body {







|


|







212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    }
    set opts [list {*}$basicOpts {*}$extra]
    lset opts end [string cat "or " [lindex $opts end]]
    return [format {bad option "%s": should be one of %s} $got [join $opts ", "]]
}
test iocmd-8.1 {fconfigure command} -returnCodes error -body {
    fconfigure
} -result {wrong # args: should be "fconfigure channel ?-option value ...?"}
test iocmd-8.2 {fconfigure command} -returnCodes error -body {
    fconfigure a b c d e f
} -result {wrong # args: should be "fconfigure channel ?-option value ...?"}
test iocmd-8.3 {fconfigure command} -returnCodes error -body {
    fconfigure a b
} -result {can not find channel named "a"}
test iocmd-8.4 {fconfigure command} -setup {
    file delete $path(test1)
    set f1 [open $path(test1) w]
} -body {
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402

test iocmd-8.23 {fconfigure -profile badprofile} -body {
    fconfigure stdin -profile froboz
} -returnCodes error -result {bad profile name "froboz": must be replace, strict, or tcl8}

test iocmd-9.1 {eof command} {
    list [catch {eof} msg] $msg $::errorCode
} {1 {wrong # args: should be "eof channelId"} {TCL WRONGARGS}}
test iocmd-9.2 {eof command} {
    list [catch {eof a b} msg] $msg $::errorCode
} {1 {wrong # args: should be "eof channelId"} {TCL WRONGARGS}}
test iocmd-9.3 {eof command} {
    catch {close file100}
    list [catch {eof file100} msg] $msg $::errorCode
} {1 {can not find channel named "file100"} {TCL LOOKUP CHANNEL file100}}

# The tests for Tcl_ExecObjCmd are in exec.test

test iocmd-10.1 {fblocked command} {
    list [catch {fblocked} msg] $msg
} {1 {wrong # args: should be "fblocked channelId"}}
test iocmd-10.2 {fblocked command} {
    list [catch {fblocked a b c d e f g} msg] $msg
} {1 {wrong # args: should be "fblocked channelId"}}
test iocmd-10.3 {fblocked command} {
    list [catch {fblocked file1000} msg] $msg
} {1 {can not find channel named "file1000"}}
test iocmd-10.4 {fblocked command} {
    list [catch {fblocked stdout} msg] $msg
} {1 {channel "stdout" wasn't opened for reading}}
test iocmd-10.5 {fblocked command} {







|


|









|


|







372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402

test iocmd-8.23 {fconfigure -profile badprofile} -body {
    fconfigure stdin -profile froboz
} -returnCodes error -result {bad profile name "froboz": must be replace, strict, or tcl8}

test iocmd-9.1 {eof command} {
    list [catch {eof} msg] $msg $::errorCode
} {1 {wrong # args: should be "eof channel"} {TCL WRONGARGS}}
test iocmd-9.2 {eof command} {
    list [catch {eof a b} msg] $msg $::errorCode
} {1 {wrong # args: should be "eof channel"} {TCL WRONGARGS}}
test iocmd-9.3 {eof command} {
    catch {close file100}
    list [catch {eof file100} msg] $msg $::errorCode
} {1 {can not find channel named "file100"} {TCL LOOKUP CHANNEL file100}}

# The tests for Tcl_ExecObjCmd are in exec.test

test iocmd-10.1 {fblocked command} {
    list [catch {fblocked} msg] $msg
} {1 {wrong # args: should be "fblocked channel"}}
test iocmd-10.2 {fblocked command} {
    list [catch {fblocked a b c d e f g} msg] $msg
} {1 {wrong # args: should be "fblocked channel"}}
test iocmd-10.3 {fblocked command} {
    list [catch {fblocked file1000} msg] $msg
} {1 {can not find channel named "file1000"}}
test iocmd-10.4 {fblocked command} {
    list [catch {fblocked stdout} msg] $msg
} {1 {channel "stdout" wasn't opened for reading}}
test iocmd-10.5 {fblocked command} {

Changes to tests/namespace.test.

3366
3367
3368
3369
3370
3371
3372
















3373
3374
3375
3376
3377
3378
3379
    rename getbytes {}
    unset i ns start end
} -result 0

test namespace-55.1 {compiled ensembles inside compiled ensembles: Bug 6d2f249a01} {
    info class [format %s constructor] oo::object
} ""

















test namespace-56.1 {bug f97d4ee020: mutually-entangled deletion} {
    namespace eval ::testing {
	proc abc {} {}
	proc def {} {}
	trace add command abc delete "rename ::testing::def {}; #"
	trace add command def delete "rename ::testing::abc {}; #"







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







3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
    rename getbytes {}
    unset i ns start end
} -result 0

test namespace-55.1 {compiled ensembles inside compiled ensembles: Bug 6d2f249a01} {
    info class [format %s constructor] oo::object
} ""

test namespace-55.2 {compiled ensembles inside safe interpreters (for safe sub-commands), bug [1095bf7f756f9aed]} -setup {
    interp create -safe si
    set code {
	proc test_comp_dict d { dict for {k v} $d {expr $v} }
    	regexp -inline {Command 1:(?:[^\n]*\n){1,5}} [::tcl::unsupported::disassemble proc test_comp_dict]
    }
} -body {
    set a [   eval $code]
    set b [si eval $code]
    list [expr {$a eq $b}] [regexp { dictFirst } $a] [regexp { dictFirst } $b] $a $b
} -cleanup {
    rename test_comp_dict {}
    unset -nocomplain code a b
    interp delete si
} -match glob -result {1 1 1 *}

test namespace-56.1 {bug f97d4ee020: mutually-entangled deletion} {
    namespace eval ::testing {
	proc abc {} {}
	proc def {} {}
	trace add command abc delete "rename ::testing::def {}; #"
	trace add command def delete "rename ::testing::abc {}; #"

Changes to tests/obj.test.

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    namespace import -force ::tcltest::*
}

::tcltest::loadTestedCommands
catch [list package require -exact tcl::test [info patchlevel]]

testConstraint testobj [llength [info commands testobj]]
testConstraint longIs32bit [expr {$tcl_platform(wordSize) == 4}]
testConstraint wideIs64bit [expr {wide(0x8000000000000000) < 0}]

test obj-1.1 {Tcl_AppendAllObjTypes, and InitTypeTable, Tcl_RegisterObjType} testobj {
    set r 1
    foreach {t} {
	bytecode
	cmdName







<







16
17
18
19
20
21
22

23
24
25
26
27
28
29
    namespace import -force ::tcltest::*
}

::tcltest::loadTestedCommands
catch [list package require -exact tcl::test [info patchlevel]]

testConstraint testobj [llength [info commands testobj]]

testConstraint wideIs64bit [expr {wide(0x8000000000000000) < 0}]

test obj-1.1 {Tcl_AppendAllObjTypes, and InitTypeTable, Tcl_RegisterObjType} testobj {
    set r 1
    foreach {t} {
	bytecode
	cmdName
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
    set x {}
    for {set i 0} {$i<100000} {incr i} {
	set x [list $x {}]
    }
    unset x
} {}

test obj-33.1 {integer overflow on input} {longIs32bit wideIs64bit} {
    set x 0x8000; append x 0000
    list [string is integer $x] [expr { wide($x) }]
} {1 2147483648}
test obj-33.2 {integer overflow on input} {longIs32bit wideIs64bit} {
    set x 0xffff; append x ffff
    list [string is integer $x] [expr { wide($x) }]
} {1 4294967295}
test obj-33.3 {integer overflow on input} {
    set x 0x10000; append x 0000
    list [string is integer $x] [expr { wide($x) }]
} {1 4294967296}
test obj-33.4 {integer overflow on input} {longIs32bit wideIs64bit} {
    set x -0x8000; append x 0000
    list [string is integer $x] [expr { wide($x) }]
} {1 -2147483648}
test obj-33.5 {integer overflow on input} {longIs32bit wideIs64bit} {
    set x -0x8000; append x 0001
    list [string is integer $x] [expr { wide($x) }]
} {1 -2147483649}
test obj-33.6 {integer overflow on input} {longIs32bit wideIs64bit} {
    set x -0xffff; append x ffff
    list [string is integer $x] [expr { wide($x) }]
} {1 -4294967295}
test obj-33.7 {integer overflow on input} {
    set x -0x10000; append x 0000
    list [string is integer $x] [expr { wide($x) }]
} {1 -4294967296}







|



|







|



|



|







542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
    set x {}
    for {set i 0} {$i<100000} {incr i} {
	set x [list $x {}]
    }
    unset x
} {}

test obj-33.1 {integer overflow on input} {wideIs64bit} {
    set x 0x8000; append x 0000
    list [string is integer $x] [expr { wide($x) }]
} {1 2147483648}
test obj-33.2 {integer overflow on input} {wideIs64bit} {
    set x 0xffff; append x ffff
    list [string is integer $x] [expr { wide($x) }]
} {1 4294967295}
test obj-33.3 {integer overflow on input} {
    set x 0x10000; append x 0000
    list [string is integer $x] [expr { wide($x) }]
} {1 4294967296}
test obj-33.4 {integer overflow on input} {wideIs64bit} {
    set x -0x8000; append x 0000
    list [string is integer $x] [expr { wide($x) }]
} {1 -2147483648}
test obj-33.5 {integer overflow on input} {wideIs64bit} {
    set x -0x8000; append x 0001
    list [string is integer $x] [expr { wide($x) }]
} {1 -2147483649}
test obj-33.6 {integer overflow on input} {wideIs64bit} {
    set x -0xffff; append x ffff
    list [string is integer $x] [expr { wide($x) }]
} {1 -4294967295}
test obj-33.7 {integer overflow on input} {
    set x -0x10000; append x 0000
    list [string is integer $x] [expr { wide($x) }]
} {1 -4294967296}

Changes to tests/pid.test.

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
    close $f
    set pids
} -cleanup {
    removeFile test1
} -result {}
test pid-1.4 {pid command} pidDefined {
    list [catch {pid a b} msg] $msg
} {1 {wrong # args: should be "pid ?channelId?"}}
test pid-1.5 {pid command} pidDefined {
    list [catch {pid gorp} msg] $msg
} {1 {can not find channel named "gorp"}}

# cleanup
::tcltest::cleanupTests
return







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
    close $f
    set pids
} -cleanup {
    removeFile test1
} -result {}
test pid-1.4 {pid command} pidDefined {
    list [catch {pid a b} msg] $msg
} {1 {wrong # args: should be "pid ?channel?"}}
test pid-1.5 {pid command} pidDefined {
    list [catch {pid gorp} msg] $msg
} {1 {can not find channel named "gorp"}}

# cleanup
::tcltest::cleanupTests
return

Changes to tests/scan.test.

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
	default {
	    return 0
	}
    }
}

testConstraint ieeeFloatingPoint [testIEEE]
testConstraint wideIs64bit [expr {wide(0x8000000000000000) < 0}]

test scan-1.1 {BuildCharSet, CharInSet} {
    list [scan foo {%[^o]} x] $x
} {1 f}
test scan-1.2 {BuildCharSet, CharInSet} {
    list [scan \]foo {%[]f]} x] $x
} {1 \]f}







<







78
79
80
81
82
83
84

85
86
87
88
89
90
91
	default {
	    return 0
	}
    }
}

testConstraint ieeeFloatingPoint [testIEEE]


test scan-1.1 {BuildCharSet, CharInSet} {
    list [scan foo {%[^o]} x] $x
} {1 f}
test scan-1.2 {BuildCharSet, CharInSet} {
    list [scan \]foo {%[]f]} x] $x
} {1 \]f}
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
#
test scan-5.11 {integer scanning} -constraints {nonPortable} -setup {
    set a {}; set b {}
} -body {
    list [scan "4294967280 4294967280" "%u %d" a b] $a \
	    [expr {$b == -16 || $b == 0x7fffffff}]
} -result {2 4294967280 1}
test scan-5.12 {integer scanning} -constraints {wideIs64bit} -setup {
    set a {}; set b {}; set c {}
} -body {
    list [scan "7810179016327718216,6c63546f6c6c6548,661432506755433062510" \
	    %ld,%lx,%lo a b c] $a $b $c
} -result {3 7810179016327718216 7810179016327718216 7810179016327718216}
test scan-5.13 {integer scanning and overflow} {
    # This test used to fail on some 64-bit systems. [Bug 1011860]







|







512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
#
test scan-5.11 {integer scanning} -constraints {nonPortable} -setup {
    set a {}; set b {}
} -body {
    list [scan "4294967280 4294967280" "%u %d" a b] $a \
	    [expr {$b == -16 || $b == 0x7fffffff}]
} -result {2 4294967280 1}
test scan-5.12 {integer scanning} -setup {
    set a {}; set b {}; set c {}
} -body {
    list [scan "7810179016327718216,6c63546f6c6c6548,661432506755433062510" \
	    %ld,%lx,%lo a b c] $a $b $c
} -result {3 7810179016327718216 7810179016327718216 7810179016327718216}
test scan-5.13 {integer scanning and overflow} {
    # This test used to fail on some 64-bit systems. [Bug 1011860]

Changes to tests/trace.test.

1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
    set {*}$args
}

test trace-21.12 {bug 2438181} -setup {
    trace add execution set2 leave {puts one two three #;}
} -body {
    set2 a hello
} -returnCodes 1 -result {wrong # args: should be "puts ?-nonewline? ?channelId? string"}

proc factorial {n} {
    if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }
    return 1
}

test trace-22.1 {recursive(1) trace execution: enter} {







|







1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
    set {*}$args
}

test trace-21.12 {bug 2438181} -setup {
    trace add execution set2 leave {puts one two three #;}
} -body {
    set2 a hello
} -returnCodes 1 -result {wrong # args: should be "puts ?-nonewline? ?channel? string"}

proc factorial {n} {
    if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }
    return 1
}

test trace-22.1 {recursive(1) trace execution: enter} {

Changes to unix/tclUnixPipe.c.

1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
{
    Tcl_Channel chan;
    PipeState *pipePtr;
    size_t i;
    Tcl_Obj *resultPtr;

    if (objc > 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
	return TCL_ERROR;
    }

    if (objc == 1) {
	Tcl_SetObjResult(interp, Tcl_NewWideIntObj(getpid()));
    } else {
	/*







|







1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
{
    Tcl_Channel chan;
    PipeState *pipePtr;
    size_t i;
    Tcl_Obj *resultPtr;

    if (objc > 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "?channel?");
	return TCL_ERROR;
    }

    if (objc == 1) {
	Tcl_SetObjResult(interp, Tcl_NewWideIntObj(getpid()));
    } else {
	/*

Changes to win/tclWinDde.c.

1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
    enum DdeSrvOptions {
	DDE_SERVERNAME_EXACT, DDE_SERVERNAME_HANDLER, DDE_SERVERNAME_LAST,
    };
    static const char *const ddeExecOptions[] = {
	"-async", "-binary", NULL
    };
    enum DdeExecOptions {
        DDE_EXEC_ASYNC, DDE_EXEC_BINARY
    };
    static const char *const ddeEvalOptions[] = {
	"-async", NULL
    };
    static const char *const ddeReqOptions[] = {
	"-binary", NULL
    };







|







1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
    enum DdeSrvOptions {
	DDE_SERVERNAME_EXACT, DDE_SERVERNAME_HANDLER, DDE_SERVERNAME_LAST,
    };
    static const char *const ddeExecOptions[] = {
	"-async", "-binary", NULL
    };
    enum DdeExecOptions {
	DDE_EXEC_ASYNC, DDE_EXEC_BINARY
    };
    static const char *const ddeEvalOptions[] = {
	"-async", NULL
    };
    static const char *const ddeReqOptions[] = {
	"-binary", NULL
    };

Changes to win/tclWinFCmd.c.

1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
	     *	fprintf(stderr, "%d\n", ((WCHAR *) nativeName)[0]);
	     */

	    Tcl_DStringInit(&dsTemp);
	    Tcl_WCharToUtfDString(nativeName, TCL_INDEX_NONE, &dsTemp);
	    Tcl_DStringFree(&ds);

            tempPath = Tcl_DStringToObj(&dsTemp);
            Tcl_ListObjReplace(NULL, splitPath, i, 1, 1, &tempPath);
	    FindClose(handle);
	}
    }

    *attributePtrPtr = Tcl_FSJoinPath(splitPath, TCL_INDEX_NONE);

    if (splitPath != NULL) {







|
|







1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
	     *	fprintf(stderr, "%d\n", ((WCHAR *) nativeName)[0]);
	     */

	    Tcl_DStringInit(&dsTemp);
	    Tcl_WCharToUtfDString(nativeName, TCL_INDEX_NONE, &dsTemp);
	    Tcl_DStringFree(&ds);

	    tempPath = Tcl_DStringToObj(&dsTemp);
	    Tcl_ListObjReplace(NULL, splitPath, i, 1, 1, &tempPath);
	    FindClose(handle);
	}
    }

    *attributePtrPtr = Tcl_FSJoinPath(splitPath, TCL_INDEX_NONE);

    if (splitPath != NULL) {

Changes to win/tclWinFile.c.

1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
    Tcl_DStringInit(bufferPtr);

    wDomain = NULL;
    domain = Tcl_UtfFindFirst(name, '@');
    if (domain == NULL) {
	const char *ptr;

        /*
         * Treat the current user as a special case because the general case
         * below does not properly retrieve the path. The NetUserGetInfo
         * call returns an empty path and the code defaults to the user's
         * name in the profiles directory. On modern Windows systems, this
         * is generally wrong as when the account is a Microsoft account,
         * for example [email protected], the directory name is
         * abcde and not abcdefghi.
         *
         * Note we could have just used env(USERPROFILE) here but
         * the intent is to retrieve (as on Unix) the system's view
         * of the home irrespective of environment settings of HOME
         * and USERPROFILE.
         *
         * Fixing this for the general user needs more investigating but
         * at least for the current user we can use a direct call.
         */
	ptr = TclpGetUserName(&ds);
	if (ptr != NULL && strcasecmp(name, ptr) == 0) {
	    HANDLE hProcess;
	    WCHAR buf[MAX_PATH];
	    DWORD nChars = sizeof(buf) / sizeof(buf[0]);
	    /* Sadly GetCurrentProcessToken not in Win 7 so slightly longer */
	    hProcess = GetCurrentProcess(); /* Need not be closed */







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







1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
    Tcl_DStringInit(bufferPtr);

    wDomain = NULL;
    domain = Tcl_UtfFindFirst(name, '@');
    if (domain == NULL) {
	const char *ptr;

	/*
	 * Treat the current user as a special case because the general case
	 * below does not properly retrieve the path. The NetUserGetInfo
	 * call returns an empty path and the code defaults to the user's
	 * name in the profiles directory. On modern Windows systems, this
	 * is generally wrong as when the account is a Microsoft account,
	 * for example [email protected], the directory name is
	 * abcde and not abcdefghi.
	 *
	 * Note we could have just used env(USERPROFILE) here but
	 * the intent is to retrieve (as on Unix) the system's view
	 * of the home irrespective of environment settings of HOME
	 * and USERPROFILE.
	 *
	 * Fixing this for the general user needs more investigating but
	 * at least for the current user we can use a direct call.
	 */
	ptr = TclpGetUserName(&ds);
	if (ptr != NULL && strcasecmp(name, ptr) == 0) {
	    HANDLE hProcess;
	    WCHAR buf[MAX_PATH];
	    DWORD nChars = sizeof(buf) / sizeof(buf[0]);
	    /* Sadly GetCurrentProcessToken not in Win 7 so slightly longer */
	    hProcess = GetCurrentProcess(); /* Need not be closed */
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
	    NULL, OPEN_EXISTING,
	    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);

    if (fileHandle != INVALID_HANDLE_VALUE) {
	BY_HANDLE_FILE_INFORMATION data;

	if (GetFileInformationByHandle(fileHandle,&data) != TRUE) {
            fileType = GetFileType(fileHandle);
            CloseHandle(fileHandle);
            if (fileType != FILE_TYPE_CHAR && fileType != FILE_TYPE_DISK) {
                Tcl_SetErrno(ENOENT);
                return -1;
            }

            /*
	     * Mock up the expected structure
	     */

            memset(&data, 0, sizeof(data));
            statPtr->st_atime = 0;
            statPtr->st_mtime = 0;
            statPtr->st_ctime = 0;
        } else {
            CloseHandle(fileHandle);
            statPtr->st_atime = ToCTime(data.ftLastAccessTime);
            statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
            statPtr->st_ctime = ToCTime(data.ftCreationTime);
        }
	attr = data.dwFileAttributes;
	statPtr->st_size = ((long long) data.nFileSizeLow) |
		(((long long) data.nFileSizeHigh) << 32);

	/*
	 * On Unix, for directories, nlink apparently depends on the number of
	 * files in the directory.  We could calculate that, but it would be a







|
|
|
|
|
|

|



|
|
|
|
|
|
|
|
|
|







2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
	    NULL, OPEN_EXISTING,
	    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);

    if (fileHandle != INVALID_HANDLE_VALUE) {
	BY_HANDLE_FILE_INFORMATION data;

	if (GetFileInformationByHandle(fileHandle,&data) != TRUE) {
	    fileType = GetFileType(fileHandle);
	    CloseHandle(fileHandle);
	    if (fileType != FILE_TYPE_CHAR && fileType != FILE_TYPE_DISK) {
		Tcl_SetErrno(ENOENT);
		return -1;
	    }

	    /*
	     * Mock up the expected structure
	     */

	    memset(&data, 0, sizeof(data));
	    statPtr->st_atime = 0;
	    statPtr->st_mtime = 0;
	    statPtr->st_ctime = 0;
	} else {
	    CloseHandle(fileHandle);
	    statPtr->st_atime = ToCTime(data.ftLastAccessTime);
	    statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
	    statPtr->st_ctime = ToCTime(data.ftCreationTime);
	}
	attr = data.dwFileAttributes;
	statPtr->st_size = ((long long) data.nFileSizeLow) |
		(((long long) data.nFileSizeHigh) << 32);

	/*
	 * On Unix, for directories, nlink apparently depends on the number of
	 * files in the directory.  We could calculate that, but it would be a
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
	statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
	statPtr->st_ctime = ToCTime(data.ftCreationTime);
    }

    dev = NativeDev(nativePath);
    mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath));
    if (fileType == FILE_TYPE_CHAR) {
        mode &= ~S_IFMT;
        mode |= S_IFCHR;
    } else if (fileType == FILE_TYPE_DISK) {
        mode &= ~S_IFMT;
        mode |= S_IFBLK;
    }

    statPtr->st_dev	= (dev_t) dev;
    statPtr->st_ino	= inode;
    statPtr->st_mode	= mode;
    statPtr->st_nlink	= nlink;
    statPtr->st_uid	= 0;







|
|

|
|







2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
	statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
	statPtr->st_ctime = ToCTime(data.ftCreationTime);
    }

    dev = NativeDev(nativePath);
    mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath));
    if (fileType == FILE_TYPE_CHAR) {
	mode &= ~S_IFMT;
	mode |= S_IFCHR;
    } else if (fileType == FILE_TYPE_DISK) {
	mode &= ~S_IFMT;
	mode |= S_IFBLK;
    }

    statPtr->st_dev	= (dev_t) dev;
    statPtr->st_ino	= inode;
    statPtr->st_mode	= mode;
    statPtr->st_nlink	= nlink;
    statPtr->st_uid	= 0;
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
    int owned = 0;

    native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);

    if (GetNamedSecurityInfoW((LPWSTR) native, SE_FILE_OBJECT,
	    OWNER_SECURITY_INFORMATION, &ownerSid, NULL, NULL, NULL,
	    &secd) != ERROR_SUCCESS) {
        /*
	 * Either not a file, or we do not have access to it in which case we
	 * are in all likelihood not the owner.
	 */

        return 0;
    }

    /*
     * Getting the current process SID is a multi-step process.  We make the
     * assumption that if a call fails, this process is so underprivileged it
     * could not possibly own anything. Normally a process can *always* look
     * up its own token.
     */

    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
        /*
	 * Find out how big the buffer needs to be.
	 */

        bufsz = 0;
        GetTokenInformation(token, TokenUser, NULL, 0, &bufsz);
        if (bufsz) {
            buf = (LPBYTE)Tcl_Alloc(bufsz);
            if (GetTokenInformation(token, TokenUser, buf, bufsz, &bufsz)) {
                owned = EqualSid(ownerSid, ((PTOKEN_USER) buf)->User.Sid);
            }
        }
        CloseHandle(token);
    }

    /*
     * Free allocations and be done.
     */

    if (secd) {
        LocalFree(secd);            /* Also frees ownerSid */
    }
    if (buf) {
        Tcl_Free(buf);
    }

    return (owned != 0);        /* Convert non-0 to 1 */
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







|




|










|



|
|
|
|
|
|
|
|
|







|


|












3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
    int owned = 0;

    native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);

    if (GetNamedSecurityInfoW((LPWSTR) native, SE_FILE_OBJECT,
	    OWNER_SECURITY_INFORMATION, &ownerSid, NULL, NULL, NULL,
	    &secd) != ERROR_SUCCESS) {
	/*
	 * Either not a file, or we do not have access to it in which case we
	 * are in all likelihood not the owner.
	 */

	return 0;
    }

    /*
     * Getting the current process SID is a multi-step process.  We make the
     * assumption that if a call fails, this process is so underprivileged it
     * could not possibly own anything. Normally a process can *always* look
     * up its own token.
     */

    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
	/*
	 * Find out how big the buffer needs to be.
	 */

	bufsz = 0;
	GetTokenInformation(token, TokenUser, NULL, 0, &bufsz);
	if (bufsz) {
	    buf = (LPBYTE)Tcl_Alloc(bufsz);
	    if (GetTokenInformation(token, TokenUser, buf, bufsz, &bufsz)) {
		owned = EqualSid(ownerSid, ((PTOKEN_USER) buf)->User.Sid);
	    }
	}
	CloseHandle(token);
    }

    /*
     * Free allocations and be done.
     */

    if (secd) {
	LocalFree(secd);            /* Also frees ownerSid */
    }
    if (buf) {
	Tcl_Free(buf);
    }

    return (owned != 0);        /* Convert non-0 to 1 */
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to win/tclWinInit.c.

512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
	if (ptr != NULL) {
	    Tcl_DStringAppend(&ds, ptr, TCL_INDEX_NONE);
	}
	if (Tcl_DStringLength(&ds) > 0) {
	    Tcl_SetVar2(interp, "env", "HOME", Tcl_DStringValue(&ds),
		    TCL_GLOBAL_ONLY);
	} else {
            /* None of HOME, HOMEDRIVE, HOMEPATH exists. Try USERPROFILE */
            ptr = Tcl_GetVar2(interp, "env", "USERPROFILE", TCL_GLOBAL_ONLY);
            if (ptr != NULL && ptr[0]) {
                Tcl_SetVar2(interp, "env", "HOME", ptr, TCL_GLOBAL_ONLY);
            } else {
                /* Last resort */
                Tcl_SetVar2(interp, "env", "HOME", "c:\\", TCL_GLOBAL_ONLY);
            }
	}
    }

    /*
     * Initialize the user name from the environment first, since this is much
     * faster than asking the system.
     * Note: cchUserNameLen is number of characters including nul terminator.







|
|
|
|
|
|
|
|







512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
	if (ptr != NULL) {
	    Tcl_DStringAppend(&ds, ptr, TCL_INDEX_NONE);
	}
	if (Tcl_DStringLength(&ds) > 0) {
	    Tcl_SetVar2(interp, "env", "HOME", Tcl_DStringValue(&ds),
		    TCL_GLOBAL_ONLY);
	} else {
	    /* None of HOME, HOMEDRIVE, HOMEPATH exists. Try USERPROFILE */
	    ptr = Tcl_GetVar2(interp, "env", "USERPROFILE", TCL_GLOBAL_ONLY);
	    if (ptr != NULL && ptr[0]) {
		Tcl_SetVar2(interp, "env", "HOME", ptr, TCL_GLOBAL_ONLY);
	    } else {
		/* Last resort */
		Tcl_SetVar2(interp, "env", "HOME", "c:\\", TCL_GLOBAL_ONLY);
	    }
	}
    }

    /*
     * Initialize the user name from the environment first, since this is much
     * faster than asking the system.
     * Note: cchUserNameLen is number of characters including nul terminator.

Changes to win/tclWinLoad.c.

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	 * Let the OS loader examine the binary search path for whatever
	 * string the user gave us which hopefully refers to a file on the
	 * binary path.
	 */

	Tcl_DString ds;

        /*
         * Remember the first error on load attempt to be used if the
         * second load attempt below also fails.
        */
        firstError = (nativeName == NULL) ?
		ERROR_MOD_NOT_FOUND : GetLastError();

	Tcl_DStringInit(&ds);
	nativeName = Tcl_UtfToWCharDString(TclGetString(pathPtr), TCL_INDEX_NONE, &ds);
	hInstance = LoadLibraryExW(nativeName, NULL,
		LOAD_WITH_ALTERED_SEARCH_PATH);
	Tcl_DStringFree(&ds);
    }

    if (hInstance == NULL) {
	DWORD lastError;
        Tcl_Obj *errMsg;

        /*
         * We choose to only use the error from the second call if the first
         * call failed due to the file not being found. Else stick to the
         * first error for reporting purposes.
         */
        if (firstError == ERROR_MOD_NOT_FOUND ||
		firstError == ERROR_DLL_NOT_FOUND) {
            lastError = GetLastError();
        } else {
            lastError = firstError;
        }

	errMsg = Tcl_ObjPrintf("couldn't load library \"%s\": ",
		TclGetString(pathPtr));

	/*
	 * Check for possible DLL errors. This doesn't work quite right,
	 * because Windows seems to only return ERROR_MOD_NOT_FOUND for just







|
|
|
|
|











|

|
|
|
|
|
|

|
|
|
|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	 * Let the OS loader examine the binary search path for whatever
	 * string the user gave us which hopefully refers to a file on the
	 * binary path.
	 */

	Tcl_DString ds;

	/*
	 * Remember the first error on load attempt to be used if the
	 * second load attempt below also fails.
	*/
	firstError = (nativeName == NULL) ?
		ERROR_MOD_NOT_FOUND : GetLastError();

	Tcl_DStringInit(&ds);
	nativeName = Tcl_UtfToWCharDString(TclGetString(pathPtr), TCL_INDEX_NONE, &ds);
	hInstance = LoadLibraryExW(nativeName, NULL,
		LOAD_WITH_ALTERED_SEARCH_PATH);
	Tcl_DStringFree(&ds);
    }

    if (hInstance == NULL) {
	DWORD lastError;
	Tcl_Obj *errMsg;

	/*
	 * We choose to only use the error from the second call if the first
	 * call failed due to the file not being found. Else stick to the
	 * first error for reporting purposes.
	 */
	if (firstError == ERROR_MOD_NOT_FOUND ||
		firstError == ERROR_DLL_NOT_FOUND) {
	    lastError = GetLastError();
	} else {
	    lastError = firstError;
	}

	errMsg = Tcl_ObjPrintf("couldn't load library \"%s\": ",
		TclGetString(pathPtr));

	/*
	 * Check for possible DLL errors. This doesn't work quite right,
	 * because Windows seems to only return ERROR_MOD_NOT_FOUND for just
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
			" is damaged", TCL_INDEX_NONE);
		break;
	    case ERROR_DLL_INIT_FAILED:
		Tcl_SetErrorCode(interp, "WIN_LOAD", "DLL_INIT_FAILED", (char *)NULL);
		Tcl_AppendToObj(errMsg, "the library initialization"
			" routine failed", TCL_INDEX_NONE);
		break;
            case ERROR_BAD_EXE_FORMAT:
		Tcl_SetErrorCode(interp, "WIN_LOAD", "BAD_EXE_FORMAT", (char *)NULL);
		Tcl_AppendToObj(errMsg, "Bad exe format. Possibly a 32/64-bit mismatch.", TCL_INDEX_NONE);
                break;
            default:
		Tcl_WinConvertError(lastError);
		Tcl_AppendToObj(errMsg, Tcl_PosixError(interp), TCL_INDEX_NONE);
	    }
	    Tcl_SetObjResult(interp, errMsg);
	}
	return TCL_ERROR;
    }







|


|
|







153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
			" is damaged", TCL_INDEX_NONE);
		break;
	    case ERROR_DLL_INIT_FAILED:
		Tcl_SetErrorCode(interp, "WIN_LOAD", "DLL_INIT_FAILED", (char *)NULL);
		Tcl_AppendToObj(errMsg, "the library initialization"
			" routine failed", TCL_INDEX_NONE);
		break;
	    case ERROR_BAD_EXE_FORMAT:
		Tcl_SetErrorCode(interp, "WIN_LOAD", "BAD_EXE_FORMAT", (char *)NULL);
		Tcl_AppendToObj(errMsg, "Bad exe format. Possibly a 32/64-bit mismatch.", TCL_INDEX_NONE);
		break;
	    default:
		Tcl_WinConvertError(lastError);
		Tcl_AppendToObj(errMsg, Tcl_PosixError(interp), TCL_INDEX_NONE);
	    }
	    Tcl_SetObjResult(interp, errMsg);
	}
	return TCL_ERROR;
    }

Changes to win/tclWinPipe.c.

2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
    Tcl_Channel chan;
    const Tcl_ChannelType *chanTypePtr;
    PipeInfo *pipePtr;
    size_t i;
    Tcl_Obj *resultPtr;

    if (objc > 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
	return TCL_ERROR;
    }
    if (objc == 1) {
	Tcl_SetObjResult(interp, Tcl_NewWideIntObj(getpid()));
    } else {
	chan = Tcl_GetChannel(interp, TclGetString(objv[1]),
		NULL);







|







2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
    Tcl_Channel chan;
    const Tcl_ChannelType *chanTypePtr;
    PipeInfo *pipePtr;
    size_t i;
    Tcl_Obj *resultPtr;

    if (objc > 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "?channel?");
	return TCL_ERROR;
    }
    if (objc == 1) {
	Tcl_SetObjResult(interp, Tcl_NewWideIntObj(getpid()));
    } else {
	chan = Tcl_GetChannel(interp, TclGetString(objv[1]),
		NULL);