Compare commits
226
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05262be331 | ||
|
|
70cf69246f | ||
|
|
7543a1313f | ||
|
|
e0e09638fe | ||
|
|
6d3b66ad23 | ||
|
|
6bd8763c2d | ||
|
|
23a421a9c1 | ||
|
|
ba737587a8 | ||
|
|
6ded4b92be | ||
|
|
6cf4a0dea3 | ||
|
|
fdcb9621bb | ||
|
|
3aef0c58f9 | ||
|
|
b05b4cf948 | ||
|
|
18a99f2522 | ||
|
|
953a44bc6e | ||
|
|
5094fb7825 | ||
|
|
d53dfb14c7 | ||
|
|
6d74232282 | ||
|
|
df8a3a6ea4 | ||
|
|
967e55306e | ||
|
|
131176ce2f | ||
|
|
77e951f2b8 | ||
|
|
8bf2e2ace2 | ||
|
|
b7f151f126 | ||
|
|
8c5fc11b5a | ||
|
|
1889ded114 | ||
|
|
21388fa31e | ||
|
|
0951d3f692 | ||
|
|
93bf87ed85 | ||
|
|
494b4c8127 | ||
|
|
bd3a6be21b | ||
|
|
962d8aed89 | ||
|
|
5b0be62536 | ||
|
|
a1fb554585 | ||
|
|
552d2bb53f | ||
|
|
1b7f525ec7 | ||
|
|
38555b60a2 | ||
|
|
c3da6c8fed | ||
|
|
468e5148b3 | ||
|
|
7ed7017d94 | ||
|
|
10f4d4565d | ||
|
|
fa28b1f243 | ||
|
|
3203978c65 | ||
|
|
9aea48988c | ||
|
|
0e0d74624b | ||
|
|
fffb0bdce5 | ||
|
|
82acd6a35a | ||
|
|
5cf1eed910 | ||
|
|
8c5476848a | ||
|
|
4df874dd7f | ||
|
|
906268caa7 | ||
|
|
1ae5fd8198 | ||
|
|
01d6e02666 | ||
|
|
e10915b565 | ||
|
|
03618f8c95 | ||
|
|
071917e1b2 | ||
|
|
1f6cec5ff3 | ||
|
|
fe7ee54772 | ||
|
|
f5ba8a8478 | ||
|
|
f4450abcf9 | ||
|
|
5e095a3a4d | ||
|
|
3eb68691b8 | ||
|
|
f0e415c1e1 | ||
|
|
cfa443421b | ||
|
|
296e4767ea | ||
|
|
fa795b478a | ||
|
|
40e214cd76 | ||
|
|
7ec4501d37 | ||
|
|
9e0cc9d630 | ||
|
|
9d2cc36a0e | ||
|
|
e4e1062338 | ||
|
|
0968aa6de7 | ||
|
|
f736bb9d86 | ||
|
|
6e7d72c158 | ||
|
|
1f7d2aae34 | ||
|
|
76edd58c3e | ||
|
|
923ff1e3ca | ||
|
|
33d81b98be | ||
|
|
234394e2df | ||
|
|
7b3ef36925 | ||
|
|
c862e57095 | ||
|
|
0229ba1283 | ||
|
|
4e84e02684 | ||
|
|
80b392ba8e | ||
|
|
e13edcba86 | ||
|
|
e95b015990 | ||
|
|
aebb7627f5 | ||
|
|
6285c13367 | ||
|
|
8f18e27691 | ||
|
|
7f3d1257ff | ||
|
|
e7b37f1737 | ||
|
|
18385b8363 | ||
|
|
d3aa6839f4 | ||
|
|
cb3d36ad5a | ||
|
|
b464703493 | ||
|
|
4d67456953 | ||
|
|
1d9ebbc740 | ||
|
|
5a3e0c869e | ||
|
|
64e7f77040 | ||
|
|
cc5dd09db3 | ||
|
|
30a9b333ba | ||
|
|
261c174d97 | ||
|
|
a6b4ef3d29 | ||
|
|
62d9150ef5 | ||
|
|
4227ef37bb | ||
|
|
7c9fe49b51 | ||
|
|
bb80189110 | ||
|
|
1923d22832 | ||
|
|
70e40dd53d | ||
|
|
7661972907 | ||
|
|
bb2f06fc73 | ||
|
|
fadb24f26a | ||
|
|
5d8ae9bf17 | ||
|
|
8e139e5cd7 | ||
|
|
da55e192ba | ||
|
|
57d266423a | ||
|
|
d29598480f | ||
|
|
7d6cf09e02 | ||
|
|
8b417f0e1e | ||
|
|
e743d3e487 | ||
|
|
a947270ff7 | ||
|
|
a1fe72fa4a | ||
|
|
85bf0db1e8 | ||
|
|
c6bb33407a | ||
|
|
e2d89615d5 | ||
|
|
ed360ca42f | ||
|
|
6b172a2131 | ||
|
|
e7b8b9d2dd | ||
|
|
152d7203ac | ||
|
|
baf9b5e9bb | ||
|
|
cbda5cb9b2 | ||
|
|
6ab1efe806 | ||
|
|
08a6b105e5 | ||
|
|
8fdf20ec2b | ||
|
|
4e6558b44a | ||
|
|
5ffda39949 | ||
|
|
79cbdf745a | ||
|
|
deec081e74 | ||
|
|
2fb6b99620 | ||
|
|
7b0b2ebd37 | ||
|
|
2a5b403768 | ||
|
|
aa2b48262b | ||
|
|
a826e66f11 | ||
|
|
8390c51fca | ||
|
|
d5e9da898f | ||
|
|
1c3c25097b | ||
|
|
190f9219d5 | ||
|
|
956059093c | ||
|
|
ce349b05df | ||
|
|
bf7b1adb89 | ||
|
|
9ae7f4dc4f | ||
|
|
1d76ffb03b | ||
|
|
7c6f71019a | ||
|
|
8f37d5c24e | ||
|
|
c3e063b0aa | ||
|
|
12345dfed8 | ||
|
|
78db448fff | ||
|
|
58f1209a70 | ||
|
|
e106525498 | ||
|
|
f0284298ad | ||
|
|
03a9d6928d | ||
|
|
5219c94af5 | ||
|
|
a970bffd00 | ||
|
|
f95599f4d4 | ||
|
|
c606ae1574 | ||
|
|
42956f6f09 | ||
|
|
417f868693 | ||
|
|
3315012c95 | ||
|
|
8660fd1af2 | ||
|
|
280034d2ab | ||
|
|
23d9ca0ec4 | ||
|
|
0892c6f37c | ||
|
|
c731ca1ffd | ||
|
|
45796af99d | ||
|
|
6bcdbfbf84 | ||
|
|
6d674a96a1 | ||
|
|
a3f58db271 | ||
|
|
2c3252bc5c | ||
|
|
d790e81db2 | ||
|
|
0563a78902 | ||
|
|
5053891183 | ||
|
|
f06c5e7af1 | ||
|
|
7fb1760f42 | ||
|
|
4c2d834fca | ||
|
|
fb260e8382 | ||
|
|
5040a69c28 | ||
|
|
38df355850 | ||
|
|
2974b57279 | ||
|
|
0c306c8f81 | ||
|
|
05f4bc701f | ||
|
|
bfaa709c2e | ||
|
|
3954b7c2a3 | ||
|
|
bab9170bdc | ||
|
|
fd83fb931e | ||
|
|
b185a55c3b | ||
|
|
f5f5ff4257 | ||
|
|
c529405c65 | ||
|
|
de0a637d7c | ||
|
|
536651d954 | ||
|
|
b9c893dbc9 | ||
|
|
6b6d121149 | ||
|
|
3eaad4bbc9 | ||
|
|
44dd5d86bc | ||
|
|
537c8e77ba | ||
|
|
5866ef6d2a | ||
|
|
0184ebda4f | ||
|
|
078a694834 | ||
|
|
e5272c9be6 | ||
|
|
596e33bb9e | ||
|
|
081c085c0f | ||
|
|
64e3a23bfd | ||
|
|
58446472bb | ||
|
|
d3dae9eba4 | ||
|
|
8c0f76a7de | ||
|
|
4d235ca93a | ||
|
|
5b86b255d4 | ||
|
|
468b1a4346 | ||
|
|
7f87f0f8ea | ||
|
|
5d13f6b527 | ||
|
|
0318ff75d9 | ||
|
|
06de3a9ba1 | ||
|
|
d838764849 | ||
|
|
8ea5f2cfce | ||
|
|
23e46e5885 | ||
|
|
d271c9f407 | ||
|
|
97041036d3 |
+61
-24
@@ -8,7 +8,7 @@
|
||||
.so man.macros
|
||||
.BS
|
||||
.SH NAME
|
||||
Tcl_GetEncoding, Tcl_FreeEncoding, Tcl_GetEncodingFromObj, Tcl_ExternalToUtfDString, Tcl_ExternalToUtf, Tcl_UtfToExternalDString, Tcl_UtfToExternal, Tcl_GetEncodingName, Tcl_SetSystemEncoding, Tcl_GetEncodingNameFromEnvironment, Tcl_GetEncodingNames, Tcl_CreateEncoding, Tcl_GetEncodingSearchPath, Tcl_SetEncodingSearchPath, Tcl_GetDefaultEncodingDir, Tcl_SetDefaultEncodingDir \- procedures for creating and using encodings
|
||||
Tcl_GetEncoding, Tcl_FreeEncoding, Tcl_GetEncodingFromObj, Tcl_ExternalToUtfDString, Tcl_UtfToExternalDStringEx, Tcl_ExternalToUtf, Tcl_UtfToExternalDString, Tcl_UtfToExternalDStringEx, Tcl_UtfToExternal, Tcl_GetEncodingName, Tcl_SetSystemEncoding, Tcl_GetEncodingNameFromEnvironment, Tcl_GetEncodingNames, Tcl_CreateEncoding, Tcl_GetEncodingSearchPath, Tcl_SetEncodingSearchPath, Tcl_GetDefaultEncodingDir, Tcl_SetDefaultEncodingDir \- procedures for creating and using encodings
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fB#include <tcl.h>\fR
|
||||
@@ -26,13 +26,13 @@ char *
|
||||
\fBTcl_ExternalToUtfDString\fR(\fIencoding, src, srcLen, dstPtr\fR)
|
||||
.sp
|
||||
int
|
||||
\fBTcl_ExternalToUtfDStringEx\fR(\fIencoding, src, srcLen, flags, dstPtr\fR)
|
||||
\fBTcl_ExternalToUtfDStringEx\fR(\fIinterp, encoding, src, srcLen, flags, dstPtr, errorIdxPtr\fR)
|
||||
.sp
|
||||
char *
|
||||
\fBTcl_UtfToExternalDString\fR(\fIencoding, src, srcLen, dstPtr\fR)
|
||||
.sp
|
||||
int
|
||||
\fBTcl_UtfToExternalDStringEx\fR(\fIencoding, src, srcLen, flags, dstPtr\fR)
|
||||
\fBTcl_UtfToExternalDStringEx\fR(\fIinterp, encoding, src, srcLen, flags, dstPtr, errorIdxPtr\fR)
|
||||
.sp
|
||||
int
|
||||
\fBTcl_ExternalToUtf\fR(\fIinterp, encoding, src, srcLen, flags, statePtr,
|
||||
@@ -105,7 +105,7 @@ encoding-specific length of the string is used.
|
||||
Pointer to an uninitialized or free \fBTcl_DString\fR in which the converted
|
||||
result will be stored.
|
||||
.AP int flags in
|
||||
Various flag bits OR-ed together.
|
||||
This is a bit mask passed in to control the operation of the encoding functions.
|
||||
\fBTCL_ENCODING_START\fR signifies that the
|
||||
source buffer is the first block in a (potentially multi-block) input
|
||||
stream, telling the conversion routine to reset to an initial state and
|
||||
@@ -113,16 +113,15 @@ perform any initialization that needs to occur before the first byte is
|
||||
converted. \fBTCL_ENCODING_END\fR signifies that the source buffer is the last
|
||||
block in a (potentially multi-block) input stream, telling the conversion
|
||||
routine to perform any finalization that needs to occur after the last
|
||||
byte is converted and then to reset to an initial state.
|
||||
\fBTCL_ENCODING_STOPONERROR\fR signifies that the conversion routine should
|
||||
return immediately upon reading a source character that does not exist in
|
||||
the target encoding; otherwise a default fallback character will
|
||||
automatically be substituted. The flag \fBTCL_ENCODING_STRICT\fR makes the
|
||||
encoder/decoder more strict in what it considers to be an invalid byte
|
||||
sequence. The flag \fBTCL_ENCODING_NOCOMPLAIN\fR has
|
||||
no effect, it is reserved for Tcl 9.0. The flag \fBTCL_ENCODING_MODIFIED\fR makes
|
||||
\fBTcl_UtfToExternalDStringEx\fR and \fBTcl_UtfToExternal\fR produce the
|
||||
byte sequence \exC0\ex80 in stead of \ex00, for the utf-8/cesu-8 encoders.
|
||||
byte is converted and then to reset to an initial state. The
|
||||
\fBTCL_PROFILE_*\fR bits defined in the \fBPROFILES\fR section below
|
||||
control the encoding profile to be used for dealing with invalid data or
|
||||
other errors in the encoding transform.
|
||||
\fBTCL_ENCODING_STOPONERROR\fR is present for backward compatibility with
|
||||
Tcl 8.6 and forces the encoding profile to \fBstrict\fR.
|
||||
|
||||
Some flags bits may not be usable with some functions as noted in the
|
||||
function descriptions below.
|
||||
.AP Tcl_EncodingState *statePtr in/out
|
||||
Used when converting a (generally long or indefinite length) byte stream
|
||||
in a piece-by-piece fashion. The conversion routine stores its current
|
||||
@@ -148,6 +147,9 @@ buffer as a result of the conversion. May be NULL.
|
||||
.AP int *dstCharsPtr out
|
||||
Filled with the number of characters that correspond to the number of bytes
|
||||
stored in the output buffer. May be NULL.
|
||||
.AP Tcl_Size *errorIdxPtr out
|
||||
Filled with the index of the byte or character that caused the encoding transform
|
||||
to fail. May be NULL.
|
||||
.AP Tcl_DString *bufPtr out
|
||||
Storage for the prescribed system encoding name.
|
||||
.AP "const Tcl_EncodingType" *typePtr in
|
||||
@@ -221,11 +223,30 @@ call \fBTcl_DStringFree\fR to free any information stored in \fIdstPtr\fR.
|
||||
When converting, if any of the characters in the source buffer cannot be
|
||||
represented in the target encoding, a default fallback character will be
|
||||
used. The return value is a pointer to the value stored in the DString.
|
||||
|
||||
.PP
|
||||
\fBTcl_ExternalToUtfDStringEx\fR is the same as \fBTcl_ExternalToUtfDString\fR,
|
||||
but it has an additional flags parameter. The return value is the index of
|
||||
the first byte in the input string causing a conversion error.
|
||||
Or TCL_INDEX_NONE if all is OK.
|
||||
\fBTcl_ExternalToUtfDStringEx\fR is a more flexible version of older
|
||||
\fBTcl_ExternalToUtfDString\fR function. It takes three additional parameters,
|
||||
\fBinterp\fR, \fBflags\fR and \fBerrorIdxPtr\fR. The \fBflags\fR parameter may
|
||||
be used to specify the profile to be used for the transform. The
|
||||
\fBTCL_ENCODING_START\fR and \fBTCL_ENCODING_END\fR bits in \fBflags\fR are
|
||||
ignored as the function assumes the entire source string to be decoded is passed
|
||||
into the function. On success, the function returns \fBTCL_ERROR\fR with the
|
||||
converted string stored in \fB*dstPtr\fR. For errors other than conversion
|
||||
errors, such as invalid flags, the function returns \fBTCL_OK\fR with an error
|
||||
message in \fBinterp\fR if it is not NULL.
|
||||
|
||||
For conversion errors, \fBTcl_ExternalToUtfDStringEx\fR returns one
|
||||
of the \fBTCL_CONVERT_*\fR errors listed below for \fBTcl_ExternalToUtf\fR.
|
||||
When one of these conversion errors is returned, an error message is
|
||||
stored in \fBinterp\fR only if \fBerrorIdxPtr\fR is NULL. Otherwise, no error message
|
||||
is stored as the function expects the caller is interested whatever is
|
||||
decoded to that point and not treating this as an immediate error condition.
|
||||
The index of the error location is stored in \fB*errorIdxPtr\fR.
|
||||
|
||||
The caller must call \fBTcl_DStringFree\fR to free up the \fB*dstPtr\fR resources
|
||||
irrespective of the return value from the function.
|
||||
|
||||
.PP
|
||||
\fBTcl_ExternalToUtf\fR converts a source buffer \fIsrc\fR from the specified
|
||||
\fIencoding\fR into UTF-8. Up to \fIsrcLen\fR bytes are converted from the
|
||||
@@ -248,12 +269,12 @@ the unconverted bytes that remained in \fIsrc\fR plus some further bytes
|
||||
from the source stream to properly convert the formerly split-up multibyte
|
||||
sequence.
|
||||
.IP \fBTCL_CONVERT_SYNTAX\fR 29
|
||||
The source buffer contained an invalid character sequence. This may occur
|
||||
The source buffer contained an invalid byte or character sequence. This may occur
|
||||
if the input stream has been damaged or if the input encoding method was
|
||||
misidentified.
|
||||
.IP \fBTCL_CONVERT_UNKNOWN\fR 29
|
||||
The source buffer contained a character that could not be represented in
|
||||
the target encoding and \fBTCL_ENCODING_STOPONERROR\fR was specified.
|
||||
the target encoding.
|
||||
.RE
|
||||
.LP
|
||||
\fBTcl_UtfToExternalDString\fR converts a source buffer \fIsrc\fR from UTF-8
|
||||
@@ -265,10 +286,14 @@ characters in the source buffer cannot be represented in the target
|
||||
encoding, a default fallback character will be used. The return value is
|
||||
a pointer to the value stored in the DString.
|
||||
.PP
|
||||
\fBTcl_UtfToExternalDStringEx\fR is the same as \fBTcl_UtfToExternalDString\fR,
|
||||
but it has an additional flags parameter. The return value is the index of
|
||||
the first byte of an utf-8 byte-sequence in the input string causing a
|
||||
conversion error. Or TCL_INDEX_NONE if all is OK.
|
||||
\fBTcl_UtfToExternalDStringEx\fR is an enhanced version of
|
||||
\fBTcl_UtfToExternalDString\fR that transforms UTF-8 encoded source data to a specified
|
||||
\fIencoding\fR. Except for the direction of the transform, the parameters and
|
||||
return values are identical to those of \fBTcl_ExternalToUtfDStringEx\fR. See
|
||||
that function above for details about the same.
|
||||
|
||||
Irrespective of the return code from the function, the caller must free
|
||||
resources associated with \fB*dstPtr\fR when the function returns.
|
||||
.PP
|
||||
\fBTcl_UtfToExternal\fR converts a source buffer \fIsrc\fR from UTF-8 into
|
||||
the specified \fIencoding\fR. Up to \fIsrcLen\fR bytes are converted from
|
||||
@@ -592,6 +617,18 @@ to the object, it will be deleted.
|
||||
.PP
|
||||
\fBTcl_GetEncodingSearchPath\fR returns an object with a reference count of at
|
||||
least 1.
|
||||
.SH "PROFILES"
|
||||
Encoding profiles define the manner in which errors in the encoding transforms
|
||||
are handled by the encoding functions. An application can specify the profile
|
||||
to be used by OR-ing the \fBflags\fR parameter passed to the function
|
||||
with at most one of \fBTCL_ENCODING_PROFILE_TCL8\fR,
|
||||
\fBTCL_ENCODING_PROFILE_STRICT\fR or \fBTCL_ENCODING_PROFILE_REPLACE\fR.
|
||||
These correspond to the \fBtcl8\fR, \fBstrict\fR and \fBreplace\fR profiles
|
||||
respectively. If none are specified, a version-dependent default profile is used.
|
||||
For Tcl 8.7, the default profile is \fBtcl8\fR.
|
||||
|
||||
For details about profiles, see the \fBPROFILES\fR section in
|
||||
the documentation of the \fBencoding\fR command.
|
||||
.SH "SEE ALSO"
|
||||
encoding(n)
|
||||
.SH KEYWORDS
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'\"
|
||||
'\" Copyright (c) 1993 The Regents of the University of California.
|
||||
'\" Copyright (c) 1994-1996 Sun Microsystems, Inc.
|
||||
'\" Copyright (c) 2023 Nathan Coulter
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
@@ -16,176 +17,152 @@ Summary of Tcl language syntax.
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The following rules define the syntax and semantics of the Tcl language:
|
||||
.IP "[1] \fBCommands.\fR"
|
||||
A Tcl script is a string containing one or more commands.
|
||||
Semi-colons and newlines are command separators unless quoted as
|
||||
described below.
|
||||
Close brackets are command terminators during command substitution
|
||||
(see below) unless quoted.
|
||||
.IP "[2] \fBEvaluation.\fR"
|
||||
A command is evaluated in two steps.
|
||||
First, the Tcl interpreter breaks the command into \fIwords\fR
|
||||
and performs substitutions as described below.
|
||||
These substitutions are performed in the same way for all
|
||||
commands.
|
||||
Secondly, the first word is used to locate a routine to
|
||||
carry out the command, and the remaining words of the command are
|
||||
passed to that routine.
|
||||
The routine is free to interpret each of its words
|
||||
in any way it likes, such as an integer, variable name, list,
|
||||
or Tcl script.
|
||||
Different commands interpret their words differently.
|
||||
.IP "[3] \fBWords.\fR"
|
||||
Words of a command are separated by white space (except for
|
||||
newlines, which are command separators).
|
||||
.IP "[4] \fBDouble quotes.\fR"
|
||||
If the first character of a word is double-quote
|
||||
.PQ \N'34'
|
||||
then the word is terminated by the next double-quote character.
|
||||
If semi-colons, close brackets, or white space characters
|
||||
(including newlines) appear between the quotes then they are treated
|
||||
as ordinary characters and included in the word.
|
||||
Command substitution, variable substitution, and backslash substitution
|
||||
are performed on the characters between the quotes as described below.
|
||||
The double-quotes are not retained as part of the word.
|
||||
.IP "[5] \fBArgument expansion.\fR"
|
||||
If a word starts with the string
|
||||
.QW {*}
|
||||
followed by a non-whitespace character, then the leading
|
||||
.QW {*}
|
||||
is removed and the rest of the word is parsed and substituted as any other
|
||||
word. After substitution, the word is parsed as a list (without command or
|
||||
variable substitutions; backslash substitutions are performed as is normal for
|
||||
a list and individual internal words may be surrounded by either braces or
|
||||
double-quote characters), and its words are added to the command being
|
||||
substituted. For instance,
|
||||
.QW "cmd a {*}{b [c]} d {*}{$e f {g h}}"
|
||||
is equivalent to
|
||||
.QW "cmd a b {[c]} d {$e} f {g h}" .
|
||||
.IP "[6] \fBBraces.\fR"
|
||||
If the first character of a word is an open brace
|
||||
.
|
||||
.IP "[1] \fBScript.\fR"
|
||||
A script is composed of zero or more commands delimited by semi-colons or
|
||||
newlines.
|
||||
.IP "[2] \fBCommand.\fR"
|
||||
A command is composed of zero or more words delimited by whitespace. The
|
||||
replacement for a substitution is included verbatim in the word. For example, a
|
||||
space in the replacement is included in the word rather than becoming a
|
||||
delimiter, and \fI\\\\\fR becomes a single backslash in the word. Each word is
|
||||
processed from left to right and each substitution is performed as soon as it
|
||||
is complete.
|
||||
For example, the command
|
||||
.RS
|
||||
.PP
|
||||
.CS
|
||||
set y [set x 0][incr x][incr x]
|
||||
.CE
|
||||
.PP
|
||||
is composed of three words, and sets the value of \fIy\fR to \fI012\fR.
|
||||
.PP
|
||||
If hash
|
||||
.PQ #
|
||||
is the first character of what would otherwise be the first word of a command,
|
||||
all characters up to the next newline are ignored.
|
||||
.RE
|
||||
.
|
||||
.IP "[3] \fBBraced word.\fR"
|
||||
If a word is enclosed in braces
|
||||
.PQ {
|
||||
and rule [5] does not apply, then
|
||||
the word is terminated by the matching close brace
|
||||
.PQ } "" .
|
||||
Braces nest within the word: for each additional open
|
||||
brace there must be an additional close brace (however,
|
||||
if an open brace or close brace within the word is
|
||||
quoted with a backslash then it is not counted in locating the
|
||||
matching close brace).
|
||||
No substitutions are performed on the characters between the
|
||||
braces except for backslash-newline substitutions described
|
||||
below, nor do semi-colons, newlines, close brackets,
|
||||
or white space receive any special interpretation.
|
||||
The word will consist of exactly the characters between the
|
||||
outer braces, not including the braces themselves.
|
||||
.IP "[7] \fBCommand substitution.\fR"
|
||||
If a word contains an open bracket
|
||||
and
|
||||
.PQ } ""
|
||||
, the braces are removed and the enclosed characters become the word. No
|
||||
substitutions are performed. Nested pairs of braces may occur within the word.
|
||||
A brace preceded by an odd number of backslashes is not considered part of a
|
||||
pair, and neither brace nor the backslashes are removed from the word.
|
||||
.
|
||||
.IP "[4] \fBQuoted word.\fR"
|
||||
If a word is enclosed in double quotes
|
||||
.PQ \N'34'
|
||||
, the double quotes are removed and the enclosed characters become the word.
|
||||
Substitutions are performed.
|
||||
.
|
||||
.IP "[5] \fBList.\fR"
|
||||
A list has the form of a single command. Newline is whitespace, and semicolon
|
||||
has no special interpretation. There is no script evaluation so there is no
|
||||
argument expansion, variable substitution, or command substitution: Dollar-sign
|
||||
and open bracket have no special interpretation, and what would be argument
|
||||
expansion in a script is invalid in a list.
|
||||
.
|
||||
.IP "[6] \fBArgument expansion.\fR"
|
||||
If
|
||||
.QW {*}
|
||||
prefixes a word, it is removed. After any remaining enclosing braces or quotes
|
||||
are processed and applicable substitutions performed, the word, which must
|
||||
be a list, is removed from the command, and in its place each word in the
|
||||
list becomes an additional word in the command. For example,
|
||||
.CS
|
||||
cmd a {*}{b [c]} d {*}{$e f {g h}}
|
||||
.CE
|
||||
is equivalent to
|
||||
.CS
|
||||
cmd a b {[c]} d {$e} f {g h} .
|
||||
.CE
|
||||
.
|
||||
.IP "[7] \fBEvaluation.\fR"
|
||||
To evaluate a script, an interpreter evaluates each successive command. The
|
||||
first word identifies a procedure, and the remaining words are passed to that
|
||||
procedure for further evaluation. The procedure interprets each argument in
|
||||
its own way, e.g. as an integer, variable name, list, mathematical expression,
|
||||
script, or in some other arbitrary way. The result of the last command is the
|
||||
result of the script.
|
||||
.
|
||||
.IP "[8] \fBCommand substitution.\fR"
|
||||
Each pair of brackets
|
||||
.PQ [
|
||||
then Tcl performs \fIcommand substitution\fR.
|
||||
To do this it invokes the Tcl interpreter recursively to process
|
||||
the characters following the open bracket as a Tcl script.
|
||||
The script may contain any number of commands and must be terminated
|
||||
by a close bracket
|
||||
.PQ ] "" .
|
||||
The result of the script (i.e. the result of its last command) is
|
||||
substituted into the word in place of the brackets and all of the
|
||||
characters between them.
|
||||
There may be any number of command substitutions in a single word.
|
||||
Command substitution is not performed on words enclosed in braces.
|
||||
.IP "[8] \fBVariable substitution.\fR"
|
||||
If a word contains a dollar-sign
|
||||
and
|
||||
.PQ ] ""
|
||||
encloses a script and is replaced by the result of that script.
|
||||
.IP "[9] \fBVariable substitution.\fR"
|
||||
Each of the following forms begins with dollar sign
|
||||
.PQ $
|
||||
followed by one of the forms
|
||||
described below, then Tcl performs \fIvariable
|
||||
substitution\fR: the dollar-sign and the following characters are
|
||||
replaced in the word by the value of a variable.
|
||||
Variable substitution may take any of the following forms:
|
||||
and is replaced by the value of the identified variable. \fIname\fR names the
|
||||
variable and is composed of ASCII letters (\fBA\fR\(en\fBZ\fR and
|
||||
\fBa\fR\(en\fBz\fR), digits (\fB0\fR\(en\fB9\fR), underscores, or namespace
|
||||
delimiters (two or more colons). \fIindex\fR is the name of an individual
|
||||
variable within an array variable, and may be empty.
|
||||
.RS
|
||||
.TP 15
|
||||
\fB$\fIname\fR
|
||||
.
|
||||
\fIName\fR is the name of a scalar variable; the name is a sequence
|
||||
of one or more characters that are a letter, digit, underscore,
|
||||
or namespace separators (two or more colons).
|
||||
Letters and digits are \fIonly\fR the standard ASCII ones (\fB0\fR\(en\fB9\fR,
|
||||
\fBA\fR\(en\fBZ\fR and \fBa\fR\(en\fBz\fR).
|
||||
\fIname\fR may not be empty.
|
||||
|
||||
.TP 15
|
||||
\fB$\fIname\fB(\fIindex\fB)\fR
|
||||
.
|
||||
\fIName\fR gives the name of an array variable and \fIindex\fR gives
|
||||
the name of an element within that array.
|
||||
\fIName\fR must contain only letters, digits, underscores, and
|
||||
namespace separators, and may be an empty string.
|
||||
Letters and digits are \fIonly\fR the standard ASCII ones (\fB0\fR\(en\fB9\fR,
|
||||
\fBA\fR\(en\fBZ\fR and \fBa\fR\(en\fBz\fR).
|
||||
Command substitutions, variable substitutions, and backslash
|
||||
substitutions are performed on the characters of \fIindex\fR.
|
||||
\fIname\fR may be empty. Substitutions are performed on \fIindex\fR.
|
||||
.TP 15
|
||||
\fB${\fIname\fB}\fR
|
||||
\fIname\fR may be empty.
|
||||
.TP 15
|
||||
\fB${\fIname(index)\fB}\fR
|
||||
.
|
||||
\fIName\fR is the name of a scalar variable or array element. It may contain
|
||||
any characters whatsoever except for close braces. It indicates an array
|
||||
element if \fIname\fR is in the form
|
||||
.QW \fIarrayName\fB(\fIindex\fB)\fR
|
||||
where \fIarrayName\fR does not contain any open parenthesis characters,
|
||||
.QW \fB(\fR ,
|
||||
or close brace characters,
|
||||
.QW \fB}\fR ,
|
||||
and \fIindex\fR can be any sequence of characters except for close brace
|
||||
characters. No further
|
||||
substitutions are performed during the parsing of \fIname\fR.
|
||||
.PP
|
||||
There may be any number of variable substitutions in a single word.
|
||||
Variable substitution is not performed on words enclosed in braces.
|
||||
.PP
|
||||
Note that variables may contain character sequences other than those listed
|
||||
above, but in that case other mechanisms must be used to access them (e.g.,
|
||||
via the \fBset\fR command's single-argument form).
|
||||
\fIname\fR may be empty. No substitutions are performed.
|
||||
.RE
|
||||
.IP "[9] \fBBackslash substitution.\fR"
|
||||
If a backslash
|
||||
Variables that are not accessible through one of the forms above may be
|
||||
accessed through other mechanisms, e.g. the \fBset\fR command.
|
||||
.IP "[10] \fBBackslash substitution.\fR"
|
||||
Each backslash
|
||||
.PQ \e
|
||||
appears within a word then \fIbackslash substitution\fR occurs.
|
||||
In all cases but those described below the backslash is dropped and
|
||||
the following character is treated as an ordinary
|
||||
character and included in the word.
|
||||
This allows characters such as double quotes, close brackets,
|
||||
and dollar signs to be included in words without triggering
|
||||
special processing.
|
||||
The following table lists the backslash sequences that are
|
||||
handled specially, along with the value that replaces each sequence.
|
||||
that is not part of one of the forms listed below is removed, and the next
|
||||
character is included in the word verbatim, which allows the inclusion of
|
||||
characters that would normally be interpreted, namely whitespace, braces,
|
||||
brackets, double quote, dollar sign, and backslash. The following sequences
|
||||
are replaced as described:
|
||||
.RS
|
||||
.RS
|
||||
.RS
|
||||
.TP 7
|
||||
\e\fBa\fR
|
||||
Audible alert (bell) (Unicode U+000007).
|
||||
Audible alert (bell) (U+7).
|
||||
.TP 7
|
||||
\e\fBb\fR
|
||||
Backspace (Unicode U+000008).
|
||||
Backspace (U+8).
|
||||
.TP 7
|
||||
\e\fBf\fR
|
||||
Form feed (Unicode U+00000C).
|
||||
Form feed (U+C).
|
||||
.TP 7
|
||||
\e\fBn\fR
|
||||
Newline (Unicode U+00000A).
|
||||
Newline (U+A).
|
||||
.TP 7
|
||||
\e\fBr\fR
|
||||
Carriage-return (Unicode U+00000D).
|
||||
Carriage-return (U+D).
|
||||
.TP 7
|
||||
\e\fBt\fR
|
||||
Tab (Unicode U+000009).
|
||||
Tab (U+9).
|
||||
.TP 7
|
||||
\e\fBv\fR
|
||||
Vertical tab (Unicode U+00000B).
|
||||
Vertical tab (U+B).
|
||||
.TP 7
|
||||
\e\fB<newline>\fIwhiteSpace\fR
|
||||
.
|
||||
A single space character replaces the backslash, newline, and all spaces
|
||||
and tabs after the newline. This backslash sequence is unique in that it
|
||||
is replaced in a separate pre-pass before the command is actually parsed.
|
||||
This means that it will be replaced even when it occurs between braces,
|
||||
and the resulting space will be treated as a word separator if it is not
|
||||
in braces or quotes.
|
||||
Newline preceded by an odd number of backslashes, along with the consecutive
|
||||
spaces and tabs that immediately follow it, is replaced by a single space.
|
||||
Because this happens before the command is split into words, it occurs even
|
||||
within braced words, and if the resulting space may subsequently be treated as
|
||||
a word delimiter.
|
||||
.TP 7
|
||||
\e\e
|
||||
Backslash
|
||||
@@ -193,83 +170,30 @@ Backslash
|
||||
.TP 7
|
||||
\e\fIooo\fR
|
||||
.
|
||||
The digits \fIooo\fR (one, two, or three of them) give a eight-bit octal
|
||||
value for the Unicode character that will be inserted, in the range
|
||||
\fI000\fR\(en\fI377\fR (i.e., the range U+000000\(enU+0000FF).
|
||||
The parser will stop just before this range overflows, or when
|
||||
the maximum of three digits is reached. The upper bits of the Unicode
|
||||
character will be 0.
|
||||
Up to three octal digits form an eight-bit value for a Unicode character in the
|
||||
range \fI0\fR\(en\fI377\fR, i.e. U+0\(enU+FF. Only the digits that result in a
|
||||
number in this range are consumed.
|
||||
.TP 7
|
||||
\e\fBx\fIhh\fR
|
||||
.
|
||||
The hexadecimal digits \fIhh\fR (one or two of them) give an eight-bit
|
||||
hexadecimal value for the Unicode character that will be inserted. The upper
|
||||
bits of the Unicode character will be 0 (i.e., the character will be in the
|
||||
range U+000000\(enU+0000FF).
|
||||
Up to two hexadecimal digits form an eight-bit value for a Unicode character in
|
||||
the range \fI0\fR\(en\fIFF\fR.
|
||||
.TP 7
|
||||
\e\fBu\fIhhhh\fR
|
||||
.
|
||||
The hexadecimal digits \fIhhhh\fR (one, two, three, or four of them) give a
|
||||
sixteen-bit hexadecimal value for the Unicode character that will be
|
||||
inserted. The upper bits of the Unicode character will be 0 (i.e., the
|
||||
character will be in the range U+000000\(enU+00FFFF).
|
||||
Up to four hexadecimal digits form a 16-bit value for a Unicode character in
|
||||
the range \fI0\fR\(en\fIFFFF\fR.
|
||||
.TP 7
|
||||
\e\fBU\fIhhhhhhhh\fR
|
||||
.
|
||||
The hexadecimal digits \fIhhhhhhhh\fR (one up to eight of them) give a
|
||||
twenty-one-bit hexadecimal value for the Unicode character that will be
|
||||
inserted, in the range U+000000\(enU+10FFFF. The parser will stop just
|
||||
before this range overflows, or when the maximum of eight digits
|
||||
is reached. The upper bits of the Unicode character will be 0.
|
||||
.RS
|
||||
.PP
|
||||
The range U+00D800\(enU+00DFFF is reserved for surrogates, which
|
||||
are illegal on their own. Therefore, such sequences will result in
|
||||
the replacement character U+FFFD. Surrogate pairs should be
|
||||
encoded as single \e\fBU\fIhhhhhhhh\fR character.
|
||||
Up to eight hexadecimal digits form a 21-bit value for a Unicode character in
|
||||
the range \fI0\fR\(en\fI10FFFF\fR. Only the digits that result in a number in
|
||||
this range are consumed.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
Backslash substitution is not performed on words enclosed in braces,
|
||||
except for backslash-newline as described above.
|
||||
.RE
|
||||
.IP "[10] \fBComments.\fR"
|
||||
If a hash character
|
||||
.PQ #
|
||||
appears at a point where Tcl is
|
||||
expecting the first character of the first word of a command,
|
||||
then the hash character and the characters that follow it, up
|
||||
through the next newline, are treated as a comment and ignored.
|
||||
The comment character only has significance when it appears
|
||||
at the beginning of a command.
|
||||
.IP "[11] \fBOrder of substitution.\fR"
|
||||
Each character is processed exactly once by the Tcl interpreter
|
||||
as part of creating the words of a command.
|
||||
For example, if variable substitution occurs then no further
|
||||
substitutions are performed on the value of the variable; the
|
||||
value is inserted into the word verbatim.
|
||||
If command substitution occurs then the nested command is
|
||||
processed entirely by the recursive call to the Tcl interpreter;
|
||||
no substitutions are performed before making the recursive
|
||||
call and no additional substitutions are performed on the result
|
||||
of the nested script.
|
||||
.RS
|
||||
.PP
|
||||
Substitutions take place from left to right, and each substitution is
|
||||
evaluated completely before attempting to evaluate the next. Thus, a
|
||||
sequence like
|
||||
.PP
|
||||
.CS
|
||||
set y [set x 0][incr x][incr x]
|
||||
.CE
|
||||
.PP
|
||||
will always set the variable \fIy\fR to the value, \fI012\fR.
|
||||
.RE
|
||||
.IP "[12] \fBSubstitution and word boundaries.\fR"
|
||||
Substitutions do not affect the word boundaries of a command,
|
||||
except for argument expansion as specified in rule [5].
|
||||
For example, during variable substitution the entire value of
|
||||
the variable becomes part of a single word, even if the variable's
|
||||
value contains spaces.
|
||||
.
|
||||
.SH KEYWORDS
|
||||
backslash, command, comment, script, substitution, variable
|
||||
'\" Local Variables:
|
||||
|
||||
+10
@@ -156,6 +156,16 @@ applied to input only.
|
||||
The default value is the empty string, except that under Windows the default
|
||||
value for reading is Control-z (\ex1A). The acceptable range is \ex01 -
|
||||
\ex7f. A value outside this range results in an error.
|
||||
.VS "TCL8.7 TIP656"
|
||||
.TP
|
||||
\fB\-profile\fR \fIprofile\fR
|
||||
.
|
||||
Specifies the encoding profile to be used on the channel. The encoding
|
||||
transforms in use for the channel's input and output will then be subject to the
|
||||
rules of that profile. Any failures will result in a channel error. See
|
||||
\fBPROFILES\fR in the \fBencoding(n)\fR documentation for details about encoding
|
||||
profiles.
|
||||
.VE "TCL8.7 TIP656"
|
||||
.TP
|
||||
\fB\-translation\fR \fItranslation\fR
|
||||
.TP
|
||||
|
||||
+146
-93
@@ -28,73 +28,41 @@ formats.
|
||||
Performs one of several encoding related operations, depending on
|
||||
\fIoption\fR. The legal \fIoption\fRs are:
|
||||
.TP
|
||||
\fBencoding convertfrom\fR ?\fB-strict\fR? ?\fB-failindex var\fR? ?\fIencoding\fR? \fIdata\fR
|
||||
\fBencoding convertfrom\fR \fB-nocomplain\fR ?\fIencoding\fR? \fIdata\fR
|
||||
.
|
||||
Convert \fIdata\fR to a Unicode string from the specified \fIencoding\fR. The
|
||||
characters in \fIdata\fR are 8 bit binary data. The resulting
|
||||
sequence of bytes is a string created by applying the given \fIencoding\fR
|
||||
to the data. If \fIencoding\fR is not specified, the current
|
||||
system encoding is used.
|
||||
.VS "TCL8.7 TIP346, TIP607, TIP601"
|
||||
.PP
|
||||
.RS
|
||||
The command does not fail on encoding errors. Instead, any not convertable bytes
|
||||
(like incomplete UTF-8 sequences, see example below) are put as byte values into
|
||||
the output stream.
|
||||
.PP
|
||||
If the option \fB-failindex\fR with a variable name is given, the error reporting
|
||||
is changed in the following manner:
|
||||
in case of a conversion error, the position of the input byte causing the error
|
||||
is returned in the given variable. The return value of the command are the
|
||||
converted characters until the first error position.
|
||||
In case of no error, the value \fI-1\fR is written to the variable. This option
|
||||
may not be used together with \fB-nocomplain\fR.
|
||||
.PP
|
||||
The option \fB-nocomplain\fR has no effect and is available for compatibility with
|
||||
TCL 9. In TCL 9, the encoding command fails with an error on any encoding issue.
|
||||
This switch restores the TCL8.7 behaviour.
|
||||
.PP
|
||||
The \fB-strict\fR option follows more strict rules in conversion. For the \fButf-8\fR
|
||||
encoder, it disallows invalid byte sequences and surrogates (which -
|
||||
otherwise - are just passed through). This option may not be used together
|
||||
with \fB-nocomplain\fR.
|
||||
.VE "TCL8.7 TIP346, TIP607, TIP601"
|
||||
.RE
|
||||
\fBencoding convertfrom\fR ?\fIencoding\fR? \fIdata\fR
|
||||
.TP
|
||||
\fBencoding convertto\fR ?\fB-strict\fR? ?\fB-failindex var\fR? ?\fIencoding\fR? \fIdata\fR
|
||||
\fBencoding convertto\fR \fB-nocomplain\fR ?\fIencoding\fR? \fIdata\fR
|
||||
\fBencoding convertfrom\fR ?\fB-profile \fIprofile\fR? ?\fB-failindex var\fR? \fIencoding\fR \fIdata\fR
|
||||
.
|
||||
Convert \fIstring\fR from Unicode to the specified \fIencoding\fR.
|
||||
The result is a sequence of bytes that represents the converted
|
||||
string. Each byte is stored in the lower 8-bits of a Unicode
|
||||
character (indeed, the resulting string is a binary string as far as
|
||||
Tcl is concerned, at least initially). If \fIencoding\fR is not
|
||||
specified, the current system encoding is used.
|
||||
.VS "TCL8.7 TIP346, TIP607, TIP601"
|
||||
.PP
|
||||
.RS
|
||||
The command does not fail on encoding errors. Instead, the replacement character
|
||||
\fB?\fR is output for any not representable character (like the dot \fB\\U2022\fR
|
||||
in \fBiso-8859-1\fR encoding, see example below).
|
||||
.PP
|
||||
If the option \fB-failindex\fR with a variable name is given, the error reporting
|
||||
is changed in the following manner:
|
||||
in case of a conversion error, the position of the input character causing the error
|
||||
is returned in the given variable. The return value of the command are the
|
||||
converted bytes until the first error position. No error condition is raised.
|
||||
In case of no error, the value \fI-1\fR is written to the variable. This option
|
||||
may not be used together with \fB-nocomplain\fR.
|
||||
.PP
|
||||
The option \fB-nocomplain\fR has no effect and is available for compatibility with
|
||||
TCL 9. In TCL 9, the encoding command fails with an error on any encoding issue.
|
||||
This switch restores the TCL8.7 behaviour.
|
||||
.PP
|
||||
The \fB-strict\fR option follows more strict rules in conversion. For the \fButf-8\fR
|
||||
encoder, it disallows surrogates (which - otherwise - are just passed through). This
|
||||
option may not be used together with \fB-nocomplain\fR.
|
||||
.VE "TCL8.7 TIP346, TIP607, TIP601"
|
||||
.RE
|
||||
Converts \fIdata\fR, which should be in binary string encoded as per
|
||||
\fIencoding\fR, to a Tcl string. If \fIencoding\fR is not specified, the current
|
||||
system encoding is used.
|
||||
|
||||
.VS "TCL8.7 TIP607, TIP656"
|
||||
The \fB-profile\fR option determines the command behavior in the presence
|
||||
of conversion errors. See \fBPROFILES\fR for details. Any premature
|
||||
termination of processing due to errors is reported through an exception if
|
||||
the \fB-failindex\fR option is not specified.
|
||||
|
||||
If the \fB-failindex\fR is specified, instead of an exception being raised
|
||||
on premature termination, the result of the conversion up to the point of the
|
||||
error is returned as the result of the command. In addition, the index
|
||||
of the source byte triggering the error is stored in \fBvar\fR. If no
|
||||
errors are encountered, the entire result of the conversion is returned and
|
||||
the value \fB-1\fR is stored in \fBvar\fR.
|
||||
.VE "TCL8.7 TIP607, TIP656"
|
||||
.TP
|
||||
\fBencoding convertto\fR ?\fIencoding\fR? \fIdata\fR
|
||||
.TP
|
||||
\fBencoding convertto\fR ?\fB-profile \fIprofile\fR? ?\fB-failindex var\fR? \fIencoding\fR \fIdata\fR
|
||||
.
|
||||
Convert \fIstring\fR to the specified \fIencoding\fR. The result is a Tcl binary
|
||||
string that contains the sequence of bytes representing the converted string in
|
||||
the specified encoding. If \fIencoding\fR is not specified, the current system
|
||||
encoding is used.
|
||||
|
||||
.VS "TCL8.7 TIP607, TIP656"
|
||||
The \fB-profile\fR and \fB-failindex\fR options have the same effect as
|
||||
described for the \fBencoding convertfrom\fR command.
|
||||
.VE "TCL8.7 TIP607, TIP656"
|
||||
.TP
|
||||
\fBencoding dirs\fR ?\fIdirectoryList\fR?
|
||||
.
|
||||
@@ -123,55 +91,140 @@ are guaranteed to be present in the list.
|
||||
Set the system encoding to \fIencoding\fR. If \fIencoding\fR is
|
||||
omitted then the command returns the current system encoding. The
|
||||
system encoding is used whenever Tcl passes strings to system calls.
|
||||
.SH EXAMPLE
|
||||
.TP
|
||||
.VS "TCL8.7 TIP656"
|
||||
\fBencoding profiles\fR
|
||||
Returns a list of the names of encoding profiles. See \fBPROFILES\fR below.
|
||||
.VE "TCL8.7 TIP656"
|
||||
\" Do not put .VS on whole section as that messes up the bullet list alignment
|
||||
.SH PROFILES
|
||||
.PP
|
||||
.VS "TCL8.7 TIP656"
|
||||
Operations involving encoding transforms may encounter several types of
|
||||
errors such as invalid sequences in the source data, characters that
|
||||
cannot be encoded in the target encoding and so on.
|
||||
A \fIprofile\fR prescribes the strategy for dealing with such errors
|
||||
in one of two ways:
|
||||
.VE "TCL8.7 TIP656"
|
||||
.
|
||||
.IP \(bu
|
||||
.VS "TCL8.7 TIP656"
|
||||
Terminating further processing of the source data. The profile does not
|
||||
determine how this premature termination is conveyed to the caller. By default,
|
||||
this is signalled by raising an exception. If the \fB-failindex\fR option
|
||||
is specified, errors are reported through that mechanism.
|
||||
.VE "TCL8.7 TIP656"
|
||||
.IP \(bu
|
||||
.VS "TCL8.7 TIP656"
|
||||
Continue further processing of the source data using a fallback strategy such
|
||||
as replacing or discarding the offending bytes in a profile-defined manner.
|
||||
.VE "TCL8.7 TIP656"
|
||||
.PP
|
||||
The following profiles are currently implemented with \fBtcl8\fR being
|
||||
the default if the \fB-profile\fR is not specified.
|
||||
.VS "TCL8.7 TIP656"
|
||||
.TP
|
||||
\fBtcl8\fR
|
||||
.
|
||||
The \fBtcl8\fR profile always follows the first strategy above and corresponds
|
||||
to the behavior of encoding transforms in Tcl 8.6. When converting from an
|
||||
external encoding \fBother than utf-8\fR to Tcl strings with the \fBencoding
|
||||
convertfrom\fR command, invalid bytes are mapped to their numerically equivalent
|
||||
code points. For example, the byte 0x80 which is invalid in ASCII would be
|
||||
mapped to code point U+0080. When converting from \fButf-8\fR, invalid bytes
|
||||
that are defined in CP1252 are mapped to their Unicode equivalents while those
|
||||
that are not fall back to the numerical equivalents. For example, byte 0x80 is
|
||||
defined by CP1252 and is therefore mapped to its Unicode equivalent U+20AC while
|
||||
byte 0x81 which is not defined by CP1252 is mapped to U+0081. As an additional
|
||||
special case, the sequence 0xC0 0x80 is mapped to U+0000.
|
||||
|
||||
When converting from Tcl strings to an external encoding format using
|
||||
\fBencoding convertto\fR, characters that cannot be represented in the
|
||||
target encoding are replaced by an encoding-dependent character, usually
|
||||
the question mark \fB?\fR.
|
||||
.TP
|
||||
\fBstrict\fR
|
||||
.
|
||||
The \fBstrict\fR profile always stops processing when an conversion error is
|
||||
encountered. The error is signalled via an exception or the \fB-failindex\fR
|
||||
option mechanism. The \fBstrict\fR profile implements a Unicode standard
|
||||
conformant behavior.
|
||||
.TP
|
||||
\fBreplace\fR
|
||||
.
|
||||
Like the \fBtcl8\fR profile, the \fBreplace\fR profile always continues
|
||||
processing on conversion errors but follows a Unicode standard conformant
|
||||
method for error handling.
|
||||
|
||||
When converting an encoded byte sequence to a Tcl string using
|
||||
\fBencoding convertfrom\fR, invalid bytes
|
||||
are replaced by the U+FFFD REPLACEMENT CHARACTER code point.
|
||||
|
||||
When encoding a Tcl string with \fBencoding convertto\fR,
|
||||
code points that cannot be represented in the
|
||||
target encoding are transformed to an encoding-specific fallback character,
|
||||
U+FFFD REPLACEMENT CHARACTER for UTF targets and generally `?` for other
|
||||
encodings.
|
||||
.VE "TCL8.7 TIP656"
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
These examples use the utility proc below that prints the Unicode code points
|
||||
comprising a Tcl string.
|
||||
.PP
|
||||
.CS
|
||||
proc codepoints {s} {join [lmap c [split $s ""] {
|
||||
string cat U+ [format %.6X [scan $c %c]]}]
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
Example 1: convert a byte sequence in Japanese euc-jp encoding to a TCL string:
|
||||
.PP
|
||||
.CS
|
||||
set s [\fBencoding convertfrom\fR euc-jp "\exA4\exCF"]
|
||||
% codepoints [\fBencoding convertfrom\fR euc-jp "\exA4\exCF"]
|
||||
U+00306F
|
||||
.CE
|
||||
.PP
|
||||
The result is the unicode codepoint:
|
||||
The result is the unicode codepoint
|
||||
.QW "\eu306F" ,
|
||||
which is the Hiragana letter HA.
|
||||
.VS "TCL8.7 TIP346, TIP607, TIP601"
|
||||
.VS "TCL8.7 TIP607, TIP656"
|
||||
.PP
|
||||
Example 2: detect the error location in an incomplete UTF-8 sequence:
|
||||
Example 2: Error handling based on profiles:
|
||||
.PP
|
||||
The letter \fBA\fR is Unicode character U+0041 and the byte "\ex80" is invalid
|
||||
in ASCII encoding.
|
||||
.CS
|
||||
% set s [\fBencoding convertfrom\fR -failindex i utf-8 "A\exC3"]
|
||||
A
|
||||
% set i
|
||||
1
|
||||
.PP
|
||||
% codepoints [encoding convertfrom -profile tcl8 ascii A\ex80]
|
||||
U+000041 U+000080
|
||||
% codepoints [encoding convertfrom -profile replace ascii A\ex80]
|
||||
U+000041 U+00FFFD
|
||||
% codepoints [encoding convertfrom -profile strict ascii A\ex80]
|
||||
unexpected byte sequence starting at index 1: '\ex80'
|
||||
.CE
|
||||
.PP
|
||||
Example 3: return the incomplete UTF-8 sequence by raw bytes:
|
||||
Example 3: Get partial data and the error location:
|
||||
.PP
|
||||
.CS
|
||||
% set s [\fBencoding convertfrom\fR -nocomplain utf-8 "A\exC3"]
|
||||
.CE
|
||||
The result is "A" followed by the byte \exC3. The option \fB-nocomplain\fR
|
||||
has no effect, but assures to get the same result with TCL9.
|
||||
.PP
|
||||
Example 4: detect the error location while transforming to ISO8859-1
|
||||
(ISO-Latin 1):
|
||||
.PP
|
||||
.CS
|
||||
% set s [\fBencoding convertto\fR -failindex i utf-8 "A\eu0141"]
|
||||
A
|
||||
% set i
|
||||
1
|
||||
% codepoints [encoding convertfrom -profile strict -failindex idx ascii AB\ex80]
|
||||
U+000041 U+000042
|
||||
% set idx
|
||||
2
|
||||
.CE
|
||||
.PP
|
||||
Example 5: replace a not representable character by the replacement character:
|
||||
Example 4: Encode a character that is not representable in ISO8859-1:
|
||||
.PP
|
||||
.CS
|
||||
% set s [\fBencoding convertto\fR -nocomplain utf-8 "A\eu0141"]
|
||||
% encoding convertto iso8859-1 A\eu0141
|
||||
A?
|
||||
% encoding convertto -profile strict iso8859-1 A\eu0141
|
||||
unexpected character at index 1: 'U+000141'
|
||||
% encoding convertto -profile strict -failindex idx iso8859-1 A\eu0141
|
||||
A
|
||||
% set idx
|
||||
1
|
||||
.CE
|
||||
The option \fB-nocomplain\fR has no effect, but assures to get the same result
|
||||
with TCL9.
|
||||
.VE "TCL8.7 TIP346, TIP607, TIP601"
|
||||
.VE "TCL8.7 TIP607, TIP656"
|
||||
.PP
|
||||
.SH "SEE ALSO"
|
||||
Tcl_GetEncoding(3), fconfigure(n)
|
||||
|
||||
+10
-27
@@ -101,8 +101,6 @@ locale-dependent system encoding used for interfacing with the operating
|
||||
system, as returned by \fBencoding system\fR.
|
||||
.RE
|
||||
.TP
|
||||
\fB\-eofchar\fR \fIchar\fR
|
||||
.TP
|
||||
\fB\-eofchar\fR \fB{\fIchar outChar\fB}\fR
|
||||
.
|
||||
This option supports DOS file systems that use Control-z (\ex1A) as an
|
||||
@@ -122,31 +120,16 @@ reading and the empty string for writing.
|
||||
The acceptable range for \fB\-eofchar\fR values is \ex01 - \ex7F;
|
||||
attempting to set \fB\-eofchar\fR to a value outside of this range will
|
||||
generate an error.
|
||||
.VS "TCL8.7 TIP633"
|
||||
.VS "TCL8.7 TIP656"
|
||||
.TP
|
||||
\fB\-nocomplainencoding\fR \fIbool\fR
|
||||
\fB\-profile\fR \fIprofile\fR
|
||||
.
|
||||
Reporting mode of encoding errors.
|
||||
If set to a \fItrue\fR value, encoding errors are resolved by a replacement
|
||||
character (output) or verbatim bytes (input). No error is thrown.
|
||||
This is the only available mode in Tcl 8.7.
|
||||
.RS
|
||||
.PP
|
||||
Starting from TCL 9.0, this value may be set to a \fIfalse\fR value to throw errors
|
||||
in case of encoding errors.
|
||||
.RE
|
||||
.VE "TCL8.7 TIP633"
|
||||
.VS "TCL8.7 TIP346"
|
||||
.TP
|
||||
\fB\-strictencoding\fR \fIbool\fR
|
||||
.
|
||||
Activate additional stricter encoding application rules.
|
||||
Default value is \fIfalse\fR.
|
||||
.RS
|
||||
.PP
|
||||
See the \fI\-strict\fR option of the \fBencoding\fR command for more information.
|
||||
.VE "TCL8.7 TIP346"
|
||||
.RE
|
||||
Specifies the encoding profile to be used on the channel. The encoding
|
||||
transforms in use for the channel's input and output will then be subject to the
|
||||
rules of that profile. Any failures will result in a channel error. See
|
||||
\fBPROFILES\fR in the \fBencoding(n)\fR documentation for details about encoding
|
||||
profiles.
|
||||
.VE "TCL8.7 TIP656"
|
||||
.TP
|
||||
\fB\-translation\fR \fImode\fR
|
||||
.TP
|
||||
@@ -303,11 +286,11 @@ set data [read $f $numDataBytes]
|
||||
close $f
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
close(n), flush(n), gets(n), open(n), puts(n), read(n), socket(n),
|
||||
close(n), encoding(n), flush(n), gets(n), open(n), puts(n), read(n), socket(n),
|
||||
Tcl_StandardChannels(3)
|
||||
.SH KEYWORDS
|
||||
blocking, buffering, carriage return, end of line, flushing, linemode,
|
||||
newline, nonblocking, platform, translation, encoding, filter, byte array,
|
||||
newline, nonblocking, platform, profile, translation, encoding, filter, byte array,
|
||||
binary
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
|
||||
+3
-2
@@ -26,8 +26,9 @@ network sockets.
|
||||
The \fBfcopy\fR
|
||||
command transfers data from \fIinchan\fR until end of file
|
||||
or \fIsize\fR bytes or characters have been
|
||||
transferred; \fIsize\fR is in bytes if the two channels are using the
|
||||
same encoding, and is in characters otherwise.
|
||||
transferred; \fIsize\fR is in bytes if the input channel is in binary mode,
|
||||
or if the two channels are using the same encoding and -strict is not specified.
|
||||
Otherwise, size is in characters.
|
||||
If no \fB\-size\fR argument is given,
|
||||
then the copy goes until end of file.
|
||||
All the data read from \fIinchan\fR is copied to \fIoutchan\fR.
|
||||
|
||||
+3
-1
@@ -9716,6 +9716,7 @@ TclNRYieldToObjCmd(
|
||||
*/
|
||||
|
||||
iPtr->execEnvPtr = corPtr->callerEEPtr;
|
||||
/* Not calling Tcl_IncrRefCount(listPtr) here because listPtr is private */
|
||||
TclSetTailcall(interp, listPtr);
|
||||
corPtr->yieldPtr = listPtr;
|
||||
iPtr->execEnvPtr = corPtr->eePtr;
|
||||
@@ -9918,8 +9919,8 @@ TclNRCoroutineActivateCallback(
|
||||
if (corPtr->yieldPtr) {
|
||||
for (runPtr = TOP_CB(interp); runPtr; runPtr = runPtr->nextPtr) {
|
||||
if (runPtr->data[1] == corPtr->yieldPtr) {
|
||||
Tcl_DecrRefCount((Tcl_Obj *)runPtr->data[1]);
|
||||
runPtr->data[1] = NULL;
|
||||
Tcl_DecrRefCount(corPtr->yieldPtr);
|
||||
corPtr->yieldPtr = NULL;
|
||||
break;
|
||||
}
|
||||
@@ -10520,6 +10521,7 @@ TclNRCoroutineObjCmd(
|
||||
corPtr->running.lineLABCPtr = corPtr->lineLABCPtr;
|
||||
corPtr->stackLevel = NULL;
|
||||
corPtr->auxNumLevels = 0;
|
||||
corPtr->yieldPtr = NULL;
|
||||
|
||||
/*
|
||||
* Create the coro's execEnv, switch to it to push the exit and coro
|
||||
|
||||
+2
-2
@@ -656,7 +656,7 @@ EncodingConvertfromObjCmd(
|
||||
char buf[TCL_INTEGER_SPACE];
|
||||
sprintf(buf, "%u", result);
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unexpected byte sequence starting at index %"
|
||||
"u: '\\x%X'", result, UCHAR(bytesPtr[result])));
|
||||
"u: '\\x%02X'", result, UCHAR(bytesPtr[result])));
|
||||
Tcl_SetErrorCode(interp, "TCL", "ENCODING", "ILLEGALSEQUENCE",
|
||||
buf, NULL);
|
||||
Tcl_DStringFree(&ds);
|
||||
@@ -732,7 +732,7 @@ EncodingConverttoObjCmd(
|
||||
if (objc == 2) {
|
||||
encoding = Tcl_GetEncoding(interp, NULL);
|
||||
data = objv[1];
|
||||
} else if (objc > 2 && objc < 6) {
|
||||
} else if (objc > 2 && objc < 7) {
|
||||
int objcUnprocessed = objc;
|
||||
data = objv[objc - 1];
|
||||
stringPtr = Tcl_GetString(objv[1]);
|
||||
|
||||
+2
-2
@@ -4317,14 +4317,14 @@ extern const TclStubs *tclStubsPtr;
|
||||
/* Handle Win64 tk.dll being loaded in Cygwin64. */
|
||||
# define Tcl_GetTime(t) \
|
||||
do { \
|
||||
union { \
|
||||
struct { \
|
||||
Tcl_Time now; \
|
||||
long long reserved; \
|
||||
} _t; \
|
||||
_t.reserved = -1; \
|
||||
tclStubsPtr->tcl_GetTime((&_t.now)); \
|
||||
if (_t.reserved != -1) { \
|
||||
_t.now.usec = _t.reserved; \
|
||||
_t.now.usec = (long) _t.reserved; \
|
||||
} \
|
||||
*(t) = _t.now; \
|
||||
} while (0)
|
||||
|
||||
+221
-84
@@ -36,7 +36,7 @@ typedef struct {
|
||||
* encoding is deleted. */
|
||||
void *clientData; /* Arbitrary value associated with encoding
|
||||
* type. Passed to conversion functions. */
|
||||
int nullSize; /* Number of 0x00 bytes that signify
|
||||
Tcl_Size nullSize; /* Number of 0x00 bytes that signify
|
||||
* end-of-string in this encoding. This number
|
||||
* is used to determine the source string
|
||||
* length when the srcLen argument is
|
||||
@@ -237,8 +237,13 @@ static Tcl_EncodingConvertProc Iso88591ToUtfProc;
|
||||
*/
|
||||
|
||||
static const Tcl_ObjType encodingType = {
|
||||
"encoding", FreeEncodingInternalRep, DupEncodingInternalRep, NULL, NULL
|
||||
"encoding",
|
||||
FreeEncodingInternalRep,
|
||||
DupEncodingInternalRep,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define EncodingSetInternalRep(objPtr, encoding) \
|
||||
do { \
|
||||
Tcl_ObjInternalRep ir; \
|
||||
@@ -369,7 +374,7 @@ int
|
||||
Tcl_SetEncodingSearchPath(
|
||||
Tcl_Obj *searchPath)
|
||||
{
|
||||
int dummy;
|
||||
Tcl_Size dummy;
|
||||
|
||||
if (TCL_ERROR == TclListObjLengthM(NULL, searchPath, &dummy)) {
|
||||
return TCL_ERROR;
|
||||
@@ -416,7 +421,7 @@ void
|
||||
TclSetLibraryPath(
|
||||
Tcl_Obj *path)
|
||||
{
|
||||
int dummy;
|
||||
Tcl_Size dummy;
|
||||
|
||||
if (TCL_ERROR == TclListObjLengthM(NULL, path, &dummy)) {
|
||||
return;
|
||||
@@ -452,7 +457,7 @@ TclSetLibraryPath(
|
||||
static void
|
||||
FillEncodingFileMap(void)
|
||||
{
|
||||
int i, numDirs = 0;
|
||||
Tcl_Size i, numDirs = 0;
|
||||
Tcl_Obj *map, *searchPath;
|
||||
|
||||
searchPath = Tcl_GetEncodingSearchPath();
|
||||
@@ -461,13 +466,13 @@ FillEncodingFileMap(void)
|
||||
map = Tcl_NewDictObj();
|
||||
Tcl_IncrRefCount(map);
|
||||
|
||||
for (i = numDirs-1; i >= 0; i--) {
|
||||
for (i = numDirs-1; i != TCL_INDEX_NONE; i--) {
|
||||
/*
|
||||
* Iterate backwards through the search path so as we overwrite
|
||||
* entries found, we favor files earlier on the search path.
|
||||
*/
|
||||
|
||||
int j, numFiles;
|
||||
Tcl_Size j, numFiles;
|
||||
Tcl_Obj *directory, *matchFileList;
|
||||
Tcl_Obj **filev;
|
||||
Tcl_GlobTypeData readableFiles = {
|
||||
@@ -519,7 +524,8 @@ FillEncodingFileMap(void)
|
||||
/* Since TCL_ENCODING_MODIFIED is only used for utf-8/cesu-8 and
|
||||
* TCL_ENCODING_LE is only used for utf-16/utf-32/ucs-2. re-use the same value */
|
||||
#define TCL_ENCODING_LE TCL_ENCODING_MODIFIED /* Little-endian encoding */
|
||||
#define TCL_ENCODING_UTF 0x200 /* For UTF-8 encoding, allow 4-byte output sequences */
|
||||
#define ENCODING_UTF 0x200 /* For UTF-8 encoding, allow 4-byte output sequences */
|
||||
#define ENCODING_INPUT 0x400 /* For UTF-8/CESU-8 encoding, means external -> internal */
|
||||
|
||||
void
|
||||
TclInitEncodingSubsystem(void)
|
||||
@@ -561,9 +567,9 @@ TclInitEncodingSubsystem(void)
|
||||
type.fromUtfProc = UtfToUtfProc;
|
||||
type.freeProc = NULL;
|
||||
type.nullSize = 1;
|
||||
type.clientData = INT2PTR(TCL_ENCODING_UTF);
|
||||
type.clientData = INT2PTR(ENCODING_UTF);
|
||||
Tcl_CreateEncoding(&type);
|
||||
type.clientData = INT2PTR(TCL_ENCODING_NOCOMPLAIN);
|
||||
type.clientData = INT2PTR(0);
|
||||
type.encodingName = "cesu-8";
|
||||
Tcl_CreateEncoding(&type);
|
||||
|
||||
@@ -572,13 +578,13 @@ TclInitEncodingSubsystem(void)
|
||||
type.freeProc = NULL;
|
||||
type.nullSize = 2;
|
||||
type.encodingName = "ucs-2le";
|
||||
type.clientData = INT2PTR(TCL_ENCODING_LE|TCL_ENCODING_NOCOMPLAIN);
|
||||
type.clientData = INT2PTR(TCL_ENCODING_LE);
|
||||
Tcl_CreateEncoding(&type);
|
||||
type.encodingName = "ucs-2be";
|
||||
type.clientData = INT2PTR(TCL_ENCODING_NOCOMPLAIN);
|
||||
type.clientData = INT2PTR(0);
|
||||
Tcl_CreateEncoding(&type);
|
||||
type.encodingName = "ucs-2";
|
||||
type.clientData = INT2PTR(isLe.c|TCL_ENCODING_NOCOMPLAIN);
|
||||
type.clientData = INT2PTR(isLe.c);
|
||||
Tcl_CreateEncoding(&type);
|
||||
|
||||
type.toUtfProc = Utf32ToUtfProc;
|
||||
@@ -600,13 +606,13 @@ TclInitEncodingSubsystem(void)
|
||||
type.freeProc = NULL;
|
||||
type.nullSize = 2;
|
||||
type.encodingName = "utf-16le";
|
||||
type.clientData = INT2PTR(TCL_ENCODING_LE);
|
||||
type.clientData = INT2PTR(TCL_ENCODING_LE|ENCODING_UTF);
|
||||
Tcl_CreateEncoding(&type);
|
||||
type.encodingName = "utf-16be";
|
||||
type.clientData = INT2PTR(0);
|
||||
type.clientData = INT2PTR(ENCODING_UTF);
|
||||
Tcl_CreateEncoding(&type);
|
||||
type.encodingName = "utf-16";
|
||||
type.clientData = INT2PTR(isLe.c);
|
||||
type.clientData = INT2PTR(isLe.c|ENCODING_UTF);
|
||||
Tcl_CreateEncoding(&type);
|
||||
|
||||
#ifndef TCL_NO_DEPRECATED
|
||||
@@ -999,7 +1005,7 @@ Tcl_GetEncodingNames(
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
Tcl_Size
|
||||
Tcl_GetEncodingNulLength(
|
||||
Tcl_Encoding encoding)
|
||||
{
|
||||
@@ -1165,7 +1171,7 @@ Tcl_ExternalToUtfDString(
|
||||
Tcl_Encoding encoding, /* The encoding for the source string, or NULL
|
||||
* for the default system encoding. */
|
||||
const char *src, /* Source string in specified encoding. */
|
||||
int srcLen, /* Source string length in bytes, or < 0 for
|
||||
Tcl_Size srcLen, /* Source string length in bytes, or < 0 for
|
||||
* encoding-specific string length. */
|
||||
Tcl_DString *dstPtr) /* Uninitialized or free DString in which the
|
||||
* converted string is stored. */
|
||||
@@ -1181,7 +1187,7 @@ Tcl_ExternalToUtfDString(
|
||||
* Tcl_ExternalToUtfDStringEx --
|
||||
*
|
||||
* Convert a source buffer from the specified encoding into UTF-8.
|
||||
* The parameter flags controls the behavior, if any of the bytes in
|
||||
* The parameter flags controls the behavior, if any of the bytes in
|
||||
* the source buffer are invalid or cannot be represented in utf-8.
|
||||
* Possible flags values:
|
||||
* TCL_ENCODING_STOPONERROR: don't replace invalid characters/bytes but
|
||||
@@ -1204,12 +1210,12 @@ Tcl_ExternalToUtfDString(
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
Tcl_Size
|
||||
Tcl_ExternalToUtfDStringEx(
|
||||
Tcl_Encoding encoding, /* The encoding for the source string, or NULL
|
||||
* for the default system encoding. */
|
||||
const char *src, /* Source string in specified encoding. */
|
||||
int srcLen, /* Source string length in bytes, or < 0 for
|
||||
Tcl_Size srcLen, /* Source string length in bytes, or < 0 for
|
||||
* encoding-specific string length. */
|
||||
int flags, /* Conversion control flags. */
|
||||
Tcl_DString *dstPtr) /* Uninitialized or free DString in which the
|
||||
@@ -1218,7 +1224,8 @@ Tcl_ExternalToUtfDStringEx(
|
||||
char *dst;
|
||||
Tcl_EncodingState state;
|
||||
const Encoding *encodingPtr;
|
||||
int dstLen, result, soFar, srcRead, dstWrote, dstChars;
|
||||
int result, soFar, srcRead, dstWrote, dstChars;
|
||||
Tcl_Size dstLen;
|
||||
const char *srcStart = src;
|
||||
|
||||
Tcl_DStringInit(dstPtr);
|
||||
@@ -1238,7 +1245,7 @@ Tcl_ExternalToUtfDStringEx(
|
||||
|
||||
flags |= TCL_ENCODING_START | TCL_ENCODING_END;
|
||||
if (encodingPtr->toUtfProc == UtfToUtfProc) {
|
||||
flags |= TCL_ENCODING_MODIFIED | TCL_ENCODING_UTF;
|
||||
flags |= ENCODING_INPUT;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
@@ -1249,7 +1256,7 @@ Tcl_ExternalToUtfDStringEx(
|
||||
src += srcRead;
|
||||
if (result != TCL_CONVERT_NOSPACE) {
|
||||
Tcl_DStringSetLength(dstPtr, soFar);
|
||||
return (result == TCL_OK) ? TCL_INDEX_NONE : (int)(src - srcStart);
|
||||
return (result == TCL_OK) ? TCL_INDEX_NONE : (Tcl_Size)(src - srcStart);
|
||||
}
|
||||
flags &= ~TCL_ENCODING_START;
|
||||
srcLen -= srcRead;
|
||||
@@ -1286,7 +1293,7 @@ Tcl_ExternalToUtf(
|
||||
Tcl_Encoding encoding, /* The encoding for the source string, or NULL
|
||||
* for the default system encoding. */
|
||||
const char *src, /* Source string in specified encoding. */
|
||||
int srcLen, /* Source string length in bytes, or < 0 for
|
||||
Tcl_Size srcLen, /* Source string length in bytes, or < 0 for
|
||||
* encoding-specific string length. */
|
||||
int flags, /* Conversion control flags. */
|
||||
Tcl_EncodingState *statePtr,/* Place for conversion routine to store state
|
||||
@@ -1296,7 +1303,7 @@ Tcl_ExternalToUtf(
|
||||
* routine under control of flags argument. */
|
||||
char *dst, /* Output buffer in which converted string is
|
||||
* stored. */
|
||||
int dstLen, /* The maximum length of output buffer in
|
||||
Tcl_Size dstLen, /* The maximum length of output buffer in
|
||||
* bytes. */
|
||||
int *srcReadPtr, /* Filled with the number of bytes from the
|
||||
* source string that were converted. This may
|
||||
@@ -1345,6 +1352,9 @@ Tcl_ExternalToUtf(
|
||||
}
|
||||
|
||||
if (!noTerminate) {
|
||||
if (dstLen < 1) {
|
||||
return TCL_CONVERT_NOSPACE;
|
||||
}
|
||||
/*
|
||||
* If there are any null characters in the middle of the buffer,
|
||||
* they will converted to the UTF-8 null character (\xC0\x80). To get
|
||||
@@ -1353,9 +1363,13 @@ Tcl_ExternalToUtf(
|
||||
*/
|
||||
|
||||
dstLen--;
|
||||
} else {
|
||||
if (dstLen < 0) {
|
||||
return TCL_CONVERT_NOSPACE;
|
||||
}
|
||||
}
|
||||
if (encodingPtr->toUtfProc == UtfToUtfProc) {
|
||||
flags |= TCL_ENCODING_MODIFIED | TCL_ENCODING_UTF;
|
||||
flags |= ENCODING_INPUT;
|
||||
}
|
||||
do {
|
||||
Tcl_EncodingState savedState = *statePtr;
|
||||
@@ -1403,7 +1417,7 @@ Tcl_UtfToExternalDString(
|
||||
Tcl_Encoding encoding, /* The encoding for the converted string, or
|
||||
* NULL for the default system encoding. */
|
||||
const char *src, /* Source string in UTF-8. */
|
||||
int srcLen, /* Source string length in bytes, or < 0 for
|
||||
Tcl_Size srcLen, /* Source string length in bytes, or < 0 for
|
||||
* strlen(). */
|
||||
Tcl_DString *dstPtr) /* Uninitialized or free DString in which the
|
||||
* converted string is stored. */
|
||||
@@ -1443,22 +1457,23 @@ Tcl_UtfToExternalDString(
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
Tcl_Size
|
||||
Tcl_UtfToExternalDStringEx(
|
||||
Tcl_Encoding encoding, /* The encoding for the converted string, or
|
||||
* NULL for the default system encoding. */
|
||||
const char *src, /* Source string in UTF-8. */
|
||||
int srcLen, /* Source string length in bytes, or < 0 for
|
||||
Tcl_Size srcLen, /* Source string length in bytes, or < 0 for
|
||||
* strlen(). */
|
||||
int flags, /* Conversion control flags. */
|
||||
int flags, /* Conversion control flags. */
|
||||
Tcl_DString *dstPtr) /* Uninitialized or free DString in which the
|
||||
* converted string is stored. */
|
||||
{
|
||||
char *dst;
|
||||
Tcl_EncodingState state;
|
||||
const Encoding *encodingPtr;
|
||||
int dstLen, result, soFar, srcRead, dstWrote, dstChars;
|
||||
int result, soFar, srcRead, dstWrote, dstChars;
|
||||
const char *srcStart = src;
|
||||
Tcl_Size dstLen;
|
||||
|
||||
Tcl_DStringInit(dstPtr);
|
||||
dst = Tcl_DStringValue(dstPtr);
|
||||
@@ -1487,7 +1502,7 @@ Tcl_UtfToExternalDStringEx(
|
||||
while (i >= soFar) {
|
||||
Tcl_DStringSetLength(dstPtr, i--);
|
||||
}
|
||||
return (result == TCL_OK) ? TCL_INDEX_NONE : (int)(src - srcStart);
|
||||
return (result == TCL_OK) ? TCL_INDEX_NONE : (Tcl_Size)(src - srcStart);
|
||||
}
|
||||
|
||||
flags &= ~TCL_ENCODING_START;
|
||||
@@ -1525,7 +1540,7 @@ Tcl_UtfToExternal(
|
||||
Tcl_Encoding encoding, /* The encoding for the converted string, or
|
||||
* NULL for the default system encoding. */
|
||||
const char *src, /* Source string in UTF-8. */
|
||||
int srcLen, /* Source string length in bytes, or < 0 for
|
||||
Tcl_Size srcLen, /* Source string length in bytes, or < 0 for
|
||||
* strlen(). */
|
||||
int flags, /* Conversion control flags. */
|
||||
Tcl_EncodingState *statePtr,/* Place for conversion routine to store state
|
||||
@@ -1535,7 +1550,7 @@ Tcl_UtfToExternal(
|
||||
* routine under control of flags argument. */
|
||||
char *dst, /* Output buffer in which converted string
|
||||
* is stored. */
|
||||
int dstLen, /* The maximum length of output buffer in
|
||||
Tcl_Size dstLen, /* The maximum length of output buffer in
|
||||
* bytes. */
|
||||
int *srcReadPtr, /* Filled with the number of bytes from the
|
||||
* source string that were converted. This may
|
||||
@@ -1577,10 +1592,17 @@ Tcl_UtfToExternal(
|
||||
dstCharsPtr = &dstChars;
|
||||
}
|
||||
|
||||
if (dstLen < encodingPtr->nullSize) {
|
||||
return TCL_CONVERT_NOSPACE;
|
||||
}
|
||||
dstLen -= encodingPtr->nullSize;
|
||||
result = encodingPtr->fromUtfProc(encodingPtr->clientData, src, srcLen,
|
||||
flags, statePtr, dst, dstLen, srcReadPtr,
|
||||
dstWrotePtr, dstCharsPtr);
|
||||
/*
|
||||
* Buffer is terminated irrespective of result. Not sure this is
|
||||
* reasonable but keep for historical/compatibility reasons.
|
||||
*/
|
||||
memset(&dst[*dstWrotePtr], '\0', encodingPtr->nullSize);
|
||||
|
||||
return result;
|
||||
@@ -1646,7 +1668,7 @@ OpenEncodingFileChannel(
|
||||
Tcl_Obj *map = TclGetProcessGlobalValue(&encodingFileMap);
|
||||
Tcl_Obj **dir, *path, *directory = NULL;
|
||||
Tcl_Channel chan = NULL;
|
||||
int i, numDirs;
|
||||
Tcl_Size i, numDirs;
|
||||
|
||||
TclListObjGetElementsM(NULL, searchPath, &numDirs, &dir);
|
||||
Tcl_IncrRefCount(nameObj);
|
||||
@@ -1911,7 +1933,7 @@ LoadTableEncoding(
|
||||
for (i = 0; i < numPages; i++) {
|
||||
int ch;
|
||||
const char *p;
|
||||
int expected = 3 + 16 * (16 * 4 + 1);
|
||||
Tcl_Size expected = 3 + 16 * (16 * 4 + 1);
|
||||
|
||||
if (Tcl_ReadChars(chan, objPtr, expected, 0) != expected) {
|
||||
return NULL;
|
||||
@@ -2147,7 +2169,7 @@ LoadEscapeEncoding(
|
||||
Tcl_DStringInit(&escapeData);
|
||||
|
||||
while (1) {
|
||||
int argc;
|
||||
Tcl_Size argc;
|
||||
const char **argv;
|
||||
char *line;
|
||||
Tcl_DString lineString;
|
||||
@@ -2302,9 +2324,9 @@ BinaryProc(
|
||||
*
|
||||
* UtfToUtfProc --
|
||||
*
|
||||
* Convert from UTF-8 to UTF-8. Note that the UTF-8 to UTF-8 translation
|
||||
* is not a no-op, because it will turn a stream of improperly formed
|
||||
* UTF-8 into a properly formed stream.
|
||||
* Converts from UTF-8 to UTF-8. Note that the UTF-8 to UTF-8 translation
|
||||
* is not a no-op, because it turns a stream of improperly formed
|
||||
* UTF-8 into a properly-formed stream.
|
||||
*
|
||||
* Results:
|
||||
* Returns TCL_OK if conversion was successful.
|
||||
@@ -2363,7 +2385,7 @@ UtfToUtfProc(
|
||||
|
||||
dstStart = dst;
|
||||
flags |= PTR2INT(clientData);
|
||||
dstEnd = dst + dstLen - ((flags & TCL_ENCODING_UTF) ? TCL_UTF_MAX : 6);
|
||||
dstEnd = dst + dstLen - ((flags & ENCODING_UTF) ? TCL_UTF_MAX : 6);
|
||||
|
||||
for (numChars = 0; src < srcEnd && numChars <= charLimit; numChars++) {
|
||||
if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) {
|
||||
@@ -2379,7 +2401,7 @@ UtfToUtfProc(
|
||||
result = TCL_CONVERT_NOSPACE;
|
||||
break;
|
||||
}
|
||||
if (UCHAR(*src) < 0x80 && !((UCHAR(*src) == 0) && (flags & TCL_ENCODING_MODIFIED))) {
|
||||
if (UCHAR(*src) < 0x80 && !((UCHAR(*src) == 0) && (flags & ENCODING_INPUT))) {
|
||||
/*
|
||||
* Copy 7bit characters, but skip null-bytes when we are in input
|
||||
* mode, so that they get converted to 0xC080.
|
||||
@@ -2387,11 +2409,13 @@ UtfToUtfProc(
|
||||
|
||||
*dst++ = *src++;
|
||||
} else if ((UCHAR(*src) == 0xC0) && (src + 1 < srcEnd)
|
||||
&& (UCHAR(src[1]) == 0x80) && (!(flags & TCL_ENCODING_MODIFIED) || ((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT) || (flags & ENCODING_FAILINDEX))) {
|
||||
&& (UCHAR(src[1]) == 0x80) && !(flags & TCL_ENCODING_MODIFIED) && (!(flags & ENCODING_INPUT)
|
||||
|| ((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT)
|
||||
|| (flags & ENCODING_FAILINDEX))) {
|
||||
/*
|
||||
* If in input mode, and -strict or -failindex is specified: This is an error.
|
||||
*/
|
||||
if (flags & TCL_ENCODING_MODIFIED) {
|
||||
if ((STOPONERROR) && (flags & ENCODING_INPUT)) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
break;
|
||||
}
|
||||
@@ -2409,33 +2433,37 @@ UtfToUtfProc(
|
||||
* unless the user has explicitly asked to be told.
|
||||
*/
|
||||
|
||||
if (flags & TCL_ENCODING_MODIFIED) {
|
||||
if (flags & ENCODING_INPUT) {
|
||||
if ((STOPONERROR) && (flags & TCL_ENCODING_CHAR_LIMIT)) {
|
||||
result = TCL_CONVERT_MULTIBYTE;
|
||||
break;
|
||||
}
|
||||
if (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT) || (flags & ENCODING_FAILINDEX)) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
break;
|
||||
}
|
||||
ch = UCHAR(*src++);
|
||||
} else {
|
||||
char chbuf[2];
|
||||
chbuf[0] = UCHAR(*src++); chbuf[1] = 0;
|
||||
TclUtfToUCS4(chbuf, &ch);
|
||||
if (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT) || (flags & ENCODING_FAILINDEX)) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
char chbuf[2];
|
||||
chbuf[0] = UCHAR(*src++); chbuf[1] = 0;
|
||||
TclUtfToUCS4(chbuf, &ch);
|
||||
dst += Tcl_UniCharToUtf(ch, dst);
|
||||
} else {
|
||||
int low;
|
||||
const char *saveSrc = src;
|
||||
size_t len = TclUtfToUCS4(src, &ch);
|
||||
if ((len < 2) && (ch != 0) && (flags & TCL_ENCODING_MODIFIED)
|
||||
&& (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT))) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
break;
|
||||
if (flags & ENCODING_INPUT) {
|
||||
if ((len < 2) && (ch != 0)
|
||||
&& (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT) || (flags & ENCODING_FAILINDEX))) {
|
||||
goto utf8Syntax;
|
||||
} else if ((ch > 0xFFFF) && !(flags & ENCODING_UTF)
|
||||
&& (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT) || (flags & ENCODING_FAILINDEX))) {
|
||||
utf8Syntax:
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const char *saveSrc = src;
|
||||
src += len;
|
||||
if (!(flags & TCL_ENCODING_UTF) && (ch > 0x3FF)) {
|
||||
if (!(flags & ENCODING_UTF) && !(flags & ENCODING_INPUT) && (ch > 0x3FF)) {
|
||||
if (ch > 0xFFFF) {
|
||||
/* CESU-8 6-byte sequence for chars > U+FFFF */
|
||||
ch -= 0x10000;
|
||||
@@ -2450,6 +2478,11 @@ UtfToUtfProc(
|
||||
* A surrogate character is detected, handle especially.
|
||||
*/
|
||||
|
||||
if (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT) && (flags & ENCODING_UTF)) {
|
||||
result = TCL_CONVERT_UNKNOWN;
|
||||
src = saveSrc;
|
||||
break;
|
||||
}
|
||||
low = ch;
|
||||
len = (src <= srcEnd-3) ? TclUtfToUCS4(src, &low) : 0;
|
||||
|
||||
@@ -2469,12 +2502,12 @@ UtfToUtfProc(
|
||||
src += len;
|
||||
dst += Tcl_UniCharToUtf(ch, dst);
|
||||
ch = low;
|
||||
} else if (STOPONERROR && !(flags & TCL_ENCODING_MODIFIED) && (((ch & ~0x7FF) == 0xD800))) {
|
||||
} else if (STOPONERROR && !(flags & ENCODING_INPUT) && (((ch & ~0x7FF) == 0xD800))) {
|
||||
result = TCL_CONVERT_UNKNOWN;
|
||||
src = saveSrc;
|
||||
break;
|
||||
} else if (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT)
|
||||
&& (flags & TCL_ENCODING_MODIFIED) && ((ch & ~0x7FF) == 0xD800)) {
|
||||
&& (flags & ENCODING_INPUT) && ((ch & ~0x7FF) == 0xD800)) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
src = saveSrc;
|
||||
break;
|
||||
@@ -2531,7 +2564,7 @@ Utf32ToUtfProc(
|
||||
const char *srcStart, *srcEnd;
|
||||
const char *dstEnd, *dstStart;
|
||||
int result, numChars, charLimit = INT_MAX;
|
||||
int ch;
|
||||
int ch = 0, bytesLeft = srcLen % 4;
|
||||
|
||||
flags |= PTR2INT(clientData);
|
||||
if (flags & TCL_ENCODING_CHAR_LIMIT) {
|
||||
@@ -2543,9 +2576,22 @@ Utf32ToUtfProc(
|
||||
* Check alignment with utf-32 (4 == sizeof(UTF-32))
|
||||
*/
|
||||
|
||||
if ((srcLen % 4) != 0) {
|
||||
if (bytesLeft != 0) {
|
||||
result = TCL_CONVERT_MULTIBYTE;
|
||||
srcLen &= -4;
|
||||
srcLen -= bytesLeft;
|
||||
}
|
||||
|
||||
/*
|
||||
* If last code point is a high surrogate, we cannot handle that yet,
|
||||
* unless we are at the end.
|
||||
*/
|
||||
|
||||
if (!(flags & TCL_ENCODING_END) && (srcLen >= 4) &&
|
||||
((src[srcLen - ((flags & TCL_ENCODING_LE)?3:2)] & 0xFC) == 0xD8) &&
|
||||
((src[srcLen - ((flags & TCL_ENCODING_LE)?2:3)]) == 0) &&
|
||||
((src[srcLen - ((flags & TCL_ENCODING_LE)?1:4)]) == 0)) {
|
||||
result = TCL_CONVERT_MULTIBYTE;
|
||||
srcLen-= 4;
|
||||
}
|
||||
|
||||
srcStart = src;
|
||||
@@ -2560,17 +2606,28 @@ Utf32ToUtfProc(
|
||||
break;
|
||||
}
|
||||
|
||||
int prev = ch;
|
||||
if (flags & TCL_ENCODING_LE) {
|
||||
ch = (src[3] & 0xFF) << 24 | (src[2] & 0xFF) << 16 | (src[1] & 0xFF) << 8 | (src[0] & 0xFF);
|
||||
} else {
|
||||
ch = (src[0] & 0xFF) << 24 | (src[1] & 0xFF) << 16 | (src[2] & 0xFF) << 8 | (src[3] & 0xFF);
|
||||
}
|
||||
if ((unsigned)ch > 0x10FFFF || (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT)
|
||||
&& ((ch & ~0x7FF) == 0xD800))) {
|
||||
if (STOPONERROR) {
|
||||
if (((prev & ~0x3FF) == 0xD800) && ((ch & ~0x3FF) != 0xDC00)) {
|
||||
/* Bug [10c2c17c32]. If Hi surrogate not followed by Lo surrogate, finish 3-byte UTF-8 */
|
||||
dst += Tcl_UniCharToUtf(-1, dst);
|
||||
}
|
||||
|
||||
if ((unsigned)ch > 0x10FFFF) {
|
||||
ch = 0xFFFD;
|
||||
if ((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
break;
|
||||
}
|
||||
} else if (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT)
|
||||
&& ((ch & ~0x7FF) == 0xD800)) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
ch = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2586,6 +2643,27 @@ Utf32ToUtfProc(
|
||||
src += sizeof(unsigned int);
|
||||
}
|
||||
|
||||
if ((ch & ~0x3FF) == 0xD800) {
|
||||
/* Bug [10c2c17c32]. If Hi surrogate, finish 3-byte UTF-8 */
|
||||
dst += Tcl_UniCharToUtf(-1, dst);
|
||||
}
|
||||
|
||||
if ((flags & TCL_ENCODING_END) && (result == TCL_CONVERT_MULTIBYTE)) {
|
||||
/* We have a single byte left-over at the end */
|
||||
if (dst > dstEnd) {
|
||||
result = TCL_CONVERT_NOSPACE;
|
||||
} else {
|
||||
/* destination is not full, so we really are at the end now */
|
||||
if ((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
} else {
|
||||
result = TCL_OK;
|
||||
dst += Tcl_UniCharToUtf(0xFFFD, dst);
|
||||
numChars++;
|
||||
src += bytesLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
*srcReadPtr = src - srcStart;
|
||||
*dstWrotePtr = dst - dstStart;
|
||||
*dstCharsPtr = numChars;
|
||||
@@ -2730,7 +2808,7 @@ Utf16ToUtfProc(
|
||||
const char *srcStart, *srcEnd;
|
||||
const char *dstEnd, *dstStart;
|
||||
int result, numChars, charLimit = INT_MAX;
|
||||
unsigned short ch;
|
||||
unsigned short ch = 0;
|
||||
|
||||
flags |= PTR2INT(clientData);
|
||||
if (flags & TCL_ENCODING_CHAR_LIMIT) {
|
||||
@@ -2748,10 +2826,11 @@ Utf16ToUtfProc(
|
||||
}
|
||||
|
||||
/*
|
||||
* If last code point is a high surrogate, we cannot handle that yet.
|
||||
* If last code point is a high surrogate, we cannot handle that yet,
|
||||
* unless we are at the end.
|
||||
*/
|
||||
|
||||
if ((srcLen >= 2) &&
|
||||
if (!(flags & TCL_ENCODING_END) && (srcLen >= 2) &&
|
||||
((src[srcLen - ((flags & TCL_ENCODING_LE)?1:2)] & 0xFC) == 0xD8)) {
|
||||
result = TCL_CONVERT_MULTIBYTE;
|
||||
srcLen-= 2;
|
||||
@@ -2769,25 +2848,71 @@ Utf16ToUtfProc(
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned short prev = ch;
|
||||
if (flags & TCL_ENCODING_LE) {
|
||||
ch = (src[1] & 0xFF) << 8 | (src[0] & 0xFF);
|
||||
} else {
|
||||
ch = (src[0] & 0xFF) << 8 | (src[1] & 0xFF);
|
||||
}
|
||||
if (((prev & ~0x3FF) == 0xD800) && ((ch & ~0x3FF) != 0xDC00)) {
|
||||
if (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT)) {
|
||||
result = TCL_CONVERT_UNKNOWN;
|
||||
src -= 2; /* Go back to beginning of high surrogate */
|
||||
dst--; /* Also undo writing a single byte too much */
|
||||
numChars--;
|
||||
break;
|
||||
}
|
||||
/* Bug [10c2c17c32]. If Hi surrogate not followed by Lo surrogate, finish 3-byte UTF-8 */
|
||||
dst += Tcl_UniCharToUtf(-1, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case for 1-byte utf chars for speed. Make sure we work with
|
||||
* unsigned short-size data.
|
||||
*/
|
||||
|
||||
if (ch && ch < 0x80) {
|
||||
if ((unsigned)ch - 1 < 0x7F) {
|
||||
*dst++ = (ch & 0xFF);
|
||||
} else if (((prev & ~0x3FF) == 0xD800) || ((ch & ~0x3FF) == 0xD800)) {
|
||||
dst += Tcl_UniCharToUtf(ch, dst);
|
||||
} else if (((ch & ~0x3FF) == 0xDC00) && ((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT)) {
|
||||
/* Lo surrogate not preceded by Hi surrogate */
|
||||
result = TCL_CONVERT_UNKNOWN;
|
||||
break;
|
||||
} else {
|
||||
*dst = 0; /* In case of lower surrogate, don't try to combine */
|
||||
dst += Tcl_UniCharToUtf(ch, dst);
|
||||
}
|
||||
src += sizeof(unsigned short);
|
||||
}
|
||||
|
||||
if ((ch & ~0x3FF) == 0xD800) {
|
||||
if ((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT) {
|
||||
result = TCL_CONVERT_UNKNOWN;
|
||||
src -= 2;
|
||||
dst--;
|
||||
numChars--;
|
||||
} else {
|
||||
/* Bug [10c2c17c32]. If Hi surrogate, finish 3-byte UTF-8 */
|
||||
dst += Tcl_UniCharToUtf(-1, dst);
|
||||
}
|
||||
}
|
||||
if ((flags & TCL_ENCODING_END) && (result == TCL_CONVERT_MULTIBYTE)) {
|
||||
/* We have a single byte left-over at the end */
|
||||
if (dst > dstEnd) {
|
||||
result = TCL_CONVERT_NOSPACE;
|
||||
} else {
|
||||
/* destination is not full, so we really are at the end now */
|
||||
if (((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT)) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
} else {
|
||||
result = TCL_OK;
|
||||
dst += Tcl_UniCharToUtf(0xFFFD, dst);
|
||||
numChars++;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*srcReadPtr = src - srcStart;
|
||||
*dstWrotePtr = dst - dstStart;
|
||||
*dstCharsPtr = numChars;
|
||||
@@ -2939,10 +3064,7 @@ UtfToUcs2Proc(
|
||||
* output buffer. */
|
||||
{
|
||||
const char *srcStart, *srcEnd, *srcClose, *dstStart, *dstEnd;
|
||||
int result, numChars;
|
||||
#if TCL_UTF_MAX < 4
|
||||
int len;
|
||||
#endif
|
||||
int result, numChars, len;
|
||||
Tcl_UniChar ch = 0;
|
||||
|
||||
flags |= PTR2INT(clientData);
|
||||
@@ -2972,17 +3094,32 @@ UtfToUcs2Proc(
|
||||
break;
|
||||
}
|
||||
#if TCL_UTF_MAX < 4
|
||||
src += (len = TclUtfToUniChar(src, &ch));
|
||||
len = TclUtfToUniChar(src, &ch);
|
||||
if ((ch >= 0xD800) && (len < 3)) {
|
||||
if (STOPONERROR) {
|
||||
result = TCL_CONVERT_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
src += len;
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
ch = 0xFFFD;
|
||||
}
|
||||
#else
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
len = TclUtfToUniChar(src, &ch);
|
||||
if (ch > 0xFFFF) {
|
||||
if (STOPONERROR) {
|
||||
result = TCL_CONVERT_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
ch = 0xFFFD;
|
||||
}
|
||||
#endif
|
||||
if (STOPONERROR && ((ch & ~0x7FF) == 0xD800)) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
break;
|
||||
}
|
||||
|
||||
src += len;
|
||||
|
||||
/*
|
||||
* Need to handle this in a way that won't cause misalignment by
|
||||
@@ -3084,7 +3221,8 @@ TableToUtfProc(
|
||||
ch = pageZero[byte];
|
||||
}
|
||||
if ((ch == 0) && (byte != 0)) {
|
||||
if (STOPONERROR) {
|
||||
if ((flags & ENCODING_FAILINDEX)
|
||||
|| ((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT)) {
|
||||
result = TCL_CONVERT_SYNTAX;
|
||||
break;
|
||||
}
|
||||
@@ -3823,8 +3961,7 @@ EscapeFromUtfProc(
|
||||
result = TCL_CONVERT_NOSPACE;
|
||||
break;
|
||||
}
|
||||
memcpy(dst, subTablePtr->sequence,
|
||||
subTablePtr->sequenceLen);
|
||||
memcpy(dst, subTablePtr->sequence, subTablePtr->sequenceLen);
|
||||
dst += subTablePtr->sequenceLen;
|
||||
}
|
||||
}
|
||||
@@ -4042,11 +4179,11 @@ unilen4(
|
||||
static void
|
||||
InitializeEncodingSearchPath(
|
||||
char **valuePtr,
|
||||
unsigned int *lengthPtr,
|
||||
TCL_HASH_TYPE *lengthPtr,
|
||||
Tcl_Encoding *encodingPtr)
|
||||
{
|
||||
const char *bytes;
|
||||
int i, numDirs, numBytes;
|
||||
Tcl_Size i, numDirs, numBytes;
|
||||
Tcl_Obj *libPathObj, *encodingObj, *searchPathObj;
|
||||
|
||||
TclNewLiteralStringObj(encodingObj, "encoding");
|
||||
|
||||
@@ -2503,8 +2503,8 @@ TEBCresume(
|
||||
* 'yieldParameter').
|
||||
*/
|
||||
|
||||
Tcl_IncrRefCount(valuePtr);
|
||||
iPtr->execEnvPtr = corPtr->callerEEPtr;
|
||||
Tcl_IncrRefCount(valuePtr);
|
||||
TclSetTailcall(interp, valuePtr);
|
||||
corPtr->yieldPtr = valuePtr;
|
||||
iPtr->execEnvPtr = corPtr->eePtr;
|
||||
|
||||
+88
-38
@@ -165,6 +165,7 @@ static int CheckForDeadChannel(Tcl_Interp *interp,
|
||||
static void CheckForStdChannelsBeingClosed(Tcl_Channel chan);
|
||||
static void CleanupChannelHandlers(Tcl_Interp *interp,
|
||||
Channel *chanPtr);
|
||||
static void CleanupTimerHandler(ChannelState *statePtr);
|
||||
static int CloseChannel(Tcl_Interp *interp, Channel *chanPtr,
|
||||
int errorCode);
|
||||
static int CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr,
|
||||
@@ -172,6 +173,7 @@ static int CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr,
|
||||
static int CloseWrite(Tcl_Interp *interp, Channel *chanPtr);
|
||||
static void CommonGetsCleanup(Channel *chanPtr);
|
||||
static int CopyData(CopyState *csPtr, int mask);
|
||||
static void DeleteTimerHandler(ChannelState *statePtr);
|
||||
static int MoveBytes(CopyState *csPtr);
|
||||
|
||||
static void MBCallback(CopyState *csPtr, Tcl_Obj *errObj);
|
||||
@@ -1730,6 +1732,7 @@ Tcl_CreateChannel(
|
||||
statePtr->scriptRecordPtr = NULL;
|
||||
statePtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE;
|
||||
statePtr->timer = NULL;
|
||||
statePtr->timerChanPtr = NULL;
|
||||
statePtr->csPtrR = NULL;
|
||||
statePtr->csPtrW = NULL;
|
||||
statePtr->outputStage = NULL;
|
||||
@@ -3187,8 +3190,8 @@ CloseChannel(
|
||||
/*
|
||||
* Cancel any outstanding timer.
|
||||
*/
|
||||
DeleteTimerHandler(statePtr);
|
||||
|
||||
Tcl_DeleteTimerHandler(statePtr->timer);
|
||||
|
||||
/*
|
||||
* Mark the channel as deleted by clearing the type structure.
|
||||
@@ -3540,7 +3543,7 @@ Tcl_Close(
|
||||
/*
|
||||
* Cancel any outstanding timer.
|
||||
*/
|
||||
Tcl_DeleteTimerHandler(statePtr->timer);
|
||||
DeleteTimerHandler(statePtr);
|
||||
|
||||
/*
|
||||
* Invoke the registered close callbacks and delete their records.
|
||||
@@ -4015,8 +4018,7 @@ Tcl_ClearChannelHandlers(
|
||||
/*
|
||||
* Cancel any outstanding timer.
|
||||
*/
|
||||
|
||||
Tcl_DeleteTimerHandler(statePtr->timer);
|
||||
DeleteTimerHandler(statePtr);
|
||||
|
||||
/*
|
||||
* Remove any references to channel handlers for this channel that may be
|
||||
@@ -7588,7 +7590,11 @@ Tcl_Eof(
|
||||
ChannelState *statePtr = ((Channel *) chan)->state;
|
||||
/* State of real channel structure. */
|
||||
|
||||
return (GotFlag(statePtr, CHANNEL_EOF) && !GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) ? 1 : 0;
|
||||
if (GotFlag(statePtr, CHANNEL_NONBLOCKING|CHANNEL_FCOPY)
|
||||
&& GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
|
||||
return 0;
|
||||
}
|
||||
return GotFlag(statePtr, CHANNEL_EOF) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -8354,7 +8360,7 @@ Tcl_SetChannelOption(
|
||||
#ifdef TCL_NO_DEPRECATED
|
||||
ResetFlag(statePtr, CHANNEL_ENCODING_NOCOMPLAIN);
|
||||
#else
|
||||
if (SetFlag(statePtr, CHANNEL_ENCODING_STRICT)) {
|
||||
if (GotFlag(statePtr, CHANNEL_ENCODING_STRICT) != CHANNEL_ENCODING_STRICT) {
|
||||
if (interp) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
"bad value for -nocomplainencoding: only true allowed",
|
||||
@@ -8800,8 +8806,10 @@ UpdateInterest(
|
||||
mask &= ~TCL_EXCEPTION;
|
||||
|
||||
if (!statePtr->timer) {
|
||||
TclChannelPreserve((Tcl_Channel)chanPtr);
|
||||
statePtr->timerChanPtr = chanPtr;
|
||||
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
|
||||
ChannelTimerProc, chanPtr);
|
||||
ChannelTimerProc, chanPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8810,6 +8818,8 @@ UpdateInterest(
|
||||
&& mask & TCL_WRITABLE
|
||||
&& GotFlag(statePtr, CHANNEL_NONBLOCKING)) {
|
||||
|
||||
TclChannelPreserve((Tcl_Channel)chanPtr);
|
||||
statePtr->timerChanPtr = chanPtr;
|
||||
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
|
||||
ChannelTimerProc,chanPtr);
|
||||
}
|
||||
@@ -8840,48 +8850,75 @@ ChannelTimerProc(
|
||||
void *clientData)
|
||||
{
|
||||
Channel *chanPtr = (Channel *)clientData;
|
||||
|
||||
/* State info for channel */
|
||||
ChannelState *statePtr = chanPtr->state;
|
||||
|
||||
/* Preserve chanPtr to guard against deallocation in Tcl_NotifyChannel. */
|
||||
TclChannelPreserve((Tcl_Channel)chanPtr);
|
||||
Tcl_Preserve(statePtr);
|
||||
statePtr->timer = NULL;
|
||||
if (statePtr->interestMask & TCL_WRITABLE
|
||||
&& GotFlag(statePtr, CHANNEL_NONBLOCKING)
|
||||
&& !GotFlag(statePtr, BG_FLUSH_SCHEDULED)
|
||||
) {
|
||||
/*
|
||||
* Restart the timer in case a channel handler reenters the event loop
|
||||
* before UpdateInterest gets called by Tcl_NotifyChannel.
|
||||
*/
|
||||
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
|
||||
ChannelTimerProc,chanPtr);
|
||||
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_WRITABLE);
|
||||
}
|
||||
/* TclChannelPreserve() must be called before the current function was
|
||||
* scheduled, is already in effect. In this function it guards against
|
||||
* deallocation in Tcl_NotifyChannel and also keps the channel preserved
|
||||
* until ChannelTimerProc is later called again.
|
||||
*/
|
||||
|
||||
/* The channel may have just been closed from within Tcl_NotifyChannel */
|
||||
if (!GotFlag(statePtr, CHANNEL_INCLOSE)) {
|
||||
if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA)
|
||||
&& (statePtr->interestMask & TCL_READABLE)
|
||||
&& (statePtr->inQueueHead != NULL)
|
||||
&& IsBufferReady(statePtr->inQueueHead)) {
|
||||
if (chanPtr->typePtr == NULL) {
|
||||
CleanupTimerHandler(statePtr);
|
||||
} else {
|
||||
Tcl_Preserve(statePtr);
|
||||
statePtr->timer = NULL;
|
||||
if (statePtr->interestMask & TCL_WRITABLE
|
||||
&& GotFlag(statePtr, CHANNEL_NONBLOCKING)
|
||||
&& !GotFlag(statePtr, BG_FLUSH_SCHEDULED)
|
||||
) {
|
||||
/*
|
||||
* Restart the timer in case a channel handler reenters the event loop
|
||||
* before UpdateInterest gets called by Tcl_NotifyChannel.
|
||||
*/
|
||||
|
||||
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
|
||||
ChannelTimerProc,chanPtr);
|
||||
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
|
||||
ChannelTimerProc,chanPtr);
|
||||
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_WRITABLE);
|
||||
} else {
|
||||
UpdateInterest(chanPtr);
|
||||
}
|
||||
}
|
||||
/* The channel may have just been closed from within Tcl_NotifyChannel */
|
||||
if (!GotFlag(statePtr, CHANNEL_INCLOSE)) {
|
||||
if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA)
|
||||
&& (statePtr->interestMask & TCL_READABLE)
|
||||
&& (statePtr->inQueueHead != NULL)
|
||||
&& IsBufferReady(statePtr->inQueueHead)) {
|
||||
/*
|
||||
* Restart the timer in case a channel handler reenters the event loop
|
||||
* before UpdateInterest gets called by Tcl_NotifyChannel.
|
||||
*/
|
||||
|
||||
Tcl_Release(statePtr);
|
||||
TclChannelRelease((Tcl_Channel)chanPtr);
|
||||
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
|
||||
ChannelTimerProc,chanPtr);
|
||||
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
|
||||
} else {
|
||||
CleanupTimerHandler(statePtr);
|
||||
UpdateInterest(chanPtr);
|
||||
}
|
||||
} else {
|
||||
CleanupTimerHandler(statePtr);
|
||||
}
|
||||
}
|
||||
Tcl_Release(statePtr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DeleteTimerHandler(
|
||||
ChannelState *statePtr
|
||||
)
|
||||
{
|
||||
if (statePtr->timer != NULL) {
|
||||
Tcl_DeleteTimerHandler(statePtr->timer);
|
||||
CleanupTimerHandler(statePtr);
|
||||
}
|
||||
}
|
||||
static void
|
||||
CleanupTimerHandler(
|
||||
ChannelState *statePtr
|
||||
){
|
||||
TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr);
|
||||
statePtr->timer = NULL;
|
||||
statePtr->timerChanPtr = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9799,6 +9836,7 @@ CopyData(
|
||||
* the bottom of the stack.
|
||||
*/
|
||||
|
||||
SetFlag(inStatePtr, CHANNEL_FCOPY);
|
||||
inBinary = (inStatePtr->encoding == NULL);
|
||||
outBinary = (outStatePtr->encoding == NULL);
|
||||
sameEncoding = inStatePtr->encoding == outStatePtr->encoding
|
||||
@@ -9820,12 +9858,20 @@ CopyData(
|
||||
Tcl_SetErrno(inStatePtr->unreportedError);
|
||||
inStatePtr->unreportedError = 0;
|
||||
goto readError;
|
||||
} else if (inStatePtr->flags & CHANNEL_ENCODING_ERROR) {
|
||||
Tcl_SetErrno(EILSEQ);
|
||||
inStatePtr->flags &= ~CHANNEL_ENCODING_ERROR;
|
||||
goto readError;
|
||||
}
|
||||
Tcl_GetChannelError(outChan, &msg);
|
||||
if ((outStatePtr->unreportedError != 0) || (msg != NULL)) {
|
||||
Tcl_SetErrno(outStatePtr->unreportedError);
|
||||
outStatePtr->unreportedError = 0;
|
||||
goto writeError;
|
||||
} else if (outStatePtr->flags & CHANNEL_ENCODING_ERROR) {
|
||||
Tcl_SetErrno(EILSEQ);
|
||||
outStatePtr->flags &= ~CHANNEL_ENCODING_ERROR;
|
||||
goto writeError;
|
||||
}
|
||||
|
||||
if (cmdPtr && (mask == 0)) {
|
||||
@@ -9906,6 +9952,7 @@ CopyData(
|
||||
TclDecrRefCount(bufObj);
|
||||
bufObj = NULL;
|
||||
}
|
||||
ResetFlag(inStatePtr, CHANNEL_FCOPY);
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
@@ -9997,6 +10044,7 @@ CopyData(
|
||||
TclDecrRefCount(bufObj);
|
||||
bufObj = NULL;
|
||||
}
|
||||
ResetFlag(inStatePtr, CHANNEL_FCOPY);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -10019,6 +10067,7 @@ CopyData(
|
||||
TclDecrRefCount(bufObj);
|
||||
bufObj = NULL;
|
||||
}
|
||||
ResetFlag(inStatePtr, CHANNEL_FCOPY);
|
||||
return TCL_OK;
|
||||
}
|
||||
} /* while */
|
||||
@@ -10071,6 +10120,7 @@ CopyData(
|
||||
}
|
||||
}
|
||||
}
|
||||
ResetFlag(inStatePtr, CHANNEL_FCOPY);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,6 +188,9 @@ typedef struct ChannelState {
|
||||
* handlers ("fileevent") on this channel. */
|
||||
Tcl_Size bufSize; /* What size buffers to allocate? */
|
||||
Tcl_TimerToken timer; /* Handle to wakeup timer for this channel. */
|
||||
Channel *timerChanPtr; /* Needed in order to decrement the refCount of
|
||||
the right channel when the timer is
|
||||
deleted. */
|
||||
struct CopyState *csPtrR; /* State of background copy for which channel
|
||||
* is input, or NULL. */
|
||||
struct CopyState *csPtrW; /* State of background copy for which channel
|
||||
@@ -233,6 +236,8 @@ typedef struct ChannelState {
|
||||
* flushed after every newline. */
|
||||
#define CHANNEL_UNBUFFERED (1<<5) /* Output to the channel must always
|
||||
* be flushed immediately. */
|
||||
#define CHANNEL_FCOPY (1<<6) /* Channel is currently doing an fcopy
|
||||
* mode. */
|
||||
#define BG_FLUSH_SCHEDULED (1<<7) /* A background flush of the queued
|
||||
* output buffers has been
|
||||
* scheduled. */
|
||||
|
||||
@@ -2830,6 +2830,7 @@ DeleteThreadReflectedChannelMap(
|
||||
Tcl_ThreadId self = Tcl_GetCurrentThread();
|
||||
ReflectedChannelMap *rcmPtr; /* The map */
|
||||
ForwardingResult *resultPtr;
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
|
||||
/*
|
||||
* The origin thread for one or more reflected channels is gone.
|
||||
@@ -2909,6 +2910,7 @@ DeleteThreadReflectedChannelMap(
|
||||
*/
|
||||
|
||||
rcmPtr = GetThreadReflectedChannelMap();
|
||||
tsdPtr->rcmPtr = NULL;
|
||||
for (hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch);
|
||||
hPtr != NULL;
|
||||
hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) {
|
||||
|
||||
@@ -417,6 +417,8 @@ Tcl_PopCallFrame(
|
||||
framePtr->nsPtr = NULL;
|
||||
|
||||
if (framePtr->tailcallPtr) {
|
||||
/* Reusing the existing reference count from framePtr->tailcallPtr, so
|
||||
* no need to Tcl_IncrRefCount(framePtr->tailcallPtr)*/
|
||||
TclSetTailcall(interp, framePtr->tailcallPtr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4849,6 +4849,7 @@ ExtendStringRepWithUnicode(
|
||||
|
||||
copyBytes:
|
||||
dst = objPtr->bytes + origLength;
|
||||
*dst = '\0';
|
||||
for (i = 0; i < numChars; i++) {
|
||||
dst += Tcl_UniCharToUtf(unicode[i], dst);
|
||||
}
|
||||
|
||||
+295
-17
@@ -70,6 +70,7 @@ static Tcl_Interp *delInterp;
|
||||
typedef struct TestCommandTokenRef {
|
||||
int id; /* Identifier for this reference. */
|
||||
Tcl_Command token; /* Tcl's token for the command. */
|
||||
const char *value;
|
||||
struct TestCommandTokenRef *nextPtr;
|
||||
/* Next in list of references. */
|
||||
} TestCommandTokenRef;
|
||||
@@ -1178,6 +1179,18 @@ TestcmdinfoCmd(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
CmdProc0(
|
||||
void *clientData, /* String to return. */
|
||||
Tcl_Interp *interp, /* Current interpreter. */
|
||||
TCL_UNUSED(int) /*argc*/,
|
||||
TCL_UNUSED(const char **) /*argv*/)
|
||||
{
|
||||
TestCommandTokenRef *refPtr = (TestCommandTokenRef *) clientData;
|
||||
Tcl_AppendResult(interp, "CmdProc1 ", refPtr->value, NULL);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
CmdProc1(
|
||||
void *clientData, /* String to return. */
|
||||
@@ -1189,6 +1202,7 @@ CmdProc1(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
CmdProc2(
|
||||
void *clientData, /* String to return. */
|
||||
@@ -1200,6 +1214,28 @@ CmdProc2(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
CmdDelProc0(
|
||||
void *clientData) /* String to save. */
|
||||
{
|
||||
TestCommandTokenRef *thisRefPtr, *prevRefPtr = NULL;
|
||||
TestCommandTokenRef *refPtr = (TestCommandTokenRef *) clientData;
|
||||
int id = refPtr->id;
|
||||
for (thisRefPtr = firstCommandTokenRef; refPtr != NULL;
|
||||
thisRefPtr = thisRefPtr->nextPtr) {
|
||||
if (thisRefPtr->id == id) {
|
||||
if (prevRefPtr != NULL) {
|
||||
prevRefPtr->nextPtr = thisRefPtr->nextPtr;
|
||||
} else {
|
||||
firstCommandTokenRef = thisRefPtr->nextPtr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prevRefPtr = thisRefPtr;
|
||||
}
|
||||
ckfree(refPtr);
|
||||
}
|
||||
|
||||
static void
|
||||
CmdDelProc1(
|
||||
void *clientData) /* String to save. */
|
||||
@@ -1253,17 +1289,16 @@ TestcmdtokenCmd(
|
||||
}
|
||||
if (strcmp(argv[1], "create") == 0) {
|
||||
refPtr = (TestCommandTokenRef *)Tcl_Alloc(sizeof(TestCommandTokenRef));
|
||||
refPtr->token = Tcl_CreateCommand(interp, argv[2], CmdProc1,
|
||||
(void *) "original", NULL);
|
||||
refPtr->token = Tcl_CreateCommand(interp, argv[2], CmdProc0,
|
||||
refPtr, CmdDelProc0);
|
||||
refPtr->id = nextCommandTokenRefId;
|
||||
refPtr->value = "original";
|
||||
nextCommandTokenRefId++;
|
||||
refPtr->nextPtr = firstCommandTokenRef;
|
||||
firstCommandTokenRef = refPtr;
|
||||
sprintf(buf, "%d", refPtr->id);
|
||||
Tcl_AppendResult(interp, buf, NULL);
|
||||
} else if (strcmp(argv[1], "name") == 0) {
|
||||
Tcl_Obj *objPtr;
|
||||
|
||||
} else {
|
||||
if (sscanf(argv[2], "%d", &id) != 1) {
|
||||
Tcl_AppendResult(interp, "bad command token \"", argv[2],
|
||||
"\"", NULL);
|
||||
@@ -1283,18 +1318,23 @@ TestcmdtokenCmd(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
objPtr = Tcl_NewObj();
|
||||
Tcl_GetCommandFullName(interp, refPtr->token, objPtr);
|
||||
if (strcmp(argv[1], "name") == 0) {
|
||||
Tcl_Obj *objPtr;
|
||||
|
||||
Tcl_AppendElement(interp,
|
||||
Tcl_GetCommandName(interp, refPtr->token));
|
||||
Tcl_AppendElement(interp, Tcl_GetString(objPtr));
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
} else {
|
||||
Tcl_AppendResult(interp, "bad option \"", argv[1],
|
||||
"\": must be create or name", NULL);
|
||||
return TCL_ERROR;
|
||||
objPtr = Tcl_NewObj();
|
||||
Tcl_GetCommandFullName(interp, refPtr->token, objPtr);
|
||||
|
||||
Tcl_AppendElement(interp,
|
||||
Tcl_GetCommandName(interp, refPtr->token));
|
||||
Tcl_AppendElement(interp, Tcl_GetString(objPtr));
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
} else {
|
||||
Tcl_AppendResult(interp, "bad option \"", argv[1],
|
||||
"\": must be create, name, or free", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -1974,6 +2014,238 @@ static void SpecialFree(
|
||||
) {
|
||||
ckfree(blockPtr - 16);
|
||||
}
|
||||
|
||||
/*
|
||||
*------------------------------------------------------------------------
|
||||
*
|
||||
* UtfTransformFn --
|
||||
*
|
||||
* Implements a direct call into Tcl_UtfToExternal and Tcl_ExternalToUtf
|
||||
* as otherwise there is no script level command that directly exercises
|
||||
* these functions (i/o command cannot test all combinations)
|
||||
* The arguments at the script level are roughly those of the above
|
||||
* functions:
|
||||
* encodingname srcbytes flags state dstlen ?srcreadvar? ?dstwrotevar? ?dstcharsvar?
|
||||
*
|
||||
* Results:
|
||||
* TCL_OK or TCL_ERROR. This any errors running the test, NOT the
|
||||
* result of Tcl_UtfToExternal or Tcl_ExternalToUtf.
|
||||
*
|
||||
* Side effects:
|
||||
*
|
||||
* The result in the interpreter is a list of the return code from the
|
||||
* Tcl_UtfToExternal/Tcl_ExternalToUtf functions, the encoding state, and
|
||||
* an encoded binary string of length dstLen. Note the string is the
|
||||
* entire output buffer, not just the part containing the decoded
|
||||
* portion. This allows for additional checks at test script level.
|
||||
*
|
||||
* If any of the srcreadvar, dstwrotevar and
|
||||
* dstcharsvar are specified and not empty, they are treated as names
|
||||
* of variables where the *srcRead, *dstWrote and *dstChars output
|
||||
* from the functions are stored.
|
||||
*
|
||||
* The function also checks internally whether nuls are correctly
|
||||
* appended as requested but the TCL_ENCODING_NO_TERMINATE flag
|
||||
* and that no buffer overflows occur.
|
||||
*------------------------------------------------------------------------
|
||||
*/
|
||||
typedef int
|
||||
UtfTransformFn(Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, int flags, Tcl_EncodingState *statePtr,
|
||||
char *dst, Tcl_Size dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr);
|
||||
static int UtfExtWrapper(
|
||||
Tcl_Interp *interp, UtfTransformFn *transformer, int objc, Tcl_Obj *const objv[])
|
||||
{
|
||||
Tcl_Encoding encoding;
|
||||
Tcl_EncodingState encState, *encStatePtr;
|
||||
Tcl_Size srcLen, bufLen;
|
||||
const unsigned char *bytes;
|
||||
unsigned char *bufPtr;
|
||||
int srcRead, dstLen, dstWrote, dstChars;
|
||||
Tcl_Obj *srcReadVar, *dstWroteVar, *dstCharsVar;
|
||||
int result;
|
||||
int flags;
|
||||
Tcl_Obj **flagObjs;
|
||||
int nflags;
|
||||
|
||||
if (objc < 7 || objc > 10) {
|
||||
Tcl_WrongNumArgs(interp,
|
||||
2,
|
||||
objv,
|
||||
"encoding srcbytes flags state dstlen ?srcreadvar? ?dstwrotevar? ?dstcharsvar?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (Tcl_GetEncodingFromObj(interp, objv[2], &encoding) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* Flags may be specified as list of integers and keywords */
|
||||
flags = 0;
|
||||
if (Tcl_ListObjGetElements(interp, objv[4], &nflags, &flagObjs) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
struct {
|
||||
const char *flagKey;
|
||||
int flag;
|
||||
} flagMap[] = {
|
||||
{"start", TCL_ENCODING_START},
|
||||
{"end", TCL_ENCODING_END},
|
||||
{"stoponerror", TCL_ENCODING_STOPONERROR},
|
||||
{"noterminate", TCL_ENCODING_NO_TERMINATE},
|
||||
{"charlimit", TCL_ENCODING_CHAR_LIMIT},
|
||||
{NULL, 0}
|
||||
};
|
||||
int i;
|
||||
for (i = 0; i < nflags; ++i) {
|
||||
int flag;
|
||||
if (Tcl_GetIntFromObj(NULL, flagObjs[i], &flag) == TCL_OK) {
|
||||
flags |= flag;
|
||||
}
|
||||
else {
|
||||
int idx;
|
||||
if (Tcl_GetIndexFromObjStruct(interp,
|
||||
flagObjs[i],
|
||||
flagMap,
|
||||
sizeof(flagMap[0]),
|
||||
"flag",
|
||||
0,
|
||||
&idx) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
flags |= flagMap[idx].flag;
|
||||
}
|
||||
}
|
||||
|
||||
/* Assumes state is integer if not "" */
|
||||
Tcl_WideInt wide;
|
||||
if (Tcl_GetWideIntFromObj(interp, objv[5], &wide) == TCL_OK) {
|
||||
encState = (Tcl_EncodingState) wide;
|
||||
encStatePtr = &encState;
|
||||
} else if (Tcl_GetCharLength(objv[5]) == 0) {
|
||||
encStatePtr = NULL;
|
||||
} else {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if (Tcl_GetIntFromObj(interp, objv[6], &dstLen) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
srcReadVar = NULL;
|
||||
dstWroteVar = NULL;
|
||||
dstCharsVar = NULL;
|
||||
if (objc > 7) {
|
||||
/* Has caller requested srcRead? */
|
||||
if (Tcl_GetCharLength(objv[7])) {
|
||||
srcReadVar = objv[7];
|
||||
}
|
||||
if (objc > 8) {
|
||||
/* Ditto for dstWrote */
|
||||
if (Tcl_GetCharLength(objv[8])) {
|
||||
dstWroteVar = objv[8];
|
||||
}
|
||||
if (objc > 9) {
|
||||
if (Tcl_GetCharLength(objv[9])) {
|
||||
dstCharsVar = objv[9];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags & TCL_ENCODING_CHAR_LIMIT) {
|
||||
/* Caller should have specified the dest char limit */
|
||||
Tcl_Obj *valueObj;
|
||||
if (dstCharsVar == NULL ||
|
||||
(valueObj = Tcl_ObjGetVar2(interp, dstCharsVar, NULL, 0)) == NULL
|
||||
) {
|
||||
Tcl_SetResult(interp,
|
||||
"dstCharsVar must be specified with integer value if "
|
||||
"TCL_ENCODING_CHAR_LIMIT set in flags.", TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (Tcl_GetIntFromObj(interp, valueObj, &dstChars) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
} else {
|
||||
dstChars = 0; /* Only used for output */
|
||||
}
|
||||
|
||||
bufLen = dstLen + 4; /* 4 -> overflow detection */
|
||||
bufPtr = (unsigned char *)Tcl_Alloc(bufLen);
|
||||
memset(bufPtr, 0xFF, dstLen); /* Need to check nul terminator */
|
||||
memmove(bufPtr + dstLen, "\xAB\xCD\xEF\xAB", 4); /* overflow detection */
|
||||
bytes = Tcl_GetByteArrayFromObj(objv[3], &srcLen); /* Last! to avoid shimmering */
|
||||
result = (*transformer)(interp, encoding, (const char *) bytes, srcLen, flags,
|
||||
encStatePtr, (char *) bufPtr, dstLen,
|
||||
srcReadVar ? &srcRead : NULL,
|
||||
&dstWrote,
|
||||
dstCharsVar ? &dstChars : NULL);
|
||||
if (memcmp(bufPtr + bufLen - 4, "\xAB\xCD\xEF\xAB", 4)) {
|
||||
Tcl_SetResult(interp,
|
||||
"Tcl_ExternalToUtf wrote past output buffer",
|
||||
TCL_STATIC);
|
||||
result = TCL_ERROR;
|
||||
} else if (result != TCL_ERROR) {
|
||||
|
||||
Tcl_Obj *resultObjs[3];
|
||||
|
||||
switch (result) {
|
||||
case TCL_OK:
|
||||
resultObjs[0] = Tcl_NewStringObj("ok", -1);
|
||||
break;
|
||||
case TCL_CONVERT_MULTIBYTE:
|
||||
resultObjs[0] = Tcl_NewStringObj("multibyte", -1);
|
||||
break;
|
||||
case TCL_CONVERT_SYNTAX:
|
||||
resultObjs[0] = Tcl_NewStringObj("syntax", -1);
|
||||
break;
|
||||
case TCL_CONVERT_UNKNOWN:
|
||||
resultObjs[0] = Tcl_NewStringObj("unknown", -1);
|
||||
break;
|
||||
case TCL_CONVERT_NOSPACE:
|
||||
resultObjs[0] = Tcl_NewStringObj("nospace", -1);
|
||||
break;
|
||||
default:
|
||||
resultObjs[0] = Tcl_NewIntObj(result);
|
||||
break;
|
||||
}
|
||||
result = TCL_OK;
|
||||
resultObjs[1] =
|
||||
encStatePtr ? Tcl_NewWideIntObj((Tcl_WideInt)encState) : Tcl_NewObj();
|
||||
resultObjs[2] = Tcl_NewByteArrayObj(bufPtr, dstLen);
|
||||
if (srcReadVar) {
|
||||
if (Tcl_ObjSetVar2(interp,
|
||||
srcReadVar,
|
||||
NULL,
|
||||
Tcl_NewIntObj(srcRead),
|
||||
TCL_LEAVE_ERR_MSG) == NULL) {
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
}
|
||||
if (dstWroteVar) {
|
||||
if (Tcl_ObjSetVar2(interp,
|
||||
dstWroteVar,
|
||||
NULL,
|
||||
Tcl_NewIntObj(dstWrote),
|
||||
TCL_LEAVE_ERR_MSG) == NULL) {
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
}
|
||||
if (dstCharsVar) {
|
||||
if (Tcl_ObjSetVar2(interp,
|
||||
dstCharsVar,
|
||||
NULL,
|
||||
Tcl_NewIntObj(dstChars),
|
||||
TCL_LEAVE_ERR_MSG) == NULL) {
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewListObj(3, resultObjs));
|
||||
}
|
||||
|
||||
ckfree(bufPtr);
|
||||
Tcl_FreeEncoding(encoding); /* Free returned reference */
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -2004,10 +2276,10 @@ TestencodingObjCmd(
|
||||
const char *string;
|
||||
TclEncoding *encodingPtr;
|
||||
static const char *const optionStrings[] = {
|
||||
"create", "delete", "nullength", NULL
|
||||
"create", "delete", "nullength", "Tcl_ExternalToUtf", "Tcl_UtfToExternal", NULL
|
||||
};
|
||||
enum options {
|
||||
ENC_CREATE, ENC_DELETE, ENC_NULLENGTH
|
||||
ENC_CREATE, ENC_DELETE, ENC_NULLENGTH, ENC_EXTTOUTF, ENC_UTFTOEXT
|
||||
};
|
||||
|
||||
if (objc < 2) {
|
||||
@@ -2076,6 +2348,12 @@ TestencodingObjCmd(
|
||||
Tcl_SetObjResult(interp,
|
||||
Tcl_NewIntObj(Tcl_GetEncodingNulLength(encoding)));
|
||||
Tcl_FreeEncoding(encoding);
|
||||
break;
|
||||
|
||||
case ENC_EXTTOUTF:
|
||||
return UtfExtWrapper(interp,Tcl_ExternalToUtf,objc,objv);
|
||||
case ENC_UTFTOEXT:
|
||||
return UtfExtWrapper(interp,Tcl_UtfToExternal,objc,objv);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
+19
-2
@@ -1269,7 +1269,7 @@ TeststringobjCmd(
|
||||
static const char *const options[] = {
|
||||
"append", "appendstrings", "get", "get2", "length", "length2",
|
||||
"set", "set2", "setlength", "maxchars", "range", "appendself",
|
||||
"appendself2", NULL
|
||||
"appendself2", "newunicode", NULL
|
||||
};
|
||||
|
||||
if (objc < 3) {
|
||||
@@ -1513,7 +1513,24 @@ TeststringobjCmd(
|
||||
Tcl_AppendUnicodeToObj(varPtr[varIndex], unicode + length, size - length);
|
||||
Tcl_SetObjResult(interp, varPtr[varIndex]);
|
||||
break;
|
||||
}
|
||||
case 13: /* newunicode*/
|
||||
unicode = (unsigned short *) ckalloc((objc - 3) * sizeof(unsigned short));
|
||||
for (i = 0; i < (objc - 3); ++i) {
|
||||
int val;
|
||||
if (Tcl_GetIntFromObj(interp, objv[i + 3], &val) != TCL_OK) {
|
||||
break;
|
||||
}
|
||||
unicode[i] = (unsigned short)val;
|
||||
}
|
||||
if (i < (objc-3)) {
|
||||
ckfree(unicode);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
SetVarToObj(varPtr, varIndex, Tcl_NewUnicodeObj(unicode, objc - 3));
|
||||
Tcl_SetObjResult(interp, varPtr[varIndex]);
|
||||
ckfree(unicode);
|
||||
break;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
+36
-35
@@ -182,25 +182,22 @@ Invalid(
|
||||
*
|
||||
* Tcl_UniCharToUtf --
|
||||
*
|
||||
* Store the given Tcl_UniChar as a sequence of UTF-8 bytes in the
|
||||
* Stores the given Tcl_UniChar as a sequence of UTF-8 bytes in the
|
||||
* provided buffer. Equivalent to Plan 9 runetochar().
|
||||
*
|
||||
* Special handling of Surrogate pairs is handled as follows:
|
||||
* When this function is called for ch being a high surrogate,
|
||||
* the first byte of the 4-byte UTF-8 sequence is produced and
|
||||
* the function returns 1. Calling the function again with a
|
||||
* low surrogate, the remaining 3 bytes of the 4-byte UTF-8
|
||||
* sequence is produced, and the function returns 3. The buffer
|
||||
* is used to remember the high surrogate between the two calls.
|
||||
* Surrogate pairs are handled as follows: When ch is a high surrogate,
|
||||
* the first byte of the 4-byte UTF-8 sequence is stored in the buffer and
|
||||
* the function returns 1. If the function is called again with a low
|
||||
* surrogate and the same buffer, the remaining 3 bytes of the 4-byte
|
||||
* UTF-8 sequence are produced.
|
||||
*
|
||||
* If no low surrogate follows the high surrogate (which is actually
|
||||
* illegal), this can be handled reasonably by calling Tcl_UniCharToUtf
|
||||
* again with ch = -1. This will produce a 3-byte UTF-8 sequence
|
||||
* again with ch = -1. This produces a 3-byte UTF-8 sequence
|
||||
* representing the high surrogate.
|
||||
*
|
||||
* Results:
|
||||
* The return values is the number of bytes in the buffer that were
|
||||
* consumed.
|
||||
* Returns the number of bytes stored into the buffer.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
@@ -223,18 +220,19 @@ Tcl_UniCharToUtf(
|
||||
}
|
||||
if (ch >= 0) {
|
||||
if (ch <= 0x7FF) {
|
||||
buf[1] = (char) ((ch | 0x80) & 0xBF);
|
||||
buf[0] = (char) ((ch >> 6) | 0xC0);
|
||||
buf[1] = (char) (0x80 | (0x3F & ch));
|
||||
buf[0] = (char) (0xC0 | (ch >> 6));
|
||||
return 2;
|
||||
}
|
||||
if (ch <= 0xFFFF) {
|
||||
if ((ch & 0xF800) == 0xD800) {
|
||||
if (ch & 0x0400) {
|
||||
/* Low surrogate */
|
||||
if (((buf[0] & 0xC0) == 0x80) && ((buf[1] & 0xCF) == 0)) {
|
||||
if ( (0x80 == (0xC0 & buf[0]))
|
||||
&& (0 == (0xCF & buf[1]))) {
|
||||
/* Previous Tcl_UniChar was a high surrogate, so combine */
|
||||
buf[2] = (char) ((ch & 0x3F) | 0x80);
|
||||
buf[1] |= (char) (((ch >> 6) & 0x0F) | 0x80);
|
||||
buf[2] = (char) (0x80 | (0x3F & ch));
|
||||
buf[1] |= (char) (0x80 | (0x0F & (ch >> 6)));
|
||||
return 3;
|
||||
}
|
||||
/* Previous Tcl_UniChar was not a high surrogate, so just output */
|
||||
@@ -244,37 +242,40 @@ Tcl_UniCharToUtf(
|
||||
/* Fill buffer with specific 3-byte (invalid) byte combination,
|
||||
so following low surrogate can recognize it and combine */
|
||||
buf[2] = (char) ((ch << 4) & 0x30);
|
||||
buf[1] = (char) (((ch >> 2) & 0x3F) | 0x80);
|
||||
buf[0] = (char) (((ch >> 8) & 0x07) | 0xF0);
|
||||
buf[1] = (char) (0x80 | (0x3F & (ch >> 2)));
|
||||
buf[0] = (char) (0xF0 | (0x07 & (ch >> 8)));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
goto three;
|
||||
}
|
||||
if (ch <= 0x10FFFF) {
|
||||
buf[3] = (char) ((ch | 0x80) & 0xBF);
|
||||
buf[2] = (char) (((ch >> 6) | 0x80) & 0xBF);
|
||||
buf[1] = (char) (((ch >> 12) | 0x80) & 0xBF);
|
||||
buf[0] = (char) ((ch >> 18) | 0xF0);
|
||||
buf[3] = (char) (0x80 | (0x3F & ch));
|
||||
buf[2] = (char) (0x80 | (0x3F & (ch >> 6)));
|
||||
buf[1] = (char) (0x80 | (0x3F & (ch >> 12)));
|
||||
buf[0] = (char) (0xF0 | (ch >> 18));
|
||||
return 4;
|
||||
}
|
||||
} else if (ch == -1) {
|
||||
if (((buf[0] & 0xC0) == 0x80) && ((buf[1] & 0xCF) == 0)
|
||||
&& ((buf[-1] & 0xF8) == 0xF0)) {
|
||||
ch = 0xD7C0 + ((buf[-1] & 0x07) << 8) + ((buf[0] & 0x3F) << 2)
|
||||
+ ((buf[1] & 0x30) >> 4);
|
||||
buf[1] = (char) ((ch | 0x80) & 0xBF);
|
||||
buf[0] = (char) (((ch >> 6) | 0x80) & 0xBF);
|
||||
buf[-1] = (char) ((ch >> 12) | 0xE0);
|
||||
if ( (0x80 == (0xC0 & buf[0]))
|
||||
&& (0 == (0xCF & buf[1]))
|
||||
&& (0xF0 == (0xF8 & buf[-1]))) {
|
||||
ch = 0xD7C0
|
||||
+ ((0x07 & buf[-1]) << 8)
|
||||
+ ((0x3F & buf[0]) << 2)
|
||||
+ ((0x30 & buf[1]) >> 4);
|
||||
buf[1] = (char) (0x80 | (0x3F & ch));
|
||||
buf[0] = (char) (0x80 | (0x3F & (ch >> 6)));
|
||||
buf[-1] = (char) (0xE0 | (ch >> 12));
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
ch = 0xFFFD;
|
||||
three:
|
||||
buf[2] = (char) ((ch | 0x80) & 0xBF);
|
||||
buf[1] = (char) (((ch >> 6) | 0x80) & 0xBF);
|
||||
buf[0] = (char) ((ch >> 12) | 0xE0);
|
||||
buf[2] = (char) (0x80 | (0x3F & ch));
|
||||
buf[1] = (char) (0x80 | (0x3F & (ch >> 6)));
|
||||
buf[0] = (char) (0xE0 | (ch >> 12));
|
||||
return 3;
|
||||
}
|
||||
|
||||
@@ -2948,7 +2949,7 @@ TclUniCharMatch(
|
||||
*
|
||||
* TclUtfToUCS4 --
|
||||
*
|
||||
* Extract the 4-byte codepoint from the leading bytes of the
|
||||
* Extracts the 4-byte codepoint from the leading bytes of the
|
||||
* Modified UTF-8 string "src". This is a utility routine to
|
||||
* contain the surrogate gymnastics in one place.
|
||||
*
|
||||
@@ -2960,8 +2961,8 @@ TclUniCharMatch(
|
||||
* enough bytes remain in the string.
|
||||
*
|
||||
* Results:
|
||||
* *usc4Ptr is filled with the UCS4 code point, and the return value is
|
||||
* the number of bytes from the UTF-8 string that were consumed.
|
||||
* Fills *usc4Ptr with the UCS4 code point and returns the number of bytes
|
||||
* consumed from the source string.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
|
||||
+47
-9
@@ -442,10 +442,25 @@ GenerateHeader(
|
||||
if (GetValue(interp, dictObj, "comment", &value) != TCL_OK) {
|
||||
goto error;
|
||||
} else if (value != NULL) {
|
||||
Tcl_EncodingState state;
|
||||
valueStr = TclGetStringFromObj(value, &len);
|
||||
Tcl_UtfToExternal(NULL, latin1enc, valueStr, len, 0, NULL,
|
||||
result = Tcl_UtfToExternal(NULL, latin1enc, valueStr, len,
|
||||
TCL_ENCODING_START|TCL_ENCODING_END|TCL_ENCODING_STOPONERROR, &state,
|
||||
headerPtr->nativeCommentBuf, MAX_COMMENT_LEN-1, NULL, &len,
|
||||
NULL);
|
||||
if (result != TCL_OK) {
|
||||
if (interp) {
|
||||
if (result == TCL_CONVERT_UNKNOWN) {
|
||||
Tcl_AppendResult(
|
||||
interp, "Comment contains characters > 0xFF", NULL);
|
||||
}
|
||||
else {
|
||||
Tcl_AppendResult(interp, "Comment too large for zip", NULL);
|
||||
}
|
||||
}
|
||||
result = TCL_ERROR; /* TCL_CONVERT_* -> TCL_ERROR*/
|
||||
goto error;
|
||||
}
|
||||
headerPtr->nativeCommentBuf[len] = '\0';
|
||||
headerPtr->header.comment = (Bytef *) headerPtr->nativeCommentBuf;
|
||||
if (extraSizePtr != NULL) {
|
||||
@@ -463,9 +478,26 @@ GenerateHeader(
|
||||
if (GetValue(interp, dictObj, "filename", &value) != TCL_OK) {
|
||||
goto error;
|
||||
} else if (value != NULL) {
|
||||
Tcl_EncodingState state;
|
||||
valueStr = TclGetStringFromObj(value, &len);
|
||||
Tcl_UtfToExternal(NULL, latin1enc, valueStr, len, 0, NULL,
|
||||
headerPtr->nativeFilenameBuf, MAXPATHLEN-1, NULL, &len, NULL);
|
||||
result = Tcl_UtfToExternal(NULL, latin1enc, valueStr, len,
|
||||
TCL_ENCODING_START|TCL_ENCODING_END|TCL_ENCODING_STOPONERROR, &state,
|
||||
headerPtr->nativeFilenameBuf, MAXPATHLEN-1, NULL, &len,
|
||||
NULL);
|
||||
if (result != TCL_OK) {
|
||||
if (interp) {
|
||||
if (result == TCL_CONVERT_UNKNOWN) {
|
||||
Tcl_AppendResult(
|
||||
interp, "Filename contains characters > 0xFF", NULL);
|
||||
}
|
||||
else {
|
||||
Tcl_AppendResult(
|
||||
interp, "Filename too large for zip", NULL);
|
||||
}
|
||||
}
|
||||
result = TCL_ERROR; /* TCL_CONVERT_* -> TCL_ERROR*/
|
||||
goto error;
|
||||
}
|
||||
headerPtr->nativeFilenameBuf[len] = '\0';
|
||||
headerPtr->header.name = (Bytef *) headerPtr->nativeFilenameBuf;
|
||||
if (extraSizePtr != NULL) {
|
||||
@@ -1196,7 +1228,8 @@ Tcl_ZlibStreamPut(
|
||||
{
|
||||
ZlibStreamHandle *zshPtr = (ZlibStreamHandle *) zshandle;
|
||||
char *dataTmp = NULL;
|
||||
int e, size, outSize, toStore;
|
||||
int e;
|
||||
int size, outSize, toStore;
|
||||
unsigned char *bytes;
|
||||
|
||||
if (zshPtr->streamEnd) {
|
||||
@@ -1325,7 +1358,8 @@ Tcl_ZlibStreamGet(
|
||||
* may get less! */
|
||||
{
|
||||
ZlibStreamHandle *zshPtr = (ZlibStreamHandle *) zshandle;
|
||||
int e, i, listLen, itemLen, dataPos = 0;
|
||||
int e;
|
||||
int i, listLen, itemLen, dataPos = 0;
|
||||
Tcl_Obj *itemObj;
|
||||
unsigned char *dataPtr, *itemPtr;
|
||||
int existing;
|
||||
@@ -1576,7 +1610,8 @@ Tcl_ZlibDeflate(
|
||||
int level,
|
||||
Tcl_Obj *gzipHeaderDictObj)
|
||||
{
|
||||
int wbits = 0, inLen = 0, e = 0, extraSize = 0;
|
||||
int wbits = 0, e = 0, extraSize = 0;
|
||||
int inLen = 0;
|
||||
Byte *inData = NULL;
|
||||
z_stream stream;
|
||||
GzipHeader header;
|
||||
@@ -1730,7 +1765,8 @@ Tcl_ZlibInflate(
|
||||
int bufferSize,
|
||||
Tcl_Obj *gzipHeaderDictObj)
|
||||
{
|
||||
int wbits = 0, inLen = 0, e = 0, newBufferSize;
|
||||
int wbits = 0, e = 0;
|
||||
int inLen = 0, newBufferSize;
|
||||
Byte *inData = NULL, *outData = NULL, *newOutData = NULL;
|
||||
z_stream stream;
|
||||
gz_header header, *headerPtr = NULL;
|
||||
@@ -2400,7 +2436,8 @@ ZlibPushSubcmd(
|
||||
const char *const *pushOptions = pushDecompressOptions;
|
||||
enum pushOptionsEnum {poDictionary, poHeader, poLevel, poLimit};
|
||||
Tcl_Obj *headerObj = NULL, *compDictObj = NULL;
|
||||
int limit = DEFAULT_BUFFER_SIZE, dummy;
|
||||
int limit = DEFAULT_BUFFER_SIZE;
|
||||
int dummy;
|
||||
|
||||
if (objc < 4) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "mode channel ?options...?");
|
||||
@@ -2942,7 +2979,8 @@ ZlibTransformClose(
|
||||
int flags)
|
||||
{
|
||||
ZlibChannelData *cd = (ZlibChannelData *)instanceData;
|
||||
int e, written, result = TCL_OK;
|
||||
int e, result = TCL_OK;
|
||||
int written;
|
||||
|
||||
if ((flags & (TCL_CLOSE_READ | TCL_CLOSE_WRITE)) != 0) {
|
||||
return EINVAL;
|
||||
|
||||
@@ -9,7 +9,7 @@ S
|
||||
0040004100420043004400450046004700480049004A004B004C004D004E004F
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E0000
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
@@ -10,8 +10,8 @@ M
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0080008100820083008400850086008700880089008A008B008C008D008E008F
|
||||
0090009100920093009400950096009700980099009A009B009C009D009E009F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
20AC0081201A0083201E2026202020210088203001602039015A0164017D0179
|
||||
009020182019201C201D202220132014009821220161203A015B0165017E017A
|
||||
20AC0000201A0000201E2026202020210000203001602039015A0164017D0179
|
||||
000020182019201C201D202220132014000021220161203A015B0165017E017A
|
||||
00A002C702D8014100A4010400A600A700A800A9015E00AB00AC00AD00AE017B
|
||||
00B000B102DB014200B400B500B600B700B80105015F00BB013D02DD013E017C
|
||||
015400C100C2010200C40139010600C7010C00C9011800CB011A00CD00CE010E
|
||||
|
||||
@@ -11,7 +11,7 @@ S
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
04020403201A0453201E20262020202120AC203004092039040A040C040B040F
|
||||
045220182019201C201D202220132014009821220459203A045A045C045B045F
|
||||
045220182019201C201D202220132014000021220459203A045A045C045B045F
|
||||
00A0040E045E040800A4049000A600A7040100A9040400AB00AC00AD00AE0407
|
||||
00B000B104060456049100B500B600B704512116045400BB0458040504550457
|
||||
0410041104120413041404150416041704180419041A041B041C041D041E041F
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
20AC0081201A0192201E20262020202102C62030016020390152008D017D008F
|
||||
009020182019201C201D20222013201402DC21220161203A0153009D017E0178
|
||||
20AC0000201A0192201E20262020202102C620300160203901520000017D0000
|
||||
000020182019201C201D20222013201402DC21220161203A01530000017E0178
|
||||
00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF
|
||||
00B000B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF
|
||||
00C000C100C200C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
20AC0081201A0192201E20262020202100882030008A2039008C008D008E008F
|
||||
009020182019201C201D20222013201400982122009A203A009C009D009E009F
|
||||
20AC0000201A0192201E20262020202100002030000020390000000000000000
|
||||
000020182019201C201D202220132014000021220000203A0000000000000000
|
||||
00A00385038600A300A400A500A600A700A800A9000000AB00AC00AD00AE2015
|
||||
00B000B100B200B3038400B500B600B703880389038A00BB038C00BD038E038F
|
||||
0390039103920393039403950396039703980399039A039B039C039D039E039F
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
20AC0081201A0192201E20262020202102C62030016020390152008D008E008F
|
||||
009020182019201C201D20222013201402DC21220161203A0153009D009E0178
|
||||
20AC0000201A0192201E20262020202102C62030016020390152000000000000
|
||||
000020182019201C201D20222013201402DC21220161203A0153000000000178
|
||||
00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF
|
||||
00B000B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF
|
||||
00C000C100C200C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
20AC0081201A0192201E20262020202102C62030008A2039008C008D008E008F
|
||||
009020182019201C201D20222013201402DC2122009A203A009C009D009E009F
|
||||
20AC0000201A0192201E20262020202102C62030000020390000000000000000
|
||||
000020182019201C201D20222013201402DC21220000203A0000000000000000
|
||||
00A000A100A200A320AA00A500A600A700A800A900D700AB00AC00AD00AE00AF
|
||||
00B000B100B200B300B400B500B600B700B800B900F700BB00BC00BD00BE00BF
|
||||
05B005B105B205B305B405B505B605B705B805B9000005BB05BC05BD05BE05BF
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
20AC0081201A0083201E20262020202100882030008A2039008C00A802C700B8
|
||||
009020182019201C201D20222013201400982122009A203A009C00AF02DB009F
|
||||
20AC0000201A0000201E2026202020210000203000002039000000A802C700B8
|
||||
000020182019201C201D202220132014000021220000203A000000AF02DB0000
|
||||
00A0000000A200A300A4000000A600A700D800A9015600AB00AC00AD00AE00C6
|
||||
00B000B100B200B300B400B500B600B700F800B9015700BB00BC00BD00BE00E6
|
||||
0104012E0100010600C400C501180112010C00C90179011601220136012A013B
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
20AC0081201A0192201E20262020202102C62030008A20390152008D008E008F
|
||||
009020182019201C201D20222013201402DC2122009A203A0153009D009E0178
|
||||
20AC0000201A0192201E20262020202102C62030000020390152000000000000
|
||||
000020182019201C201D20222013201402DC21220000203A0153000000000178
|
||||
00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF
|
||||
00B000B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF
|
||||
00C000C100C2010200C400C500C600C700C800C900CA00CB030000CD00CE00CF
|
||||
|
||||
@@ -11,7 +11,7 @@ S
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
00B000B72219221A259225002502253C2524252C251C25342510250C25142518
|
||||
03B2221E03C600B100BD00BC224800AB00BBFEF7FEF8009B009CFEFBFEFC009F
|
||||
03B2221E03C600B100BD00BC224800AB00BBFEF7FEF800000000FEFBFEFC0000
|
||||
00A000ADFE8200A300A4FE8400000000FE8EFE8FFE95FE99060CFE9DFEA1FEA5
|
||||
0660066106620663066406650666066706680669FED1061BFEB1FEB5FEB9061F
|
||||
00A2FE80FE81FE83FE85FECAFE8BFE8DFE91FE93FE97FE9BFE9FFEA3FEA7FEA9
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0080008100820083008400850386008700B700AC00A620182019038820150389
|
||||
038A03AA038C00930094038E03AB00A9038F00B200B303AC00A303AD03AE03AF
|
||||
0000000000000000000000000386000000B700AC00A620182019038820150389
|
||||
038A03AA038C00000000038E03AB00A9038F00B200B303AC00A303AD03AE03AF
|
||||
03CA039003CC03CD039103920393039403950396039700BD0398039900AB00BB
|
||||
25912592259325022524039A039B039C039D256325512557255D039E039F2510
|
||||
25142534252C251C2500253C03A003A1255A25542569256625602550256C03A3
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
20AC008100820083008420260086008700880089008A008B008C008D008E008F
|
||||
009020182019201C201D20222013201400980099009A009B009C009D009E009F
|
||||
20AC000000000000000020260000000000000000000000000000000000000000
|
||||
000020182019201C201D20222013201400000000000000000000000000000000
|
||||
00A00E010E020E030E040E050E060E070E080E090E0A0E0B0E0C0E0D0E0E0E0F
|
||||
0E100E110E120E130E140E150E160E170E180E190E1A0E1B0E1C0E1D0E1E0E1F
|
||||
0E200E210E220E230E240E250E260E270E280E290E2A0E2B0E2C0E2D0E2E0E2F
|
||||
|
||||
@@ -10,7 +10,7 @@ M
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0080000000000000000000850086000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F
|
||||
FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F
|
||||
|
||||
@@ -10,7 +10,7 @@ M
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0080000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
@@ -10,8 +10,8 @@ M
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0080008100820083008400850086008700880089008A008B008C008D008E008F
|
||||
0090009100920093009400950096009700980099009A009B009C009D009E009F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
2730273127322733273427352736273727382739273A273B273C273D273E273F
|
||||
2740274127422743274427452746274727482749274A274B25CF274D25A0274F
|
||||
27502751275225B225BC25C6275625D727582759275A275B275C275D275E007F
|
||||
0080008100820083008400850086008700880089008A008B008C008D008E008F
|
||||
0090009100920093009400950096009700980099009A009B009C009D009E009F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000276127622763276427652766276726632666266526602460246124622463
|
||||
2464246524662467246824692776277727782779277A277B277C277D277E277F
|
||||
2780278127822783278427852786278727882789278A278B278C278D278E278F
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Encoding file: ebcdic, single-byte
|
||||
S
|
||||
006F 0 1
|
||||
00
|
||||
|
||||
@@ -10,8 +10,8 @@ M
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0080008100820083008400850086008700880089008A008B008C008D008E008F
|
||||
0090009100920093009400950096009700980099009A009B009C009D009E009F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
@@ -10,8 +10,8 @@ M
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0080008100820083008400850086008700880089008A008B008C008D0000008F
|
||||
0090009100920093009400950096009700980099009A009B009C009D009E009F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
@@ -10,8 +10,8 @@ M
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0080008100820083008400850086008700880089008A008B008C008D008E008F
|
||||
0090009100920093009400950096009700980099009A009B009C009D009E009F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D203E007F
|
||||
0080008100820083008400850086008700880089008A008B008C008D008E008F
|
||||
0090009100920093009400950096009700980099009A009B009C009D009E009F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F
|
||||
FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F
|
||||
FF80FF81FF82FF83FF84FF85FF86FF87FF88FF89FF8AFF8BFF8CFF8DFF8EFF8F
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D203E007F
|
||||
0080008100820083008400850086008700880089008A008B008C008D008E008F
|
||||
0090009100920093009400950096009700980099009A009B009C009D009E009F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F
|
||||
FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F
|
||||
FF80FF81FF82FF83FF84FF85FF86FF87FF88FF89FF8AFF8BFF8CFF8DFF8EFF8F
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
2730273127322733273427352736273727382739273A273B273C273D273E273F
|
||||
2740274127422743274427452746274727482749274A274B25CF274D25A0274F
|
||||
27502751275225B225BC25C6275625D727582759275A275B275C275D275E007F
|
||||
F8D7F8D8F8D9F8DAF8DBF8DCF8DDF8DEF8DFF8E0F8E1F8E2F8E3F8E4008E008F
|
||||
0090009100920093009400950096009700980099009A009B009C009D009E009F
|
||||
F8D7F8D8F8D9F8DAF8DBF8DCF8DDF8DEF8DFF8E0F8E1F8E2F8E3F8E400000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000276127622763276427652766276726632666266526602460246124622463
|
||||
2464246524662467246824692776277727782779277A277B277C277D277E277F
|
||||
2780278127822783278427852786278727882789278A278B278C278D278E278F
|
||||
|
||||
@@ -10,7 +10,7 @@ M
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0080000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00A0FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F
|
||||
FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F
|
||||
|
||||
@@ -10,7 +10,7 @@ M
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0080000000000000000000850086008700000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F
|
||||
FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F
|
||||
|
||||
@@ -10,8 +10,8 @@ S
|
||||
03A0039803A103A303A403A503C203A9039E03A80396005B2234005D22A5005F
|
||||
F8E503B103B203C703B403B503C603B303B703B903D503BA03BB03BC03BD03BF
|
||||
03C003B803C103C303C403C503D603C903BE03C803B6007B007C007D223C007F
|
||||
0080008100820083008400850086008700880089008A008B008C008D008E008F
|
||||
0090009100920093009400950096009700980099009A009B009C009D009E009F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
000003D2203222642044221E0192266326662665266021942190219121922193
|
||||
00B000B12033226500D7221D2202202200F72260226122482026F8E6F8E721B5
|
||||
21352111211C21182297229522052229222A2283228722842282228622082209
|
||||
|
||||
@@ -9,7 +9,7 @@ S
|
||||
0040004100420043004400450046004700480049004A004B004C004D004E004F
|
||||
0050005100520053005400550056005700580059005A005B005C005D005E005F
|
||||
0060006100620063006400650066006700680069006A006B006C006D006E006F
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E0000
|
||||
0070007100720073007400750076007700780079007A007B007C007D007E007F
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
00000E010E020E030E040E050E060E070E080E090E0A0E0B0E0C0E0D0E0E0E0F
|
||||
|
||||
@@ -12,7 +12,7 @@ apply {{dir} {
|
||||
0 tcl::idna 1.0.1 {cookiejar idna.tcl}
|
||||
0 platform 1.0.19 {platform platform.tcl}
|
||||
0 platform::shell 1.1.4 {platform shell.tcl}
|
||||
1 tcltest 2.5.5 {tcltest tcltest.tcl}
|
||||
1 tcltest 2.5.6 {tcltest tcltest.tcl}
|
||||
} {
|
||||
if {$isafe && !$safe} continue
|
||||
package ifneeded $package $version [list source [file join $dir {*}$file]]
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
# full path name of this file's directory.
|
||||
|
||||
if {![package vsatisfies [package provide Tcl] 8.5-]} {return}
|
||||
package ifneeded tcltest 2.5.5 [list source [file join $dir tcltest.tcl]]
|
||||
package ifneeded tcltest 2.5.6 [list source [file join $dir tcltest.tcl]]
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace eval tcltest {
|
||||
# When the version number changes, be sure to update the pkgIndex.tcl file,
|
||||
# and the install directory in the Makefiles. When the minor version
|
||||
# changes (new feature) be sure to update the man page as well.
|
||||
variable Version 2.5.5
|
||||
variable Version 2.5.6
|
||||
|
||||
# Compatibility support for dumb variables defined in tcltest 1
|
||||
# Do not use these. Call [package provide Tcl] and [info patchlevel]
|
||||
@@ -1134,6 +1134,39 @@ proc tcltest::SafeFetch {n1 n2 op} {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# tcltest::Asciify --
|
||||
#
|
||||
# Transforms the passed string to contain only printable ascii characters.
|
||||
# Useful for printing to terminals. Non-printables are mapped to
|
||||
# \x, \u or \U sequences.
|
||||
#
|
||||
# Arguments:
|
||||
# s - string to transform
|
||||
#
|
||||
# Results:
|
||||
# The transformed strings
|
||||
#
|
||||
# Side effects:
|
||||
# None.
|
||||
|
||||
proc tcltest::Asciify {s} {
|
||||
set print ""
|
||||
foreach c [split $s ""] {
|
||||
set i [scan $c %c]
|
||||
if {[string is print $c] && ($i <= 127)} {
|
||||
append print $c
|
||||
} elseif {$i <= 0xFF} {
|
||||
append print \\x[format %02X $i]
|
||||
} elseif {$i <= 0xFFFF} {
|
||||
append print \\u[format %04X $i]
|
||||
} else {
|
||||
append print \\U[format %08X $i]
|
||||
}
|
||||
}
|
||||
return $print
|
||||
}
|
||||
|
||||
# tcltest::ConstraintInitializer --
|
||||
#
|
||||
# Get or set a script that when evaluated in the tcltest namespace
|
||||
@@ -2221,9 +2254,9 @@ proc tcltest::test {name description args} {
|
||||
if {$scriptCompare} {
|
||||
puts [outputChannel] "---- Error testing result: $scriptMatch"
|
||||
} else {
|
||||
puts [outputChannel] "---- Result was:\n$actualAnswer"
|
||||
puts [outputChannel] "---- Result was:\n[Asciify $actualAnswer]"
|
||||
puts [outputChannel] "---- Result should have been\
|
||||
($match matching):\n$result"
|
||||
($match matching):\n[Asciify $result]"
|
||||
}
|
||||
}
|
||||
if {$errorCodeFailure} {
|
||||
|
||||
+1
-1
@@ -348,7 +348,7 @@ test basic-20.2 {Tcl_GetCommandInfo, names for commands created outside namespac
|
||||
test basic-20.3 {Tcl_GetCommandInfo, #-quoting} testcmdtoken {
|
||||
catch {rename \# ""}
|
||||
set x [testcmdtoken create \#]
|
||||
testcmdtoken name $x
|
||||
return [testcmdtoken name $x]
|
||||
} {{#} ::#}
|
||||
|
||||
test basic-21.1 {Tcl_GetCommandName} {emptyTest} {
|
||||
|
||||
+24
-22
@@ -50,6 +50,8 @@ namespace eval ::tcl::test::io {
|
||||
testConstraint notWinCI [expr {
|
||||
$::tcl_platform(platform) ne "windows" || ![info exists ::env(CI)]}]
|
||||
testConstraint notOSX [expr {$::tcl_platform(os) ne "Darwin"}]
|
||||
# File permissions broken on wsl without some "exotic" wsl configuration
|
||||
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
|
||||
testConstraint specialfiles [expr {[file exists /dev/zero] || [file exists NUL]}]
|
||||
|
||||
# You need a *very* special environment to do some tests. In particular,
|
||||
@@ -119,7 +121,7 @@ test chan-io-1.6 {Tcl_WriteChars: WriteBytes} {
|
||||
chan puts -nonewline $f "a\x4D\x00"
|
||||
chan close $f
|
||||
contents $path(test1)
|
||||
} "aM\x00"
|
||||
} aM\x00
|
||||
test chan-io-1.7 {Tcl_WriteChars: WriteChars} {
|
||||
set f [open $path(test1) w]
|
||||
chan configure $f -encoding shiftjis
|
||||
@@ -284,7 +286,7 @@ test chan-io-3.6 {WriteChars: (stageRead + dstWrote == 0)} -body {
|
||||
# last byte of A plus the all of B) appended.
|
||||
set f [open $path(test1) w]
|
||||
chan configure $f -encoding shiftjis -buffersize 16
|
||||
chan puts -nonewline $f "12345678901234AB"
|
||||
chan puts -nonewline $f 12345678901234AB
|
||||
set x [list [contents $path(test1)]]
|
||||
chan close $f
|
||||
lappend x [contents $path(test1)]
|
||||
@@ -1216,7 +1218,7 @@ test chan-io-8.7 {PeekAhead: cleanup} -setup {
|
||||
chan puts -nonewline $f "abcdefghijklmno\r"
|
||||
# here
|
||||
lappend x [chan gets $f line] $line [testchannel queuedcr $f]
|
||||
chan puts -nonewline $f "\x1A"
|
||||
chan puts -nonewline $f \x1A
|
||||
lappend x [chan gets $f line] $line
|
||||
} -cleanup {
|
||||
chan close $f
|
||||
@@ -1372,22 +1374,22 @@ test chan-io-12.4 {ReadChars: split-up char} -setup {
|
||||
chan configure $f -encoding shiftjis
|
||||
vwait [namespace which -variable x]
|
||||
chan configure $f -encoding binary -blocking 1
|
||||
chan puts -nonewline $f "\x7B"
|
||||
chan puts -nonewline $f \x7B
|
||||
after 500 ;# Give the cat process time to catch up
|
||||
chan configure $f -encoding shiftjis -blocking 0
|
||||
vwait [namespace which -variable x]
|
||||
return $x
|
||||
} -cleanup {
|
||||
chan close $f
|
||||
} -result [list "123456789012345" 1 "本" 0]
|
||||
} -result [list "123456789012345" 1 本 0]
|
||||
test chan-io-12.5 {ReadChars: chan events on partial characters} -setup {
|
||||
variable x {}
|
||||
} -constraints {stdio fileevent} -body {
|
||||
set path(test1) [makeFile {
|
||||
chan configure stdout -encoding binary -buffering none
|
||||
chan gets stdin; chan puts -nonewline "\xE7"
|
||||
chan gets stdin; chan puts -nonewline "\x89"
|
||||
chan gets stdin; chan puts -nonewline "\xA6"
|
||||
chan gets stdin; chan puts -nonewline \xE7
|
||||
chan gets stdin; chan puts -nonewline \x89
|
||||
chan gets stdin; chan puts -nonewline \xA6
|
||||
} test1]
|
||||
set f [openpipe r+ $path(test1)]
|
||||
chan event $f readable [namespace code {
|
||||
@@ -4980,7 +4982,7 @@ test chan-io-38.2 {Tcl_SetChannelBufferSize, Tcl_GetChannelBufferSize} -setup {
|
||||
test chan-io-38.3 {Tcl_SetChannelBufferSize, changing buffersize between reads} {
|
||||
# This test crashes the interp if Bug #427196 is not fixed
|
||||
set chan [open [info script] r]
|
||||
chan configure $chan -buffersize 10
|
||||
chan configure $chan -buffersize 10 -encoding utf-8
|
||||
set var [chan read $chan 2]
|
||||
chan configure $chan -buffersize 32
|
||||
append var [chan read $chan]
|
||||
@@ -5211,7 +5213,7 @@ test chan-io-39.17 {Tcl_SetChannelOption: -encoding, clearing CHANNEL_NEED_MORE_
|
||||
} -constraints {stdio fileevent} -body {
|
||||
set f [openpipe r+ $path(cat)]
|
||||
chan configure $f -encoding binary
|
||||
chan puts -nonewline $f "\xE7"
|
||||
chan puts -nonewline $f \xE7
|
||||
chan flush $f
|
||||
chan configure $f -encoding utf-8 -blocking 0
|
||||
chan event $f readable [namespace code { lappend x [chan read $f] }]
|
||||
@@ -5348,7 +5350,7 @@ test chan-io-40.1 {POSIX open access modes: RDWR} -setup {
|
||||
} -result {zzy abzzy}
|
||||
test chan-io-40.2 {POSIX open access modes: CREAT} -setup {
|
||||
file delete $path(test3)
|
||||
} -constraints {unix} -body {
|
||||
} -constraints {unix notWsl} -body {
|
||||
set f [open $path(test3) {WRONLY CREAT} 0o600]
|
||||
file stat $path(test3) stats
|
||||
set x [format 0o%03o [expr {$stats(mode) & 0o777}]]
|
||||
@@ -5361,7 +5363,7 @@ test chan-io-40.2 {POSIX open access modes: CREAT} -setup {
|
||||
} -result {0o600 {line 1}}
|
||||
test chan-io-40.3 {POSIX open access modes: CREAT} -setup {
|
||||
file delete $path(test3)
|
||||
} -constraints {unix umask} -body {
|
||||
} -constraints {unix umask notWsl} -body {
|
||||
# This test only works if your umask is 2, like ouster's.
|
||||
chan close [open $path(test3) {WRONLY CREAT}]
|
||||
file stat $path(test3) stats
|
||||
@@ -6736,8 +6738,8 @@ test chan-io-52.5 {TclCopyChannel, all} -constraints {fcopy} -setup {
|
||||
} -body {
|
||||
set f1 [open $thisScript]
|
||||
set f2 [open $path(test1) w]
|
||||
chan configure $f1 -translation lf -blocking 0
|
||||
chan configure $f2 -translation lf -blocking 0
|
||||
chan configure $f1 -translation lf -encoding iso8859-1 -blocking 0
|
||||
chan configure $f2 -translation lf -encoding iso8859-1 -blocking 0
|
||||
chan copy $f1 $f2 -size -1 ;# -1 means 'copy all', same as if no -size specified.
|
||||
set result [list [chan configure $f1 -blocking] [chan configure $f2 -blocking]]
|
||||
chan close $f1
|
||||
@@ -6752,8 +6754,8 @@ test chan-io-52.5a {TclCopyChannel, all, other negative value} -setup {
|
||||
} -constraints {fcopy} -body {
|
||||
set f1 [open $thisScript]
|
||||
set f2 [open $path(test1) w]
|
||||
chan configure $f1 -translation lf -blocking 0
|
||||
chan configure $f2 -translation lf -blocking 0
|
||||
chan configure $f1 -translation lf -encoding iso8859-1 -blocking 0
|
||||
chan configure $f2 -translation lf -encoding iso8859-1 -blocking 0
|
||||
chan copy $f1 $f2 -size -2 ;# < 0 behaves like -1, copy all
|
||||
set result [list [chan configure $f1 -blocking] [chan configure $f2 -blocking]]
|
||||
chan close $f1
|
||||
@@ -6768,8 +6770,8 @@ test chan-io-52.5b {TclCopyChannel, all, wrap to negative value} -setup {
|
||||
} -constraints {fcopy} -body {
|
||||
set f1 [open $thisScript]
|
||||
set f2 [open $path(test1) w]
|
||||
chan configure $f1 -translation lf -blocking 0
|
||||
chan configure $f2 -translation lf -blocking 0
|
||||
chan configure $f1 -translation lf -encoding iso8859-1 -blocking 0
|
||||
chan configure $f2 -translation lf -encoding iso8859-1 -blocking 0
|
||||
chan copy $f1 $f2 -size 3221176172 ;# Wrapped to < 0, behaves like -1, copy all
|
||||
set result [list [chan configure $f1 -blocking] [chan configure $f2 -blocking]]
|
||||
chan close $f1
|
||||
@@ -6802,8 +6804,8 @@ test chan-io-52.7 {TclCopyChannel} -constraints {fcopy} -setup {
|
||||
} -body {
|
||||
set f1 [open $thisScript]
|
||||
set f2 [open $path(test1) w]
|
||||
chan configure $f1 -translation lf -blocking 0
|
||||
chan configure $f2 -translation lf -blocking 0
|
||||
chan configure $f1 -translation lf -encoding iso8859-1 -blocking 0
|
||||
chan configure $f2 -translation lf -encoding iso8859-1 -blocking 0
|
||||
chan copy $f1 $f2
|
||||
set result [list [chan configure $f1 -blocking] [chan configure $f2 -blocking]]
|
||||
if {[file size $thisScript] == [file size $path(test1)]} {
|
||||
@@ -6848,7 +6850,7 @@ set path(utf8-rp.txt) [makeFile {} utf8-rp.txt]
|
||||
# Create kyrillic file, use lf translation to avoid os eol issues
|
||||
set out [open $path(kyrillic.txt) w]
|
||||
chan configure $out -encoding koi8-r -translation lf
|
||||
chan puts $out "АА"
|
||||
chan puts $out АА
|
||||
chan close $out
|
||||
test chan-io-52.9 {TclCopyChannel & encodings} {fcopy} {
|
||||
# Copy kyrillic to UTF-8, using chan copy.
|
||||
@@ -6886,7 +6888,7 @@ test chan-io-52.10 {TclCopyChannel & encodings} {fcopy} {
|
||||
test chan-io-52.11 {TclCopyChannel & encodings} -setup {
|
||||
set f [open $path(utf8-fcopy.txt) w]
|
||||
fconfigure $f -encoding utf-8 -translation lf
|
||||
puts $f "АА"
|
||||
puts $f АА
|
||||
close $f
|
||||
} -constraints {fcopy} -body {
|
||||
# binary to encoding => the input has to be in utf-8 to make sense to the
|
||||
|
||||
+5
-3
@@ -32,6 +32,8 @@ testConstraint linkDirectory [expr {
|
||||
&& [lindex [file system [temporaryDirectory]] 1] eq "NTFS")
|
||||
}]
|
||||
testConstraint notWine [expr {![info exists ::env(CI_USING_WINE)]}]
|
||||
# File permissions broken on wsl without some "exotic" wsl configuration
|
||||
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
|
||||
|
||||
global env
|
||||
set cmdAHwd [pwd]
|
||||
@@ -1019,7 +1021,7 @@ test cmdAH-16.2 {Tcl_FileObjCmd: readable} {
|
||||
-result 1
|
||||
}
|
||||
test cmdAH-16.3 {Tcl_FileObjCmd: readable} {
|
||||
-constraints {unix notRoot testchmod}
|
||||
-constraints {unix notRoot testchmod notWsl}
|
||||
-setup {testchmod 0o333 $gorpfile}
|
||||
-body {file readable $gorpfile}
|
||||
-result 0
|
||||
@@ -1052,7 +1054,7 @@ set gorpfile [makeFile abcde gorp.file]
|
||||
test cmdAH-18.1 {Tcl_FileObjCmd: executable} -returnCodes error -body {
|
||||
file executable a b
|
||||
} -result {wrong # args: should be "file executable name"}
|
||||
test cmdAH-18.2 {Tcl_FileObjCmd: executable} {notRoot} {
|
||||
test cmdAH-18.2 {Tcl_FileObjCmd: executable} {notRoot notWsl} {
|
||||
file executable $gorpfile
|
||||
} 0
|
||||
test cmdAH-18.3 {Tcl_FileObjCmd: executable} {unix testchmod} {
|
||||
@@ -1600,7 +1602,7 @@ test cmdAH-28.4 {Tcl_FileObjCmd: stat} -setup {
|
||||
file stat $gorpfile stat
|
||||
list $stat(nlink) $stat(size) $stat(type)
|
||||
} -result {1 12 file}
|
||||
test cmdAH-28.5 {Tcl_FileObjCmd: stat} -constraints {unix} -setup {
|
||||
test cmdAH-28.5 {Tcl_FileObjCmd: stat} -constraints {unix notWsl} -setup {
|
||||
unset -nocomplain stat
|
||||
} -body {
|
||||
file stat $gorpfile stat
|
||||
|
||||
@@ -211,6 +211,38 @@ test dstring-2.15 {appending list elements} -constraints testdstring -setup {
|
||||
} -cleanup {
|
||||
testdstring free
|
||||
} -result {x #}
|
||||
test dstring-2.16 {appending list elements - bug [46dda6fc29] segfault} -constraints testdstring -setup {
|
||||
testdstring free
|
||||
} -body {
|
||||
testdstring element "\\\n"; # Will setfault
|
||||
testdstring get
|
||||
} -cleanup {
|
||||
testdstring free
|
||||
} -result \\\\\\n
|
||||
test dstring-2.17 {appending list elements - bug [46dda6fc29] segfault} -constraints testdstring -setup {
|
||||
testdstring free
|
||||
} -body {
|
||||
testdstring element "\\\{"; # Will setfault
|
||||
testdstring get
|
||||
} -cleanup {
|
||||
testdstring free
|
||||
} -result [list [list \{]]
|
||||
test dstring-2.18 {appending list elements - bug [46dda6fc29] segfault} -constraints testdstring -setup {
|
||||
testdstring free
|
||||
} -body {
|
||||
testdstring element "\\\}"; # Will setfault
|
||||
testdstring get
|
||||
} -cleanup {
|
||||
testdstring free
|
||||
} -result [list [list \}]]
|
||||
test dstring-2.19 {appending list elements - bug [46dda6fc29] segfault} -constraints testdstring -setup {
|
||||
testdstring free
|
||||
} -body {
|
||||
testdstring element "\\\\"; # Will setfault
|
||||
testdstring get
|
||||
} -cleanup {
|
||||
testdstring free
|
||||
} -result [list [list \\]]
|
||||
|
||||
test dstring-3.1 {nested sublists} -constraints testdstring -setup {
|
||||
testdstring free
|
||||
|
||||
+196
-13
@@ -171,7 +171,7 @@ test encoding-6.2 {Tcl_CreateEncoding: replace encoding} {testencoding} {
|
||||
|
||||
test encoding-7.1 {Tcl_ExternalToUtfDString: small buffer} {
|
||||
encoding convertfrom jis0208 8c8c8c8c
|
||||
} "吾吾吾吾"
|
||||
} 吾吾吾吾
|
||||
test encoding-7.2 {Tcl_UtfToExternalDString: big buffer} {
|
||||
set a 8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C
|
||||
append a $a
|
||||
@@ -193,7 +193,7 @@ test encoding-8.1 {Tcl_ExternalToUtf} {
|
||||
close $f
|
||||
file delete [file join [temporaryDirectory] dummy]
|
||||
return $x
|
||||
} "ab乎g"
|
||||
} ab乎g
|
||||
|
||||
test encoding-9.1 {Tcl_UtfToExternalDString: small buffer} {
|
||||
encoding convertto jis0208 "吾吾吾吾"
|
||||
@@ -213,7 +213,7 @@ test encoding-9.2 {Tcl_UtfToExternalDString: big buffer} {
|
||||
test encoding-10.1 {Tcl_UtfToExternal} {
|
||||
set f [open [file join [temporaryDirectory] dummy] w]
|
||||
fconfigure $f -translation binary -encoding shiftjis
|
||||
puts -nonewline $f "ab乎g"
|
||||
puts -nonewline $f ab乎g
|
||||
close $f
|
||||
set f [open [file join [temporaryDirectory] dummy] r]
|
||||
fconfigure $f -translation binary -encoding iso8859-1
|
||||
@@ -248,7 +248,7 @@ test encoding-11.1 {LoadEncodingFile: unknown encoding} {testencoding} {
|
||||
} {1 {unknown encoding "jis0208"} 8C}
|
||||
test encoding-11.2 {LoadEncodingFile: single-byte} {
|
||||
encoding convertfrom jis0201 \xA1
|
||||
} "。"
|
||||
} 。
|
||||
test encoding-11.3 {LoadEncodingFile: double-byte} {
|
||||
encoding convertfrom jis0208 8C
|
||||
} 乎
|
||||
@@ -452,6 +452,27 @@ test encoding-15.24 {UtfToUtfProc CESU-8 bug [048dd20b4171c8da]} {
|
||||
binary scan $y H* z
|
||||
list [string length $y] $z
|
||||
} {2 cfbf}
|
||||
test encoding-15.25 {UtfToUtfProc CESU-8} {
|
||||
encoding convertfrom cesu-8 \x00
|
||||
} \x00
|
||||
test encoding-15.26 {UtfToUtfProc CESU-8} {
|
||||
encoding convertfrom cesu-8 \xC0\x80
|
||||
} \x00
|
||||
test encoding-15.27 {UtfToUtfProc -strict CESU-8} {
|
||||
encoding convertfrom -strict cesu-8 \x00
|
||||
} \x00
|
||||
test encoding-15.28 {UtfToUtfProc -strict CESU-8} -body {
|
||||
encoding convertfrom -strict cesu-8 \xC0\x80
|
||||
} -returnCodes 1 -result {unexpected byte sequence starting at index 0: '\xC0'}
|
||||
test encoding-15.29 {UtfToUtfProc CESU-8} {
|
||||
encoding convertto cesu-8 \x00
|
||||
} \x00
|
||||
test encoding-15.30 {UtfToUtfProc -strict CESU-8} {
|
||||
encoding convertto -strict cesu-8 \x00
|
||||
} \x00
|
||||
test encoding-15.31 {UtfToUtfProc -strict CESU-8 (bytes F0-F4 are invalid)} -body {
|
||||
encoding convertfrom -strict cesu-8 \xF1\x86\x83\x9C
|
||||
} -returnCodes 1 -result {unexpected byte sequence starting at index 0: '\xF1'}
|
||||
|
||||
test encoding-16.1 {Utf16ToUtfProc} -body {
|
||||
set val [encoding convertfrom utf-16 NN]
|
||||
@@ -481,11 +502,83 @@ test encoding-16.7 {Utf32ToUtfProc} -body {
|
||||
set val [encoding convertfrom utf-32be \0\0NN]
|
||||
list $val [format %x [scan $val %c]]
|
||||
} -result "乎 4e4e"
|
||||
test encoding-16.8 {Utf32ToUtfProc} -body {
|
||||
set val [encoding convertfrom -nocomplain utf-32 \x41\x00\x00\x41]
|
||||
list $val [format %x [scan $val %c]]
|
||||
} -result "\uFFFD fffd"
|
||||
test encoding-16.9 {Utf32ToUtfProc} -body {
|
||||
encoding convertfrom utf-32le \x00\xD8\x00\x00
|
||||
} -result \uD800
|
||||
test encoding-16.10 {Utf32ToUtfProc} -body {
|
||||
encoding convertfrom utf-32le \x00\xDC\x00\x00
|
||||
} -result \uDC00
|
||||
test encoding-16.11 {Utf32ToUtfProc} -body {
|
||||
encoding convertfrom utf-32le \x00\xD8\x00\x00\x00\xDC\x00\x00
|
||||
} -result \uD800\uDC00
|
||||
test encoding-16.12 {Utf32ToUtfProc} -body {
|
||||
encoding convertfrom utf-32le \x00\xDC\x00\x00\x00\xD8\x00\x00
|
||||
} -result \uDC00\uD800
|
||||
test encoding-16.13 {Utf16ToUtfProc} -body {
|
||||
encoding convertfrom utf-16le \x00\xD8
|
||||
} -result \uD800
|
||||
test encoding-16.14 {Utf16ToUtfProc} -body {
|
||||
encoding convertfrom utf-16le \x00\xDC
|
||||
} -result \uDC00
|
||||
test encoding-16.15 {Utf16ToUtfProc} -body {
|
||||
encoding convertfrom utf-16le \x00\xD8\x00\xDC
|
||||
} -result \uD800\uDC00
|
||||
test encoding-16.16 {Utf16ToUtfProc} -body {
|
||||
encoding convertfrom utf-16le \x00\xDC\x00\xD8
|
||||
} -result \uDC00\uD800
|
||||
test encoding-16.17 {Utf32ToUtfProc} -body {
|
||||
list [encoding convertfrom -strict -failindex idx utf-32le \x41\x00\x00\x00\x00\xD8\x00\x00\x42\x00\x00\x00] [set idx]
|
||||
} -result {A 4}
|
||||
|
||||
test encoding-16.18 {
|
||||
Utf16ToUtfProc, Tcl_UniCharToUtf, surrogate pairs in utf-16
|
||||
} -body {
|
||||
apply [list {} {
|
||||
for {set i 0xD800} {$i < 0xDBFF} {incr i} {
|
||||
for {set j 0xDC00} {$j < 0xDFFF} {incr j} {
|
||||
set string [binary format S2 [list $i $j]]
|
||||
set status [catch {
|
||||
set decoded [encoding convertfrom utf-16be $string]
|
||||
set encoded [encoding convertto utf-16be $decoded]
|
||||
}]
|
||||
if {$status || ( $encoded ne $string )} {
|
||||
return [list [format %x $i] [format %x $j]]
|
||||
}
|
||||
}
|
||||
}
|
||||
return done
|
||||
} [namespace current]]
|
||||
} -result done
|
||||
test encoding-16.19 {Utf16ToUtfProc, bug [d19fe0a5b]} -body {
|
||||
encoding convertfrom utf-16 "\x41\x41\x41"
|
||||
} -result \u4141\uFFFD
|
||||
test encoding-16.20 {Utf16ToUtfProc, bug [d19fe0a5b]} -constraints deprecated -body {
|
||||
encoding convertfrom utf-16 "\xD8\xD8"
|
||||
} -result \uD8D8
|
||||
test encoding-16.21 {Utf16ToUtfProc, bug [d19fe0a5b]} -body {
|
||||
encoding convertfrom utf-32 "\x00\x00\x00\x00\x41\x41"
|
||||
} -result \x00\uFFFD
|
||||
test encoding-16.22 {Utf16ToUtfProc, strict, bug [db7a085bd9]} -body {
|
||||
encoding convertfrom -strict utf-16le \x00\xD8
|
||||
} -returnCodes 1 -result {unexpected byte sequence starting at index 0: '\x00'}
|
||||
test encoding-16.23 {Utf16ToUtfProc, strict, bug [db7a085bd9]} -body {
|
||||
encoding convertfrom -strict utf-16le \x00\xDC
|
||||
} -returnCodes 1 -result {unexpected byte sequence starting at index 0: '\x00'}
|
||||
test encoding-16.24 {Utf32ToUtfProc} -body {
|
||||
encoding convertfrom utf-32 "\xFF\xFF\xFF\xFF"
|
||||
} -result \uFFFD
|
||||
test encoding-16.25 {Utf32ToUtfProc} -body {
|
||||
encoding convertfrom utf-32 "\x01\x00\x00\x01"
|
||||
} -result \uFFFD
|
||||
|
||||
test encoding-17.1 {UtfToUtf16Proc} -body {
|
||||
encoding convertto utf-16 "\U460DC"
|
||||
} -result "\xD8\xD8\xDC\xDC"
|
||||
test encoding-17.2 {UtfToUcs2Proc} -body {
|
||||
test encoding-17.2 {UtfToUcs2Proc, invalid testcase, see [5607d6482c]} -constraints deprecated -body {
|
||||
encoding convertfrom utf-16 [encoding convertto ucs-2 "\U460DC"]
|
||||
} -result "\uFFFD"
|
||||
test encoding-17.3 {UtfToUtf16Proc} -body {
|
||||
@@ -512,15 +605,50 @@ test encoding-17.9 {Utf32ToUtfProc} -body {
|
||||
test encoding-17.10 {Utf32ToUtfProc} -body {
|
||||
encoding convertfrom -nocomplain utf-32 "\xFF\xFF\xFF\xFF"
|
||||
} -result \uFFFD
|
||||
test encoding-17.11 {Utf32ToUtfProc} -body {
|
||||
encoding convertfrom -strict utf-32le "\x00\xD8\x00\x00"
|
||||
} -returnCodes error -result {unexpected byte sequence starting at index 0: '\x00'}
|
||||
test encoding-17.12 {Utf32ToUtfProc} -body {
|
||||
encoding convertfrom -strict utf-32le "\x00\xDC\x00\x00"
|
||||
} -returnCodes error -result {unexpected byte sequence starting at index 0: '\x00'}
|
||||
|
||||
|
||||
test encoding-18.1 {TableToUtfProc error on invalid input with -strict} -body {
|
||||
test encoding-18.1 {TableToUtfProc on invalid input} -constraints deprecated -body {
|
||||
list [catch {encoding convertto jis0208 \\} res] $res
|
||||
} -result {0 !)}
|
||||
test encoding-18.2 {TableToUtfProc on invalid input with -strict} -body {
|
||||
list [catch {encoding convertto -strict jis0208 \\} res] $res
|
||||
} -result {1 {unexpected character at index 0: 'U+00005C'}}
|
||||
test encoding-18.3 {TableToUtfProc on invalid input with -strict -failindex} -body {
|
||||
list [catch {encoding convertto -strict -failindex pos jis0208 \\} res] $res $pos
|
||||
} -result {0 {} 0}
|
||||
test encoding-18.4 {TableToUtfProc on invalid input with -failindex -strict} -body {
|
||||
list [catch {encoding convertto -failindex pos -strict jis0208 \\} res] $res $pos
|
||||
} -result {0 {} 0}
|
||||
test encoding-18.5 {TableToUtfProc on invalid input with -failindex} -body {
|
||||
list [catch {encoding convertto -failindex pos jis0208 \\} res] $res $pos
|
||||
} -result {0 {} 0}
|
||||
test encoding-18.6 {TableToUtfProc on invalid input with -nocomplain} -body {
|
||||
list [catch {encoding convertto -nocomplain jis0208 \\} res] $res
|
||||
} -result {0 !)}
|
||||
|
||||
|
||||
test encoding-19.1 {TableFromUtfProc} {
|
||||
} {}
|
||||
test encoding-19.1 {TableFromUtfProc} -body {
|
||||
encoding convertfrom ascii AÁ
|
||||
} -result AÁ
|
||||
test encoding-19.2 {TableFromUtfProc} -body {
|
||||
encoding convertfrom -nocomplain ascii AÁ
|
||||
} -result AÁ
|
||||
test encoding-19.3 {TableFromUtfProc} -body {
|
||||
encoding convertfrom -strict ascii AÁ
|
||||
} -returnCodes 1 -result {unexpected byte sequence starting at index 1: '\xC1'}
|
||||
test encoding-19.4 {TableFromUtfProc} -body {
|
||||
list [encoding convertfrom -failindex idx ascii AÁ] [set idx]
|
||||
} -result {A 1}
|
||||
test encoding-19.5 {TableFromUtfProc} -body {
|
||||
list [encoding convertfrom -failindex idx -strict ascii AÁ] [set idx]
|
||||
} -result {A 1}
|
||||
test encoding-19.6 {TableFromUtfProc} -body {
|
||||
list [encoding convertfrom -failindex idx -strict ascii AÁB] [set idx]
|
||||
} -result {A 1}
|
||||
|
||||
test encoding-20.1 {TableFreefProc} {
|
||||
} {}
|
||||
@@ -663,7 +791,7 @@ test encoding-24.14 {Parse valid or invalid utf-8} {
|
||||
} 1
|
||||
test encoding-24.15 {Parse valid or invalid utf-8} -constraints deprecated -body {
|
||||
encoding convertfrom utf-8 "Z\xE0\x80"
|
||||
} -result Z\xE0\x80
|
||||
} -result Z\xE0\u20AC
|
||||
test encoding-24.16 {Parse valid or invalid utf-8} -constraints testbytestring -body {
|
||||
encoding convertto utf-8 [testbytestring "Z\u4343\x80"]
|
||||
} -returnCodes 1 -result {expected byte sequence but character 1 was '䍃' (U+004343)}
|
||||
@@ -739,6 +867,21 @@ test encoding-24.39 {Try to generate invalid utf-8 with -strict} -body {
|
||||
test encoding-24.40 {Try to generate invalid utf-8 with -nocomplain} -body {
|
||||
encoding convertto -nocomplain utf-8 \uD800
|
||||
} -result \xED\xA0\x80
|
||||
test encoding-24.41 {Parse invalid utf-8 with -strict} -body {
|
||||
encoding convertfrom -strict utf-8 \xED\xA0\x80\xED\xB0\x80
|
||||
} -returnCodes 1 -result {unexpected byte sequence starting at index 0: '\xED'}
|
||||
test encoding-24.42 {Parse invalid utf-8, fallback to cp1252 [885c86a9a0]} -body {
|
||||
encoding convertfrom -nocomplain utf-8 \xF0\x80\x80\x80
|
||||
} -result \xF0\u20AC\u20AC\u20AC
|
||||
test encoding-24.43 {Parse invalid utf-8, fallback to cp1252 [885c86a9a0]} -body {
|
||||
encoding convertfrom -nocomplain utf-8 \x80
|
||||
} -result \u20AC
|
||||
test encoding-24.44 {Try to generate invalid ucs-2 with -strict} -body {
|
||||
encoding convertto -strict ucs-2 \uD800
|
||||
} -returnCodes 1 -result {unexpected character at index 0: 'U+00D800'}
|
||||
test encoding-24.45 {Try to generate invalid ucs-2 with -strict} -body {
|
||||
encoding convertto -strict ucs-2 \U10000
|
||||
} -returnCodes 1 -result {unexpected character at index 0: 'U+010000'}
|
||||
|
||||
file delete [file join [temporaryDirectory] iso2022.txt]
|
||||
|
||||
@@ -893,7 +1036,9 @@ test encoding-27.2 {encoding dirs basic behavior} -returnCodes error -body {
|
||||
test encoding-28.0 {all encodings load} -body {
|
||||
set string hello
|
||||
foreach name [encoding names] {
|
||||
incr count
|
||||
if {$name ne "unicode"} {
|
||||
incr count
|
||||
}
|
||||
encoding convertto -nocomplain $name $string
|
||||
|
||||
# discard the cached internal representation of Tcl_Encoding
|
||||
@@ -901,10 +1046,48 @@ test encoding-28.0 {all encodings load} -body {
|
||||
llength $name
|
||||
}
|
||||
return $count
|
||||
} -result [expr {[info exists ::tcl_precision] ? 92 : 91}]
|
||||
} -result 91
|
||||
|
||||
runtests
|
||||
|
||||
test encoding-bug-183a1adcc0-1 {Bug [183a1adcc0] Buffer overflow Tcl_UtfToExternal} -constraints {
|
||||
testencoding
|
||||
} -body {
|
||||
# Note - buffers are initialized to \xff
|
||||
list [catch {testencoding Tcl_UtfToExternal utf-16 A {start end} {} 1} result] $result
|
||||
} -result [list 0 [list nospace {} \xff]]
|
||||
|
||||
test encoding-bug-183a1adcc0-2 {Bug [183a1adcc0] Buffer overflow Tcl_UtfToExternal} -constraints {
|
||||
testencoding
|
||||
} -body {
|
||||
# Note - buffers are initialized to \xff
|
||||
list [catch {testencoding Tcl_UtfToExternal utf-16 A {start end} {} 0} result] $result
|
||||
} -result [list 0 [list nospace {} {}]]
|
||||
|
||||
test encoding-bug-183a1adcc0-3 {Bug [183a1adcc0] Buffer overflow Tcl_UtfToExternal} -constraints {
|
||||
testencoding
|
||||
} -body {
|
||||
# Note - buffers are initialized to \xff
|
||||
list [catch {testencoding Tcl_UtfToExternal utf-16 A {start end} {} 2} result] $result
|
||||
} -result [list 0 [list nospace {} \x00\x00]]
|
||||
|
||||
test encoding-bug-183a1adcc0-4 {Bug [183a1adcc0] Buffer overflow Tcl_UtfToExternal} -constraints {
|
||||
testencoding
|
||||
} -body {
|
||||
# Note - buffers are initialized to \xff
|
||||
list [catch {testencoding Tcl_UtfToExternal utf-16 A {start end} {} 3} result] $result
|
||||
} -result [list 0 [list nospace {} \x00\x00\xff]]
|
||||
|
||||
test encoding-bug-183a1adcc0-5 {Bug [183a1adcc0] Buffer overflow Tcl_UtfToExternal} -constraints {
|
||||
testencoding ucs2 knownBug
|
||||
} -body {
|
||||
# The knownBug constraint is because test depends on TCL_UTF_MAX and
|
||||
# also UtfToUtf16 assumes space required in destination buffer is
|
||||
# sizeof(Tcl_UniChar) which is incorrect when TCL_UTF_MAX==4
|
||||
# Note - buffers are initialized to \xff
|
||||
list [catch {testencoding Tcl_UtfToExternal utf-16 A {start end} {} 4} result] $result
|
||||
} -result [list 0 [list ok {} [expr {$::tcl_platform(byteOrder) eq "littleEndian" ? "\x41\x00" : "\x00\x41"}]\x00\x00]]
|
||||
|
||||
}
|
||||
|
||||
test encoding-29.0 {get encoding nul terminator lengths} -constraints {
|
||||
|
||||
+124
-55
@@ -27,7 +27,7 @@ testConstraint winLessThan10 0
|
||||
testConstraint notNetworkFilesystem 0
|
||||
testConstraint reg 0
|
||||
if {[testConstraint win]} {
|
||||
catch {
|
||||
if {[catch {
|
||||
# Is the registry extension already static to this shell?
|
||||
try {
|
||||
load {} Registry
|
||||
@@ -38,10 +38,16 @@ if {[testConstraint win]} {
|
||||
load $::reglib Registry
|
||||
}
|
||||
testConstraint reg 1
|
||||
} regError]} {
|
||||
catch {package require registry; testConstraint reg 1}
|
||||
}
|
||||
}
|
||||
|
||||
testConstraint notInCIenv [expr {![info exists ::env(CI)] || !$::env(CI)}]
|
||||
|
||||
# File permissions broken on wsl without some "exotic" wsl configuration
|
||||
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
|
||||
|
||||
set tmpspace /tmp;# default value
|
||||
# Find a group that exists on this Unix system, or else skip tests that
|
||||
# require Unix groups.
|
||||
@@ -97,6 +103,45 @@ if {[testConstraint unix]} {
|
||||
}
|
||||
}
|
||||
|
||||
# Try getting a lower case glob pattern that will match the home directory of
|
||||
# a given user to test ~user and [file tildeexpand ~user]. Note this may not
|
||||
# be the same as ~ even when "user" is current user. For example, on Unix
|
||||
# platforms ~ will return HOME envvar, but ~user will lookup password file
|
||||
# bypassing HOME. If home directory not found, returns *$user* so caller can
|
||||
# succeed by using glob matching under the hope that the path contains
|
||||
# the user name.
|
||||
proc gethomedirglob {user} {
|
||||
if {[testConstraint unix]} {
|
||||
if {![catch {
|
||||
exec {*}[auto_execok sh] -c "echo ~$user"
|
||||
} home]} {
|
||||
set home [string trim $home]
|
||||
if {$home ne ""} {
|
||||
# Expect exact match (except case), no glob * added
|
||||
return [string tolower $home]
|
||||
}
|
||||
}
|
||||
} elseif {[testConstraint reg]} {
|
||||
# Windows with registry extension loaded
|
||||
if {![catch {
|
||||
set sid [exec {*}[auto_execok powershell] -Command "(Get-LocalUser -Name '$user')\[0\].sid.Value"]
|
||||
set sid [string trim $sid]
|
||||
# Get path from the Windows registry
|
||||
set home [registry get "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\$sid" ProfileImagePath]
|
||||
set home [string trim [string tolower $home]]
|
||||
} result]} {
|
||||
if {$home ne ""} {
|
||||
# file join for \ -> /
|
||||
return [file join [string tolower $home]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Caller will need to use glob matching and hope user
|
||||
# name is in the home directory path
|
||||
return *[string tolower $user]*
|
||||
}
|
||||
|
||||
proc createfile {file {string a}} {
|
||||
set f [open $file w]
|
||||
puts -nonewline $f $string
|
||||
@@ -354,7 +399,7 @@ test fCmd-4.10 {TclFileMakeDirsCmd: exists, is dir} -setup {
|
||||
} -result {1 1}
|
||||
test fCmd-4.11 {TclFileMakeDirsCmd: doesn't exist: errno != ENOENT} -setup {
|
||||
cleanup
|
||||
} -constraints {unix notRoot testchmod} -returnCodes error -body {
|
||||
} -constraints {unix notRoot testchmod notWsl} -returnCodes error -body {
|
||||
file mkdir td1/td2/td3
|
||||
testchmod 0 td1/td2
|
||||
file mkdir td1/td2/td3/td4
|
||||
@@ -372,7 +417,7 @@ test fCmd-4.13 {TclFileMakeDirsCmd: doesn't exist: errno == ENOENT} -setup {
|
||||
test fCmd-4.14 {TclFileMakeDirsCmd: TclpCreateDirectory fails} -setup {
|
||||
cleanup
|
||||
file delete -force foo
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir foo
|
||||
file attr foo -perm 0o40000
|
||||
file mkdir foo/tf1
|
||||
@@ -384,7 +429,7 @@ test fCmd-4.16 {TclFileMakeDirsCmd: TclpCreateDirectory succeeds} -setup {
|
||||
} -constraints {notRoot} -body {
|
||||
file mkdir tf1
|
||||
file exists tf1
|
||||
} -result {1}
|
||||
} -result 1
|
||||
|
||||
test fCmd-5.1 {TclFileDeleteCmd: FileForceOption fails} -constraints {notRoot} -body {
|
||||
file delete -xyz
|
||||
@@ -497,7 +542,7 @@ test fCmd-6.5 {CopyRenameOneFile: lstat(target) != 0} -setup {
|
||||
} -result {tf2}
|
||||
test fCmd-6.6 {CopyRenameOneFile: errno != ENOENT} -setup {
|
||||
cleanup
|
||||
} -constraints {unix notRoot testchmod} -body {
|
||||
} -constraints {unix notRoot testchmod notWsl} -body {
|
||||
file mkdir td1
|
||||
testchmod 0 td1
|
||||
createfile tf1
|
||||
@@ -616,7 +661,7 @@ test fCmd-6.22 {CopyRenameOneFile: copy/rename: !S_ISDIR(source)} -setup {
|
||||
} -result [file join $tmpspace tf1]
|
||||
test fCmd-6.23 {CopyRenameOneFile: TclpCopyDirectory failed} -setup {
|
||||
cleanup $tmpspace
|
||||
} -constraints {xdev notRoot} -body {
|
||||
} -constraints {xdev notRoot notWsl} -body {
|
||||
file mkdir td1/td2/td3
|
||||
file attributes td1 -permissions 0
|
||||
file rename td1 $tmpspace
|
||||
@@ -668,7 +713,7 @@ test fCmd-6.27 {CopyRenameOneFile: TclpCopyDirectory failed} -setup {
|
||||
} -match glob -result {error renaming "td1" to "/tmp/tcl*/td1": file already exists}
|
||||
test fCmd-6.28 {CopyRenameOneFile: TclpCopyDirectory failed} -setup {
|
||||
cleanup $tmpspace
|
||||
} -constraints {notRoot xdev} -body {
|
||||
} -constraints {notRoot xdev notWsl} -body {
|
||||
file mkdir td1/td2/td3
|
||||
file attributes td1/td2/td3 -permissions 0
|
||||
file rename td1 $tmpspace
|
||||
@@ -685,7 +730,7 @@ test fCmd-6.29 {CopyRenameOneFile: TclpCopyDirectory passed} -setup {
|
||||
} -result [file join $tmpspace td1 td2]
|
||||
test fCmd-6.30 {CopyRenameOneFile: TclpRemoveDirectory failed} -setup {
|
||||
cleanup $tmpspace
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir foo/bar
|
||||
file attr foo -perm 0o40555
|
||||
file rename foo/bar $tmpspace
|
||||
@@ -760,7 +805,7 @@ test fCmd-8.3 {file copy and path translation: ensure correct error} -body {
|
||||
|
||||
test fCmd-9.1 {file rename: comprehensive: EACCES} -setup {
|
||||
cleanup
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir td1
|
||||
file mkdir td2
|
||||
file attr td2 -perm 0o40000
|
||||
@@ -786,7 +831,7 @@ test fCmd-9.3 {file rename: comprehensive: file to new name} -setup {
|
||||
} -result {{tf3 tf4} 1 0}
|
||||
test fCmd-9.4 {file rename: comprehensive: dir to new name} -setup {
|
||||
cleanup
|
||||
} -constraints {unix notRoot testchmod notDarwin9} -body {
|
||||
} -constraints {unix notRoot testchmod notDarwin9 notWsl} -body {
|
||||
file mkdir td1 td2
|
||||
testchmod 0o555 td2
|
||||
file rename td1 td3
|
||||
@@ -807,7 +852,7 @@ test fCmd-9.5 {file rename: comprehensive: file to self} -setup {
|
||||
} -result {tf1 tf2 1 0}
|
||||
test fCmd-9.6 {file rename: comprehensive: dir to self} -setup {
|
||||
cleanup
|
||||
} -constraints {unix notRoot testchmod} -body {
|
||||
} -constraints {unix notRoot testchmod notWsl} -body {
|
||||
file mkdir td1
|
||||
file mkdir td2
|
||||
testchmod 0o555 td2
|
||||
@@ -1001,7 +1046,7 @@ test fCmd-10.2 {file copy: comprehensive: file to new name} -setup {
|
||||
} -result {{tf1 tf2 tf3 tf4} tf1 tf2 1 0}
|
||||
test fCmd-10.3 {file copy: comprehensive: dir to new name} -setup {
|
||||
cleanup
|
||||
} -constraints {unix notRoot testchmod} -body {
|
||||
} -constraints {unix notRoot testchmod notWsl} -body {
|
||||
file mkdir [file join td1 tdx]
|
||||
file mkdir [file join td2 tdy]
|
||||
testchmod 0o555 td2
|
||||
@@ -1020,6 +1065,7 @@ test fCmd-10.3.1 {file copy: comprehensive: dir to new name} -setup {
|
||||
file mkdir [file join td1 tdx]
|
||||
file mkdir [file join td2 tdy]
|
||||
testchmod 0o555 td2
|
||||
testchmod 0o555 td2/tdy; # Above line removes inherited perms. So restore.
|
||||
file copy td1 td3
|
||||
file copy td2 td4
|
||||
list [lsort [glob td*]] [glob -directory td3 t*] \
|
||||
@@ -1041,10 +1087,19 @@ test fCmd-10.4 {file copy: comprehensive: file to existing file} -setup {
|
||||
createfile tfd2
|
||||
createfile tfd3
|
||||
createfile tfd4
|
||||
testchmod 0o444 tfs3
|
||||
testchmod 0o444 tfs4
|
||||
testchmod 0o444 tfd2
|
||||
testchmod 0o444 tfd4
|
||||
if {$::tcl_platform(platform) eq "windows"} {
|
||||
# On Windows testchmode will attach an ACL which file copy cannot handle
|
||||
# so use good old attributes which file copy does understand
|
||||
file attribute tfs3 -readonly 1
|
||||
file attribute tfs4 -readonly 1
|
||||
file attribute tfd2 -readonly 1
|
||||
file attribute tfd4 -readonly 1
|
||||
} else {
|
||||
testchmod 0o444 tfs3
|
||||
testchmod 0o444 tfs4
|
||||
testchmod 0o444 tfd2
|
||||
testchmod 0o444 tfd4
|
||||
}
|
||||
set msg [list [catch {file copy tf1 tf2} msg] $msg]
|
||||
file copy -force tfs1 tfd1
|
||||
file copy -force tfs2 tfd2
|
||||
@@ -1078,7 +1133,7 @@ test fCmd-10.5 {file copy: comprehensive: dir to empty dir} -setup {
|
||||
} -result [subst {{td1 td2 tdd1 tdd2 tdd3 tdd4 tds1 tds2 tds3 tds4} {1 {error copying "td1" to "[file join td2 td1]": file already exists}} {1 {error copying "tds1" to "[file join tdd1 tds1]": file already exists}} 1 1 1}]
|
||||
test fCmd-10.6 {file copy: comprehensive: dir to non-empty dir} -setup {
|
||||
cleanup
|
||||
} -constraints {notRoot unixOrWin testchmod} -body {
|
||||
} -constraints {notRoot unixOrWin testchmod notWsl} -body {
|
||||
file mkdir tds1
|
||||
file mkdir tds2
|
||||
file mkdir [file join tdd1 tds1 xxx]
|
||||
@@ -1102,7 +1157,7 @@ test fCmd-10.7 {file rename: comprehensive: file to new name and dir} -setup {
|
||||
} -result [subst {{tf1 tf2} {[file join td1 tf3] [file join td1 tf4]} 1 0}]
|
||||
test fCmd-10.8 {file rename: comprehensive: dir to new name and dir} -setup {
|
||||
cleanup
|
||||
} -constraints {unix notRoot testchmod} -body {
|
||||
} -constraints {unix notRoot testchmod notWsl} -body {
|
||||
file mkdir td1
|
||||
file mkdir td2
|
||||
file mkdir td3
|
||||
@@ -1194,7 +1249,7 @@ test fCmd-11.5 {TclFileRenameCmd: > 1 source & target is not a dir} -setup {
|
||||
catch {file rename tfa1 tfa2 tfa3}
|
||||
} -cleanup {
|
||||
file delete tfa1 tfa2 tfa3
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-11.6 {TclFileRenameCmd: : single file into directory} -setup {
|
||||
catch {file delete -force -- tfa1 tfad}
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1239,7 +1294,7 @@ test fCmd-12.1 {renamefile: source filename translation failing} -setup {
|
||||
catch {file rename ~/tfa1 tfa2}
|
||||
} -cleanup {
|
||||
set ::env(HOME) $temp
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-12.2 {renamefile: src filename translation failing} -setup {
|
||||
set temp $::env(HOME)
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1251,7 +1306,7 @@ test fCmd-12.2 {renamefile: src filename translation failing} -setup {
|
||||
} -cleanup {
|
||||
set ::env(HOME) $temp
|
||||
file delete -force tfad
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-12.3 {renamefile: stat failing on source} -setup {
|
||||
catch {file delete -force -- tfa1 tfa2}
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1296,10 +1351,10 @@ test fCmd-12.7 {renamefile: renaming directory into offspring} -setup {
|
||||
catch {file rename tfad tfad/dir}
|
||||
} -cleanup {
|
||||
file delete -force tfad
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-12.8 {renamefile: generic error} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir tfa
|
||||
file mkdir tfa/dir
|
||||
file attributes tfa -permissions 0o555
|
||||
@@ -1307,7 +1362,7 @@ test fCmd-12.8 {renamefile: generic error} -setup {
|
||||
} -cleanup {
|
||||
catch {file attributes tfa -permissions 0o777}
|
||||
file delete -force tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-12.9 {renamefile: moving a file across volumes} -setup {
|
||||
cleanup $tmpspace
|
||||
} -constraints {unix notRoot} -body {
|
||||
@@ -1369,7 +1424,7 @@ test fCmd-13.5 {TclCopyFilesCmd: target filename translation failing} -setup {
|
||||
catch { file copy tfa ~/foobar }
|
||||
} -cleanup {
|
||||
set ::env(HOME) $temp
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-13.6 {TclCopyFilesCmd: > 1 source & target is not a dir} -setup {
|
||||
catch {file delete -force -- tfa1 tfa2 tfa3}
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1379,7 +1434,7 @@ test fCmd-13.6 {TclCopyFilesCmd: > 1 source & target is not a dir} -setup {
|
||||
catch {file copy tfa1 tfa2 tfa3}
|
||||
} -cleanup {
|
||||
file delete tfa1 tfa2 tfa3
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-13.7 {TclCopyFilesCmd: single file into directory} -setup {
|
||||
catch {file delete -force -- tfa1 tfad}
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1425,7 +1480,7 @@ test fCmd-14.1 {copyfile: source filename translation failing} -setup {
|
||||
catch {file copy ~/tfa1 tfa2}
|
||||
} -cleanup {
|
||||
set ::env(HOME) $temp
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-14.2 {copyfile: dst filename translation failing} -setup {
|
||||
set temp $::env(HOME)
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1486,14 +1541,14 @@ test fCmd-14.7 {copyfile: copy directory succeeding} -setup {
|
||||
} -result {1 1}
|
||||
test fCmd-14.8 {copyfile: copy directory failing} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir tfa/dir/a/b/c
|
||||
file attributes tfa/dir -permissions 0
|
||||
catch {file copy tfa tfa2}
|
||||
} -cleanup {
|
||||
file attributes tfa/dir -permissions 0o777
|
||||
file delete -force tfa tfa2
|
||||
} -result {1}
|
||||
} -result 1
|
||||
|
||||
#
|
||||
# Coverage tests for TclMkdirCmd()
|
||||
@@ -1506,7 +1561,7 @@ test fCmd-15.1 {TclMakeDirsCmd: target filename translation failing} -setup {
|
||||
catch {file mkdir ~/tfa}
|
||||
} -cleanup {
|
||||
set ::env(HOME) $temp
|
||||
} -result {1}
|
||||
} -result 1
|
||||
#
|
||||
# Can Tcl_SplitPath return argc == 0? If so them we need a test for that code.
|
||||
#
|
||||
@@ -1517,7 +1572,7 @@ test fCmd-15.2 {TclMakeDirsCmd - one directory} -setup {
|
||||
file isdirectory tfa
|
||||
} -cleanup {
|
||||
file delete tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-15.3 {TclMakeDirsCmd: - two directories} -setup {
|
||||
catch {file delete -force -- tfa1 tfa2}
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1536,7 +1591,7 @@ test fCmd-15.4 {TclMakeDirsCmd - stat failing} -setup {
|
||||
} -cleanup {
|
||||
file attributes tfa -permissions 0o777
|
||||
file delete -force tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-15.5 {TclMakeDirsCmd: - making a directory several levels deep} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1544,7 +1599,7 @@ test fCmd-15.5 {TclMakeDirsCmd: - making a directory several levels deep} -setup
|
||||
file isdir tfa/a/b/c
|
||||
} -cleanup {
|
||||
file delete -force tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-15.6 {TclMakeDirsCmd: - trying to overwrite a file} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1568,7 +1623,7 @@ test fCmd-15.8 {TclFileMakeDirsCmd: trying to create an existing dir} -body {
|
||||
file isdir tfa
|
||||
} -constraints {notRoot} -cleanup {
|
||||
file delete tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
|
||||
# Coverage tests for TclDeleteFilesCommand()
|
||||
test fCmd-16.1 {test the -- argument} -constraints {notRoot} -setup {
|
||||
@@ -1592,7 +1647,7 @@ test fCmd-16.3 {test bad option} -constraints {notRoot} -setup {
|
||||
catch {file delete -dog tfa}
|
||||
} -cleanup {
|
||||
file delete tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-16.4 {accept zero files (TIP 323)} -body {
|
||||
file delete
|
||||
} -result {}
|
||||
@@ -1607,7 +1662,7 @@ test fCmd-16.6 {delete: source filename translation failing} -setup {
|
||||
catch {file delete ~/tfa}
|
||||
} -cleanup {
|
||||
set ::env(HOME) $temp
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-16.7 {remove a non-empty directory without -force} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1616,7 +1671,7 @@ test fCmd-16.7 {remove a non-empty directory without -force} -setup {
|
||||
catch {file delete tfa}
|
||||
} -cleanup {
|
||||
file delete -force tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-16.8 {remove a normal file} -constraints {notRoot} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -body {
|
||||
@@ -1625,10 +1680,10 @@ test fCmd-16.8 {remove a normal file} -constraints {notRoot} -setup {
|
||||
catch {file delete tfa}
|
||||
} -cleanup {
|
||||
file delete -force tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-16.9 {error while deleting file} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir tfa
|
||||
createfile tfa/a
|
||||
file attributes tfa -permissions 0o555
|
||||
@@ -1641,7 +1696,7 @@ test fCmd-16.9 {error while deleting file} -setup {
|
||||
} -cleanup {
|
||||
file attributes tfa -permissions 0o777
|
||||
file delete -force tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-16.10 {deleting multiple files} -constraints {notRoot} -setup {
|
||||
catch {file delete -force -- tfa1 tfa2}
|
||||
} -body {
|
||||
@@ -1659,14 +1714,14 @@ test fCmd-16.11 {TclFileDeleteCmd: removing a nonexistant file} -setup {
|
||||
# More coverage tests for mkpath()
|
||||
test fCmd-17.1 {mkdir stat failing on target but not ENOENT} -setup {
|
||||
catch {file delete -force -- tfa1}
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir tfa1
|
||||
file attributes tfa1 -permissions 0o555
|
||||
catch {file mkdir tfa1/tfa2}
|
||||
} -cleanup {
|
||||
file attributes tfa1 -permissions 0o777
|
||||
file delete -force tfa1
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-17.2 {mkdir several levels deep - relative} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -1683,7 +1738,7 @@ test fCmd-17.3 {mkdir several levels deep - absolute} -setup {
|
||||
file isdir $f
|
||||
} -cleanup {
|
||||
file delete $f [file join [pwd] tfa]
|
||||
} -result {1}
|
||||
} -result 1
|
||||
|
||||
#
|
||||
# Functionality tests for TclFileRenameCmd()
|
||||
@@ -1844,7 +1899,7 @@ test fCmd-18.15 {TclFileRenameCmd : rename a file to a symlink dir} -setup {
|
||||
checkcontent tfa1/tfa2 $s
|
||||
} -cleanup {
|
||||
file delete -force tfa1 tfalink
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-18.16 {TclFileRenameCmd: rename a dangling symlink} -setup {
|
||||
catch {file delete -force -- tfa1 tfalink}
|
||||
} -constraints {unix notRoot} -body {
|
||||
@@ -1869,7 +1924,7 @@ test fCmd-19.1 {remove empty directory} -constraints {notRoot} -setup {
|
||||
} -result {0}
|
||||
test fCmd-19.2 {rmdir error besides EEXIST} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir tfa
|
||||
file mkdir tfa/a
|
||||
file attributes tfa -permissions 0o555
|
||||
@@ -1877,7 +1932,7 @@ test fCmd-19.2 {rmdir error besides EEXIST} -setup {
|
||||
} -cleanup {
|
||||
file attributes tfa -permissions 0o777
|
||||
file delete -force tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-19.3 {recursive remove} -constraints {notRoot} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -body {
|
||||
@@ -1897,7 +1952,7 @@ test fCmd-19.3 {recursive remove} -constraints {notRoot} -setup {
|
||||
#
|
||||
test fCmd-20.1 {TraverseUnixTree : failure opening a subdirectory directory} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir tfa
|
||||
file mkdir tfa/a
|
||||
file attributes tfa/a -permissions 00000
|
||||
@@ -1905,7 +1960,7 @@ test fCmd-20.1 {TraverseUnixTree : failure opening a subdirectory directory} -se
|
||||
} -cleanup {
|
||||
file attributes tfa/a -permissions 0o777
|
||||
file delete -force tfa
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-20.2 {TraverseUnixTree : recursive delete of large directory: Bug 1034337} -setup {
|
||||
catch {file delete -force -- tfa}
|
||||
} -constraints {unix notRoot} -body {
|
||||
@@ -1958,7 +2013,7 @@ test fCmd-21.4 {copy : more than one source and target is not a directory} -setu
|
||||
catch {file copy tfa1 tfa2 tfa3}
|
||||
} -cleanup {
|
||||
file delete tfa1 tfa2 tfa3
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-21.5 {copy : multiple files into directory} -constraints {notRoot} -setup {
|
||||
catch {file delete -force -- tfa1 tfa2 tfad}
|
||||
} -body {
|
||||
@@ -2083,7 +2138,7 @@ test fCmd-22.2 {TclpRenameFile: attempt to overwrite itself} -setup {
|
||||
checkcontent tfa1 $s
|
||||
} -cleanup {
|
||||
file delete tfa1
|
||||
} -result {1}
|
||||
} -result 1
|
||||
test fCmd-22.3 {TclpRenameFile: rename dir to existing dir} -setup {
|
||||
catch {file delete -force -- d1 tfad}
|
||||
} -constraints {notRoot} -body {
|
||||
@@ -2543,7 +2598,7 @@ test fCmd-30.2 {file readable on 'NTUSER.DAT'} -constraints {win notWine} -body
|
||||
expr {[info exists env(USERPROFILE)]
|
||||
&& [file exists $env(USERPROFILE)/NTUSER.DAT]
|
||||
&& [file readable $env(USERPROFILE)/NTUSER.DAT]}
|
||||
} -result {1}
|
||||
} -result 1
|
||||
# At least one CI environment (GitHub Actions) is set up with the page file in
|
||||
# an unusual location; skip the test if that is so.
|
||||
test fCmd-30.3 {file readable on 'pagefile.sys'} -constraints {win notInCIenv} -body {
|
||||
@@ -2599,13 +2654,20 @@ test fCmd-31.6 {file home USER} -body {
|
||||
# env(HOME) even when user is current user. Assume result contains user
|
||||
# name, else not sure how to check
|
||||
string tolower [file home $::tcl_platform(user)]
|
||||
} -match glob -result [string tolower "*$::tcl_platform(user)*"]
|
||||
} -match glob -result [gethomedirglob $::tcl_platform(user)]
|
||||
test fCmd-31.7 {file home UNKNOWNUSER} -body {
|
||||
file home nosuchuser
|
||||
} -returnCodes error -result {user "nosuchuser" doesn't exist}
|
||||
test fCmd-31.8 {file home extra arg} -body {
|
||||
file home $::tcl_platform(user) arg
|
||||
} -returnCodes error -result {wrong # args: should be "file home ?user?"}
|
||||
test fCmd-31.9 {file home USER does not follow env(HOME)} -setup {
|
||||
set ::env(HOME) [file join $::env(HOME) foo]
|
||||
} -cleanup {
|
||||
set ::env(HOME) [file dirname $::env(HOME)]
|
||||
} -body {
|
||||
string tolower [file home $::tcl_platform(user)]
|
||||
} -match glob -result [gethomedirglob $::tcl_platform(user)]
|
||||
|
||||
test fCmd-32.1 {file tildeexpand ~} -body {
|
||||
file tildeexpand ~
|
||||
@@ -2641,7 +2703,7 @@ test fCmd-32.5 {file tildeexpand ~USER} -body {
|
||||
# env(HOME) even when user is current user. Assume result contains user
|
||||
# name, else not sure how to check
|
||||
string tolower [file tildeexpand ~$::tcl_platform(user)]
|
||||
} -match glob -result [string tolower "*$::tcl_platform(user)*"]
|
||||
} -match glob -result [gethomedirglob $::tcl_platform(user)]
|
||||
test fCmd-32.6 {file tildeexpand ~UNKNOWNUSER} -body {
|
||||
file tildeexpand ~nosuchuser
|
||||
} -returnCodes error -result {user "nosuchuser" doesn't exist}
|
||||
@@ -2656,7 +2718,7 @@ test fCmd-32.9 {file tildeexpand ~USER/bar} -body {
|
||||
# env(HOME) even when user is current user. Assume result contains user
|
||||
# name, else not sure how to check
|
||||
string tolower [file tildeexpand ~$::tcl_platform(user)/bar]
|
||||
} -match glob -result [string tolower "*$::tcl_platform(user)*/bar"]
|
||||
} -match glob -result [file join [gethomedirglob $::tcl_platform(user)] bar]
|
||||
test fCmd-32.10 {file tildeexpand ~UNKNOWNUSER} -body {
|
||||
file tildeexpand ~nosuchuser/foo
|
||||
} -returnCodes error -result {user "nosuchuser" doesn't exist}
|
||||
@@ -2680,7 +2742,14 @@ test fCmd-32.16 {file tildeexpand ~USER\\bar} -body {
|
||||
# env(HOME) even when user is current user. Assume result contains user
|
||||
# name, else not sure how to check
|
||||
string tolower [file tildeexpand ~$::tcl_platform(user)\\bar]
|
||||
} -constraints win -match glob -result [string tolower "*$::tcl_platform(user)*/bar"]
|
||||
} -constraints win -match glob -result [file join [gethomedirglob $::tcl_platform(user)] bar]
|
||||
test fCmd-32.17 {file tildeexpand ~USER does not mirror HOME} -setup {
|
||||
set ::env(HOME) [file join $::env(HOME) foo]
|
||||
} -cleanup {
|
||||
set ::env(HOME) [file dirname $::env(HOME)]
|
||||
} -body {
|
||||
string tolower [file tildeexpand ~$::tcl_platform(user)]
|
||||
} -match glob -result [gethomedirglob $::tcl_platform(user)]
|
||||
|
||||
|
||||
# cleanup
|
||||
|
||||
@@ -276,6 +276,16 @@ test filesystem-1.30.1 {normalisation of existing user} -body {
|
||||
test filesystem-1.30.2 {normalisation of nonexistent user specified as user@domain} -body {
|
||||
file normalize ~nonexistentuser@nonexistentdomain
|
||||
} -returnCodes error -result {user "nonexistentuser@nonexistentdomain" doesn't exist}
|
||||
test filesystem-1.30.3 {file normalization should distinguish between ~ and ~user} -setup {
|
||||
set oldhome $::env(HOME)
|
||||
set olduserhome [file normalize ~$::tcl_platform(user)]
|
||||
set ::env(HOME) [file join $oldhome temp]
|
||||
} -cleanup {
|
||||
set env(HOME) $oldhome
|
||||
} -body {
|
||||
list [string equal [file normalize ~] $::env(HOME)] \
|
||||
[string equal $olduserhome [file normalize ~$::tcl_platform(user)]]
|
||||
} -result {1 1}
|
||||
test filesystem-1.31 {link normalisation: link near filesystem root} {testsetplatform} {
|
||||
testsetplatform unix
|
||||
file normalize /foo/../bar
|
||||
|
||||
+121
-57
@@ -48,6 +48,8 @@ testConstraint testservicemode [llength [info commands testservicemode]]
|
||||
testConstraint notWinCI [expr {
|
||||
$::tcl_platform(platform) ne "windows" || ![info exists ::env(CI)]}]
|
||||
testConstraint notOSX [expr {$::tcl_platform(os) ne "Darwin"}]
|
||||
# File permissions broken on wsl without some "exotic" wsl configuration
|
||||
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
|
||||
|
||||
# You need a *very* special environment to do some tests. In
|
||||
# particular, many file systems do not support large-files...
|
||||
@@ -5474,7 +5476,7 @@ test io-38.3 {Tcl_SetChannelBufferSize, changing buffersize between reads} {
|
||||
# This test crashes the interp if Bug #427196 is not fixed
|
||||
|
||||
set chan [open [info script] r]
|
||||
fconfigure $chan -buffersize 10
|
||||
fconfigure $chan -buffersize 10 -encoding utf-8
|
||||
set var [read $chan 2]
|
||||
fconfigure $chan -buffersize 32
|
||||
append var [read $chan]
|
||||
@@ -5675,13 +5677,20 @@ test io-39.15 {Tcl_SetChannelOption: -encoding, binary & utf-8} {
|
||||
close $f
|
||||
set x
|
||||
} 牦
|
||||
test io-39.16 {Tcl_SetChannelOption: -encoding, errors} {
|
||||
test io-39.16 {Tcl_SetChannelOption: -encoding (shortened to "-en"), errors} -body {
|
||||
file delete $path(test1)
|
||||
set f [open $path(test1) w]
|
||||
set result [list [catch {fconfigure $f -encoding foobar} msg] $msg]
|
||||
fconfigure $f -en foobar
|
||||
} -cleanup {
|
||||
close $f
|
||||
set result
|
||||
} {1 {unknown encoding "foobar"}}
|
||||
} -returnCodes 1 -result {unknown encoding "foobar"}
|
||||
test io-39.16a {Tcl_SetChannelOption: -encoding (invalid shortening to "-e"), errors} -body {
|
||||
file delete $path(test1)
|
||||
set f [open $path(test1) w]
|
||||
fconfigure $f -e foobar
|
||||
} -cleanup {
|
||||
close $f
|
||||
} -returnCodes 1 -match glob -result {bad option "-e": should be one of *}
|
||||
test io-39.17 {Tcl_SetChannelOption: -encoding, clearing CHANNEL_NEED_MORE_DATA} {stdio fileevent} {
|
||||
set f [open "|[list [interpreter] $path(cat)]" r+]
|
||||
fconfigure $f -encoding binary
|
||||
@@ -5813,7 +5822,7 @@ test io-40.1 {POSIX open access modes: RDWR} {
|
||||
close $f
|
||||
set x
|
||||
} {zzy abzzy}
|
||||
test io-40.2 {POSIX open access modes: CREAT} {unix} {
|
||||
test io-40.2 {POSIX open access modes: CREAT} {unix notWsl} {
|
||||
file delete $path(test3)
|
||||
set f [open $path(test3) {WRONLY CREAT} 0o600]
|
||||
file stat $path(test3) stats
|
||||
@@ -5825,7 +5834,7 @@ test io-40.2 {POSIX open access modes: CREAT} {unix} {
|
||||
close $f
|
||||
set x
|
||||
} {0o600 {line 1}}
|
||||
test io-40.3 {POSIX open access modes: CREAT} {unix umask} {
|
||||
test io-40.3 {POSIX open access modes: CREAT} {unix umask notWsl} {
|
||||
# This test only works if your umask is 2, like ouster's.
|
||||
file delete $path(test3)
|
||||
set f [open $path(test3) {WRONLY CREAT}]
|
||||
@@ -7280,8 +7289,8 @@ test io-52.5 {TclCopyChannel, all} {fcopy} {
|
||||
file delete $path(test1)
|
||||
set f1 [open $thisScript]
|
||||
set f2 [open $path(test1) w]
|
||||
fconfigure $f1 -translation lf -blocking 0
|
||||
fconfigure $f2 -translation lf -blocking 0
|
||||
fconfigure $f1 -translation lf -encoding iso8859-1 -blocking 0
|
||||
fconfigure $f2 -translation lf -encoding iso8859-1 -blocking 0
|
||||
fcopy $f1 $f2 -size -1 ;# -1 means 'copy all', same as if no -size specified.
|
||||
set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]]
|
||||
close $f1
|
||||
@@ -7297,8 +7306,8 @@ test io-52.5a {TclCopyChannel, all, other negative value} {fcopy} {
|
||||
file delete $path(test1)
|
||||
set f1 [open $thisScript]
|
||||
set f2 [open $path(test1) w]
|
||||
fconfigure $f1 -translation lf -blocking 0
|
||||
fconfigure $f2 -translation lf -blocking 0
|
||||
fconfigure $f1 -translation lf -encoding iso8859-1 -blocking 0
|
||||
fconfigure $f2 -translation lf -encoding iso8859-1 -blocking 0
|
||||
fcopy $f1 $f2 -size -2 ;# < 0 behaves like -1, copy all
|
||||
set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]]
|
||||
close $f1
|
||||
@@ -7314,8 +7323,8 @@ test io-52.5b {TclCopyChannel, all, wrap to negative value} {fcopy} {
|
||||
file delete $path(test1)
|
||||
set f1 [open $thisScript]
|
||||
set f2 [open $path(test1) w]
|
||||
fconfigure $f1 -translation lf -blocking 0
|
||||
fconfigure $f2 -translation lf -blocking 0
|
||||
fconfigure $f1 -translation lf -encoding iso8859-1 -blocking 0
|
||||
fconfigure $f2 -translation lf -encoding iso8859-1 -blocking 0
|
||||
fcopy $f1 $f2 -size 3221176172 ;# Wrapped to < 0, behaves like -1, copy all
|
||||
set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]]
|
||||
close $f1
|
||||
@@ -7348,8 +7357,8 @@ test io-52.7 {TclCopyChannel} {fcopy} {
|
||||
file delete $path(test1)
|
||||
set f1 [open $thisScript]
|
||||
set f2 [open $path(test1) w]
|
||||
fconfigure $f1 -translation lf -blocking 0
|
||||
fconfigure $f2 -translation lf -blocking 0
|
||||
fconfigure $f1 -translation lf -encoding iso8859-1 -blocking 0
|
||||
fconfigure $f2 -translation lf -encoding iso8859-1 -blocking 0
|
||||
fcopy $f1 $f2
|
||||
set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]]
|
||||
set s1 [file size $thisScript]
|
||||
@@ -7609,6 +7618,103 @@ test io-52.19 {coverage of eofChar handling} {
|
||||
close $out
|
||||
file size $path(test2)
|
||||
} 8
|
||||
test io-52.20 {TclCopyChannel & encodings} -setup {
|
||||
set out [open $path(utf8-fcopy.txt) w]
|
||||
fconfigure $out -encoding utf-8 -translation lf
|
||||
puts $out "Á"
|
||||
close $out
|
||||
} -constraints {fcopy} -body {
|
||||
# binary to encoding => the input has to be
|
||||
# in utf-8 to make sense to the encoder
|
||||
|
||||
set in [open $path(utf8-fcopy.txt) r]
|
||||
set out [open $path(kyrillic.txt) w]
|
||||
|
||||
# Using "-encoding ascii" means reading the "Á" gives an error
|
||||
fconfigure $in -encoding ascii -strictencoding 1
|
||||
fconfigure $out -encoding koi8-r -translation lf
|
||||
|
||||
fcopy $in $out
|
||||
} -cleanup {
|
||||
close $in
|
||||
close $out
|
||||
} -returnCodes 1 -match glob -result {error reading "file*": illegal byte sequence}
|
||||
test io-52.21 {TclCopyChannel & encodings} -setup {
|
||||
set out [open $path(utf8-fcopy.txt) w]
|
||||
fconfigure $out -encoding utf-8 -translation lf
|
||||
puts $out "Á"
|
||||
close $out
|
||||
} -constraints {fcopy} -body {
|
||||
# binary to encoding => the input has to be
|
||||
# in utf-8 to make sense to the encoder
|
||||
|
||||
set in [open $path(utf8-fcopy.txt) r]
|
||||
set out [open $path(kyrillic.txt) w]
|
||||
|
||||
# Using "-encoding ascii" means writing the "Á" gives an error
|
||||
fconfigure $in -encoding utf-8
|
||||
fconfigure $out -encoding ascii -translation lf -strictencoding 1
|
||||
|
||||
fcopy $in $out
|
||||
} -cleanup {
|
||||
close $in
|
||||
close $out
|
||||
} -returnCodes 1 -match glob -result {error writing "file*": illegal byte sequence}
|
||||
test io-52.22 {TclCopyChannel & encodings} -setup {
|
||||
set out [open $path(utf8-fcopy.txt) w]
|
||||
fconfigure $out -encoding utf-8 -translation lf
|
||||
puts $out "Á"
|
||||
close $out
|
||||
} -constraints {fcopy} -body {
|
||||
# binary to encoding => the input has to be
|
||||
# in utf-8 to make sense to the encoder
|
||||
|
||||
set in [open $path(utf8-fcopy.txt) r]
|
||||
set out [open $path(kyrillic.txt) w]
|
||||
|
||||
# Using "-encoding ascii" means reading the "Á" gives an error
|
||||
fconfigure $in -encoding ascii -strictencoding 1
|
||||
fconfigure $out -encoding koi8-r -translation lf
|
||||
proc ::xxx args {
|
||||
set ::s0 $args
|
||||
}
|
||||
|
||||
fcopy $in $out -command ::xxx
|
||||
vwait ::s0
|
||||
set ::s0
|
||||
} -cleanup {
|
||||
close $in
|
||||
close $out
|
||||
unset ::s0
|
||||
} -match glob -result {0 {error reading "file*": illegal byte sequence}}
|
||||
test io-52.23 {TclCopyChannel & encodings} -setup {
|
||||
set out [open $path(utf8-fcopy.txt) w]
|
||||
fconfigure $out -encoding utf-8 -translation lf
|
||||
puts $out "Á"
|
||||
close $out
|
||||
} -constraints {fcopy} -body {
|
||||
# binary to encoding => the input has to be
|
||||
# in utf-8 to make sense to the encoder
|
||||
|
||||
set in [open $path(utf8-fcopy.txt) r]
|
||||
set out [open $path(kyrillic.txt) w]
|
||||
|
||||
# Using "-encoding ascii" means writing the "Á" gives an error
|
||||
fconfigure $in -encoding utf-8
|
||||
fconfigure $out -encoding ascii -translation lf -strictencoding 1
|
||||
proc ::xxx args {
|
||||
set ::s0 $args
|
||||
}
|
||||
|
||||
fcopy $in $out -command ::xxx
|
||||
vwait ::s0
|
||||
set ::s0
|
||||
} -cleanup {
|
||||
close $in
|
||||
close $out
|
||||
unset ::s0
|
||||
} -match glob -result {0 {error writing "file*": illegal byte sequence}}
|
||||
|
||||
|
||||
test io-53.1 {CopyData} {fcopy} {
|
||||
file delete $path(test1)
|
||||
@@ -9046,48 +9152,6 @@ test io-75.5 {invalid utf-8 encoding read is ignored (-nocomplainencoding 1)} -s
|
||||
removeFile io-75.5
|
||||
} -result 4181
|
||||
|
||||
test io-75.6 {invalid utf-8 encoding read is not ignored (-strictencoding 1)} -setup {
|
||||
set fn [makeFile {} io-75.6]
|
||||
set f [open $fn w+]
|
||||
fconfigure $f -encoding binary
|
||||
# \x81 is invalid in utf-8
|
||||
puts -nonewline $f A\x81
|
||||
flush $f
|
||||
seek $f 0
|
||||
fconfigure $f -encoding utf-8 -buffering none -eofchar "" -translation lf -strictencoding 1
|
||||
} -body {
|
||||
set d [read $f]
|
||||
binary scan $d H* hd
|
||||
lappend hd [catch {read $f} msg]
|
||||
close $f
|
||||
lappend hd $msg
|
||||
} -cleanup {
|
||||
removeFile io-75.6
|
||||
} -match glob -result {41 1 {error reading "*": illegal byte sequence}}
|
||||
|
||||
test io-75.7 {invalid utf-8 encoding eof handling (-strictencoding 1)} -setup {
|
||||
set fn [makeFile {} io-75.7]
|
||||
set f [open $fn w+]
|
||||
fconfigure $f -encoding binary
|
||||
# \xA1 is invalid in utf-8. -eofchar is not detected, because it comes later.
|
||||
puts -nonewline $f A\xA1\x1A
|
||||
flush $f
|
||||
seek $f 0
|
||||
fconfigure $f -encoding utf-8 -buffering none -eofchar \x1A -translation lf -strictencoding 1
|
||||
} -body {
|
||||
set d [read $f]
|
||||
binary scan $d H* hd
|
||||
lappend hd [eof $f]
|
||||
lappend hd [catch {read $f} msg]
|
||||
lappend hd $msg
|
||||
fconfigure $f -encoding iso8859-1
|
||||
lappend hd [read $f];# We changed encoding, so now we can read the \xA1
|
||||
close $f
|
||||
set hd
|
||||
} -cleanup {
|
||||
removeFile io-75.7
|
||||
} -match glob -result {41 0 1 {error reading "*": illegal byte sequence} ¡}
|
||||
|
||||
test io-75.8 {invalid utf-8 encoding eof handling (-strictencoding 1)} -setup {
|
||||
set fn [makeFile {} io-75.8]
|
||||
set f [open $fn w+]
|
||||
|
||||
@@ -376,6 +376,16 @@ test iocmd-8.21 {fconfigure command / -nocomplainencoding 0 error} -constraints
|
||||
} -body {
|
||||
fconfigure $console -nocomplainencoding 0
|
||||
} -returnCodes error -result "bad value for -nocomplainencoding: only true allowed"
|
||||
test iocmd-8.22 {fconfigure command / -nocomplainencoding 0, no error if -strictencoding already defined} -setup {
|
||||
set console stdin
|
||||
set oldmode [fconfigure $console -strictencoding]
|
||||
} -body {
|
||||
fconfigure $console -strictencoding 1
|
||||
fconfigure $console -nocomplainencoding 0
|
||||
fconfigure $console -nocomplainencoding
|
||||
} -cleanup {
|
||||
fconfigure $console -strictencoding $oldmode
|
||||
} -result 0
|
||||
|
||||
|
||||
test iocmd-9.1 {eof command} {
|
||||
|
||||
+85
-1
@@ -634,6 +634,58 @@ test iortrans-4.9 {chan read, gets, bug 2921116} -setup {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace eval reflector {
|
||||
proc initialize {_ chan mode} {
|
||||
return {initialize finalize watch read}
|
||||
}
|
||||
|
||||
|
||||
proc finalize {_ chan} {
|
||||
namespace delete $_
|
||||
}
|
||||
|
||||
|
||||
proc read {_ chan count} {
|
||||
namespace upvar $_ source source
|
||||
set res [string range $source 0 $count-1]
|
||||
set source [string range $source $count end]
|
||||
return $res
|
||||
}
|
||||
|
||||
|
||||
proc watch {_ chan events} {
|
||||
after 0 [list chan postevent $chan read]
|
||||
return read
|
||||
}
|
||||
|
||||
namespace ensemble create -parameters _
|
||||
namespace export *
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
namespace eval inputfilter {
|
||||
proc initialize {chan mode} {
|
||||
return {initialize finalize read}
|
||||
}
|
||||
|
||||
proc read {chan buffer} {
|
||||
return $buffer
|
||||
}
|
||||
|
||||
proc finalize chan {
|
||||
namespace delete $chan
|
||||
}
|
||||
|
||||
namespace ensemble create
|
||||
namespace export *
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Channel read transform that is just the identity - pass all through
|
||||
proc idxform {cmd handle args} {
|
||||
switch -- $cmd {
|
||||
@@ -2089,7 +2141,39 @@ test iortrans.tf-11.1 {origin thread of moved transform destroyed during access}
|
||||
thread::release $tidb
|
||||
} -result {Owner lost}
|
||||
|
||||
# ### ### ### ######### ######### #########
|
||||
|
||||
test iortrans-ea69b0258a9833cb {
|
||||
Crash when using a channel transformation on TCP client socket
|
||||
|
||||
"line two" does not make it into result. This issue should probably be
|
||||
addressed, but it is outside the scope of this test.
|
||||
} -setup {
|
||||
set res {}
|
||||
set read 0
|
||||
} -body {
|
||||
namespace eval reflector1 {
|
||||
variable source "line one\nline two"
|
||||
interp alias {} [namespace current]::dispatch {} [
|
||||
namespace parent]::reflector [namespace current]
|
||||
}
|
||||
set chan [chan create read [namespace which reflector1::dispatch]]
|
||||
chan configure $chan -blocking 0
|
||||
chan push $chan inputfilter
|
||||
chan event $chan read [list ::apply [list chan {
|
||||
variable res
|
||||
variable read
|
||||
set gets [gets $chan]
|
||||
append res $gets
|
||||
incr read
|
||||
} [namespace current]] $chan]
|
||||
vwait [namespace current]::read
|
||||
chan pop $chan
|
||||
vwait [namespace current]::read
|
||||
return $res
|
||||
} -cleanup {
|
||||
catch {unset read}
|
||||
close $chan
|
||||
} -result {line one}
|
||||
|
||||
cleanupTests
|
||||
return
|
||||
|
||||
@@ -69,8 +69,8 @@ test stringObj-4.2 {Tcl_SetObjLength procedure, string gets longer} {testobj dep
|
||||
testobj freeallvars
|
||||
teststringobj set 1 abcdef
|
||||
teststringobj setlength 1 10
|
||||
list [teststringobj length 1] [teststringobj length2 1]
|
||||
} {10 10}
|
||||
teststringobj length 1
|
||||
} 10
|
||||
test stringObj-4.3 {Tcl_SetObjLength procedure, string gets longer} {testobj utf32 deprecated} {
|
||||
testobj freeallvars
|
||||
teststringobj set 1 abcdef
|
||||
@@ -78,7 +78,7 @@ test stringObj-4.3 {Tcl_SetObjLength procedure, string gets longer} {testobj utf
|
||||
list [teststringobj length 1] [teststringobj length2 1] \
|
||||
[teststringobj get 1]
|
||||
} {10 10 abcdefxyzq}
|
||||
test stringObj-4.4 {Tcl_SetObjLength procedure, "expty string", length 0} {testobj deprecated} {
|
||||
test stringObj-4.4 {Tcl_SetObjLength procedure, "empty string", length 0} {testobj deprecated} {
|
||||
testobj freeallvars
|
||||
testobj newobj 1
|
||||
teststringobj setlength 1 0
|
||||
|
||||
+8
-5
@@ -22,6 +22,9 @@ if {"::tcltest" ni [namespace children]} {
|
||||
namespace import -force ::tcltest::*
|
||||
}
|
||||
|
||||
# File permissions broken on wsl without some "exotic" wsl configuration
|
||||
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
|
||||
|
||||
namespace eval ::tcltest::test {
|
||||
|
||||
namespace import ::tcltest::*
|
||||
@@ -306,7 +309,7 @@ test tcltest-5.3 {testConstraint - constraint empty (tcltest::safeFetch)} {
|
||||
#}
|
||||
|
||||
test tcltest-5.5 {InitConstraints: list of built-in constraints} \
|
||||
-constraints {!singleTestInterp} \
|
||||
-constraints {!singleTestInterp notWsl} \
|
||||
-setup {tcltest::InitConstraints} \
|
||||
-body { lsort [array names ::tcltest::testConstraints] } \
|
||||
-result [lsort {
|
||||
@@ -552,11 +555,11 @@ switch -- $::tcl_platform(platform) {
|
||||
default {
|
||||
# note in FAT/NTFS we won't be able to protect directory with read-only attribute...
|
||||
catch {file attributes $notWriteableDir -readonly 1}
|
||||
catch {testchmod 0 $notWriteableDir}
|
||||
catch {testchmod 0o444 $notWriteableDir}
|
||||
}
|
||||
}
|
||||
test tcltest-8.3 {tcltest a.tcl -tmpdir notReadableDir} {
|
||||
-constraints {unix notRoot}
|
||||
-constraints {unix notRoot notWsl}
|
||||
-body {
|
||||
child msg $a -tmpdir $notReadableDir
|
||||
return $msg
|
||||
@@ -572,7 +575,7 @@ testConstraint notFAT [expr {
|
||||
}]
|
||||
# FAT/NTFS permissions are fairly hopeless; ignore this test if that FS is used
|
||||
test tcltest-8.4 {tcltest a.tcl -tmpdir notWriteableDir} {
|
||||
-constraints {unixOrWin notRoot notFAT}
|
||||
-constraints {unixOrWin notRoot notFAT notWsl}
|
||||
-body {
|
||||
child msg $a -tmpdir $notWriteableDir
|
||||
return $msg
|
||||
@@ -645,7 +648,7 @@ test tcltest-8.11 {tcltest a.tcl -testdir thisdirectoryisafile} {
|
||||
-result {*not a directory*}
|
||||
}
|
||||
test tcltest-8.12 {tcltest a.tcl -testdir notReadableDir} {
|
||||
-constraints {unix notRoot}
|
||||
-constraints {unix notRoot notWsl}
|
||||
-body {
|
||||
child msg $a -testdir $notReadableDir
|
||||
return $msg
|
||||
|
||||
+7
-5
@@ -18,6 +18,8 @@ if {"::tcltest" ni [namespace children]} {
|
||||
catch [list package require -exact tcl::test [info patchlevel]]
|
||||
|
||||
testConstraint testchmod [llength [info commands testchmod]]
|
||||
# File permissions broken on wsl without some "exotic" wsl configuration
|
||||
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
|
||||
|
||||
# These tests really need to be run from a writable directory, which
|
||||
# it is assumed [temporaryDirectory] is.
|
||||
@@ -94,7 +96,7 @@ if {[testConstraint unix] && [testConstraint notRoot]} {
|
||||
|
||||
test unixFCmd-1.1 {TclpRenameFile: EACCES} -setup {
|
||||
cleanup
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir td1/td2/td3
|
||||
file attributes td1/td2 -permissions 0
|
||||
file rename td1/td2/td3 td2
|
||||
@@ -135,7 +137,7 @@ test unixFCmd-1.6 {TclpRenameFile: ENOTDIR} {emptyTest unix notRoot} {
|
||||
} {}
|
||||
test unixFCmd-1.7 {TclpRenameFile: EXDEV} -setup {
|
||||
cleanup
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
file mkdir foo/bar
|
||||
file attr foo -perm 0o40555
|
||||
file rename foo/bar /tmp
|
||||
@@ -219,7 +221,7 @@ test unixFCmd-2.4 {TclpCopyFile: src is fifo} -setup {
|
||||
} -result {fifo fifo}
|
||||
test unixFCmd-2.5 {TclpCopyFile: copy attributes} -setup {
|
||||
cleanup
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
close [open tf1 a]
|
||||
file attributes tf1 -permissions 0o472
|
||||
file copy tf1 tf2
|
||||
@@ -334,7 +336,7 @@ test unixFCmd-16.3 {SetOwnerAttribute - invalid owner} -setup {
|
||||
|
||||
test unixFCmd-17.1 {SetPermissionsAttribute} -setup {
|
||||
catch {file delete -force -- foo.test}
|
||||
} -constraints {unix notRoot} -body {
|
||||
} -constraints {unix notRoot notWsl} -body {
|
||||
close [open foo.test w]
|
||||
list [file attributes foo.test -permissions 0] \
|
||||
[file attributes foo.test -permissions]
|
||||
@@ -366,7 +368,7 @@ test unixFCmd-17.4 {SetPermissionsAttribute} -setup {
|
||||
close [open foo.test w]
|
||||
set ::i 4
|
||||
proc permcheck {testnum permList expected} {
|
||||
test $testnum {SetPermissionsAttribute} {unix notRoot} {
|
||||
test $testnum {SetPermissionsAttribute} {unix notRoot notWsl} {
|
||||
set result {}
|
||||
foreach permstr $permList {
|
||||
file attributes foo.test -permissions $permstr
|
||||
|
||||
+62
-55
@@ -45,15 +45,20 @@ proc contents {file} {
|
||||
set r
|
||||
}
|
||||
|
||||
proc cleanupRecurse {args} {
|
||||
# Assumes no loops via links!
|
||||
# Need to change permissions BEFORE deletion
|
||||
testchmod 0o777 {*}$args
|
||||
foreach victim $args {
|
||||
if {[file isdirectory $victim]} {
|
||||
cleanupRecurse {*}[glob -nocomplain -directory $victim td* tf* Test*]
|
||||
}
|
||||
file delete -force $victim
|
||||
}
|
||||
}
|
||||
proc cleanup {args} {
|
||||
foreach p ". $args" {
|
||||
set x ""
|
||||
catch {
|
||||
set x [glob -directory $p tf* td*]
|
||||
}
|
||||
if {$x != ""} {
|
||||
catch {file delete -force -- {*}$x}
|
||||
}
|
||||
foreach p [list [pwd] {*}$args] {
|
||||
cleanupRecurse {*}[glob -nocomplain -directory $p tf* td*]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,8 +250,9 @@ test winFCmd-1.23 {TclpRenameFile: move dir into self} -setup {
|
||||
test winFCmd-1.24 {TclpRenameFile: move a root dir} -setup {
|
||||
cleanup
|
||||
} -constraints {win testfile} -body {
|
||||
# Error code depends on Windows version
|
||||
testfile mv / c:/
|
||||
} -returnCodes error -result EINVAL
|
||||
} -returnCodes error -result {^(EINVAL|ENOENT)$} -match regexp
|
||||
test winFCmd-1.25 {TclpRenameFile: cross file systems} -setup {
|
||||
cleanup
|
||||
} -constraints {win cdrom testfile} -body {
|
||||
@@ -379,12 +385,12 @@ test winFCmd-1.38 {TclpRenameFile: check rename of conflicting inodes} -setup {
|
||||
cleanup
|
||||
} -constraints {win winNonZeroInodes knownMsvcBug notInCIenv} -body {
|
||||
file mkdir td1
|
||||
foreach {a b} [MakeFiles td1] break
|
||||
lassign [MakeFiles td1] a b
|
||||
file rename -force $a $b
|
||||
file exists $a
|
||||
} -cleanup {
|
||||
cleanup
|
||||
} -result {0}
|
||||
} -result 0
|
||||
|
||||
|
||||
test winFCmd-2.1 {TclpCopyFile: errno: EACCES} -setup {
|
||||
@@ -450,11 +456,11 @@ test winFCmd-2.12 {TclpCopyFile: CopyFile succeeds} -setup {
|
||||
cleanup
|
||||
} -constraints {win testfile} -body {
|
||||
createfile tf1 tf1
|
||||
testchmod 0 tf1
|
||||
file attribute tf1 -readonly 1
|
||||
testfile cp tf1 tf2
|
||||
list [contents tf2] [file writable tf2]
|
||||
} -cleanup {
|
||||
catch {testchmod 0o666 tf1}
|
||||
testchmod 0o660 tf1
|
||||
cleanup
|
||||
} -result {tf1 0}
|
||||
test winFCmd-2.13 {TclpCopyFile: CopyFile fails} -setup {
|
||||
@@ -496,11 +502,10 @@ test winFCmd-2.17 {TclpCopyFile: dst is readonly} -setup {
|
||||
} -constraints {win testfile testchmod} -body {
|
||||
createfile tf1 tf1
|
||||
createfile tf2 tf2
|
||||
testchmod 0 tf2
|
||||
file attribute tf2 -readonly 1
|
||||
testfile cp tf1 tf2
|
||||
list [file writable tf2] [contents tf2]
|
||||
} -cleanup {
|
||||
catch {testchmod 0o666 tf2}
|
||||
cleanup
|
||||
} -result {1 tf1}
|
||||
|
||||
@@ -578,7 +583,6 @@ test winFCmd-3.11 {TclpDeleteFile: still can't remove path} -setup {
|
||||
testfile rm tf1
|
||||
} -cleanup {
|
||||
close $fd
|
||||
catch {testchmod 0o666 tf1}
|
||||
cleanup
|
||||
} -returnCodes error -result EACCES
|
||||
|
||||
@@ -617,15 +621,18 @@ test winFCmd-5.1 {TclpCopyDirectory: calls TraverseWinTree} -setup {
|
||||
|
||||
test winFCmd-6.1 {TclpRemoveDirectory: errno: EACCES} -setup {
|
||||
cleanup
|
||||
} -constraints {win testfile testchmod knownMsvcBug notInCIenv} -body {
|
||||
file mkdir td1
|
||||
testchmod 0 td1
|
||||
testfile rmdir td1
|
||||
file exists td1
|
||||
} -constraints {win testfile testchmod notInCIenv} -body {
|
||||
# Parent's FILE_DELETE_CHILD setting permits deletion of subdir
|
||||
# even when subdir DELETE mask is clear. So we need an intermediate
|
||||
# parent td0 with FILE_DELETE_CHILD turned off while allowing R/W.
|
||||
file mkdir td0/td1
|
||||
testchmod 0o777 td0
|
||||
testchmod 0 td0/td1
|
||||
testfile rmdir td0/td1
|
||||
file exists td0/td1
|
||||
} -returnCodes error -cleanup {
|
||||
catch {testchmod 0o666 td1}
|
||||
cleanup
|
||||
} -result {td1 EACCES}
|
||||
} -result {td0/td1 EACCES}
|
||||
# This next test has a very hokey way of matching...
|
||||
test winFCmd-6.2 {TclpRemoveDirectory: errno: EEXIST} -setup {
|
||||
cleanup
|
||||
@@ -633,7 +640,7 @@ test winFCmd-6.2 {TclpRemoveDirectory: errno: EEXIST} -setup {
|
||||
file mkdir td1/td2
|
||||
list [catch {testfile rmdir td1} msg] [file tail $msg]
|
||||
} -result {1 {td1 EEXIST}}
|
||||
test winFCmd-6.3 {TclpRemoveDirectory: errno: EACCES} {win emptyTest} {
|
||||
test winFCmd-6.3 {TclpRemoveDirectory: errno: EACCES} {win emptyTest trashSystem} {
|
||||
# can't test this w/o removing everything on your hard disk first!
|
||||
# testfile rmdir /
|
||||
} {}
|
||||
@@ -669,17 +676,7 @@ test winFCmd-6.8 {TclpRemoveDirectory: RemoveDirectory fails} -setup {
|
||||
createfile tf1
|
||||
list [catch {testfile rmdir tf1} msg] [file tail $msg]
|
||||
} -result {1 {tf1 ENOTDIR}}
|
||||
test winFCmd-6.9 {TclpRemoveDirectory: errno == EACCES} -setup {
|
||||
cleanup
|
||||
} -constraints {win testfile testchmod knownMsvcBug notInCIenv} -body {
|
||||
file mkdir td1
|
||||
testchmod 0 td1
|
||||
testfile rmdir td1
|
||||
file exists td1
|
||||
} -returnCodes error -cleanup {
|
||||
catch {testchmod 0o666 td1}
|
||||
cleanup
|
||||
} -result {td1 EACCES}
|
||||
# winFCmd-6.9 removed - was exact dup of winFCmd-6.1
|
||||
test winFCmd-6.11 {TclpRemoveDirectory: attr == -1} -setup {
|
||||
cleanup
|
||||
} -constraints {win testfile notInCIenv} -body {
|
||||
@@ -689,15 +686,19 @@ test winFCmd-6.11 {TclpRemoveDirectory: attr == -1} -setup {
|
||||
} -returnCodes error -match regexp -result {^/ E(ACCES|EXIST)$}
|
||||
test winFCmd-6.13 {TclpRemoveDirectory: write-protected} -setup {
|
||||
cleanup
|
||||
} -constraints {win testfile testchmod knownMsvcBug notInCIenv} -body {
|
||||
file mkdir td1
|
||||
testchmod 0 td1
|
||||
testfile rmdir td1
|
||||
file exists td1
|
||||
} -constraints {win testfile testchmod notInCIenv} -body {
|
||||
# Parent's FILE_DELETE_CHILD setting permits deletion of subdir
|
||||
# even when subdir DELETE mask is clear. So we need an intermediate
|
||||
# parent td0 with FILE_DELETE_CHILD turned off while allowing R/W.
|
||||
file mkdir td0/td1
|
||||
testchmod 0o770 td0
|
||||
testchmod 0o444 td0/td1
|
||||
testfile rmdir td0/td1
|
||||
file exists td0/td1
|
||||
} -cleanup {
|
||||
catch {testchmod 0o666 td1}
|
||||
testchmod 0o770 td0/td1
|
||||
cleanup
|
||||
} -returnCodes error -result {td1 EACCES}
|
||||
} -returnCodes error -result {td0/td1 EACCES}
|
||||
# This next test has a very hokey way of matching...
|
||||
test winFCmd-6.15 {TclpRemoveDirectory: !recursive} -setup {
|
||||
cleanup
|
||||
@@ -791,11 +792,12 @@ test winFCmd-7.11 {TraverseWinTree: call TraversalCopy: DOTREE_PRED} -setup {
|
||||
} -constraints {win testfile testchmod} -body {
|
||||
file mkdir td1
|
||||
createfile td1/tf1 tf1
|
||||
testchmod 0 td1
|
||||
testchmod 0o770 td1/tf1; # Else tf2 will have no ACL after td1 testchmod
|
||||
testchmod 0o400 td1
|
||||
testfile cpdir td1 td2
|
||||
list [file exists td2] [file writable td2]
|
||||
} -cleanup {
|
||||
catch {testchmod 0o666 td1}
|
||||
testchmod 0o660 td1
|
||||
cleanup
|
||||
} -result {1 1}
|
||||
test winFCmd-7.12 {TraverseWinTree: call TraversalDelete: DOTREE_PRED} -setup {
|
||||
@@ -862,11 +864,12 @@ test winFCmd-7.19 {TraverseWinTree: call TraversalCopy: DOTREE_POSTD} -setup {
|
||||
} -constraints {win testfile testchmod} -body {
|
||||
file mkdir td1
|
||||
createfile td1/tf1 tf1
|
||||
testchmod 0 td1
|
||||
testchmod 0o770 td1/tf1; # Else tf2 will have no ACL after td1 testchmod
|
||||
testchmod 0o400 td1
|
||||
testfile cpdir td1 td2
|
||||
list [file exists td2] [file writable td2]
|
||||
} -cleanup {
|
||||
catch {testchmod 0o666 td1}
|
||||
testchmod 0o660 td1
|
||||
cleanup
|
||||
} -result {1 1}
|
||||
test winFCmd-7.20 {TraverseWinTree: call TraversalDelete: DOTREE_POSTD} -setup {
|
||||
@@ -893,11 +896,12 @@ test winFCmd-8.2 {TraversalCopy: DOTREE_PRED} -setup {
|
||||
cleanup
|
||||
} -constraints {win testfile testchmod} -body {
|
||||
file mkdir td1/td2
|
||||
testchmod 0 td1
|
||||
testchmod 0o770 td1/td2; # Else td2 will have no ACL after td1 testchmod
|
||||
testchmod 0o400 td1
|
||||
testfile cpdir td1 td2
|
||||
list [file writable td1] [file writable td1/td2]
|
||||
} -cleanup {
|
||||
catch {testchmod 0o666 td1}
|
||||
testchmod 0o660 td1
|
||||
cleanup
|
||||
} -result {0 1}
|
||||
test winFCmd-8.3 {TraversalCopy: DOTREE_POSTD} -setup {
|
||||
@@ -918,15 +922,19 @@ test winFCmd-9.1 {TraversalDelete: DOTREE_F} -setup {
|
||||
} -result {}
|
||||
test winFCmd-9.3 {TraversalDelete: DOTREE_PRED} -setup {
|
||||
cleanup
|
||||
} -constraints {win testfile testchmod knownMsvcBug notInCIenv} -body {
|
||||
file mkdir td1/td2
|
||||
testchmod 0 td1
|
||||
testfile rmdir -force td1
|
||||
} -constraints {win testfile testchmod notInCIenv} -body {
|
||||
# Parent's FILE_DELETE_CHILD setting permits deletion of subdir
|
||||
# even when subdir DELETE mask is clear. So we need an intermediate
|
||||
# parent td0 with FILE_DELETE_CHILD turned off while allowing R/W.
|
||||
file mkdir td0/td1/td2
|
||||
testchmod 0o770 td0
|
||||
testchmod 0o400 td0/td1
|
||||
testfile rmdir -force td0/td1
|
||||
file exists td1
|
||||
} -cleanup {
|
||||
catch {testchmod 0o666 td1}
|
||||
testchmod 0o770 td0/td1
|
||||
cleanup
|
||||
} -returnCodes error -result {td1 EACCES}
|
||||
} -returnCodes error -result {td0/td1 EACCES}
|
||||
test winFCmd-9.4 {TraversalDelete: DOTREE_POSTD} -setup {
|
||||
cleanup
|
||||
} -constraints {win testfile} -body {
|
||||
@@ -1417,7 +1425,6 @@ test winFCmd-19.9 {Windows devices path names} -constraints win -body {
|
||||
# }
|
||||
#}
|
||||
|
||||
# cleanup
|
||||
cleanup
|
||||
::tcltest::cleanupTests
|
||||
return
|
||||
|
||||
+1
-4
@@ -19,9 +19,6 @@ if {"::tcltest" ni [namespace children]} {
|
||||
catch [list package require -exact tcl::test [info patchlevel]]
|
||||
|
||||
testConstraint testwinclock [llength [info commands testwinclock]]
|
||||
# Some things fail under all Continuous Integration systems for subtle reasons
|
||||
# such as CI often running with elevated privileges in a container.
|
||||
testConstraint notInCIenv [expr {![info exists ::env(CI)]}]
|
||||
|
||||
# The next two tests will crash on Windows if the check for negative
|
||||
# clock values is not done properly.
|
||||
@@ -43,7 +40,7 @@ test winTime-1.2 {TclpGetDate} {win} {
|
||||
# with the Windows clock. 30 sec really isn't enough,
|
||||
# but how much time does a tester have patience for?
|
||||
|
||||
test winTime-2.1 {Synchronization of Tcl and Windows clocks} {testwinclock notInCIenv} {
|
||||
test winTime-2.1 {Synchronization of Tcl and Windows clocks} testwinclock {
|
||||
# May fail due to OS/hardware discrepancies. See:
|
||||
# http://support.microsoft.com/default.aspx?scid=kb;en-us;274323
|
||||
set failed {}
|
||||
|
||||
@@ -486,6 +486,38 @@ test zlib-8.18 {Bug dd260aaf: fconfigure} -setup {
|
||||
catch {close $inSide}
|
||||
catch {close $outSide}
|
||||
} -result {{one two} {one two}}
|
||||
test zlib-8.19 {zlib transformation, bug f9eafc3886} -constraints zlib -setup {
|
||||
set file [makeFile {} test.gz]
|
||||
} -body {
|
||||
set f [zlib push gzip [open $file w] -header [list comment [string repeat A 500]]]
|
||||
} -cleanup {
|
||||
catch {close $f}
|
||||
removeFile $file
|
||||
} -returnCodes 1 -result {Comment too large for zip}
|
||||
test zlib-8.20 {zlib transformation, bug f9eafc3886} -constraints zlib -setup {
|
||||
set file [makeFile {} test.gz]
|
||||
} -body {
|
||||
set f [zlib push gzip [open $file w] -header [list filename [string repeat A 5000]]]
|
||||
} -cleanup {
|
||||
catch {close $f}
|
||||
removeFile $file
|
||||
} -returnCodes 1 -result {Filename too large for zip}
|
||||
test zlib-8.21 {zlib transformation, bug f9eafc3886} -constraints zlib -setup {
|
||||
set file [makeFile {} test.gz]
|
||||
} -body {
|
||||
set f [zlib push gzip [open $file w] -header [list comment \u100]]
|
||||
} -cleanup {
|
||||
catch {close $f}
|
||||
removeFile $file
|
||||
} -returnCodes 1 -result {Comment contains characters > 0xFF}
|
||||
test zlib-8.22 {zlib transformation, bug f9eafc3886} -constraints zlib -setup {
|
||||
set file [makeFile {} test.gz]
|
||||
} -body {
|
||||
set f [zlib push gzip [open $file w] -header [list filename \u100]]
|
||||
} -cleanup {
|
||||
catch {close $f}
|
||||
removeFile $file
|
||||
} -returnCodes 1 -result {Filename contains characters > 0xFF}
|
||||
|
||||
test zlib-9.1 "check fcopy with push" -constraints zlib -setup {
|
||||
set sfile [makeFile {} testsrc.gz]
|
||||
|
||||
@@ -71,11 +71,6 @@ encodings: clean txt2enc $(EUC_ENCODINGS)
|
||||
done
|
||||
@echo
|
||||
@echo Compiling special versions of encoding files.
|
||||
@for p in ascii.txt; do \
|
||||
enc=`echo $$p | sed 's/\..*$$/\.enc/'`; \
|
||||
echo $$enc; \
|
||||
./txt2enc -m $$p > $$enc; \
|
||||
done
|
||||
@for p in jis0208.txt; do \
|
||||
enc=`echo $$p | sed 's/\..*$$/\.enc/'`; \
|
||||
echo $$enc; \
|
||||
|
||||
@@ -106,7 +106,7 @@ main(int argc, char **argv)
|
||||
fputs(" -f\tfallback character (default: QUESTION MARK)\n", stderr);
|
||||
fputs(" -t\toverride implicit type with single, double, or multi\n", stderr);
|
||||
fputs(" -s\tsymbol+ascii encoding\n", stderr);
|
||||
fputs(" -m\tdon't implicitly include range 0080 to 00FF\n", stderr);
|
||||
fputs(" -m\tdon't implicitly include 007F\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -208,10 +208,8 @@ main(int argc, char **argv)
|
||||
toUnicode[0][i] = i;
|
||||
}
|
||||
if (fixmissing) {
|
||||
for (i = 0x7F; i < 0xA0; i++) {
|
||||
if (toUnicode[i] == NULL && toUnicode[0][i] == 0) {
|
||||
toUnicode[0][i] = i;
|
||||
}
|
||||
if (toUnicode[0x7F] == NULL && toUnicode[0][0x7F] == 0) {
|
||||
toUnicode[0][0x7F] = 0x7F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#! /usr/bin/env tclsh
|
||||
|
||||
|
||||
proc main {sourcetype source} {
|
||||
switch $sourcetype {
|
||||
file {
|
||||
set chan [open $source]
|
||||
try {
|
||||
set data [read $chan]
|
||||
} finally {
|
||||
close $chan
|
||||
}
|
||||
}
|
||||
string {
|
||||
set data $source
|
||||
}
|
||||
default {
|
||||
error [list {wrong # args}]
|
||||
}
|
||||
}
|
||||
set found [regexp -inline -all {blocks are\
|
||||
(?:(?:(?:definitely|indirectly|possibly) lost)|still reachable)} $data]
|
||||
if {[llength $found]} {
|
||||
puts 0
|
||||
} else {
|
||||
puts 1
|
||||
}
|
||||
flush stdout
|
||||
}
|
||||
main {*}$argv
|
||||
@@ -1,3 +1,17 @@
|
||||
#{
|
||||
# Tcl_GetChannelOption/TcpGetOptionProc/TcphostPortList/getnameinfo/gethostbyaddr_r
|
||||
# Memcheck:Leak
|
||||
# match-leak-kinds: reachable
|
||||
# fun:malloc
|
||||
# fun:strdup
|
||||
# ...
|
||||
# fun:module_load
|
||||
# ...
|
||||
# fun:getnameinfo
|
||||
# ...
|
||||
# fun:Tcl_GetChannelOption
|
||||
#}
|
||||
|
||||
{
|
||||
TclCreatesocketAddress/getaddrinfo/calloc
|
||||
Memcheck:Leak
|
||||
@@ -8,6 +22,16 @@
|
||||
fun:TclCreateSocketAddress
|
||||
}
|
||||
|
||||
{
|
||||
TclCreatesocketAddress/getaddrinfo/malloc
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite
|
||||
fun:malloc
|
||||
...
|
||||
fun:getaddrinfo
|
||||
fun:TclCreateSocketAddress
|
||||
}
|
||||
|
||||
{
|
||||
TclCreatesocketAddress/getaddrinfo/malloc
|
||||
Memcheck:Leak
|
||||
@@ -18,6 +42,18 @@
|
||||
fun:TclCreateSocketAddress
|
||||
}
|
||||
|
||||
{
|
||||
TclpDlopen/decompose_rpath
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: reachable
|
||||
fun:malloc
|
||||
fun:decompose_rpath
|
||||
...
|
||||
fun:dlopen_doit
|
||||
...
|
||||
fun:TclpDlopen
|
||||
}
|
||||
|
||||
{
|
||||
TclpDlopen/load
|
||||
Memcheck:Leak
|
||||
@@ -71,6 +107,46 @@
|
||||
fun:TclpGetGrNam
|
||||
}
|
||||
|
||||
{
|
||||
TclpGeHostByName/gethostbyname_r/strdup/malloc
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: reachable
|
||||
fun:malloc
|
||||
fun:strdup
|
||||
...
|
||||
fun:dl_open_worker
|
||||
...
|
||||
fun:do_dlopen
|
||||
...
|
||||
fun:TclpGetHostByName
|
||||
}
|
||||
|
||||
{
|
||||
TclpGeHostByName/gethostbyname_r/calloc
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: reachable
|
||||
fun:calloc
|
||||
...
|
||||
fun:dl_open_worker
|
||||
...
|
||||
fun:do_dlopen
|
||||
...
|
||||
fun:TclpGetHostByName
|
||||
}
|
||||
|
||||
{
|
||||
TclpGeHostByName/gethostbyname_r/malloc
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: reachable
|
||||
fun:malloc
|
||||
...
|
||||
fun:dl_open_worker
|
||||
...
|
||||
fun:do_dlopen
|
||||
...
|
||||
fun:TclpGetHostByName
|
||||
}
|
||||
|
||||
{
|
||||
TclpGetPwNam/getpwname_r/__nss_next2/calloc
|
||||
Memcheck:Leak
|
||||
@@ -104,6 +180,57 @@
|
||||
fun:TclpGetPwNam
|
||||
}
|
||||
|
||||
{
|
||||
TclpGetGrGid/getgrgid_r/module_load
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: reachable
|
||||
fun:calloc
|
||||
...
|
||||
fun:module_load
|
||||
...
|
||||
fun:TclpGetGrGid
|
||||
}
|
||||
|
||||
{
|
||||
TclpGetGrGid/getgrgid_r/module_load
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: reachable
|
||||
fun:malloc
|
||||
...
|
||||
fun:module_load
|
||||
...
|
||||
fun:TclpGetGrGid
|
||||
}
|
||||
|
||||
{
|
||||
TcphostPortList/getnameinfo/module_load/calloc
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite,reachable
|
||||
fun:calloc
|
||||
...
|
||||
fun:dl_open_worker_begin
|
||||
...
|
||||
fun:module_load
|
||||
...
|
||||
fun:getnameinfo
|
||||
fun:TcpHostPortList
|
||||
}
|
||||
|
||||
{
|
||||
# see sourceware glibc Bug 14984 - getnameinfo() might be leaking memory
|
||||
TcphostPortList/getnameinfo/module_load/mallco
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite,reachable
|
||||
fun:malloc
|
||||
...
|
||||
fun:dl_open_worker_begin
|
||||
...
|
||||
fun:module_load
|
||||
...
|
||||
fun:getnameinfo
|
||||
fun:TcpHostPortList
|
||||
}
|
||||
|
||||
{
|
||||
TclpThreadExit/pthread_exit/calloc
|
||||
Memcheck:Leak
|
||||
@@ -124,3 +251,13 @@
|
||||
fun:TclpThreadExit
|
||||
}
|
||||
|
||||
{
|
||||
TclpThreadExit/pthread_exit/malloc
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite
|
||||
fun:malloc
|
||||
...
|
||||
fun:pthread_exit
|
||||
fun:TclpThreadExit
|
||||
}
|
||||
|
||||
|
||||
+22
-2
@@ -952,6 +952,26 @@ valgrind: ${TCL_EXE} ${TCLTEST_EXE}
|
||||
$(TOP_DIR)/tests/all.tcl -singleproc 1 -constraints valgrind \
|
||||
$(TESTFLAGS)
|
||||
|
||||
testresults/valgrind/%.result: ${TCL_EXE} ${TCLTEST_EXE}
|
||||
@mkdir -p testresults/valgrind
|
||||
$(SHELL_ENV) $(VALGRIND) $(VALGRINDARGS) ./${TCLTEST_EXE} \
|
||||
$(TOP_DIR)/tests/all.tcl -singleproc 1 -constraints valgrind \
|
||||
-file $(basename $(notdir $@)) > $@ 2>&1
|
||||
.PRECIOUS: testresults/valgrind/%.result
|
||||
|
||||
|
||||
testresults/valgrind/%.success: testresults/valgrind/%.result
|
||||
@printf '%s' valgrind >&2
|
||||
@printf ' %s' $(basename $(notdir $@)) >&2
|
||||
@printf '\n >&2'
|
||||
@status=$$(./${TCLTEST_EXE} $(TOP_DIR)/tools/valgrind_check_success \
|
||||
file $(basename $@).result); \
|
||||
if [ "$$status" -eq 1 ]; then exit 0; else exit 1; fi
|
||||
|
||||
valgrind_each: $(addprefix testresults/valgrind/,$(addsuffix .success,$(notdir\
|
||||
$(wildcard $(TOP_DIR)/tests/*.test))))
|
||||
|
||||
|
||||
valgrindshell: ${TCL_EXE}
|
||||
$(SHELL_ENV) $(VALGRIND) $(VALGRINDARGS) ./${TCL_EXE} $(SCRIPT)
|
||||
|
||||
@@ -1051,9 +1071,9 @@ install-libraries: libraries
|
||||
@echo "Installing package msgcat 1.7.1 as a Tcl Module"
|
||||
@$(INSTALL_DATA) $(TOP_DIR)/library/msgcat/msgcat.tcl \
|
||||
"$(MODULE_INSTALL_DIR)/8.7/msgcat-1.7.1.tm"
|
||||
@echo "Installing package tcltest 2.5.5 as a Tcl Module"
|
||||
@echo "Installing package tcltest 2.5.6 as a Tcl Module"
|
||||
@$(INSTALL_DATA) $(TOP_DIR)/library/tcltest/tcltest.tcl \
|
||||
"$(MODULE_INSTALL_DIR)/8.5/tcltest-2.5.5.tm"
|
||||
"$(MODULE_INSTALL_DIR)/8.5/tcltest-2.5.6.tm"
|
||||
@echo "Installing package platform 1.0.19 as a Tcl Module"
|
||||
@$(INSTALL_DATA) $(TOP_DIR)/library/platform/platform.tcl \
|
||||
"$(MODULE_INSTALL_DIR)/8.4/platform-1.0.19.tm"
|
||||
|
||||
Vendored
-50
@@ -7631,56 +7631,6 @@ printf "%s\n" "#define _LARGEFILE64_SOURCE 1" >>confdefs.h
|
||||
tcl_flags="$tcl_flags _LARGEFILE64_SOURCE"
|
||||
fi
|
||||
|
||||
|
||||
if test ${tcl_cv_flag__largefile_source64+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else $as_nop
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <sys/stat.h>
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
char *p = (char *)open64;
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"
|
||||
then :
|
||||
tcl_cv_flag__largefile_source64=no
|
||||
else $as_nop
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#define _LARGEFILE_SOURCE64 1
|
||||
#include <sys/stat.h>
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
char *p = (char *)open64;
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"
|
||||
then :
|
||||
tcl_cv_flag__largefile_source64=yes
|
||||
else $as_nop
|
||||
tcl_cv_flag__largefile_source64=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
fi
|
||||
|
||||
if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then
|
||||
|
||||
printf "%s\n" "#define _LARGEFILE_SOURCE64 1" >>confdefs.h
|
||||
|
||||
tcl_flags="$tcl_flags _LARGEFILE_SOURCE64"
|
||||
fi
|
||||
|
||||
if test "x${tcl_flags}" = "x" ; then
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5
|
||||
printf "%s\n" "none" >&6; }
|
||||
|
||||
@@ -2329,7 +2329,6 @@ AC_DEFUN([SC_TCL_LINK_LIBS], [
|
||||
# Might define the following vars:
|
||||
# _ISOC99_SOURCE
|
||||
# _LARGEFILE64_SOURCE
|
||||
# _LARGEFILE_SOURCE64
|
||||
#
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
@@ -2353,8 +2352,6 @@ AC_DEFUN([SC_TCL_EARLY_FLAGS],[
|
||||
[char *p = (char *)strtoll; char *q = (char *)strtoull;])
|
||||
SC_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include <sys/stat.h>],
|
||||
[struct stat64 buf; int i = stat64("/", &buf);])
|
||||
SC_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include <sys/stat.h>],
|
||||
[char *p = (char *)open64;])
|
||||
if test "x${tcl_flags}" = "x" ; then
|
||||
AC_MSG_RESULT([none])
|
||||
else
|
||||
|
||||
@@ -492,9 +492,6 @@
|
||||
/* Add the _LARGEFILE64_SOURCE flag when building */
|
||||
#undef _LARGEFILE64_SOURCE
|
||||
|
||||
/* Add the _LARGEFILE_SOURCE64 flag when building */
|
||||
#undef _LARGEFILE_SOURCE64
|
||||
|
||||
/* # needed in sys/socket.h Should OS/390 do the right thing with sockets? */
|
||||
#undef _OE_SOCKETS
|
||||
|
||||
|
||||
+6
-6
@@ -1033,10 +1033,10 @@ TcpGetOptionProc(
|
||||
|
||||
if ((len == 0) || ((len > 1) && (optionName[1] == 'k') &&
|
||||
(strncmp(optionName, "-keepalive", len) == 0))) {
|
||||
#if defined(SO_KEEPALIVE)
|
||||
socklen_t size;
|
||||
#endif
|
||||
int opt = 0;
|
||||
#if defined(SO_KEEPALIVE)
|
||||
socklen_t size = sizeof(opt);
|
||||
#endif
|
||||
|
||||
if (len == 0) {
|
||||
Tcl_DStringAppendElement(dsPtr, "-keepalive");
|
||||
@@ -1053,10 +1053,10 @@ TcpGetOptionProc(
|
||||
|
||||
if ((len == 0) || ((len > 1) && (optionName[1] == 'n') &&
|
||||
(strncmp(optionName, "-nodelay", len) == 0))) {
|
||||
#if defined(SOL_TCP) && defined(TCP_NODELAY)
|
||||
socklen_t size;
|
||||
#endif
|
||||
int opt = 0;
|
||||
#if defined(SOL_TCP) && defined(TCP_NODELAY)
|
||||
socklen_t size = sizeof(opt);
|
||||
#endif
|
||||
|
||||
if (len == 0) {
|
||||
Tcl_DStringAppendElement(dsPtr, "-nodelay");
|
||||
|
||||
+2
-2
@@ -889,8 +889,8 @@ install-libraries: libraries install-tzdata install-msgs
|
||||
done;
|
||||
@echo "Installing package msgcat 1.7.1 as a Tcl Module";
|
||||
@$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl "$(MODULE_INSTALL_DIR)/8.7/msgcat-1.7.1.tm";
|
||||
@echo "Installing package tcltest 2.5.5 as a Tcl Module";
|
||||
@$(COPY) $(ROOT_DIR)/library/tcltest/tcltest.tcl "$(MODULE_INSTALL_DIR)/8.5/tcltest-2.5.5.tm";
|
||||
@echo "Installing package tcltest 2.5.6 as a Tcl Module";
|
||||
@$(COPY) $(ROOT_DIR)/library/tcltest/tcltest.tcl "$(MODULE_INSTALL_DIR)/8.5/tcltest-2.5.6.tm";
|
||||
@echo "Installing package platform 1.0.19 as a Tcl Module";
|
||||
@$(COPY) $(ROOT_DIR)/library/platform/platform.tcl "$(MODULE_INSTALL_DIR)/8.4/platform-1.0.19.tm";
|
||||
@echo "Installing package platform::shell 1.1.4 as a Tcl Module";
|
||||
|
||||
+2
-2
@@ -379,7 +379,7 @@ TclWinDriveLetterForVolMountPoint(
|
||||
if (!alreadyStored) {
|
||||
dlPtr2 = (MountPointMap *)ckalloc(sizeof(MountPointMap));
|
||||
dlPtr2->volumeName = (WCHAR *)TclNativeDupInternalRep(Target);
|
||||
dlPtr2->driveLetter = (char) drive[0];
|
||||
dlPtr2->driveLetter = (WCHAR) drive[0];
|
||||
dlPtr2->nextPtr = driveLetterLookup;
|
||||
driveLetterLookup = dlPtr2;
|
||||
}
|
||||
@@ -405,7 +405,7 @@ TclWinDriveLetterForVolMountPoint(
|
||||
|
||||
dlPtr2 = (MountPointMap *)ckalloc(sizeof(MountPointMap));
|
||||
dlPtr2->volumeName = (WCHAR *)TclNativeDupInternalRep((void *)mountPoint);
|
||||
dlPtr2->driveLetter = -1;
|
||||
dlPtr2->driveLetter = (WCHAR)-1;
|
||||
dlPtr2->nextPtr = driveLetterLookup;
|
||||
driveLetterLookup = dlPtr2;
|
||||
Tcl_MutexUnlock(&mountPointMap);
|
||||
|
||||
+3
-3
@@ -700,7 +700,7 @@ FileInputProc(
|
||||
|
||||
if (ReadFile(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &bytesRead,
|
||||
(LPOVERLAPPED) NULL) != FALSE) {
|
||||
return bytesRead;
|
||||
return (int)bytesRead;
|
||||
}
|
||||
|
||||
Tcl_WinConvertError(GetLastError());
|
||||
@@ -757,7 +757,7 @@ FileOutputProc(
|
||||
return -1;
|
||||
}
|
||||
infoPtr->dirty = 1;
|
||||
return bytesWritten;
|
||||
return (int)bytesWritten;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1572,7 +1572,7 @@ NativeIsComPort(
|
||||
const WCHAR *nativePath) /* Path of file to access, native encoding. */
|
||||
{
|
||||
const WCHAR *p = (const WCHAR *) nativePath;
|
||||
int i, len = wcslen(p);
|
||||
size_t i, len = wcslen(p);
|
||||
|
||||
/*
|
||||
* 1. Look for com[1-9]:?
|
||||
|
||||
+31
-37
@@ -1457,21 +1457,39 @@ TclpGetUserHome(
|
||||
if (domain == NULL) {
|
||||
const char *ptr;
|
||||
|
||||
/*
|
||||
* No domain. Firstly check it's the current user
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 abcdefghi@outlook.com, 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) {
|
||||
/*
|
||||
* Try safest and fastest way to get current user home
|
||||
*/
|
||||
|
||||
ptr = TclGetEnv("HOME", &ds);
|
||||
if (ptr != NULL) {
|
||||
Tcl_JoinPath(1, &ptr, bufferPtr);
|
||||
rc = 1;
|
||||
result = Tcl_DStringValue(bufferPtr);
|
||||
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 */
|
||||
if (hProcess) {
|
||||
HANDLE hToken;
|
||||
if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
|
||||
if (GetUserProfileDirectoryW(hToken, buf, &nChars)) {
|
||||
result = Tcl_WCharToUtfDString(buf, nChars-1, (bufferPtr));
|
||||
rc = 1;
|
||||
}
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
Tcl_DStringFree(&ds);
|
||||
@@ -1543,30 +1561,6 @@ TclpGetUserHome(
|
||||
if (wDomain != NULL) {
|
||||
NetApiBufferFree((void *) wDomain);
|
||||
}
|
||||
if (result == NULL) {
|
||||
/*
|
||||
* Look in the "Password Lists" section of system.ini for the local
|
||||
* user. There are also entries in that section that begin with a "*"
|
||||
* character that are used by Windows for other purposes; ignore user
|
||||
* names beginning with a "*".
|
||||
*/
|
||||
|
||||
char buf[MAX_PATH];
|
||||
|
||||
if (name[0] != '*') {
|
||||
if (GetPrivateProfileStringA("Password Lists", name, "", buf,
|
||||
MAX_PATH, "system.ini") > 0) {
|
||||
/*
|
||||
* User exists, but there is no such thing as a home directory
|
||||
* in system.ini. Return "{Windows drive}:/".
|
||||
*/
|
||||
|
||||
GetWindowsDirectoryA(buf, MAX_PATH);
|
||||
Tcl_DStringAppend(bufferPtr, buf, 3);
|
||||
result = Tcl_DStringValue(bufferPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+2
-2
@@ -56,10 +56,10 @@ Tcl_ConsolePanic(
|
||||
if (IsDebuggerPresent()) {
|
||||
OutputDebugStringW(msgString);
|
||||
} else if (_isatty(2)) {
|
||||
WriteConsoleW(handle, msgString, wcslen(msgString), &dummy, 0);
|
||||
WriteConsoleW(handle, msgString, (DWORD)wcslen(msgString), &dummy, 0);
|
||||
} else {
|
||||
buf[0] = '\xEF'; buf[1] = '\xBB'; buf[2] = '\xBF'; /* UTF-8 bom */
|
||||
WriteFile(handle, buf, strlen(buf), &dummy, 0);
|
||||
WriteFile(handle, buf, (DWORD)strlen(buf), &dummy, 0);
|
||||
WriteFile(handle, "\n", 1, &dummy, 0);
|
||||
FlushFileBuffers(handle);
|
||||
}
|
||||
|
||||
+165
-151
@@ -22,9 +22,8 @@
|
||||
/*
|
||||
* For TestplatformChmod on Windows
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#include <aclapi.h>
|
||||
#endif
|
||||
#include <sddl.h>
|
||||
|
||||
/*
|
||||
* MinGW 3.4.2 does not define this.
|
||||
@@ -414,176 +413,189 @@ TestExceptionCmd(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* This "chmod" works sufficiently for test script purposes. Do not expect
|
||||
* it to be exact emulation of Unix chmod (not sure if that's even possible)
|
||||
*/
|
||||
static int
|
||||
TestplatformChmod(
|
||||
const char *nativePath,
|
||||
int pmode)
|
||||
{
|
||||
static const SECURITY_INFORMATION infoBits = OWNER_SECURITY_INFORMATION
|
||||
| GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
|
||||
/* don't reset change permissions mask (WRITE_DAC, allow test-cases restore it to cleanup) */
|
||||
static const DWORD readOnlyMask = FILE_DELETE_CHILD | FILE_ADD_FILE
|
||||
| FILE_ADD_SUBDIRECTORY | FILE_WRITE_EA | FILE_APPEND_DATA
|
||||
| FILE_WRITE_DATA
|
||||
| DELETE;
|
||||
|
||||
/*
|
||||
* References to security functions (only available on NT and later).
|
||||
* Note FILE_DELETE_CHILD missing from dirWriteMask because we do
|
||||
* not want overriding of child's delete setting when testing
|
||||
*/
|
||||
static const DWORD dirWriteMask =
|
||||
FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA |
|
||||
FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | STANDARD_RIGHTS_WRITE | DELETE |
|
||||
SYNCHRONIZE;
|
||||
static const DWORD dirReadMask =
|
||||
FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_LIST_DIRECTORY |
|
||||
STANDARD_RIGHTS_READ | SYNCHRONIZE;
|
||||
/* Note - default user privileges allow ignoring TRAVERSE setting */
|
||||
static const DWORD dirExecuteMask =
|
||||
FILE_TRAVERSE | STANDARD_RIGHTS_READ | SYNCHRONIZE;
|
||||
|
||||
const BOOL set_readOnly = !(pmode & 0222);
|
||||
BOOL acl_readOnly_found = FALSE, curAclPresent, curAclDefaulted;
|
||||
SID_IDENTIFIER_AUTHORITY userSidAuthority = {
|
||||
SECURITY_WORLD_SID_AUTHORITY
|
||||
};
|
||||
BYTE *secDesc = 0;
|
||||
DWORD secDescLen, attr, newAclSize;
|
||||
ACL_SIZE_INFORMATION ACLSize;
|
||||
PACL curAcl, newAcl = 0;
|
||||
WORD j;
|
||||
SID *userSid = 0;
|
||||
char *userDomain = 0;
|
||||
static const DWORD fileWriteMask =
|
||||
FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_WRITE_DATA |
|
||||
FILE_APPEND_DATA | STANDARD_RIGHTS_WRITE | DELETE | SYNCHRONIZE;
|
||||
static const DWORD fileReadMask =
|
||||
FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA |
|
||||
STANDARD_RIGHTS_READ | SYNCHRONIZE;
|
||||
static const DWORD fileExecuteMask =
|
||||
FILE_EXECUTE | STANDARD_RIGHTS_READ | SYNCHRONIZE;
|
||||
|
||||
DWORD attr, newAclSize;
|
||||
PACL newAcl = NULL;
|
||||
int res = 0;
|
||||
|
||||
/*
|
||||
* Process the chmod request.
|
||||
*/
|
||||
HANDLE hToken = NULL;
|
||||
int i;
|
||||
int nSids = 0;
|
||||
struct {
|
||||
PSID pSid;
|
||||
DWORD mask;
|
||||
DWORD sidLen;
|
||||
} aceEntry[3];
|
||||
DWORD dw;
|
||||
int isDir;
|
||||
TOKEN_USER *pTokenUser = NULL;
|
||||
|
||||
res = -1; /* Assume failure */
|
||||
|
||||
attr = GetFileAttributesA(nativePath);
|
||||
|
||||
/*
|
||||
* nativePath not found
|
||||
*/
|
||||
|
||||
if (attr == 0xFFFFFFFF) {
|
||||
res = -1;
|
||||
goto done; /* Not found */
|
||||
}
|
||||
|
||||
isDir = (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* If nativePath is not a directory, there is no special handling.
|
||||
*/
|
||||
|
||||
if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
/* Get process SID */
|
||||
if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dw) &&
|
||||
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
goto done;
|
||||
}
|
||||
pTokenUser = (TOKEN_USER *)ckalloc(dw);
|
||||
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dw, &dw)) {
|
||||
goto done;
|
||||
}
|
||||
aceEntry[nSids].sidLen = GetLengthSid(pTokenUser->User.Sid);
|
||||
aceEntry[nSids].pSid = ckalloc(aceEntry[nSids].sidLen);
|
||||
if (!CopySid(aceEntry[nSids].sidLen,
|
||||
aceEntry[nSids].pSid,
|
||||
pTokenUser->User.Sid)) {
|
||||
ckfree(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the result to error, if the ACL change is successful it will be
|
||||
* reset to 0.
|
||||
* Always include DACL modify rights so we don't get locked out
|
||||
*/
|
||||
|
||||
res = -1;
|
||||
|
||||
/*
|
||||
* Read the security descriptor for the directory. Note the first call
|
||||
* obtains the size of the security descriptor.
|
||||
*/
|
||||
|
||||
if (!GetFileSecurityA(nativePath, infoBits, NULL, 0, &secDescLen)) {
|
||||
DWORD secDescLen2 = 0;
|
||||
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
goto done;
|
||||
aceEntry[nSids].mask = READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE |
|
||||
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES;
|
||||
if (pmode & 0700) {
|
||||
/* Owner permissions. Assumes current process is owner */
|
||||
if (pmode & 0400) {
|
||||
aceEntry[nSids].mask |= isDir ? dirReadMask : fileReadMask;
|
||||
}
|
||||
|
||||
secDesc = (BYTE *)ckalloc(secDescLen);
|
||||
if (!GetFileSecurityA(nativePath, infoBits,
|
||||
(PSECURITY_DESCRIPTOR) secDesc, secDescLen, &secDescLen2)
|
||||
|| (secDescLen < secDescLen2)) {
|
||||
goto done;
|
||||
if (pmode & 0200) {
|
||||
aceEntry[nSids].mask |= isDir ? dirWriteMask : fileWriteMask;
|
||||
}
|
||||
if (pmode & 0100) {
|
||||
aceEntry[nSids].mask |= isDir ? dirExecuteMask : fileExecuteMask;
|
||||
}
|
||||
}
|
||||
++nSids;
|
||||
|
||||
/*
|
||||
* Get the World SID.
|
||||
*/
|
||||
if (pmode & 0070) {
|
||||
/* Group permissions. */
|
||||
|
||||
userSid = (SID *)ckalloc(GetSidLengthRequired((UCHAR) 1));
|
||||
InitializeSid(userSid, &userSidAuthority, (BYTE) 1);
|
||||
*(GetSidSubAuthority(userSid, 0)) = SECURITY_WORLD_RID;
|
||||
TOKEN_PRIMARY_GROUP *pTokenGroup;
|
||||
|
||||
/*
|
||||
* If curAclPresent == false then curAcl and curAclDefaulted not valid.
|
||||
*/
|
||||
/* Get primary group SID */
|
||||
if (!GetTokenInformation(
|
||||
hToken, TokenPrimaryGroup, NULL, 0, &dw) &&
|
||||
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
goto done;
|
||||
}
|
||||
pTokenGroup = (TOKEN_PRIMARY_GROUP *)ckalloc(dw);
|
||||
if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dw, &dw)) {
|
||||
ckfree(pTokenGroup);
|
||||
goto done;
|
||||
}
|
||||
aceEntry[nSids].sidLen = GetLengthSid(pTokenGroup->PrimaryGroup);
|
||||
aceEntry[nSids].pSid = ckalloc(aceEntry[nSids].sidLen);
|
||||
if (!CopySid(aceEntry[nSids].sidLen, aceEntry[nSids].pSid, pTokenGroup->PrimaryGroup)) {
|
||||
ckfree(pTokenGroup);
|
||||
ckfree(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
|
||||
goto done;
|
||||
}
|
||||
ckfree(pTokenGroup);
|
||||
|
||||
if (!GetSecurityDescriptorDacl((PSECURITY_DESCRIPTOR) secDesc,
|
||||
&curAclPresent, &curAcl, &curAclDefaulted)) {
|
||||
goto done;
|
||||
}
|
||||
if (!curAclPresent || !curAcl) {
|
||||
ACLSize.AclBytesInUse = 0;
|
||||
ACLSize.AceCount = 0;
|
||||
} else if (!GetAclInformation(curAcl, &ACLSize, sizeof(ACLSize),
|
||||
AclSizeInformation)) {
|
||||
goto done;
|
||||
/* Generate mask for group ACL */
|
||||
|
||||
aceEntry[nSids].mask = 0;
|
||||
if (pmode & 0040) {
|
||||
aceEntry[nSids].mask |= isDir ? dirReadMask : fileReadMask;
|
||||
}
|
||||
if (pmode & 0020) {
|
||||
aceEntry[nSids].mask |= isDir ? dirWriteMask : fileWriteMask;
|
||||
}
|
||||
if (pmode & 0010) {
|
||||
aceEntry[nSids].mask |= isDir ? dirExecuteMask : fileExecuteMask;
|
||||
}
|
||||
++nSids;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate memory for the new ACL.
|
||||
*/
|
||||
if (pmode & 0007) {
|
||||
/* World permissions */
|
||||
PSID pWorldSid;
|
||||
if (!ConvertStringSidToSidA("S-1-1-0", &pWorldSid)) {
|
||||
goto done;
|
||||
}
|
||||
aceEntry[nSids].sidLen = GetLengthSid(pWorldSid);
|
||||
aceEntry[nSids].pSid = ckalloc(aceEntry[nSids].sidLen);
|
||||
if (!CopySid(aceEntry[nSids].sidLen, aceEntry[nSids].pSid, pWorldSid)) {
|
||||
LocalFree(pWorldSid);
|
||||
ckfree(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
|
||||
goto done;
|
||||
}
|
||||
LocalFree(pWorldSid);
|
||||
|
||||
newAclSize = ACLSize.AclBytesInUse + sizeof(ACCESS_DENIED_ACE)
|
||||
+ GetLengthSid(userSid) - sizeof(DWORD);
|
||||
newAcl = (PACL) ckalloc(newAclSize);
|
||||
/* Generate mask for world ACL */
|
||||
|
||||
/*
|
||||
* Initialize the new ACL.
|
||||
*/
|
||||
aceEntry[nSids].mask = 0;
|
||||
if (pmode & 0004) {
|
||||
aceEntry[nSids].mask |= isDir ? dirReadMask : fileReadMask;
|
||||
}
|
||||
if (pmode & 0002) {
|
||||
aceEntry[nSids].mask |= isDir ? dirWriteMask : fileWriteMask;
|
||||
}
|
||||
if (pmode & 0001) {
|
||||
aceEntry[nSids].mask |= isDir ? dirExecuteMask : fileExecuteMask;
|
||||
}
|
||||
++nSids;
|
||||
}
|
||||
|
||||
/* Allocate memory and initialize the new ACL. */
|
||||
|
||||
newAclSize = sizeof(ACL);
|
||||
/* Add in size required for each ACE entry in the ACL */
|
||||
for (i = 0; i < nSids; ++i) {
|
||||
newAclSize +=
|
||||
offsetof(ACCESS_ALLOWED_ACE, SidStart) + aceEntry[i].sidLen;
|
||||
}
|
||||
newAcl = (PACL)ckalloc(newAclSize);
|
||||
if (!InitializeAcl(newAcl, newAclSize, ACL_REVISION)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add denied to make readonly, this will be known as a "read-only tag".
|
||||
*/
|
||||
|
||||
if (set_readOnly && !AddAccessDeniedAce(newAcl, ACL_REVISION,
|
||||
readOnlyMask, userSid)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
acl_readOnly_found = FALSE;
|
||||
for (j = 0; j < ACLSize.AceCount; j++) {
|
||||
LPVOID pACE2;
|
||||
ACE_HEADER *phACE2;
|
||||
|
||||
if (!GetAce(curAcl, j, &pACE2)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
phACE2 = (ACE_HEADER *) pACE2;
|
||||
|
||||
/*
|
||||
* Do NOT propagate inherited ACEs.
|
||||
*/
|
||||
|
||||
if (phACE2->AceFlags & INHERITED_ACE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip the "read-only tag" restriction (either added above, or it is
|
||||
* being removed).
|
||||
*/
|
||||
|
||||
if (phACE2->AceType == ACCESS_DENIED_ACE_TYPE) {
|
||||
ACCESS_DENIED_ACE *pACEd = (ACCESS_DENIED_ACE *) phACE2;
|
||||
|
||||
if (pACEd->Mask == readOnlyMask
|
||||
&& EqualSid(userSid, (PSID) &pACEd->SidStart)) {
|
||||
acl_readOnly_found = TRUE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the current ACE from the old to the new ACL.
|
||||
*/
|
||||
|
||||
if (!AddAce(newAcl, ACL_REVISION, MAXDWORD, (PACL *) pACE2,
|
||||
((PACE_HEADER) pACE2)->AceSize)) {
|
||||
for (i = 0; i < nSids; ++i) {
|
||||
if (!AddAccessAllowedAce(newAcl, ACL_REVISION, aceEntry[i].mask, aceEntry[i].pSid)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
@@ -593,36 +605,38 @@ TestplatformChmod(
|
||||
* to remove inherited ACL (we need to overwrite the default ACL's in this case)
|
||||
*/
|
||||
|
||||
if (set_readOnly == acl_readOnly_found || SetNamedSecurityInfoA(
|
||||
(LPSTR) nativePath, SE_FILE_OBJECT,
|
||||
DACL_SECURITY_INFORMATION /*| PROTECTED_DACL_SECURITY_INFORMATION*/,
|
||||
NULL, NULL, newAcl, NULL) == ERROR_SUCCESS) {
|
||||
if (SetNamedSecurityInfoA((LPSTR)nativePath,
|
||||
SE_FILE_OBJECT,
|
||||
DACL_SECURITY_INFORMATION |
|
||||
PROTECTED_DACL_SECURITY_INFORMATION,
|
||||
NULL,
|
||||
NULL,
|
||||
newAcl,
|
||||
NULL) == ERROR_SUCCESS) {
|
||||
res = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
if (secDesc) {
|
||||
ckfree(secDesc);
|
||||
if (pTokenUser) {
|
||||
ckfree(pTokenUser);
|
||||
}
|
||||
if (hToken) {
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
if (newAcl) {
|
||||
ckfree(newAcl);
|
||||
}
|
||||
if (userSid) {
|
||||
ckfree(userSid);
|
||||
}
|
||||
if (userDomain) {
|
||||
ckfree(userDomain);
|
||||
for (i = 0; i < nSids; ++i) {
|
||||
ckfree(aceEntry[i].pSid);
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run normal chmod command.
|
||||
*/
|
||||
|
||||
/* Run normal chmod command */
|
||||
return chmod(nativePath, pmode);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user