Compare commits
169
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63be474164 | ||
|
|
5e3ca11761 | ||
|
|
6ab540f5ff | ||
|
|
63b0fef31a | ||
|
|
bb503004b6 | ||
|
|
267cdaec03 | ||
|
|
a2ce3dab9b | ||
|
|
6a4d06759e | ||
|
|
6966f0a2b1 | ||
|
|
89a84af271 | ||
|
|
bb5d24622f | ||
|
|
813979693c | ||
|
|
c8da3bbfaf | ||
|
|
35f5b82868 | ||
|
|
5e7a1545a6 | ||
|
|
f4651a5660 | ||
|
|
a0290b85c5 | ||
|
|
8145564d30 | ||
|
|
66ef201ad7 | ||
|
|
6d943ef7b5 | ||
|
|
1c13d543f4 | ||
|
|
263de53394 | ||
|
|
a410c0d8d5 | ||
|
|
ecec1703aa | ||
|
|
36a1a69178 | ||
|
|
edb38932e8 | ||
|
|
46aab3eb09 | ||
|
|
ce025f259b | ||
|
|
f6af18a947 | ||
|
|
b729965a3c | ||
|
|
0cab7d260b | ||
|
|
708eadd19e | ||
|
|
7bbadfe0e0 | ||
|
|
4523d8df2c | ||
|
|
791f1c2741 | ||
|
|
d431841a06 | ||
|
|
dffe6bc7f1 | ||
|
|
423f761169 | ||
|
|
ba42e43e97 | ||
|
|
4f1ea4779b | ||
|
|
e6fdfbe93b | ||
|
|
bd706be303 | ||
|
|
4e12ee1bc4 | ||
|
|
7672af7212 | ||
|
|
eae621b175 | ||
|
|
5eef06ea24 | ||
|
|
9333525d11 | ||
|
|
911c1c6237 | ||
|
|
49a9e59311 | ||
|
|
242d4d7095 | ||
|
|
9cb3b15616 | ||
|
|
6d0cc0c589 | ||
|
|
d9bc6cbae2 | ||
|
|
388266030b | ||
|
|
ede72e80ac | ||
|
|
7bf3f83abd | ||
|
|
d3fd405e6b | ||
|
|
eed54b6281 | ||
|
|
6dbdfc31d2 | ||
|
|
35d6c2453e | ||
|
|
f7f4cbb151 | ||
|
|
f5e8751307 | ||
|
|
7855612da6 | ||
|
|
7f26fedbcc | ||
|
|
47e9dbdc37 | ||
|
|
8fd1568405 | ||
|
|
78ee8c697e | ||
|
|
08f43a1ff4 | ||
|
|
1f71d7079b | ||
|
|
5cef8b0f8e | ||
|
|
5f0cf291f5 | ||
|
|
5500074eff | ||
|
|
db133f0144 | ||
|
|
66525c95ee | ||
|
|
86c6a11cdb | ||
|
|
13bdb0305c | ||
|
|
2a19591dc7 | ||
|
|
411bfad9f4 | ||
|
|
f58e9ed842 | ||
|
|
e383cd7b26 | ||
|
|
3a3fd2954f | ||
|
|
f44e7c1795 | ||
|
|
04604552b2 | ||
|
|
b5d6b4f138 | ||
|
|
ad02c0b532 | ||
|
|
28e500cbf9 | ||
|
|
637c7dbc7e | ||
|
|
49879791f4 | ||
|
|
8262e514d0 | ||
|
|
5a8d06b076 | ||
|
|
008f1c98d0 | ||
|
|
383c53f80e | ||
|
|
ba9cf35aa3 | ||
|
|
db41a49d9c | ||
|
|
cbbab84b71 | ||
|
|
47152d94c1 | ||
|
|
5b5bd699ff | ||
|
|
69868ee129 | ||
|
|
1dd89810eb | ||
|
|
53795bd199 | ||
|
|
603e23c2a9 | ||
|
|
3f03f8189e | ||
|
|
c576cbec93 | ||
|
|
5c4f8d88b5 | ||
|
|
9c5c1a721f | ||
|
|
bf868c1c56 | ||
|
|
a69614b432 | ||
|
|
ef7ea2c390 | ||
|
|
5470f13299 | ||
|
|
c0effc5b46 | ||
|
|
15f27ca8f2 | ||
|
|
b5273bc1fa | ||
|
|
cdba31b9d5 | ||
|
|
bb504b06b4 | ||
|
|
55717aeaea | ||
|
|
8615597984 | ||
|
|
a333bbaa12 | ||
|
|
2bc847ac57 | ||
|
|
9283692888 | ||
|
|
017b8b10b6 | ||
|
|
4ddfe70ae2 | ||
|
|
53dc25e532 | ||
|
|
542b57cf21 | ||
|
|
e36fd891e4 | ||
|
|
954b241f34 | ||
|
|
3f56494834 | ||
|
|
6a811b97b9 | ||
|
|
1900da6d24 | ||
|
|
8f38d12eee | ||
|
|
3f5f45f002 | ||
|
|
e6528cb48d | ||
|
|
041184928d | ||
|
|
b108063f75 | ||
|
|
9ce336b3d1 | ||
|
|
b5da760544 | ||
|
|
7e520e2089 | ||
|
|
07af7d5337 | ||
|
|
696a9ba3f9 | ||
|
|
9db6776dbe | ||
|
|
1c6a242b2e | ||
|
|
a58db736cf | ||
|
|
449ea43718 | ||
|
|
260c2634b9 | ||
|
|
6d0db57c02 | ||
|
|
11593d64b8 | ||
|
|
e4a0b9dbfd | ||
|
|
bb770e33f8 | ||
|
|
d048128004 | ||
|
|
eecece2afe | ||
|
|
74c7068a25 | ||
|
|
59360240b3 | ||
|
|
91ba235b3c | ||
|
|
d13fe1e431 | ||
|
|
f361c1805c | ||
|
|
52b8ad45d1 | ||
|
|
9b6c85d82e | ||
|
|
88b8fc30a2 | ||
|
|
1a0463ea04 | ||
|
|
cab91124b4 | ||
|
|
8d9ea7c132 | ||
|
|
c5558280d7 | ||
|
|
3913f5f7ae | ||
|
|
e8c69aa654 | ||
|
|
b2b37d97cf | ||
|
|
4796adf5cb | ||
|
|
2c02c2ae5d | ||
|
|
ef824b7395 | ||
|
|
2930daf68c | ||
|
|
0481e3ca74 |
+31
-13
@@ -9,18 +9,18 @@
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
Tcl_ClassSetConstructor, Tcl_ClassSetDestructor, Tcl_MethodDeclarerClass, Tcl_MethodDeclarerObject, Tcl_MethodIsPublic, Tcl_MethodIsType, Tcl_MethodName, Tcl_NewInstanceMethod, Tcl_NewMethod, Tcl_ObjectContextInvokeNext, Tcl_ObjectContextIsFiltering, Tcl_ObjectContextMethod, Tcl_ObjectContextObject, Tcl_ObjectContextSkippedArgs \- manipulate methods and method-call contexts
|
||||
Tcl_ClassSetConstructor, Tcl_ClassSetDestructor, Tcl_MethodDeclarerClass, Tcl_MethodDeclarerObject, Tcl_MethodIsPublic, Tcl_MethodIsPrivate, Tcl_MethodIsType, Tcl_MethodName, Tcl_NewInstanceMethod, Tcl_NewMethod, Tcl_ObjectContextInvokeNext, Tcl_ObjectContextIsFiltering, Tcl_ObjectContextMethod, Tcl_ObjectContextObject, Tcl_ObjectContextSkippedArgs \- manipulate methods and method-call contexts
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fB#include <tclOO.h>\fR
|
||||
.sp
|
||||
Tcl_Method
|
||||
\fBTcl_NewMethod\fR(\fIinterp, class, nameObj, isPublic,
|
||||
methodTypePtr, clientData\fR)
|
||||
\fBTcl_NewMethod\fR(\fIinterp, class, nameObj, flags, methodTypePtr,
|
||||
clientData\fR)
|
||||
.sp
|
||||
Tcl_Method
|
||||
\fBTcl_NewInstanceMethod\fR(\fIinterp, object, nameObj, isPublic,
|
||||
methodTypePtr, clientData\fR)
|
||||
\fBTcl_NewInstanceMethod\fR(\fIinterp, object, nameObj, flags, methodTypePtr,
|
||||
clientData\fR)
|
||||
.sp
|
||||
\fBTcl_ClassSetConstructor\fR(\fIinterp, class, method\fR)
|
||||
.sp
|
||||
@@ -35,8 +35,13 @@ Tcl_Object
|
||||
Tcl_Obj *
|
||||
\fBTcl_MethodName\fR(\fImethod\fR)
|
||||
.sp
|
||||
.VS TIP500
|
||||
int
|
||||
\fBTcl_MethodIsPublic\fR(\fImethod\fR)
|
||||
.VE TIP500
|
||||
.sp
|
||||
int
|
||||
\fBTcl_MethodIsPrivate\fR(\fImethod\fR)
|
||||
.sp
|
||||
int
|
||||
\fBTcl_MethodIsType\fR(\fImethod, methodTypePtr, clientDataPtr\fR)
|
||||
@@ -66,10 +71,15 @@ The class to create the method in.
|
||||
.AP Tcl_Obj *nameObj in
|
||||
The name of the method to create. Should not be NULL unless creating
|
||||
constructors or destructors.
|
||||
.AP int isPublic in
|
||||
A flag saying what the visibility of the method is. The only supported public
|
||||
values of this flag are 0 for a non-exported method, and 1 for an exported
|
||||
method.
|
||||
.AP int flags in
|
||||
A flag saying (currently) what the visibility of the method is. The supported
|
||||
public values of this flag are \fBTCL_OO_METHOD_PUBLIC\fR (which is fixed at 1
|
||||
for backward compatibility) for an exported method,
|
||||
\fBTCL_OO_METHOD_UNEXPORTED\fR (which is fixed at 0 for backward
|
||||
compatibility) for a non-exported method,
|
||||
.VS TIP500
|
||||
and \fBTCL_OO_METHOD_PRIVATE\fR for a private method.
|
||||
.VE TIP500
|
||||
.AP Tcl_MethodType *methodTypePtr in
|
||||
A description of the type of the method to create, or the type of method to
|
||||
compare against.
|
||||
@@ -105,8 +115,12 @@ Given a method, the entity that declared it can be found using
|
||||
attached to (or NULL if the method is not attached to any class) and
|
||||
\fBTcl_MethodDeclarerObject\fR which returns the object that the method is
|
||||
attached to (or NULL if the method is not attached to an object). The name of
|
||||
the method can be retrieved with \fBTcl_MethodName\fR and whether the method
|
||||
is exported is retrieved with \fBTcl_MethodIsPublic\fR. The type of the method
|
||||
the method can be retrieved with \fBTcl_MethodName\fR, whether the method
|
||||
is exported is retrieved with \fBTcl_MethodIsPublic\fR,
|
||||
.VS TIP500
|
||||
and whether the method is private is retrieved with \fBTcl_MethodIsPrivate\fR.
|
||||
.VE TIP500
|
||||
The type of the method
|
||||
can also be introspected upon to a limited degree; the function
|
||||
\fBTcl_MethodIsType\fR returns whether a method is of a particular type,
|
||||
assigning the per-method \fIclientData\fR to the variable pointed to by
|
||||
@@ -117,8 +131,12 @@ Methods are created by \fBTcl_NewMethod\fR and \fBTcl_NewInstanceMethod\fR,
|
||||
which
|
||||
create a method attached to a class or an object respectively. In both cases,
|
||||
the \fInameObj\fR argument gives the name of the method to create, the
|
||||
\fIisPublic\fR argument states whether the method should be exported
|
||||
initially, the \fImethodTypePtr\fR argument describes the implementation of
|
||||
\fIflags\fR argument states whether the method should be exported
|
||||
initially
|
||||
.VS TIP500
|
||||
or be marked as a private method,
|
||||
.VE TIP500
|
||||
the \fImethodTypePtr\fR argument describes the implementation of
|
||||
the method (see the \fBMETHOD TYPES\fR section below) and the \fIclientData\fR
|
||||
argument gives some implementation-specific data that is passed on to the
|
||||
implementation of the method when it is called.
|
||||
|
||||
+12
-1
@@ -7,7 +7,7 @@
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc \- report fatal error and abort
|
||||
Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc, Tcl_ConsolePanic \- report fatal error and abort
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fB#include <tcl.h>\fR
|
||||
@@ -21,6 +21,9 @@ void
|
||||
void
|
||||
\fBTcl_SetPanicProc\fR(\fIpanicProc\fR)
|
||||
.sp
|
||||
void
|
||||
\fBTcl_ConsolePanic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR)
|
||||
.sp
|
||||
.SH ARGUMENTS
|
||||
.AS Tcl_PanicProc *panicProc
|
||||
.AP "const char*" format in
|
||||
@@ -54,6 +57,14 @@ message is sent to the debugger in stead. If the windows executable
|
||||
does not have a stderr channel (e.g. \fBwish.exe\fR), then a
|
||||
system dialog box is used to display the panic message.
|
||||
.PP
|
||||
If your application doesn't use \fBTcl_Main\fR or \fBTk_Main\fR
|
||||
and you want to implicitly use the stderr channel of your
|
||||
application's C runtime (in stead of the stderr channel of the
|
||||
C runtime used by Tcl), you can call \fBTcl_SetPanicProc\fR
|
||||
with \fBTcl_ConsolePanic\fR as its argument. On platforms which
|
||||
only have one C runtime (almost all platforms except Windows)
|
||||
\fBTcl_ConsolePanic\fR is equivalent to NULL.
|
||||
.PP
|
||||
\fBTcl_SetPanicProc\fR may be used to modify the behavior of
|
||||
\fBTcl_Panic\fR. The \fIpanicProc\fR argument should match the
|
||||
type \fBTcl_PanicProc\fR:
|
||||
|
||||
+124
-37
@@ -82,17 +82,14 @@ by a superclass; subclass exports override superclass visibility, and may in
|
||||
turn be overridden by instances.
|
||||
.TP
|
||||
\fBfilter\fR ?\fI\-slotOperation\fR? ?\fImethodName ...\fR?
|
||||
.VS
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
.VE
|
||||
sets or updates the list of method names that are used to guard whether
|
||||
method call to instances of the class may be called and what the method's
|
||||
results are. Each \fImethodName\fR names a single filtering method (which may
|
||||
be exposed or not exposed); it is not an error for a non-existent method to be
|
||||
named since they may be defined by subclasses.
|
||||
.VS
|
||||
By default, this slot works by appending.
|
||||
.VE
|
||||
.TP
|
||||
\fBforward\fI name cmdName \fR?\fIarg ...\fR?
|
||||
.
|
||||
@@ -105,6 +102,13 @@ fully-qualified, the command will be searched for in each object's namespace,
|
||||
using the instances' namespace's path, or by looking in the global namespace.
|
||||
The method will be exported if \fIname\fR starts with a lower-case letter, and
|
||||
non-exported otherwise.
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), this command creates private forwarded methods.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.TP
|
||||
\fBmethod\fI name argList bodyScript\fR
|
||||
.
|
||||
@@ -117,17 +121,40 @@ be a namespace that is unique to the current object. The method will be
|
||||
exported if \fIname\fR starts with a lower-case letter, and non-exported
|
||||
otherwise; this behavior can be overridden via \fBexport\fR and
|
||||
\fBunexport\fR.
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), this command creates private procedure-like methods.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.TP
|
||||
\fBmixin\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
|
||||
.VS
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
.VE
|
||||
sets or updates the list of additional classes that are to be mixed into
|
||||
all the instances of the class being defined. Each \fIclassName\fR argument
|
||||
names a single class that is to be mixed in.
|
||||
.VS
|
||||
By default, this slot works by replacement.
|
||||
.VE
|
||||
.TP
|
||||
\fBprivate \fIcmd arg...\fR
|
||||
.TP
|
||||
\fBprivate \fIscript\fR
|
||||
.
|
||||
.VS TIP500
|
||||
This evaluates the \fIscript\fR (or the list of command and arguments given by
|
||||
\fIcmd\fR and \fIarg\fRs) in a context where the definitions made on the
|
||||
current class will be private definitions.
|
||||
.RS
|
||||
.PP
|
||||
The following class definition commands are affected by \fBprivate\fR:
|
||||
\fBforward\fR, \fBmethod\fR, \fBself\fR, and \fBvariable\fR. Nesting
|
||||
\fBprivate\fR inside \fBprivate\fR has no cumulative effect; the innermost
|
||||
definition context is just a private definition context. All other definition
|
||||
commands have no difference in behavior when used in a private definition
|
||||
context.
|
||||
.RE
|
||||
.VE TIP500
|
||||
.TP
|
||||
\fBrenamemethod\fI fromName toName\fR
|
||||
.
|
||||
@@ -159,21 +186,23 @@ operates identically to
|
||||
If no arguments at all are used, this gives the name of the class currently
|
||||
being configured.
|
||||
.VE TIP470
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), the definitions on the class object will also be made in a private
|
||||
definition context.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.TP
|
||||
\fBsuperclass\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
|
||||
.VS
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
.VE
|
||||
allows the alteration of the superclasses of the class being defined.
|
||||
Each \fIclassName\fR argument names one class that is to be a superclass of
|
||||
the defined class. Note that objects must not be changed from being classes to
|
||||
being non-classes or vice-versa, that an empty parent class is equivalent to
|
||||
\fBoo::object\fR, and that the parent classes of \fBoo::object\fR and
|
||||
\fBoo::class\fR may not be modified.
|
||||
.VS
|
||||
By default, this slot works by replacement.
|
||||
.VE
|
||||
.TP
|
||||
\fBunexport\fI name \fR?\fIname ...\fR?
|
||||
.
|
||||
@@ -185,18 +214,31 @@ actually defined by a superclass; subclass unexports override superclass
|
||||
visibility, and may be overridden by instance unexports.
|
||||
.TP
|
||||
\fBvariable\fR ?\fI\-slotOperation\fR? ?\fIname ...\fR?
|
||||
.VS
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below) arranges for each of the named
|
||||
variables to be automatically made
|
||||
available in the methods, constructor and destructor declared by the class
|
||||
being defined. Each variable name must not have any namespace
|
||||
separators and must not look like an array access. All variables will be
|
||||
actually present in the instance object on which the method is executed. Note
|
||||
actually present in the namespace of the instance object on which the method
|
||||
is executed. Note
|
||||
that the variable lists declared by a superclass or subclass are completely
|
||||
disjoint, as are variable lists declared by instances; the list of variable
|
||||
names is just for methods (and constructors and destructors) declared by this
|
||||
class. By default, this slot works by appending.
|
||||
.VE
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), this slot manipulates the list of private variable bindings for this
|
||||
class. In a private variable binding, the name of the variable within the
|
||||
instance object is different to the name given in the definition; the name
|
||||
used in the definition is the name that you use to access the variable within
|
||||
the methods of this class, and the name of the variable in the instance
|
||||
namespace has a unique prefix that makes accidental use from other classes
|
||||
extremely unlikely.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.SS "CONFIGURING OBJECTS"
|
||||
.PP
|
||||
The following commands are supported in the \fIdefScript\fR for
|
||||
@@ -223,18 +265,15 @@ being defined. Note that the methods themselves may be actually defined by a
|
||||
class or superclass; object exports override class visibility.
|
||||
.TP
|
||||
\fBfilter\fR ?\fI\-slotOperation\fR? ?\fImethodName ...\fR?
|
||||
.VS
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
.VE
|
||||
sets or updates the list of method names that are used to guard whether a
|
||||
method call to the object may be called and what the method's results are.
|
||||
Each \fImethodName\fR names a single filtering method (which may be exposed or
|
||||
not exposed); it is not an error for a non-existent method to be named. Note
|
||||
that the actual list of filters also depends on the filters set upon any
|
||||
classes that the object is an instance of.
|
||||
.VS
|
||||
By default, this slot works by appending.
|
||||
.VE
|
||||
.TP
|
||||
\fBforward\fI name cmdName \fR?\fIarg ...\fR?
|
||||
.
|
||||
@@ -244,6 +283,13 @@ additional arguments, \fIarg\fR etc., added before those arguments specified
|
||||
by the caller of the method. Forwarded methods should be deleted using the
|
||||
\fBmethod\fR subcommand. The method will be exported if \fIname\fR starts with
|
||||
a lower-case letter, and non-exported otherwise.
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), this command creates private forwarded methods.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.TP
|
||||
\fBmethod\fI name argList bodyScript\fR
|
||||
.
|
||||
@@ -254,17 +300,38 @@ method will be \fIbodyScript\fR. When the body of the method is evaluated, the
|
||||
current namespace of the method will be a namespace that is unique to the
|
||||
object. The method will be exported if \fIname\fR starts with a lower-case
|
||||
letter, and non-exported otherwise.
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), this command creates private procedure-like methods.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.TP
|
||||
\fBmixin\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
|
||||
.VS
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
.VE
|
||||
sets or updates a per-object list of additional classes that are to be
|
||||
mixed into the object. Each argument, \fIclassName\fR, names a single class
|
||||
that is to be mixed in.
|
||||
.VS
|
||||
By default, this slot works by replacement.
|
||||
.VE
|
||||
.TP
|
||||
\fBprivate \fIcmd arg...\fR
|
||||
.TP
|
||||
\fBprivate \fIscript\fR
|
||||
.VS TIP500
|
||||
This evaluates the \fIscript\fR (or the list of command and arguments given by
|
||||
\fIcmd\fR and \fIarg\fRs) in a context where the definitions made on the
|
||||
current object will be private definitions.
|
||||
.RS
|
||||
.PP
|
||||
The following class definition commands are affected by \fBprivate\fR:
|
||||
\fBforward\fR, \fBmethod\fR, and \fBvariable\fR. Nesting \fBprivate\fR inside
|
||||
\fBprivate\fR has no cumulative effect; the innermost definition context is
|
||||
just a private definition context. All other definition commands have no
|
||||
difference in behavior when used in a private definition context.
|
||||
.RE
|
||||
.VE TIP500
|
||||
.TP
|
||||
\fBrenamemethod\fI fromName toName\fR
|
||||
.
|
||||
@@ -275,7 +342,6 @@ that the object is an instance of. Does not change the export status of the
|
||||
method; if it was exported before, it will be afterwards.
|
||||
.TP
|
||||
\fBself \fR
|
||||
.
|
||||
.VS TIP470
|
||||
This gives the name of the object currently being configured.
|
||||
.VE TIP470
|
||||
@@ -289,15 +355,42 @@ object being defined. Note that the methods themselves may be actually defined
|
||||
by a class; instance unexports override class visibility.
|
||||
.TP
|
||||
\fBvariable\fR ?\fI\-slotOperation\fR? ?\fIname ...\fR?
|
||||
.VS
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below) arranges for each of the named
|
||||
variables to be automatically made available in the methods declared by the
|
||||
object being defined. Each variable name must not have any namespace
|
||||
separators and must not look like an array access. All variables will be
|
||||
actually present in the object on which the method is executed. Note that the
|
||||
actually present in the namespace of the object on which the method is
|
||||
executed. Note that the
|
||||
variable lists declared by the classes and mixins of which the object is an
|
||||
instance are completely disjoint; the list of variable names is just for
|
||||
methods declared by this object. By default, this slot works by appending.
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), this slot manipulates the list of private variable bindings for this
|
||||
object. In a private variable binding, the name of the variable within the
|
||||
instance object is different to the name given in the definition; the name
|
||||
used in the definition is the name that you use to access the variable within
|
||||
the methods of this instance object, and the name of the variable in the
|
||||
instance namespace has a unique prefix that makes accidental use from
|
||||
superclass methods extremely unlikely.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.SH "PRIVATE METHODS"
|
||||
.VS TIP500
|
||||
When a class or instance has a private method, that private method can only be
|
||||
invoked from within methods of that class or instance. Other callers of the
|
||||
object's methods \fIcannot\fR invoke private methods, it is as if the private
|
||||
methods do not exist. However, a private method of a class \fIcan\fR be
|
||||
invoked from the class's methods when those methods are being used on another
|
||||
instance object; this means that a class can use them to coordinate behaviour
|
||||
between several instances of itself without interfering with how other
|
||||
classes (especially either subclasses or superclasses) interact. Private
|
||||
methods precede all mixed in classes in the method call order (as reported by
|
||||
\fBself call\fR).
|
||||
.VE TIP500
|
||||
.SH "SLOTTED DEFINITIONS"
|
||||
Some of the configurable definitions of a class or object are \fIslotted
|
||||
definitions\fR. This means that the configuration is implemented by a slot
|
||||
@@ -305,20 +398,17 @@ object, that is an instance of the class \fBoo::Slot\fR, which manages a list
|
||||
of values (class names, variable names, etc.) that comprises the contents of
|
||||
the slot. The class defines three operations (as methods) that may be done on
|
||||
the slot:
|
||||
.VE
|
||||
.TP
|
||||
\fIslot\fR \fB\-append\fR ?\fImember ...\fR?
|
||||
.VS
|
||||
.
|
||||
This appends the given \fImember\fR elements to the slot definition.
|
||||
.VE
|
||||
.TP
|
||||
\fIslot\fR \fB\-clear\fR
|
||||
.VS
|
||||
.
|
||||
This sets the slot definition to the empty list.
|
||||
.VE
|
||||
.TP
|
||||
\fIslot\fR \fB\-set\fR ?\fImember ...\fR?
|
||||
.VS
|
||||
.
|
||||
This replaces the slot definition with the given \fImember\fR elements.
|
||||
.PP
|
||||
A consequence of this is that any use of a slot's default operation where the
|
||||
@@ -331,17 +421,15 @@ which is forwarded to the default operation of the slot (thus, for the class
|
||||
slot, this is forwarded to
|
||||
.QW "\fBmy \-append\fR" ),
|
||||
and these methods which provide the implementation interface:
|
||||
.VE
|
||||
.TP
|
||||
\fIslot\fR \fBGet\fR
|
||||
.VS
|
||||
.
|
||||
Returns a list that is the current contents of the slot. This method must
|
||||
always be called from a stack frame created by a call to \fBoo::define\fR or
|
||||
\fBoo::objdefine\fR.
|
||||
.VE
|
||||
.TP
|
||||
\fIslot\fR \fBSet \fIelementList\fR
|
||||
.VS
|
||||
.
|
||||
Sets the contents of the slot to the list \fIelementList\fR and returns the
|
||||
empty string. This method must always be called from a stack frame created by
|
||||
a call to \fBoo::define\fR or \fBoo::objdefine\fR.
|
||||
@@ -352,7 +440,6 @@ an unknown method handler to tie all these pieces together, and they hide
|
||||
their \fBdestroy\fR method so that it is not invoked inadvertently. It is
|
||||
\fIrecommended\fR that any user changes to the slot mechanism be restricted to
|
||||
defining new operations whose names start with a hyphen.
|
||||
.VE
|
||||
.SH EXAMPLES
|
||||
This example demonstrates how to use both forms of the \fBoo::define\fR and
|
||||
\fBoo::objdefine\fR commands (they work in the same way), as well as
|
||||
|
||||
+152
-98
@@ -35,10 +35,9 @@ Returns the body of procedure \fIprocname\fR. \fIProcname\fR must be
|
||||
the name of a Tcl command procedure.
|
||||
.TP
|
||||
\fBinfo class\fI subcommand class\fR ?\fIarg ...\fR
|
||||
.VS 8.6
|
||||
.
|
||||
Returns information about the class, \fIclass\fR. The \fIsubcommand\fRs are
|
||||
described in \fBCLASS INTROSPECTION\fR below.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo cmdcount\fR
|
||||
.
|
||||
@@ -78,11 +77,10 @@ command is not complete, the script can delay evaluating it until additional
|
||||
lines have been typed to complete the command.
|
||||
.TP
|
||||
\fBinfo coroutine\fR
|
||||
.VS 8.6
|
||||
.
|
||||
Returns the name of the currently executing \fBcoroutine\fR, or the empty
|
||||
string if either no coroutine is currently executing, or the current coroutine
|
||||
has been deleted (but has not yet returned or yielded since deletion).
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo default \fIprocname arg varname\fR
|
||||
.
|
||||
@@ -93,7 +91,7 @@ Otherwise it returns \fB1\fR and places the default value of \fIarg\fR
|
||||
into variable \fIvarname\fR.
|
||||
.TP
|
||||
\fBinfo errorstack \fR?\fIinterp\fR?
|
||||
.VS 8.6
|
||||
.
|
||||
Returns, in a form that is programmatically easy to parse, the function names
|
||||
and arguments at each level from the call stack of the last error in the given
|
||||
\fIinterp\fR, or in the current one if not specified.
|
||||
@@ -118,7 +116,6 @@ options dictionary returned by 3-argument \fBcatch\fR; \fBinfo errorstack\fR
|
||||
is a convenient way of retrieving it for uncaught errors at top-level in an
|
||||
interactive \fBtclsh\fR.
|
||||
.RE
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo exists \fIvarName\fR
|
||||
.
|
||||
@@ -329,10 +326,9 @@ was invoked. If Tcl was unable to identify the file, then an empty
|
||||
string is returned.
|
||||
.TP
|
||||
\fBinfo object\fI subcommand object\fR ?\fIarg ...\fR
|
||||
.VS 8.6
|
||||
.
|
||||
Returns information about the object, \fIobject\fR. The \fIsubcommand\fRs are
|
||||
described in \fBOBJECT INTROSPECTION\fR below.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo patchlevel\fR
|
||||
.
|
||||
@@ -399,20 +395,22 @@ Note that a currently-visible variable may not yet
|
||||
if it has not
|
||||
been set (e.g. a variable declared but not set by \fBvariable\fR).
|
||||
.SS "CLASS INTROSPECTION"
|
||||
.VS 8.6
|
||||
.PP
|
||||
The following \fIsubcommand\fR values are supported by \fBinfo class\fR:
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class call\fI class method\fR
|
||||
.VS
|
||||
.
|
||||
Returns a description of the method implementations that are used to provide a
|
||||
stereotypical instance of \fIclass\fR's implementation of \fImethod\fR
|
||||
(stereotypical instances being objects instantiated by a class without having
|
||||
any object-specific definitions added). This consists of a list of lists of
|
||||
four elements, where each sublist consists of a word that describes the
|
||||
general type of method implementation (being one of \fBmethod\fR for an
|
||||
ordinary method, \fBfilter\fR for an applied filter, and \fBunknown\fR for a
|
||||
ordinary method, \fBfilter\fR for an applied filter,
|
||||
.VS TIP500
|
||||
\fBprivate\fR for a private method,
|
||||
.VE TIP500
|
||||
and \fBunknown\fR for a
|
||||
method that is invoked as part of unknown method handling), a word giving the
|
||||
name of the particular method invoked (which is always the same as
|
||||
\fImethod\fR for the \fBmethod\fR type, and
|
||||
@@ -423,122 +421,149 @@ implementation (see \fBinfo class methodtype\fR).
|
||||
.RS
|
||||
.PP
|
||||
Note that there is no inspection of whether the method implementations
|
||||
actually use \fBnext\fR to transfer control along the call chain.
|
||||
actually use \fBnext\fR to transfer control along the call chain,
|
||||
.VS TIP500
|
||||
and the call chains that this command files do not actually contain private
|
||||
methods.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class constructor\fI class\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a description of the definition of the constructor of
|
||||
class \fIclass\fR. The definition is described as a two element list; the first
|
||||
element is the list of arguments to the constructor in a form suitable for
|
||||
passing to another call to \fBproc\fR or a method definition, and the second
|
||||
element is the body of the constructor. If no constructor is present, this
|
||||
returns the empty list.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class definition\fI class method\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a description of the definition of the method named
|
||||
\fImethod\fR of class \fIclass\fR. The definition is described as a two element
|
||||
list; the first element is the list of arguments to the method in a form
|
||||
suitable for passing to another call to \fBproc\fR or a method definition, and
|
||||
the second element is the body of the method.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class destructor\fI class\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns the body of the destructor of class \fIclass\fR. If no
|
||||
destructor is present, this returns the empty string.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class filters\fI class\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns the list of filter methods set on the class.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class forward\fI class method\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns the argument list for the method forwarding called
|
||||
\fImethod\fR that is set on the class called \fIclass\fR.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class instances\fI class\fR ?\fIpattern\fR?
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a list of instances of class \fIclass\fR. If the
|
||||
optional \fIpattern\fR argument is present, it constrains the list of returned
|
||||
instances to those that match it according to the rules of \fBstring match\fR.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class methods\fI class\fR ?\fIoptions...\fR?
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a list of all public (i.e. exported) methods of the
|
||||
class called \fIclass\fR. Any of the following \fIoption\fRs may be
|
||||
specified, controlling exactly which method names are returned:
|
||||
.RS
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fB\-all\fR
|
||||
.VS 8.6
|
||||
If the \fB\-all\fR flag is given, the list of methods will include those
|
||||
.
|
||||
If the \fB\-all\fR flag is given,
|
||||
.VS TIP500
|
||||
and the \fB\-scope\fR flag is not given,
|
||||
.VE TIP500
|
||||
the list of methods will include those
|
||||
methods defined not just by the class, but also by the class's superclasses
|
||||
and mixins.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fB\-private\fR
|
||||
.VS 8.6
|
||||
If the \fB\-private\fR flag is given, the list of methods will also include
|
||||
the private (i.e. non-exported) methods of the class (and superclasses and
|
||||
.
|
||||
If the \fB\-private\fR flag is given,
|
||||
.VS TIP500
|
||||
and the \fB\-scope\fR flag is not given,
|
||||
.VE TIP500
|
||||
the list of methods will also include
|
||||
the non-exported methods of the class (and superclasses and
|
||||
mixins, if \fB\-all\fR is also given).
|
||||
.VS TIP500
|
||||
Note that this naming is an unfortunate clash with true private methods; this
|
||||
option name is retained for backward compatibility.
|
||||
.VE TIP500
|
||||
.TP
|
||||
\fB\-scope\fI scope\fR
|
||||
.VS TIP500
|
||||
Returns a list of all methods on \fIclass\fR that have the given visibility
|
||||
\fIscope\fR. When this option is supplied, both the \fB\-all\fR and
|
||||
\fB\-private\fR options are ignored. The valid values for \fIscope\fR are:
|
||||
.RS
|
||||
.IP \fBpublic\fR 3
|
||||
Only methods with \fIpublic\fR scope (i.e., callable from anywhere by any instance
|
||||
of this class) are to be returned.
|
||||
.IP \fBunexported\fR 3
|
||||
Only methods with \fIunexported\fR scope (i.e., only callable via \fBmy\fR) are to
|
||||
be returned.
|
||||
.IP \fBprivate\fR 3
|
||||
Only methods with \fIprivate\fR scope (i.e., only callable from within this class's
|
||||
methods) are to be returned.
|
||||
.RE
|
||||
.VE TIP500
|
||||
.RE
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class methodtype\fI class method\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a description of the type of implementation used for
|
||||
the method named \fImethod\fR of class \fIclass\fR. When the result is
|
||||
\fBmethod\fR, further information can be discovered with \fBinfo class
|
||||
definition\fR, and when the result is \fBforward\fR, further information can
|
||||
be discovered with \fBinfo class forward\fR.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class mixins\fI class\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a list of all classes that have been mixed into the
|
||||
class named \fIclass\fR.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class subclasses\fI class\fR ?\fIpattern\fR?
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a list of direct subclasses of class \fIclass\fR. If
|
||||
the optional \fIpattern\fR argument is present, it constrains the list of
|
||||
returned classes to those that match it according to the rules of
|
||||
\fBstring match\fR.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class superclasses\fI class\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a list of direct superclasses of class \fIclass\fR in
|
||||
inheritance precedence order.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo class variables\fI class\fR
|
||||
.VS 8.6
|
||||
\fBinfo class variables\fI class\fR ?\fB\-private\fR?
|
||||
.
|
||||
This subcommand returns a list of all variables that have been declared for
|
||||
the class named \fIclass\fR (i.e. that are automatically present in the
|
||||
class's methods, constructor and destructor).
|
||||
.VS TIP500
|
||||
If the \fB\-private\fR option is specified, this lists the private variables
|
||||
declared instead.
|
||||
.VE TIP500
|
||||
.SS "OBJECT INTROSPECTION"
|
||||
.PP
|
||||
The following \fIsubcommand\fR values are supported by \fBinfo object\fR:
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object call\fI object method\fR
|
||||
.VS 8.6
|
||||
.
|
||||
Returns a description of the method implementations that are used to provide
|
||||
\fIobject\fR's implementation of \fImethod\fR. This consists of a list of
|
||||
lists of four elements, where each sublist consists of a word that describes
|
||||
the general type of method implementation (being one of \fBmethod\fR for an
|
||||
ordinary method, \fBfilter\fR for an applied filter, and \fBunknown\fR for a
|
||||
ordinary method, \fBfilter\fR for an applied filter,
|
||||
.VS TIP500
|
||||
\fBprivate\fR for a private method,
|
||||
.VE TIP500
|
||||
and \fBunknown\fR for a
|
||||
method that is invoked as part of unknown method handling), a word giving the
|
||||
name of the particular method invoked (which is always the same as
|
||||
\fImethod\fR for the \fBmethod\fR type, and
|
||||
@@ -550,128 +575,160 @@ implementation (see \fBinfo object methodtype\fR).
|
||||
.RS
|
||||
.PP
|
||||
Note that there is no inspection of whether the method implementations
|
||||
actually use \fBnext\fR to transfer control along the call chain.
|
||||
actually use \fBnext\fR to transfer control along the call chain,
|
||||
.VS TIP500
|
||||
and the call chains that this command files do not actually contain private
|
||||
methods.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object class\fI object\fR ?\fIclassName\fR?
|
||||
.VS 8.6
|
||||
.
|
||||
If \fIclassName\fR is unspecified, this subcommand returns class of the
|
||||
\fIobject\fR object. If \fIclassName\fR is present, this subcommand returns a
|
||||
boolean value indicating whether the \fIobject\fR is of that class.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object creationid\fI object\fR
|
||||
.VS TIP500
|
||||
Returns the unique creation identifier for the \fIobject\fR object. This
|
||||
creation identifier is unique to the object (within a Tcl interpreter) and
|
||||
cannot be controlled at object creation time or altered afterwards.
|
||||
.RS
|
||||
.PP
|
||||
\fIImplementation note:\fR the creation identifier is used to generate unique
|
||||
identifiers associated with the object, especially for private variables.
|
||||
.RE
|
||||
.VE TIP500
|
||||
.TP
|
||||
\fBinfo object definition\fI object method\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a description of the definition of the method named
|
||||
\fImethod\fR of object \fIobject\fR. The definition is described as a two
|
||||
element list; the first element is the list of arguments to the method in a
|
||||
form suitable for passing to another call to \fBproc\fR or a method definition,
|
||||
and the second element is the body of the method.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object filters\fI object\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns the list of filter methods set on the object.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object forward\fI object method\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns the argument list for the method forwarding called
|
||||
\fImethod\fR that is set on the object called \fIobject\fR.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object isa\fI category object\fR ?\fIarg\fR?
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand tests whether an object belongs to a particular category,
|
||||
returning a boolean value that indicates whether the \fIobject\fR argument
|
||||
meets the criteria for the category. The supported categories are:
|
||||
.VE 8.6
|
||||
.RS
|
||||
.TP
|
||||
\fBinfo object isa class\fI object\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This returns whether \fIobject\fR is a class (i.e. an instance of
|
||||
\fBoo::class\fR or one of its subclasses).
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object isa metaclass\fI object\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This returns whether \fIobject\fR is a class that can manufacture classes
|
||||
(i.e. is \fBoo::class\fR or a subclass of it).
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object isa mixin\fI object class\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This returns whether \fIclass\fR is directly mixed into \fIobject\fR.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object isa object\fI object\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This returns whether \fIobject\fR really is an object.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object isa typeof\fI object class\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This returns whether \fIclass\fR is the type of \fIobject\fR (i.e. whether
|
||||
\fIobject\fR is an instance of \fIclass\fR or one of its subclasses, whether
|
||||
direct or indirect).
|
||||
.RE
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object methods\fI object\fR ?\fIoption...\fR?
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a list of all public (i.e. exported) methods of the
|
||||
object called \fIobject\fR. Any of the following \fIoption\fRs may be
|
||||
specified, controlling exactly which method names are returned:
|
||||
.RS
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fB\-all\fR
|
||||
.VS 8.6
|
||||
If the \fB\-all\fR flag is given, the list of methods will include those
|
||||
.
|
||||
If the \fB\-all\fR flag is given,
|
||||
.VS TIP500
|
||||
and the \fB\-scope\fR flag is not given,
|
||||
.VE TIP500
|
||||
the list of methods will include those
|
||||
methods defined not just by the object, but also by the object's class and
|
||||
mixins, plus the superclasses of those classes.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fB\-private\fR
|
||||
.VS 8.6
|
||||
If the \fB\-private\fR flag is given, the list of methods will also include
|
||||
the private (i.e. non-exported) methods of the object (and classes, if
|
||||
.
|
||||
If the \fB\-private\fR flag is given,
|
||||
.VS TIP500
|
||||
and the \fB\-scope\fR flag is not given,
|
||||
.VE TIP500
|
||||
the list of methods will also include
|
||||
the non-exported methods of the object (and classes, if
|
||||
\fB\-all\fR is also given).
|
||||
.VS TIP500
|
||||
Note that this naming is an unfortunate clash with true private methods; this
|
||||
option name is retained for backward compatibility.
|
||||
.VE TIP500
|
||||
.TP
|
||||
\fB\-scope\fI scope\fR
|
||||
.VS TIP500
|
||||
Returns a list of all methods on \fIobject\fR that have the given visibility
|
||||
\fIscope\fR. When this option is supplied, both the \fB\-all\fR and
|
||||
\fB\-private\fR options are ignored. The valid values for \fIscope\fR are:
|
||||
.RS
|
||||
.IP \fBpublic\fR 3
|
||||
Only methods with \fIpublic\fR scope (i.e., callable from anywhere) are to be
|
||||
returned.
|
||||
.IP \fBunexported\fR 3
|
||||
Only methods with \fIunexported\fR scope (i.e., only callable via \fBmy\fR) are to
|
||||
be returned.
|
||||
.IP \fBprivate\fR 3
|
||||
Only methods with \fIprivate\fR scope (i.e., only callable from within this object's
|
||||
instance methods) are to be returned.
|
||||
.RE
|
||||
.VE TIP500
|
||||
.RE
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object methodtype\fI object method\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a description of the type of implementation used for
|
||||
the method named \fImethod\fR of object \fIobject\fR. When the result is
|
||||
\fBmethod\fR, further information can be discovered with \fBinfo object
|
||||
definition\fR, and when the result is \fBforward\fR, further information can
|
||||
be discovered with \fBinfo object forward\fR.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object mixins\fI object\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a list of all classes that have been mixed into the
|
||||
object named \fIobject\fR.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object namespace\fI object\fR
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns the name of the internal namespace of the object named
|
||||
\fIobject\fR.
|
||||
.VE 8.6
|
||||
.TP
|
||||
\fBinfo object variables\fI object\fR
|
||||
.VS 8.6
|
||||
\fBinfo object variables\fI object\fRR ?\fB\-private\fR?
|
||||
.
|
||||
This subcommand returns a list of all variables that have been declared for
|
||||
the object named \fIobject\fR (i.e. that are automatically present in the
|
||||
object's methods).
|
||||
.VE 8.6
|
||||
.VS TIP500
|
||||
If the \fB\-private\fR option is specified, this lists the private variables
|
||||
declared instead.
|
||||
.VE TIP500
|
||||
.TP
|
||||
\fBinfo object vars\fI object\fR ?\fIpattern\fR?
|
||||
.VS 8.6
|
||||
.
|
||||
This subcommand returns a list of all variables in the private namespace of
|
||||
the object named \fIobject\fR. If the optional \fIpattern\fR argument is
|
||||
given, it is a filter (in the syntax of a \fBstring match\fR glob pattern)
|
||||
@@ -680,7 +737,6 @@ from the list returned by \fBinfo object variables\fR; that can include
|
||||
variables that are currently unset, whereas this can include variables that
|
||||
are not automatically included by any of \fIobject\fR's methods (or those of
|
||||
its class, superclasses or mixins).
|
||||
.VE 8.6
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
This command prints out a procedure suitable for saving in a Tcl
|
||||
@@ -703,7 +759,6 @@ proc printProc {procName} {
|
||||
}
|
||||
.CE
|
||||
.SS "EXAMPLES WITH OBJECTS"
|
||||
.VS 8.6
|
||||
.PP
|
||||
Every object necessarily knows what its class is; this information is
|
||||
trivially extractable through introspection:
|
||||
@@ -724,8 +779,10 @@ method and get how it is defined. This procedure illustrates how:
|
||||
proc getDef {obj method} {
|
||||
foreach inf [\fBinfo object call\fR $obj $method] {
|
||||
lassign $inf calltype name locus methodtype
|
||||
|
||||
# Assume no forwards or filters, and hence no $calltype
|
||||
# or $methodtype checks...
|
||||
|
||||
if {$locus eq "object"} {
|
||||
return [\fBinfo object definition\fR $obj $name]
|
||||
} else {
|
||||
@@ -748,7 +805,9 @@ proc getDef {obj method} {
|
||||
# Assume no forwards
|
||||
return [\fBinfo object definition\fR $obj $method]
|
||||
}
|
||||
|
||||
set cls [\fBinfo object class\fR $obj]
|
||||
|
||||
while {$method ni [\fBinfo class methods\fR $cls]} {
|
||||
# Assume the simple case
|
||||
set cls [lindex [\fBinfo class superclass\fR $cls] 0]
|
||||
@@ -756,22 +815,17 @@ proc getDef {obj method} {
|
||||
error "no definition for $method"
|
||||
}
|
||||
}
|
||||
|
||||
# Assume no forwards
|
||||
return [\fBinfo class definition\fR $cls $method]
|
||||
}
|
||||
.CE
|
||||
.VE 8.6
|
||||
.SH "SEE ALSO"
|
||||
.VS 8.6
|
||||
global(n), oo::class(n), oo::define(n), oo::object(n), proc(n), self(n),
|
||||
.VE 8.6
|
||||
tcl_library(n), tcl_patchLevel(n), tcl_version(n)
|
||||
.SH KEYWORDS
|
||||
command, information, interpreter, introspection, level, namespace,
|
||||
.VS 8.6
|
||||
object,
|
||||
.VE 8.6
|
||||
procedure, variable
|
||||
object, procedure, variable
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
|
||||
@@ -19,13 +19,18 @@ package require TclOO
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The \fBmy\fR command is used to allow methods of objects to invoke any method
|
||||
The \fBmy\fR command is used to allow methods of objects to invoke methods
|
||||
of the object (or its class). In particular, the set of valid values for
|
||||
\fImethodName\fR is the set of all methods supported by an object and its
|
||||
superclasses, including those that are not exported. The object upon which the
|
||||
method is invoked is always the one that is the current context of the method
|
||||
(i.e. the object that is returned by \fBself object\fR) from which the
|
||||
\fBmy\fR command is invoked.
|
||||
superclasses, including those that are not exported
|
||||
.VS TIP500
|
||||
and private methods of the object or class when used within another method
|
||||
defined by that object or class.
|
||||
.VE TIP500
|
||||
The object upon which the method is invoked is the one that owns the namespace
|
||||
that the \fBmy\fR command is contained in initially (\fBNB:\fR the link
|
||||
remains if the command is renamed), which is the currently invoked object by
|
||||
default.
|
||||
.PP
|
||||
Each object has its own \fBmy\fR command, contained in its instance namespace.
|
||||
.SH EXAMPLES
|
||||
@@ -40,16 +45,38 @@ oo::class create c {
|
||||
puts [incr counter]
|
||||
}
|
||||
}
|
||||
|
||||
c create o
|
||||
o count \fI\(-> prints "1"\fR
|
||||
o count \fI\(-> prints "2"\fR
|
||||
o count \fI\(-> prints "3"\fR
|
||||
.CE
|
||||
.PP
|
||||
This example shows how you can use \fBmy\fR to make callbacks to private
|
||||
methods from outside the object (from a \fBtrace\fR), using
|
||||
\fBnamespace code\fR to enter the correct context:
|
||||
.PP
|
||||
.CS
|
||||
oo::class create HasCallback {
|
||||
method makeCallback {} {
|
||||
return [namespace code {
|
||||
\fBmy\fR Callback
|
||||
}]
|
||||
}
|
||||
|
||||
method Callback {args} {
|
||||
puts "callback: $args"
|
||||
}
|
||||
}
|
||||
|
||||
set o [HasCallback new]
|
||||
trace add variable xyz write [$o makeCallback]
|
||||
set xyz "called" \fI\(-> prints "callback: xyz {} write"\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
next(n), oo::object(n), self(n)
|
||||
.SH KEYWORDS
|
||||
method, method visibility, object, private method, public method
|
||||
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
|
||||
@@ -112,6 +112,7 @@ oo::class create theSuperclass {
|
||||
puts "in the superclass, args = $args"
|
||||
}
|
||||
}
|
||||
|
||||
oo::class create theSubclass {
|
||||
superclass theSuperclass
|
||||
method example {args} {
|
||||
@@ -121,6 +122,7 @@ oo::class create theSubclass {
|
||||
puts "after chaining from subclass"
|
||||
}
|
||||
}
|
||||
|
||||
theSubclass create obj
|
||||
oo::objdefine obj method example args {
|
||||
puts "per-object method, args = $args"
|
||||
@@ -167,6 +169,7 @@ oo::class create cache {
|
||||
\fI# Compute value, insert into cache, and return it\fR
|
||||
return [set ValueCache($key) [\fBnext\fR {*}$args]]
|
||||
}
|
||||
|
||||
method flushCache {} {
|
||||
my variable ValueCache
|
||||
unset ValueCache
|
||||
@@ -178,10 +181,12 @@ oo::class create cache {
|
||||
oo::object create demo
|
||||
oo::objdefine demo {
|
||||
mixin cache
|
||||
|
||||
method compute {a b c} {
|
||||
after 3000 \fI;# Simulate deep thought\fR
|
||||
return [expr {$a + $b * $c}]
|
||||
}
|
||||
|
||||
method compute2 {a b c} {
|
||||
after 3000 \fI;# Simulate deep thought\fR
|
||||
return [expr {$a * $b + $c}]
|
||||
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2017 Frederic Bonnet.
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH process n 8.7 Tcl "Tcl Built-In Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
tcl::process \- Subprocess management
|
||||
.SH SYNOPSIS
|
||||
\fB::tcl::process \fIoption \fR?\fIarg arg ...\fR?
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
This command provides a way to manage subprocesses created by the \fBopen\fR
|
||||
and \fBexec\fR commands. The legal \fIoptions\fR (which may be abbreviated) are:
|
||||
.TP
|
||||
\fB::tcl::process list\fR
|
||||
.
|
||||
Returns the list of subprocess PIDs.
|
||||
.TP
|
||||
\fB::tcl::process status\fR ?\fIswitches\fR? ?\fIpids\fR?
|
||||
.
|
||||
Returns a dictionary mapping subprocess PIDs to their respective status. If
|
||||
\fIpids\fR is specified as a list of PIDs then the command only returns the
|
||||
status of the matching subprocesses if they exist, and raises an error
|
||||
otherwise. For active processes, the status is an empty value. For terminated
|
||||
processes, the status is a list with the following format:
|
||||
.QW "{code ?\fImsg errorCode\fR?}" ,
|
||||
where:
|
||||
.RS
|
||||
.TP
|
||||
\fBcode\fR\0
|
||||
.
|
||||
is a standard Tcl return code,
|
||||
.TP
|
||||
\fBmsg\fR\0
|
||||
.
|
||||
is the human-readable error message,
|
||||
.TP
|
||||
\fBerrorCode\fR\0
|
||||
.
|
||||
uses the same format as the \fBerrorCode\fR global variable
|
||||
.RE
|
||||
Note that \fBmsg\fR and \fBerrorCode\fR are only present for abnormally
|
||||
terminated processes (i.e. those where \fBcode\fR is nonzero). Under the hood
|
||||
this command calls \fBTcl_WaitPid\fR with the \fBWNOHANG\fR flag set for
|
||||
non-blocking behavior, unless the \fB\-wait\fR switch is set (see below).
|
||||
.RS
|
||||
.PP
|
||||
Additionally, \fB::tcl::process status\fR accepts the following switches:
|
||||
.TP
|
||||
\fB\-wait\fR\0
|
||||
.
|
||||
By default the command returns immediately (the underlying \fBTcl_WaitPid\fR is
|
||||
called with the \fBWNOHANG\fR flag set) unless this switch is set. If \fBpids\fR
|
||||
is specified as a list of PIDs then the command waits until the status of the
|
||||
matching subprocesses are available. If \fBpids\fR is not specified then it
|
||||
waits for all known subprocesses.
|
||||
.TP
|
||||
\fB\-\|\-\fR
|
||||
.
|
||||
Marks the end of switches. The argument following this one will
|
||||
be treated as the first \fIarg\fR even if it starts with a \fB\-\fR.
|
||||
.RE
|
||||
.TP
|
||||
\fB::tcl::process purge ?\fIpids\fR?
|
||||
.
|
||||
Cleans up all data associated with terminated subprocesses. If \fBpids\fR is
|
||||
specified as a list of PIDs then the command only cleanup data for the matching
|
||||
subprocesses if they exist, and raises an error otherwise. If the process is
|
||||
still active then it does nothing.
|
||||
.TP
|
||||
\fB::tcl::process autopurge ?\fIflag\fR?
|
||||
.
|
||||
Automatic purge facility. If \fBflag\fR is specified as a boolean value then it
|
||||
activates or deactivate autopurge. In all cases it returns the current status as
|
||||
a boolean value. When autopurge is active, \fBTcl_ReapDetachedProcs\fR is called
|
||||
each time the exec command is executed or a pipe channel created by open is
|
||||
closed. When autopurge is inactive, \fB::tcl::process\fR purge must be called
|
||||
explicitly. By default autopurge is active.
|
||||
.RE
|
||||
.SH "EXAMPLES"
|
||||
.PP
|
||||
.CS
|
||||
\fB::tcl::process autopurge\fR
|
||||
\fI\(-> true\fR
|
||||
\fB::tcl::process autopurge\fR false
|
||||
\fI\(-> false\fR
|
||||
|
||||
set pid1 [exec command1 a b c | command2 d e f &]
|
||||
\fI\(-> 123 456\fR
|
||||
set chan [open "|command1 a b c | command2 d e f"]
|
||||
\fI\(-> file123\fR
|
||||
set pid2 [pid $chan]
|
||||
\fI\(-> 789 1011\fR
|
||||
|
||||
\fB::tcl::process list\fR
|
||||
\fI\(-> 123 456 789 1011\fR
|
||||
|
||||
\fB::tcl::process status\fR
|
||||
\fI\(-> 123 0 456 {1 "child killed: write on pipe with no readers" {CHILDKILLED 456 SIGPIPE "write on pipe with no readers"}} 789 {1 "child suspended: background tty read" {CHILDSUSP 789 SIGTTIN "background tty read"}} 1011 {}\fR
|
||||
|
||||
\fB::tcl::process status\fR 123
|
||||
\fI\(-> 123 0\fR
|
||||
|
||||
\fB::tcl::process status\fR 1011
|
||||
\fI\(-> 1011 {}\fR
|
||||
|
||||
\fB::tcl::process status\fR -wait
|
||||
\fI\(-> 123 0 456 {1 "child killed: write on pipe with no readers" {CHILDKILLED 456 SIGPIPE "write on pipe with no readers"}} 789 {1 "child suspended: background tty read" {CHILDSUSP 789 SIGTTIN "background tty read"}} 1011 {1 "child process exited abnormally" {CHILDSTATUS 1011 -1}}\fR
|
||||
|
||||
\fB::tcl::process status\fR 1011
|
||||
\fI\(-> 1011 {1 "child process exited abnormally" {CHILDSTATUS 1011 -1}}\fR
|
||||
|
||||
\fB::tcl::process purge\fR
|
||||
exec command1 1 2 3 &
|
||||
\fI\(-> 1213\fR
|
||||
\fB::tcl::process list\fR
|
||||
\fI\(-> 1213\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
exec(n), open(n), Tcl_DetachPids(3), Tcl_WaitPid(3), Tcl_ReapDetachedProcs(3)
|
||||
.SH "KEYWORDS"
|
||||
background, child, detach, process, wait
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" End:
|
||||
+6
-1
@@ -32,7 +32,12 @@ implement the current call chain. The first element is the same as would be
|
||||
reported by \fBinfo object\fR \fBcall\fR for the current method (except that this
|
||||
also reports useful values from within constructors and destructors, whose
|
||||
names are reported as \fB<constructor>\fR and \fB<destructor>\fR
|
||||
respectively), and the second element is an index into the first element's
|
||||
respectively,
|
||||
.VS TIP500
|
||||
and for private methods, which are described as being \fBprivate\fR instead of
|
||||
being a \fBmethod\fR),
|
||||
.VE TIP500
|
||||
and the second element is an index into the first element's
|
||||
list that indicates which actual implementation is currently executing (the
|
||||
first implementation to execute is always at index 0).
|
||||
.TP
|
||||
|
||||
+14
-31
@@ -89,6 +89,10 @@ extern "C" {
|
||||
# define JOIN(a,b) JOIN1(a,b)
|
||||
# define JOIN1(a,b) a##b
|
||||
#endif
|
||||
|
||||
#ifndef TCL_THREADS
|
||||
# define TCL_THREADS 1
|
||||
#endif
|
||||
#endif /* !TCL_NO_DEPRECATED */
|
||||
|
||||
/*
|
||||
@@ -103,15 +107,10 @@ extern "C" {
|
||||
#ifndef RC_INVOKED
|
||||
|
||||
/*
|
||||
* Special macro to define mutexes, that doesn't do anything if we are not
|
||||
* using threads.
|
||||
* Special macro to define mutexes.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#define TCL_DECLARE_MUTEX(name) static Tcl_Mutex name;
|
||||
#else
|
||||
#define TCL_DECLARE_MUTEX(name)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Tcl's public routine Tcl_FSSeek() uses the values SEEK_SET, SEEK_CUR, and
|
||||
@@ -2146,9 +2145,9 @@ typedef struct Tcl_EncodingType {
|
||||
|
||||
/*
|
||||
* The maximum number of bytes that are necessary to represent a single
|
||||
* Unicode character in UTF-8. The valid values should be 3, 4 or 6
|
||||
* (or perhaps 1 if we want to support a non-unicode enabled core). If 3 or
|
||||
* 4, then Tcl_UniChar must be 2-bytes in size (UCS-2) (the default). If 6,
|
||||
* Unicode character in UTF-8. The valid values are 4 and 6
|
||||
* (or perhaps 1 if we want to support a non-unicode enabled core). If 4,
|
||||
* then Tcl_UniChar must be 2-bytes in size (UCS-2) (the default). If 6,
|
||||
* then Tcl_UniChar must be 4-bytes in size (UCS-4). At this time UCS-2 mode
|
||||
* is the default and recommended mode. UCS-4 is experimental and not
|
||||
* recommended. It works for the core, but most extensions expect UCS-2.
|
||||
@@ -2361,6 +2360,11 @@ const char * Tcl_InitStubs(Tcl_Interp *interp, const char *version,
|
||||
int exact, int magic);
|
||||
const char * TclTomMathInitializeStubs(Tcl_Interp *interp,
|
||||
const char *version, int epoch, int revision);
|
||||
#if defined(_WIN32)
|
||||
TCL_NORETURN void Tcl_ConsolePanic(const char *format, ...);
|
||||
#else
|
||||
# define Tcl_ConsolePanic ((Tcl_PanicProc *)0)
|
||||
#endif
|
||||
|
||||
#ifdef USE_TCL_STUBS
|
||||
#if TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE
|
||||
@@ -2392,7 +2396,7 @@ const char * TclTomMathInitializeStubs(Tcl_Interp *interp,
|
||||
*/
|
||||
|
||||
#define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \
|
||||
((Tcl_CreateInterp)()))
|
||||
((Tcl_SetPanicProc(Tcl_ConsolePanic), Tcl_CreateInterp)()))
|
||||
EXTERN void Tcl_MainEx(int argc, char **argv,
|
||||
Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);
|
||||
EXTERN const char * Tcl_PkgInitStubsCheck(Tcl_Interp *interp,
|
||||
@@ -2550,27 +2554,6 @@ EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr);
|
||||
#define Tcl_CreateHashEntry(tablePtr, key, newPtr) \
|
||||
(*((tablePtr)->createProc))(tablePtr, (const char *)(key), newPtr)
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------------
|
||||
* Macros that eliminate the overhead of the thread synchronization functions
|
||||
* when compiling without thread support.
|
||||
*/
|
||||
|
||||
#ifndef TCL_THREADS
|
||||
#undef Tcl_MutexLock
|
||||
#define Tcl_MutexLock(mutexPtr)
|
||||
#undef Tcl_MutexUnlock
|
||||
#define Tcl_MutexUnlock(mutexPtr)
|
||||
#undef Tcl_MutexFinalize
|
||||
#define Tcl_MutexFinalize(mutexPtr)
|
||||
#undef Tcl_ConditionNotify
|
||||
#define Tcl_ConditionNotify(condPtr)
|
||||
#undef Tcl_ConditionWait
|
||||
#define Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
|
||||
#undef Tcl_ConditionFinalize
|
||||
#define Tcl_ConditionFinalize(condPtr)
|
||||
#endif /* TCL_THREADS */
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------------
|
||||
* Deprecated Tcl functions:
|
||||
|
||||
+3
-3
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "tclInt.h"
|
||||
#if !defined(TCL_THREADS) || !defined(USE_THREAD_ALLOC)
|
||||
#if !TCL_THREADS || !defined(USE_THREAD_ALLOC)
|
||||
|
||||
#if USE_TCLALLOC
|
||||
|
||||
@@ -121,7 +121,7 @@ static struct block bigBlocks={ /* Big blocks aren't suballocated. */
|
||||
* variable.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
static Tcl_Mutex *allocMutexPtr;
|
||||
#endif
|
||||
static int allocInit = 0;
|
||||
@@ -171,7 +171,7 @@ TclInitAlloc(void)
|
||||
{
|
||||
if (!allocInit) {
|
||||
allocInit = 1;
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
allocMutexPtr = Tcl_GetAllocMutex();
|
||||
#endif
|
||||
}
|
||||
|
||||
+37
-29
@@ -749,7 +749,7 @@ Tcl_CreateInterp(void)
|
||||
* cache was already initialised by the call to alloc the interp struct.
|
||||
*/
|
||||
|
||||
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
|
||||
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
|
||||
iPtr->allocCache = TclpGetAllocCache();
|
||||
#else
|
||||
iPtr->allocCache = NULL;
|
||||
@@ -964,7 +964,7 @@ Tcl_CreateInterp(void)
|
||||
#endif /* !TCL_NO_DEPRECATED */
|
||||
TclpSetVariables(interp);
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* The existence of the "threaded" element of the tcl_platform array
|
||||
* indicates that this particular Tcl shell has been compiled with threads
|
||||
@@ -2295,30 +2295,33 @@ Tcl_CreateObjCommand(
|
||||
}
|
||||
|
||||
Tcl_Command
|
||||
TclCreateObjCommandInNs (
|
||||
TclCreateObjCommandInNs(
|
||||
Tcl_Interp *interp,
|
||||
const char *cmdName, /* Name of command, without any namespace components */
|
||||
const char *cmdName, /* Name of command, without any namespace
|
||||
* components. */
|
||||
Tcl_Namespace *namespace, /* The namespace to create the command in */
|
||||
Tcl_ObjCmdProc *proc, /* Object-based function to associate with
|
||||
* name. */
|
||||
ClientData clientData, /* Arbitrary value to pass to object
|
||||
* function. */
|
||||
Tcl_CmdDeleteProc *deleteProc
|
||||
Tcl_CmdDeleteProc *deleteProc)
|
||||
/* If not NULL, gives a function to call when
|
||||
* this command is deleted. */
|
||||
) {
|
||||
{
|
||||
int deleted = 0, isNew = 0;
|
||||
Command *cmdPtr;
|
||||
ImportRef *oldRefPtr = NULL;
|
||||
ImportedCmdData *dataPtr;
|
||||
Tcl_HashEntry *hPtr;
|
||||
Namespace *nsPtr = (Namespace *) namespace;
|
||||
|
||||
/*
|
||||
* If the command name we seek to create already exists, we need to
|
||||
* delete that first. That can be tricky in the presence of traces.
|
||||
* Loop until we no longer find an existing command in the way, or
|
||||
* until we've deleted one command and that didn't finish the job.
|
||||
* If the command name we seek to create already exists, we need to delete
|
||||
* that first. That can be tricky in the presence of traces. Loop until we
|
||||
* no longer find an existing command in the way, or until we've deleted
|
||||
* one command and that didn't finish the job.
|
||||
*/
|
||||
|
||||
while (1) {
|
||||
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, cmdName, &isNew);
|
||||
|
||||
@@ -2330,16 +2333,18 @@ TclCreateObjCommandInNs (
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* An existing command conflicts. Try to delete it.
|
||||
*/
|
||||
|
||||
/* An existing command conflicts. Try to delete it.. */
|
||||
cmdPtr = Tcl_GetHashValue(hPtr);
|
||||
|
||||
/*
|
||||
* [***] This is wrong. See Tcl Bug a16752c252.
|
||||
* However, this buggy behavior is kept under particular
|
||||
* circumstances to accommodate deployed binaries of the
|
||||
* "tclcompiler" program. http://sourceforge.net/projects/tclpro/
|
||||
* that crash if the bug is fixed.
|
||||
* [***] This is wrong. See Tcl Bug a16752c252. However, this buggy
|
||||
* behavior is kept under particular circumstances to accommodate
|
||||
* deployed binaries of the "tclcompiler" program
|
||||
* http://sourceforge.net/projects/tclpro/
|
||||
* that crash if the bug is fixed.
|
||||
*/
|
||||
|
||||
if (cmdPtr->objProc == TclInvokeStringCommand
|
||||
@@ -2363,12 +2368,15 @@ TclCreateObjCommandInNs (
|
||||
cmdPtr->flags |= CMD_REDEF_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* Make sure namespace doesn't get deallocated. */
|
||||
/*
|
||||
* Make sure namespace doesn't get deallocated.
|
||||
*/
|
||||
|
||||
cmdPtr->nsPtr->refCount++;
|
||||
|
||||
Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
|
||||
nsPtr = (Namespace *) TclEnsureNamespace(interp,
|
||||
(Tcl_Namespace *)cmdPtr->nsPtr);
|
||||
(Tcl_Namespace *) cmdPtr->nsPtr);
|
||||
TclNsDecrRefCount(cmdPtr->nsPtr);
|
||||
|
||||
if (cmdPtr->flags & CMD_REDEF_IN_PROGRESS) {
|
||||
@@ -2380,9 +2388,9 @@ TclCreateObjCommandInNs (
|
||||
}
|
||||
if (!isNew) {
|
||||
/*
|
||||
* If the deletion callback recreated the command, just throw away
|
||||
* the new command (if we try to delete it again, we could get
|
||||
* stuck in an infinite loop).
|
||||
* If the deletion callback recreated the command, just throw away the
|
||||
* new command (if we try to delete it again, we could get stuck in an
|
||||
* infinite loop).
|
||||
*/
|
||||
|
||||
ckfree(Tcl_GetHashValue(hPtr));
|
||||
@@ -2437,6 +2445,7 @@ TclCreateObjCommandInNs (
|
||||
cmdPtr->importRefPtr = oldRefPtr;
|
||||
while (oldRefPtr != NULL) {
|
||||
Command *refCmdPtr = oldRefPtr->importedCmdPtr;
|
||||
|
||||
dataPtr = refCmdPtr->objClientData;
|
||||
dataPtr->realCmdPtr = cmdPtr;
|
||||
oldRefPtr = oldRefPtr->nextPtr;
|
||||
@@ -8276,23 +8285,26 @@ Tcl_NRCreateCommand(
|
||||
* this command is deleted. */
|
||||
{
|
||||
Command *cmdPtr = (Command *)
|
||||
Tcl_CreateObjCommand(interp,cmdName,proc,clientData,deleteProc);
|
||||
Tcl_CreateObjCommand(interp, cmdName, proc, clientData,
|
||||
deleteProc);
|
||||
|
||||
cmdPtr->nreProc = nreProc;
|
||||
return (Tcl_Command) cmdPtr;
|
||||
}
|
||||
|
||||
Tcl_Command
|
||||
TclNRCreateCommandInNs (
|
||||
TclNRCreateCommandInNs(
|
||||
Tcl_Interp *interp,
|
||||
const char *cmdName,
|
||||
Tcl_Namespace *nsPtr,
|
||||
Tcl_ObjCmdProc *proc,
|
||||
Tcl_ObjCmdProc *nreProc,
|
||||
ClientData clientData,
|
||||
Tcl_CmdDeleteProc *deleteProc) {
|
||||
Tcl_CmdDeleteProc *deleteProc)
|
||||
{
|
||||
Command *cmdPtr = (Command *)
|
||||
TclCreateObjCommandInNs(interp,cmdName,nsPtr,proc,clientData,deleteProc);
|
||||
TclCreateObjCommandInNs(interp, cmdName, nsPtr, proc, clientData,
|
||||
deleteProc);
|
||||
|
||||
cmdPtr->nreProc = nreProc;
|
||||
return (Tcl_Command) cmdPtr;
|
||||
@@ -8396,7 +8408,6 @@ TclPushTailcallPoint(
|
||||
TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL);
|
||||
((Interp *) interp)->numLevels++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -8432,7 +8443,6 @@ TclSetTailcall(
|
||||
}
|
||||
runPtr->data[1] = listPtr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -8508,7 +8518,6 @@ TclNRTailcallObjCmd(
|
||||
}
|
||||
return TCL_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -8576,7 +8585,6 @@ TclNRReleaseValues(
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Tcl_NRAddCallback(
|
||||
|
||||
@@ -156,7 +156,7 @@ TclInitDbCkalloc(void)
|
||||
if (!ckallocInit) {
|
||||
ckallocInit = 1;
|
||||
ckallocMutexPtr = Tcl_GetAllocMutex();
|
||||
#ifndef TCL_THREADS
|
||||
#if !TCL_THREADS
|
||||
/* Silence compiler warning */
|
||||
(void)ckallocMutexPtr;
|
||||
#endif
|
||||
|
||||
+46
-178
@@ -597,9 +597,9 @@ Tcl_RegsubObjCmd(
|
||||
* slightly modified version of the one pair STR_MAP code.
|
||||
*/
|
||||
|
||||
int slen, nocase;
|
||||
int slen, nocase, wsrclc;
|
||||
int (*strCmpFn)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned long);
|
||||
Tcl_UniChar *p, wsrclc;
|
||||
Tcl_UniChar *p;
|
||||
|
||||
numMatches = 0;
|
||||
nocase = (cflags & TCL_REG_NOCASE);
|
||||
@@ -2001,8 +2001,8 @@ StringMapCmd(
|
||||
* larger strings.
|
||||
*/
|
||||
|
||||
int mapLen;
|
||||
Tcl_UniChar *mapString, u2lc;
|
||||
int mapLen, u2lc;
|
||||
Tcl_UniChar *mapString;
|
||||
|
||||
ustring2 = Tcl_GetUnicodeFromObj(mapElemv[0], &length2);
|
||||
p = ustring1;
|
||||
@@ -2033,8 +2033,8 @@ StringMapCmd(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Tcl_UniChar **mapStrings, *u2lc = NULL;
|
||||
int *mapLens;
|
||||
Tcl_UniChar **mapStrings;
|
||||
int *mapLens, *u2lc = NULL;
|
||||
|
||||
/*
|
||||
* Precompute pointers to the unicode string and length. This saves us
|
||||
@@ -2046,7 +2046,7 @@ StringMapCmd(
|
||||
mapStrings = TclStackAlloc(interp, mapElemc*2*sizeof(Tcl_UniChar *));
|
||||
mapLens = TclStackAlloc(interp, mapElemc * 2 * sizeof(int));
|
||||
if (nocase) {
|
||||
u2lc = TclStackAlloc(interp, mapElemc * sizeof(Tcl_UniChar));
|
||||
u2lc = TclStackAlloc(interp, mapElemc * sizeof(int));
|
||||
}
|
||||
for (index = 0; index < mapElemc; index++) {
|
||||
mapStrings[index] = Tcl_GetUnicodeFromObj(mapElemv[index],
|
||||
@@ -2546,10 +2546,8 @@ StringEqualCmd(
|
||||
* the expr string comparison in INST_EQ/INST_NEQ/INST_LT/...).
|
||||
*/
|
||||
|
||||
const char *string1, *string2;
|
||||
int length1, length2, i, match, length, nocase = 0, reqlength = -1;
|
||||
typedef int (*strCmpFn_t)(const char *, const char *, unsigned int);
|
||||
strCmpFn_t strCmpFn;
|
||||
const char *string2;
|
||||
int length, i, match, nocase = 0, reqlength = -1;
|
||||
|
||||
if (objc < 3 || objc > 6) {
|
||||
str_cmp_args:
|
||||
@@ -2559,11 +2557,11 @@ StringEqualCmd(
|
||||
}
|
||||
|
||||
for (i = 1; i < objc-2; i++) {
|
||||
string2 = TclGetStringFromObj(objv[i], &length2);
|
||||
if ((length2 > 1) && !strncmp(string2, "-nocase", (size_t)length2)) {
|
||||
string2 = TclGetStringFromObj(objv[i], &length);
|
||||
if ((length > 1) && !strncmp(string2, "-nocase", (size_t)length)) {
|
||||
nocase = 1;
|
||||
} else if ((length2 > 1)
|
||||
&& !strncmp(string2, "-length", (size_t)length2)) {
|
||||
} else if ((length > 1)
|
||||
&& !strncmp(string2, "-length", (size_t)length)) {
|
||||
if (i+1 >= objc-2) {
|
||||
goto str_cmp_args;
|
||||
}
|
||||
@@ -2588,78 +2586,7 @@ StringEqualCmd(
|
||||
|
||||
objv += objc-2;
|
||||
|
||||
if ((reqlength == 0) || (objv[0] == objv[1])) {
|
||||
/*
|
||||
* Always match at 0 chars of if it is the same obj.
|
||||
*/
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
if (!nocase && TclIsPureByteArray(objv[0]) &&
|
||||
TclIsPureByteArray(objv[1])) {
|
||||
/*
|
||||
* Use binary versions of comparisons since that won't cause undue
|
||||
* type conversions and it is much faster. Only do this if we're
|
||||
* case-sensitive (which is all that really makes sense with byte
|
||||
* arrays anyway, and we have no memcasecmp() for some reason... :^)
|
||||
*/
|
||||
|
||||
string1 = (char *) Tcl_GetByteArrayFromObj(objv[0], &length1);
|
||||
string2 = (char *) Tcl_GetByteArrayFromObj(objv[1], &length2);
|
||||
strCmpFn = (strCmpFn_t) memcmp;
|
||||
} else if ((objv[0]->typePtr == &tclStringType)
|
||||
&& (objv[1]->typePtr == &tclStringType)) {
|
||||
/*
|
||||
* Do a unicode-specific comparison if both of the args are of String
|
||||
* type. In benchmark testing this proved the most efficient check
|
||||
* between the unicode and string comparison operations.
|
||||
*/
|
||||
|
||||
string1 = (char *) Tcl_GetUnicodeFromObj(objv[0], &length1);
|
||||
string2 = (char *) Tcl_GetUnicodeFromObj(objv[1], &length2);
|
||||
strCmpFn = (strCmpFn_t)
|
||||
(nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp);
|
||||
} else {
|
||||
/*
|
||||
* As a catch-all we will work with UTF-8. We cannot use memcmp() as
|
||||
* that is unsafe with any string containing NUL (\xC0\x80 in Tcl's
|
||||
* utf rep). We can use the more efficient TclpUtfNcmp2 if we are
|
||||
* case-sensitive and no specific length was requested.
|
||||
*/
|
||||
|
||||
string1 = (char *) TclGetStringFromObj(objv[0], &length1);
|
||||
string2 = (char *) TclGetStringFromObj(objv[1], &length2);
|
||||
if ((reqlength < 0) && !nocase) {
|
||||
strCmpFn = (strCmpFn_t) TclpUtfNcmp2;
|
||||
} else {
|
||||
length1 = Tcl_NumUtfChars(string1, length1);
|
||||
length2 = Tcl_NumUtfChars(string2, length2);
|
||||
strCmpFn = (strCmpFn_t) (nocase ? Tcl_UtfNcasecmp : Tcl_UtfNcmp);
|
||||
}
|
||||
}
|
||||
|
||||
if ((reqlength < 0) && (length1 != length2)) {
|
||||
match = 1; /* This will be reversed below. */
|
||||
} else {
|
||||
length = (length1 < length2) ? length1 : length2;
|
||||
if (reqlength > 0 && reqlength < length) {
|
||||
length = reqlength;
|
||||
} else if (reqlength < 0) {
|
||||
/*
|
||||
* The requested length is negative, so we ignore it by setting it
|
||||
* to length + 1 so we correct the match var.
|
||||
*/
|
||||
|
||||
reqlength = length + 1;
|
||||
}
|
||||
|
||||
match = strCmpFn(string1, string2, (unsigned) length);
|
||||
if ((match == 0) && (reqlength > length)) {
|
||||
match = length1 - length2;
|
||||
}
|
||||
}
|
||||
match = TclStringCmp(objv[0], objv[1], 0, nocase, reqlength);
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(match ? 0 : 1));
|
||||
return TCL_OK;
|
||||
@@ -2696,11 +2623,31 @@ StringCmpCmd(
|
||||
* the expr string comparison in INST_EQ/INST_NEQ/INST_LT/...).
|
||||
*/
|
||||
|
||||
const char *string1, *string2;
|
||||
int length1, length2, i, match, length, nocase = 0, reqlength = -1;
|
||||
typedef int (*strCmpFn_t)(const char *, const char *, unsigned int);
|
||||
strCmpFn_t strCmpFn;
|
||||
int match, nocase, reqlength, status;
|
||||
|
||||
status = TclStringCmpOpts(interp, objc, objv, &nocase, &reqlength);
|
||||
if (status != TCL_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
objv += objc-2;
|
||||
match = TclStringCmp(objv[0], objv[1], 0, nocase, reqlength);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(match));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
int TclStringCmpOpts(
|
||||
Tcl_Interp *interp, /* Current interpreter. */
|
||||
int objc, /* Number of arguments. */
|
||||
Tcl_Obj *const objv[], /* Argument objects. */
|
||||
int *nocase,
|
||||
int *reqlength)
|
||||
{
|
||||
int i, length;
|
||||
const char *string;
|
||||
|
||||
*reqlength = -1;
|
||||
*nocase = 0;
|
||||
if (objc < 3 || objc > 6) {
|
||||
str_cmp_args:
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
@@ -2709,106 +2656,27 @@ StringCmpCmd(
|
||||
}
|
||||
|
||||
for (i = 1; i < objc-2; i++) {
|
||||
string2 = TclGetStringFromObj(objv[i], &length2);
|
||||
if ((length2 > 1) && !strncmp(string2, "-nocase", (size_t)length2)) {
|
||||
nocase = 1;
|
||||
} else if ((length2 > 1)
|
||||
&& !strncmp(string2, "-length", (size_t)length2)) {
|
||||
string = TclGetStringFromObj(objv[i], &length);
|
||||
if ((length > 1) && !strncmp(string, "-nocase", (size_t)length)) {
|
||||
*nocase = 1;
|
||||
} else if ((length > 1)
|
||||
&& !strncmp(string, "-length", (size_t)length)) {
|
||||
if (i+1 >= objc-2) {
|
||||
goto str_cmp_args;
|
||||
}
|
||||
i++;
|
||||
if (TclGetIntFromObj(interp, objv[i], &reqlength) != TCL_OK) {
|
||||
if (TclGetIntFromObj(interp, objv[i], reqlength) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
} else {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"bad option \"%s\": must be -nocase or -length",
|
||||
string2));
|
||||
string));
|
||||
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "option",
|
||||
string2, NULL);
|
||||
string, NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* From now on, we only access the two objects at the end of the argument
|
||||
* array.
|
||||
*/
|
||||
|
||||
objv += objc-2;
|
||||
|
||||
if ((reqlength == 0) || (objv[0] == objv[1])) {
|
||||
/*
|
||||
* Always match at 0 chars of if it is the same obj.
|
||||
*/
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
if (!nocase && TclIsPureByteArray(objv[0]) &&
|
||||
TclIsPureByteArray(objv[1])) {
|
||||
/*
|
||||
* Use binary versions of comparisons since that won't cause undue
|
||||
* type conversions and it is much faster. Only do this if we're
|
||||
* case-sensitive (which is all that really makes sense with byte
|
||||
* arrays anyway, and we have no memcasecmp() for some reason... :^)
|
||||
*/
|
||||
|
||||
string1 = (char *) Tcl_GetByteArrayFromObj(objv[0], &length1);
|
||||
string2 = (char *) Tcl_GetByteArrayFromObj(objv[1], &length2);
|
||||
strCmpFn = (strCmpFn_t) memcmp;
|
||||
} else if ((objv[0]->typePtr == &tclStringType)
|
||||
&& (objv[1]->typePtr == &tclStringType)) {
|
||||
/*
|
||||
* Do a unicode-specific comparison if both of the args are of String
|
||||
* type. In benchmark testing this proved the most efficient check
|
||||
* between the unicode and string comparison operations.
|
||||
*/
|
||||
|
||||
string1 = (char *) Tcl_GetUnicodeFromObj(objv[0], &length1);
|
||||
string2 = (char *) Tcl_GetUnicodeFromObj(objv[1], &length2);
|
||||
strCmpFn = (strCmpFn_t)
|
||||
(nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp);
|
||||
} else {
|
||||
/*
|
||||
* As a catch-all we will work with UTF-8. We cannot use memcmp() as
|
||||
* that is unsafe with any string containing NUL (\xC0\x80 in Tcl's
|
||||
* utf rep). We can use the more efficient TclpUtfNcmp2 if we are
|
||||
* case-sensitive and no specific length was requested.
|
||||
*/
|
||||
|
||||
string1 = (char *) TclGetStringFromObj(objv[0], &length1);
|
||||
string2 = (char *) TclGetStringFromObj(objv[1], &length2);
|
||||
if ((reqlength < 0) && !nocase) {
|
||||
strCmpFn = (strCmpFn_t) TclpUtfNcmp2;
|
||||
} else {
|
||||
length1 = Tcl_NumUtfChars(string1, length1);
|
||||
length2 = Tcl_NumUtfChars(string2, length2);
|
||||
strCmpFn = (strCmpFn_t) (nocase ? Tcl_UtfNcasecmp : Tcl_UtfNcmp);
|
||||
}
|
||||
}
|
||||
|
||||
length = (length1 < length2) ? length1 : length2;
|
||||
if (reqlength > 0 && reqlength < length) {
|
||||
length = reqlength;
|
||||
} else if (reqlength < 0) {
|
||||
/*
|
||||
* The requested length is negative, so we ignore it by setting it to
|
||||
* length + 1 so we correct the match var.
|
||||
*/
|
||||
|
||||
reqlength = length + 1;
|
||||
}
|
||||
|
||||
match = strCmpFn(string1, string2, (unsigned) length);
|
||||
if ((match == 0) && (reqlength > length)) {
|
||||
match = length1 - length2;
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp,
|
||||
Tcl_NewIntObj((match > 0) ? 1 : (match < 0) ? -1 : 0));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
+23
-21
@@ -27,7 +27,6 @@ static void CompileReturnInternal(CompileEnv *envPtr,
|
||||
Tcl_Obj *returnOpts);
|
||||
static int IndexTailVarIfKnown(Tcl_Interp *interp,
|
||||
Tcl_Token *varTokenPtr, CompileEnv *envPtr);
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -127,9 +126,12 @@ TclCompileGlobalCmd(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* TODO: Consider what value can pass through the
|
||||
* IndexTailVarIfKnown() screen. Full CompileWord()
|
||||
* likely does not apply here. Push known value instead. */
|
||||
/*
|
||||
* TODO: Consider what value can pass through the
|
||||
* IndexTailVarIfKnown() screen. Full CompileWord() likely does not
|
||||
* apply here. Push known value instead.
|
||||
*/
|
||||
|
||||
CompileWord(envPtr, varTokenPtr, interp, i);
|
||||
TclEmitInstInt4( INST_NSUPVAR, localIndex, envPtr);
|
||||
}
|
||||
@@ -270,7 +272,7 @@ TclCompileIfCmd(
|
||||
jumpIndex = jumpFalseFixupArray.next;
|
||||
jumpFalseFixupArray.next++;
|
||||
TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
|
||||
jumpFalseFixupArray.fixup+jumpIndex);
|
||||
jumpFalseFixupArray.fixup + jumpIndex);
|
||||
}
|
||||
code = TCL_OK;
|
||||
}
|
||||
@@ -317,7 +319,7 @@ TclCompileIfCmd(
|
||||
}
|
||||
jumpEndFixupArray.next++;
|
||||
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
|
||||
jumpEndFixupArray.fixup+jumpIndex);
|
||||
jumpEndFixupArray.fixup + jumpIndex);
|
||||
|
||||
/*
|
||||
* Fix the target of the jumpFalse after the test. Generate a 4
|
||||
@@ -329,7 +331,7 @@ TclCompileIfCmd(
|
||||
|
||||
TclAdjustStackDepth(-1, envPtr);
|
||||
if (TclFixupForwardJumpToHere(envPtr,
|
||||
jumpFalseFixupArray.fixup+jumpIndex, 120)) {
|
||||
jumpFalseFixupArray.fixup + jumpIndex, 120)) {
|
||||
/*
|
||||
* Adjust the code offset for the proceeding jump to the end
|
||||
* of the "if" command.
|
||||
@@ -412,7 +414,7 @@ TclCompileIfCmd(
|
||||
for (j = jumpEndFixupArray.next; j > 0; j--) {
|
||||
jumpIndex = (j - 1); /* i.e. process the closest jump first. */
|
||||
if (TclFixupForwardJumpToHere(envPtr,
|
||||
jumpEndFixupArray.fixup+jumpIndex, 127)) {
|
||||
jumpEndFixupArray.fixup + jumpIndex, 127)) {
|
||||
/*
|
||||
* Adjust the immediately preceeding "ifFalse" jump. We moved it's
|
||||
* target (just after this jump) down three bytes.
|
||||
@@ -920,7 +922,7 @@ TclCompileLappendCmd(
|
||||
CompileWord(envPtr, valueTokenPtr, interp, i);
|
||||
valueTokenPtr = TokenAfter(valueTokenPtr);
|
||||
}
|
||||
TclEmitInstInt4( INST_LIST, numWords-2, envPtr);
|
||||
TclEmitInstInt4( INST_LIST, numWords - 2, envPtr);
|
||||
if (isScalar) {
|
||||
if (localIndex < 0) {
|
||||
TclEmitOpcode( INST_LAPPEND_LIST_STK, envPtr);
|
||||
@@ -997,7 +999,7 @@ TclCompileLassignCmd(
|
||||
*/
|
||||
|
||||
PushVarNameWord(interp, tokenPtr, envPtr, 0, &localIndex,
|
||||
&isScalar, idx+2);
|
||||
&isScalar, idx + 2);
|
||||
|
||||
/*
|
||||
* Emit instructions to get the idx'th item out of the list value on
|
||||
@@ -1414,7 +1416,7 @@ TclCompileLinsertCmd(
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
CompileWord(envPtr, tokenPtr, interp, i);
|
||||
}
|
||||
TclEmitInstInt4( INST_LIST, i-3, envPtr);
|
||||
TclEmitInstInt4( INST_LIST, i - 3, envPtr);
|
||||
|
||||
if (idx == TCL_INDEX_START) {
|
||||
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
|
||||
@@ -1439,7 +1441,7 @@ TclCompileLinsertCmd(
|
||||
}
|
||||
TclEmitInstInt4( INST_OVER, 1, envPtr);
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
|
||||
TclEmitInt4( idx-1, envPtr);
|
||||
TclEmitInt4( idx - 1, envPtr);
|
||||
TclEmitInstInt4( INST_REVERSE, 3, envPtr);
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
|
||||
TclEmitInt4( TCL_INDEX_END, envPtr);
|
||||
@@ -2234,7 +2236,7 @@ TclCompileRegexpCmd(
|
||||
}
|
||||
|
||||
if (!simple) {
|
||||
CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords-2);
|
||||
CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords - 2);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2242,7 +2244,7 @@ TclCompileRegexpCmd(
|
||||
*/
|
||||
|
||||
varTokenPtr = TokenAfter(varTokenPtr);
|
||||
CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords-1);
|
||||
CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords - 1);
|
||||
|
||||
if (simple) {
|
||||
if (exact && !nocase) {
|
||||
@@ -2426,7 +2428,7 @@ TclCompileRegsubCmd(
|
||||
PushLiteral(envPtr, bytes, len);
|
||||
bytes = TclGetStringFromObj(replacementObj, &len);
|
||||
PushLiteral(envPtr, bytes, len);
|
||||
CompileWord(envPtr, stringTokenPtr, interp, parsePtr->numWords-2);
|
||||
CompileWord(envPtr, stringTokenPtr, interp, parsePtr->numWords - 2);
|
||||
TclEmitOpcode( INST_STR_MAP, envPtr);
|
||||
|
||||
done:
|
||||
@@ -2555,7 +2557,7 @@ TclCompileReturnCmd(
|
||||
*/
|
||||
|
||||
if (explicitResult) {
|
||||
CompileWord(envPtr, wordTokenPtr, interp, numWords-1);
|
||||
CompileWord(envPtr, wordTokenPtr, interp, numWords - 1);
|
||||
} else {
|
||||
/*
|
||||
* No explict result argument, so default result is empty string.
|
||||
@@ -2633,7 +2635,7 @@ TclCompileReturnCmd(
|
||||
*/
|
||||
|
||||
if (explicitResult) {
|
||||
CompileWord(envPtr, wordTokenPtr, interp, numWords-1);
|
||||
CompileWord(envPtr, wordTokenPtr, interp, numWords - 1);
|
||||
} else {
|
||||
PushStringLiteral(envPtr, "");
|
||||
}
|
||||
@@ -2864,12 +2866,12 @@ TclCompileVariableCmd(
|
||||
CompileWord(envPtr, varTokenPtr, interp, i);
|
||||
TclEmitInstInt4( INST_VARIABLE, localIndex, envPtr);
|
||||
|
||||
if (i+1 < numWords) {
|
||||
if (i + 1 < numWords) {
|
||||
/*
|
||||
* A value has been given: set the variable, pop the value
|
||||
*/
|
||||
|
||||
CompileWord(envPtr, valueTokenPtr, interp, i+1);
|
||||
CompileWord(envPtr, valueTokenPtr, interp, i + 1);
|
||||
Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
|
||||
TclEmitOpcode( INST_POP, envPtr);
|
||||
}
|
||||
@@ -2945,7 +2947,7 @@ IndexTailVarIfKnown(
|
||||
tailName = TclGetStringFromObj(tailPtr, &len);
|
||||
|
||||
if (len) {
|
||||
if (*(tailName+len-1) == ')') {
|
||||
if (*(tailName + len - 1) == ')') {
|
||||
/*
|
||||
* Possible array: bail out
|
||||
*/
|
||||
@@ -2959,7 +2961,7 @@ IndexTailVarIfKnown(
|
||||
*/
|
||||
|
||||
for (p = tailName + len -1; p > tailName; p--) {
|
||||
if ((*p == ':') && (*(p-1) == ':')) {
|
||||
if ((*p == ':') && (*(p - 1) == ':')) {
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
|
||||
+57
-51
@@ -87,8 +87,8 @@ static const Tcl_ObjType ensembleCmdType = {
|
||||
};
|
||||
|
||||
/*
|
||||
* The internal rep for caching ensemble subcommand lookups and
|
||||
* spell corrections.
|
||||
* The internal rep for caching ensemble subcommand lookups and spelling
|
||||
* corrections.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
@@ -98,10 +98,9 @@ typedef struct {
|
||||
Command *token; /* Reference to the command for which this
|
||||
* structure is a cache of the resolution. */
|
||||
Tcl_Obj *fix; /* Corrected spelling, if needed. */
|
||||
Tcl_HashEntry *hPtr; /* Direct link to entry in the subcommand
|
||||
* hash table. */
|
||||
Tcl_HashEntry *hPtr; /* Direct link to entry in the subcommand hash
|
||||
* table. */
|
||||
} EnsembleCmdRep;
|
||||
|
||||
|
||||
static inline Tcl_Obj *
|
||||
NewNsObj(
|
||||
@@ -111,9 +110,8 @@ NewNsObj(
|
||||
|
||||
if (namespacePtr == TclGetGlobalNamespace(nsPtr->interp)) {
|
||||
return Tcl_NewStringObj("::", 2);
|
||||
} else {
|
||||
return Tcl_NewStringObj(nsPtr->fullName, -1);
|
||||
}
|
||||
return Tcl_NewStringObj(nsPtr->fullName, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -147,7 +145,7 @@ TclNamespaceEnsembleCmd(
|
||||
{
|
||||
Tcl_Namespace *namespacePtr;
|
||||
Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp), *cxtPtr,
|
||||
*foundNsPtr, *altFoundNsPtr, *actualCxtPtr;
|
||||
*foundNsPtr, *altFoundNsPtr, *actualCxtPtr;
|
||||
Tcl_Command token;
|
||||
Tcl_DictSearch search;
|
||||
Tcl_Obj *listObj;
|
||||
@@ -302,7 +300,8 @@ TclNamespaceEnsembleCmd(
|
||||
Tcl_DictObjPut(NULL, patchedDict, subcmdWordsObj,
|
||||
newList);
|
||||
}
|
||||
Tcl_DictObjNext(&search, &subcmdWordsObj,&listObj, &done);
|
||||
Tcl_DictObjNext(&search, &subcmdWordsObj, &listObj,
|
||||
&done);
|
||||
} while (!done);
|
||||
|
||||
if (allocatedMapFlag) {
|
||||
@@ -336,8 +335,8 @@ TclNamespaceEnsembleCmd(
|
||||
}
|
||||
|
||||
TclGetNamespaceForQualName(interp, name, cxtPtr,
|
||||
TCL_CREATE_NS_IF_UNKNOWN, &foundNsPtr, &altFoundNsPtr, &actualCxtPtr,
|
||||
&simpleName);
|
||||
TCL_CREATE_NS_IF_UNKNOWN, &foundNsPtr, &altFoundNsPtr,
|
||||
&actualCxtPtr, &simpleName);
|
||||
|
||||
/*
|
||||
* Create the ensemble. Note that this might delete another ensemble
|
||||
@@ -347,8 +346,8 @@ TclNamespaceEnsembleCmd(
|
||||
*/
|
||||
|
||||
token = TclCreateEnsembleInNs(interp, simpleName,
|
||||
(Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr,
|
||||
(permitPrefix ? TCL_ENSEMBLE_PREFIX : 0));
|
||||
(Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr,
|
||||
(permitPrefix ? TCL_ENSEMBLE_PREFIX : 0));
|
||||
Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj);
|
||||
Tcl_SetEnsembleMappingDict(interp, token, mapObj);
|
||||
Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj);
|
||||
@@ -576,7 +575,8 @@ TclNamespaceEnsembleCmd(
|
||||
Tcl_AppendStringsToObj(newCmd, "::", NULL);
|
||||
}
|
||||
Tcl_AppendObjToObj(newCmd, listv[0]);
|
||||
Tcl_ListObjReplace(NULL, newList, 0,1, 1,&newCmd);
|
||||
Tcl_ListObjReplace(NULL, newList, 0, 1, 1,
|
||||
&newCmd);
|
||||
if (patchedDict == NULL) {
|
||||
patchedDict = Tcl_DuplicateObj(objv[1]);
|
||||
}
|
||||
@@ -650,15 +650,13 @@ TclNamespaceEnsembleCmd(
|
||||
Tcl_Command
|
||||
TclCreateEnsembleInNs(
|
||||
Tcl_Interp *interp,
|
||||
|
||||
const char *name, /* Simple name of command to create (no */
|
||||
/* namespace components). */
|
||||
Tcl_Namespace /* Name of namespace to create the command in. */
|
||||
*nameNsPtr,
|
||||
Tcl_Namespace
|
||||
*ensembleNsPtr, /* Name of the namespace for the ensemble. */
|
||||
int flags
|
||||
)
|
||||
const char *name, /* Simple name of command to create (no
|
||||
* namespace components). */
|
||||
Tcl_Namespace *nameNsPtr, /* Name of namespace to create the command
|
||||
* in. */
|
||||
Tcl_Namespace *ensembleNsPtr,
|
||||
/* Name of the namespace for the ensemble. */
|
||||
int flags)
|
||||
{
|
||||
Namespace *nsPtr = (Namespace *) ensembleNsPtr;
|
||||
EnsembleConfig *ensemblePtr;
|
||||
@@ -666,8 +664,8 @@ TclCreateEnsembleInNs(
|
||||
|
||||
ensemblePtr = ckalloc(sizeof(EnsembleConfig));
|
||||
token = TclNRCreateCommandInNs(interp, name,
|
||||
(Tcl_Namespace *) nameNsPtr, NsEnsembleImplementationCmd,
|
||||
NsEnsembleImplementationCmdNR, ensemblePtr, DeleteEnsembleConfig);
|
||||
(Tcl_Namespace *) nameNsPtr, NsEnsembleImplementationCmd,
|
||||
NsEnsembleImplementationCmdNR, ensemblePtr, DeleteEnsembleConfig);
|
||||
if (token == NULL) {
|
||||
ckfree(ensemblePtr);
|
||||
return NULL;
|
||||
@@ -701,18 +699,15 @@ TclCreateEnsembleInNs(
|
||||
}
|
||||
|
||||
return ensemblePtr->token;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_CreateEnsemble
|
||||
*
|
||||
* Create a simple ensemble attached to the given namespace.
|
||||
*
|
||||
* Deprecated by TclCreateEnsembleInNs.
|
||||
* Create a simple ensemble attached to the given namespace. Deprecated
|
||||
* (internally) by TclCreateEnsembleInNs.
|
||||
*
|
||||
* Value
|
||||
*
|
||||
@@ -732,8 +727,8 @@ Tcl_CreateEnsemble(
|
||||
Tcl_Namespace *namespacePtr,
|
||||
int flags)
|
||||
{
|
||||
Namespace *nsPtr = (Namespace *)namespacePtr, *foundNsPtr, *altNsPtr,
|
||||
*actualNsPtr;
|
||||
Namespace *nsPtr = (Namespace *) namespacePtr, *foundNsPtr, *altNsPtr,
|
||||
*actualNsPtr;
|
||||
const char * simpleName;
|
||||
|
||||
if (nsPtr == NULL) {
|
||||
@@ -741,11 +736,10 @@ Tcl_CreateEnsemble(
|
||||
}
|
||||
|
||||
TclGetNamespaceForQualName(interp, name, nsPtr, TCL_CREATE_NS_IF_UNKNOWN,
|
||||
&foundNsPtr, &altNsPtr, &actualNsPtr, &simpleName);
|
||||
&foundNsPtr, &altNsPtr, &actualNsPtr, &simpleName);
|
||||
return TclCreateEnsembleInNs(interp, simpleName,
|
||||
(Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr, flags);
|
||||
(Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr, flags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -2117,22 +2111,27 @@ TclSpellFix(
|
||||
iPtr->ensembleRewrite.numInsertedObjs = 0;
|
||||
}
|
||||
|
||||
/* Compute the valid length of the ensemble root */
|
||||
/*
|
||||
* Compute the valid length of the ensemble root.
|
||||
*/
|
||||
|
||||
size = iPtr->ensembleRewrite.numRemovedObjs + objc
|
||||
- iPtr->ensembleRewrite.numInsertedObjs;
|
||||
- iPtr->ensembleRewrite.numInsertedObjs;
|
||||
|
||||
search = iPtr->ensembleRewrite.sourceObjs;
|
||||
if (search[0] == NULL) {
|
||||
/* Awful casting abuse here */
|
||||
/*
|
||||
* Awful casting abuse here...
|
||||
*/
|
||||
search = (Tcl_Obj *const *) search[1];
|
||||
}
|
||||
|
||||
if (badIdx < iPtr->ensembleRewrite.numInsertedObjs) {
|
||||
/*
|
||||
* Misspelled value was inserted. We cannot directly jump
|
||||
* to the bad value, but have to search.
|
||||
* Misspelled value was inserted. We cannot directly jump to the bad
|
||||
* value, but have to search.
|
||||
*/
|
||||
|
||||
idx = 1;
|
||||
while (idx < size) {
|
||||
if (search[idx] == bad) {
|
||||
@@ -2156,13 +2155,14 @@ TclSpellFix(
|
||||
|
||||
search = iPtr->ensembleRewrite.sourceObjs;
|
||||
if (search[0] == NULL) {
|
||||
store = (Tcl_Obj **)search[2];
|
||||
} else {
|
||||
store = (Tcl_Obj **) search[2];
|
||||
} else {
|
||||
Tcl_Obj **tmp = ckalloc(3 * sizeof(Tcl_Obj *));
|
||||
|
||||
tmp[0] = NULL;
|
||||
tmp[1] = (Tcl_Obj *)iPtr->ensembleRewrite.sourceObjs;
|
||||
tmp[2] = (Tcl_Obj *)ckalloc(size * sizeof(Tcl_Obj *));
|
||||
memcpy(tmp[2], tmp[1], size*sizeof(Tcl_Obj *));
|
||||
tmp[1] = (Tcl_Obj *) iPtr->ensembleRewrite.sourceObjs;
|
||||
tmp[2] = (Tcl_Obj *) ckalloc(size * sizeof(Tcl_Obj *));
|
||||
memcpy(tmp[2], tmp[1], size * sizeof(Tcl_Obj *));
|
||||
|
||||
iPtr->ensembleRewrite.sourceObjs = (Tcl_Obj *const *) tmp;
|
||||
TclNRAddCallback(interp, FreeER, tmp, NULL, NULL, NULL);
|
||||
@@ -2589,7 +2589,9 @@ BuildEnsembleConfig(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Usual case where we can freely act on the list and dict. */
|
||||
/*
|
||||
* Usual case where we can freely act on the list and dict.
|
||||
*/
|
||||
|
||||
for (i = 0; i < subc; i++) {
|
||||
name = TclGetString(subv[i]);
|
||||
@@ -2598,7 +2600,10 @@ BuildEnsembleConfig(
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Lookup target in the dictionary */
|
||||
/*
|
||||
* Lookup target in the dictionary.
|
||||
*/
|
||||
|
||||
if (mapDict) {
|
||||
Tcl_DictObjGet(NULL, mapDict, subv[i], &target);
|
||||
if (target) {
|
||||
@@ -2610,10 +2615,11 @@ BuildEnsembleConfig(
|
||||
|
||||
/*
|
||||
* target was not in the dictionary so map onto the namespace.
|
||||
* Note in this case that we do not guarantee that the
|
||||
* command is actually there; that is the programmer's
|
||||
* responsibility (or [::unknown] of course).
|
||||
* Note in this case that we do not guarantee that the command
|
||||
* is actually there; that is the programmer's responsibility
|
||||
* (or [::unknown] of course).
|
||||
*/
|
||||
|
||||
cmdObj = Tcl_NewStringObj(name, -1);
|
||||
cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
|
||||
Tcl_SetHashValue(hPtr, cmdPrefixObj);
|
||||
|
||||
+5
-5
@@ -100,7 +100,7 @@ typedef struct ThreadSpecificData {
|
||||
} ThreadSpecificData;
|
||||
static Tcl_ThreadDataKey dataKey;
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
typedef struct {
|
||||
Tcl_ThreadCreateProc *proc; /* Main() function of the thread */
|
||||
ClientData clientData; /* The one argument to Main() */
|
||||
@@ -1043,7 +1043,7 @@ TclInitSubsystems(void)
|
||||
#if USE_TCLALLOC
|
||||
TclInitAlloc(); /* Process wide mutex init */
|
||||
#endif
|
||||
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
|
||||
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
|
||||
TclInitThreadAlloc(); /* Setup thread allocator caches */
|
||||
#endif
|
||||
#ifdef TCL_MEM_DEBUG
|
||||
@@ -1220,7 +1220,7 @@ Tcl_Finalize(void)
|
||||
* Close down the thread-specific object allocator.
|
||||
*/
|
||||
|
||||
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
|
||||
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
|
||||
TclFinalizeThreadAlloc();
|
||||
#endif
|
||||
|
||||
@@ -1538,7 +1538,7 @@ Tcl_UpdateObjCmd(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -1601,7 +1601,7 @@ Tcl_CreateThread(
|
||||
int flags) /* Flags controlling behaviour of the new
|
||||
* thread. */
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
ThreadClientData *cdPtr = ckalloc(sizeof(ThreadClientData));
|
||||
int result;
|
||||
|
||||
|
||||
+10
-80
@@ -5088,88 +5088,10 @@ TEBCresume(
|
||||
value2Ptr = OBJ_AT_TOS;
|
||||
valuePtr = OBJ_UNDER_TOS;
|
||||
|
||||
if (valuePtr == value2Ptr) {
|
||||
match = 0;
|
||||
} else {
|
||||
/*
|
||||
* We only need to check (in)equality when we have equal length
|
||||
* strings. We can use memcmp in all (n)eq cases because we
|
||||
* don't need to worry about lexical LE/BE variance.
|
||||
*/
|
||||
|
||||
typedef int (*memCmpFn_t)(const void*, const void*, size_t);
|
||||
memCmpFn_t memCmpFn;
|
||||
{
|
||||
int checkEq = ((*pc == INST_EQ) || (*pc == INST_NEQ)
|
||||
|| (*pc == INST_STR_EQ) || (*pc == INST_STR_NEQ));
|
||||
|
||||
if (TclIsPureByteArray(valuePtr)
|
||||
&& TclIsPureByteArray(value2Ptr)) {
|
||||
s1 = (char *) Tcl_GetByteArrayFromObj(valuePtr, &s1len);
|
||||
s2 = (char *) Tcl_GetByteArrayFromObj(value2Ptr, &s2len);
|
||||
memCmpFn = memcmp;
|
||||
} else if ((valuePtr->typePtr == &tclStringType)
|
||||
&& (value2Ptr->typePtr == &tclStringType)) {
|
||||
/*
|
||||
* Do a unicode-specific comparison if both of the args are of
|
||||
* String type. If the char length == byte length, we can do a
|
||||
* memcmp. In benchmark testing this proved the most efficient
|
||||
* check between the unicode and string comparison operations.
|
||||
*/
|
||||
|
||||
s1len = Tcl_GetCharLength(valuePtr);
|
||||
s2len = Tcl_GetCharLength(value2Ptr);
|
||||
if ((s1len == valuePtr->length)
|
||||
&& (valuePtr->bytes != NULL)
|
||||
&& (s2len == value2Ptr->length)
|
||||
&& (value2Ptr->bytes != NULL)) {
|
||||
s1 = valuePtr->bytes;
|
||||
s2 = value2Ptr->bytes;
|
||||
memCmpFn = memcmp;
|
||||
} else {
|
||||
s1 = (char *) Tcl_GetUnicode(valuePtr);
|
||||
s2 = (char *) Tcl_GetUnicode(value2Ptr);
|
||||
if (
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
1
|
||||
#else
|
||||
checkEq
|
||||
#endif
|
||||
) {
|
||||
memCmpFn = memcmp;
|
||||
s1len *= sizeof(Tcl_UniChar);
|
||||
s2len *= sizeof(Tcl_UniChar);
|
||||
} else {
|
||||
memCmpFn = (memCmpFn_t) Tcl_UniCharNcmp;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* strcmp can't do a simple memcmp in order to handle the
|
||||
* special Tcl \xC0\x80 null encoding for utf-8.
|
||||
*/
|
||||
|
||||
s1 = TclGetStringFromObj(valuePtr, &s1len);
|
||||
s2 = TclGetStringFromObj(value2Ptr, &s2len);
|
||||
if (checkEq) {
|
||||
memCmpFn = memcmp;
|
||||
} else {
|
||||
memCmpFn = (memCmpFn_t) TclpUtfNcmp2;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkEq && (s1len != s2len)) {
|
||||
match = 1;
|
||||
} else {
|
||||
/*
|
||||
* The comparison function should compare up to the minimum
|
||||
* byte length only.
|
||||
*/
|
||||
match = memCmpFn(s1, s2,
|
||||
(size_t) ((s1len < s2len) ? s1len : s2len));
|
||||
if (match == 0) {
|
||||
match = s1len - s2len;
|
||||
}
|
||||
}
|
||||
match = TclStringCmp(valuePtr, value2Ptr, checkEq, 0, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5739,6 +5661,14 @@ TEBCresume(
|
||||
value2Ptr = OBJ_AT_TOS;
|
||||
valuePtr = OBJ_UNDER_TOS;
|
||||
|
||||
/*
|
||||
Try to determine, without triggering generation of a string
|
||||
representation, whether one value is not a number.
|
||||
*/
|
||||
if (TclCheckEmptyString(valuePtr) > 0 || TclCheckEmptyString(value2Ptr) > 0) {
|
||||
goto stringCompare;
|
||||
}
|
||||
|
||||
if (GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK
|
||||
|| GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK) {
|
||||
/*
|
||||
|
||||
+24
-24
@@ -39,7 +39,7 @@ static int ReflectOutput(ClientData clientData, const char *buf,
|
||||
int toWrite, int *errorCodePtr);
|
||||
static void ReflectWatch(ClientData clientData, int mask);
|
||||
static int ReflectBlock(ClientData clientData, int mode);
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
static void ReflectThread(ClientData clientData, int action);
|
||||
static int ReflectEventRun(Tcl_Event *ev, int flags);
|
||||
static int ReflectEventDelete(Tcl_Event *ev, ClientData cd);
|
||||
@@ -76,7 +76,7 @@ static const Tcl_ChannelType tclRChannelType = {
|
||||
NULL, /* Flush channel. Not used by core. NULL'able */
|
||||
NULL, /* Handle events. NULL'able */
|
||||
ReflectSeekWide, /* Move access point (64 bit). NULL'able */
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
ReflectThread, /* thread action, tracking owner */
|
||||
#else
|
||||
NULL, /* thread action */
|
||||
@@ -97,7 +97,7 @@ typedef struct {
|
||||
* interpreter/thread containing its Tcl
|
||||
* command is gone.
|
||||
*/
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
Tcl_ThreadId thread; /* Thread the 'interp' belongs to. == Handler thread */
|
||||
Tcl_ThreadId owner; /* Thread owning the structure. == Channel thread */
|
||||
#endif
|
||||
@@ -201,7 +201,7 @@ typedef enum {
|
||||
#define NEGIMPL(a,b)
|
||||
#define HAS(x,f) (x & FLAG(f))
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Thread specific types and structures.
|
||||
*
|
||||
@@ -451,7 +451,7 @@ static const char *msg_read_toomuch = "{read delivered more than requested}";
|
||||
static const char *msg_write_toomuch = "{write wrote more than requested}";
|
||||
static const char *msg_write_nothing = "{write wrote nothing}";
|
||||
static const char *msg_seek_beforestart = "{Tried to seek before origin}";
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
static const char *msg_send_originlost = "{Channel thread lost}";
|
||||
#endif /* TCL_THREADS */
|
||||
static const char *msg_send_dstlost = "{Owner lost}";
|
||||
@@ -706,7 +706,7 @@ TclChanCreateObjCmd(
|
||||
Tcl_Panic("TclChanCreateObjCmd: duplicate channel names");
|
||||
}
|
||||
Tcl_SetHashValue(hPtr, chan);
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
rcmPtr = GetThreadReflectedChannelMap();
|
||||
hPtr = Tcl_CreateHashEntry(&rcmPtr->map, chanPtr->state->channelName,
|
||||
&isNew);
|
||||
@@ -750,7 +750,7 @@ TclChanCreateObjCmd(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
typedef struct {
|
||||
Tcl_Event header;
|
||||
ReflectedChannel *rcPtr;
|
||||
@@ -917,11 +917,11 @@ TclChanPostEventObjCmd(
|
||||
* We have the channel and the events to post.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rcPtr->owner == rcPtr->thread) {
|
||||
#endif
|
||||
Tcl_NotifyChannel(chan, events);
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
} else {
|
||||
ReflectEvent *ev = ckalloc(sizeof(ReflectEvent));
|
||||
|
||||
@@ -1137,7 +1137,7 @@ ReflectClose(
|
||||
* if lost?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rcPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -1169,7 +1169,7 @@ ReflectClose(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rcPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -1216,7 +1216,7 @@ ReflectClose(
|
||||
Tcl_DeleteHashEntry(hPtr);
|
||||
}
|
||||
}
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
rcmPtr = GetThreadReflectedChannelMap();
|
||||
hPtr = Tcl_FindHashEntry(&rcmPtr->map,
|
||||
Tcl_GetChannelName(rcPtr->chan));
|
||||
@@ -1267,7 +1267,7 @@ ReflectInput(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rcPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -1373,7 +1373,7 @@ ReflectOutput(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rcPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -1502,7 +1502,7 @@ ReflectSeekWide(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rcPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -1625,7 +1625,7 @@ ReflectWatch(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rcPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -1683,7 +1683,7 @@ ReflectBlock(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rcPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -1719,7 +1719,7 @@ ReflectBlock(
|
||||
return errorNum;
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -1789,7 +1789,7 @@ ReflectSetOption(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rcPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -1868,7 +1868,7 @@ ReflectGetOption(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rcPtr->thread != Tcl_GetCurrentThread()) {
|
||||
int opcode;
|
||||
ForwardParam p;
|
||||
@@ -2131,7 +2131,7 @@ NewReflectedChannel(
|
||||
rcPtr->chan = NULL;
|
||||
rcPtr->interp = interp;
|
||||
rcPtr->dead = 0;
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
rcPtr->thread = Tcl_GetCurrentThread();
|
||||
#endif
|
||||
rcPtr->mode = mode;
|
||||
@@ -2506,7 +2506,7 @@ DeleteReflectedChannelMap(
|
||||
Tcl_HashEntry *hPtr; /* Search variable. */
|
||||
ReflectedChannel *rcPtr;
|
||||
Tcl_Channel chan;
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
ForwardingResult *resultPtr;
|
||||
ForwardingEvent *evPtr;
|
||||
ForwardParam *paramPtr;
|
||||
@@ -2536,7 +2536,7 @@ DeleteReflectedChannelMap(
|
||||
Tcl_DeleteHashTable(&rcmPtr->map);
|
||||
ckfree(&rcmPtr->map);
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* The origin interpreter for one or more reflected channels is gone.
|
||||
*/
|
||||
@@ -2622,7 +2622,7 @@ DeleteReflectedChannelMap(
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
+19
-19
@@ -127,7 +127,7 @@ typedef struct {
|
||||
* in the argv, see below. The separate field
|
||||
* gives us direct access, needed when working
|
||||
* with the reflection maps. */
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
Tcl_ThreadId thread; /* Thread the 'interp' belongs to. */
|
||||
#endif
|
||||
|
||||
@@ -220,7 +220,7 @@ typedef enum {
|
||||
#define NEGIMPL(a,b)
|
||||
#define HAS(x,f) (x & FLAG(f))
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Thread specific types and structures.
|
||||
*
|
||||
@@ -438,7 +438,7 @@ static void DeleteReflectedTransformMap(ClientData clientData,
|
||||
|
||||
static const char *msg_read_unsup = "{read not supported by Tcl driver}";
|
||||
static const char *msg_write_unsup = "{write not supported by Tcl driver}";
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
static const char *msg_send_originlost = "{Channel thread lost}";
|
||||
static const char *msg_send_dstlost = "{Owner lost}";
|
||||
#endif /* TCL_THREADS */
|
||||
@@ -699,7 +699,7 @@ TclChanPushObjCmd(
|
||||
Tcl_Panic("TclChanPushObjCmd: duplicate transformation handle");
|
||||
}
|
||||
Tcl_SetHashValue(hPtr, rtPtr);
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
rtmPtr = GetThreadReflectedTransformMap();
|
||||
hPtr = Tcl_CreateHashEntry(&rtmPtr->map, TclGetString(rtId), &isNew);
|
||||
Tcl_SetHashValue(hPtr, rtPtr);
|
||||
@@ -911,7 +911,7 @@ ReflectClose(
|
||||
* if lost?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -938,7 +938,7 @@ ReflectClose(
|
||||
|
||||
if (HAS(rtPtr->methods, METH_DRAIN) && !rtPtr->readIsDrained) {
|
||||
if (!TransformDrain(rtPtr, &errorCode)) {
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
Tcl_EventuallyFree(rtPtr,
|
||||
(Tcl_FreeProc *) FreeReflectedTransform);
|
||||
@@ -952,7 +952,7 @@ ReflectClose(
|
||||
|
||||
if (HAS(rtPtr->methods, METH_FLUSH)) {
|
||||
if (!TransformFlush(rtPtr, &errorCode, FLUSH_WRITE)) {
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
Tcl_EventuallyFree(rtPtr,
|
||||
(Tcl_FreeProc *) FreeReflectedTransform);
|
||||
@@ -968,7 +968,7 @@ ReflectClose(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -1025,7 +1025,7 @@ ReflectClose(
|
||||
* under a channel by deleting the owning thread.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
rtmPtr = GetThreadReflectedTransformMap();
|
||||
hPtr = Tcl_FindHashEntry(&rtmPtr->map, TclGetString(rtPtr->handle));
|
||||
if (hPtr) {
|
||||
@@ -1767,7 +1767,7 @@ NewReflectedTransform(
|
||||
|
||||
rtPtr->chan = NULL;
|
||||
rtPtr->methods = 0;
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
rtPtr->thread = Tcl_GetCurrentThread();
|
||||
#endif
|
||||
rtPtr->parent = parentChan;
|
||||
@@ -2152,7 +2152,7 @@ DeleteReflectedTransformMap(
|
||||
Tcl_HashSearch hSearch; /* Search variable. */
|
||||
Tcl_HashEntry *hPtr; /* Search variable. */
|
||||
ReflectedTransform *rtPtr;
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
ForwardingResult *resultPtr;
|
||||
ForwardingEvent *evPtr;
|
||||
ForwardParam *paramPtr;
|
||||
@@ -2182,7 +2182,7 @@ DeleteReflectedTransformMap(
|
||||
Tcl_DeleteHashTable(&rtmPtr->map);
|
||||
ckfree(&rtmPtr->map);
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* The origin interpreter for one or more reflected channels is gone.
|
||||
*/
|
||||
@@ -2254,7 +2254,7 @@ DeleteReflectedTransformMap(
|
||||
#endif /* TCL_THREADS */
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -3088,7 +3088,7 @@ TransformRead(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -3144,7 +3144,7 @@ TransformWrite(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -3210,7 +3210,7 @@ TransformDrain(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -3260,7 +3260,7 @@ TransformFlush(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -3315,7 +3315,7 @@ TransformClear(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -3347,7 +3347,7 @@ TransformLimit(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
|
||||
+2
-2
@@ -3197,8 +3197,8 @@ TclSkipUnlink(
|
||||
#ifndef AUFS_SUPER_MAGIC
|
||||
#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
|
||||
#endif /* AUFS_SUPER_MAGIC */
|
||||
if ((statfs(Tcl_GetString (shlibFile), &fs) == 0) &&
|
||||
(fs.f_type == AUFS_SUPER_MAGIC)) {
|
||||
if ((statfs(Tcl_GetString(shlibFile), &fs) == 0)
|
||||
&& (fs.f_type == AUFS_SUPER_MAGIC)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1075,7 +1075,7 @@ declare 9 win {
|
||||
}
|
||||
# new for 8.4.20+/8.5.12+ Cygwin only
|
||||
declare 10 win {
|
||||
Tcl_DirEntry *TclpReaddir(DIR *dir)
|
||||
Tcl_DirEntry *TclpReaddir(TclDIR *dir)
|
||||
}
|
||||
# Removed in 8.3.1 (for Win32s only):
|
||||
#declare 10 win {
|
||||
@@ -1212,7 +1212,7 @@ declare 9 unix {
|
||||
# Added in 8.4:
|
||||
|
||||
declare 10 unix {
|
||||
Tcl_DirEntry *TclpReaddir(DIR *dir)
|
||||
Tcl_DirEntry *TclpReaddir(TclDIR *dir)
|
||||
}
|
||||
# Slots 11 and 12 are forwarders for functions that were promoted to
|
||||
# generic Stubs
|
||||
|
||||
+60
-27
@@ -136,6 +136,26 @@ typedef int ptrdiff_t;
|
||||
# define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
#if !defined(TCL_THREADS)
|
||||
# define TCL_THREADS 1
|
||||
#endif
|
||||
#if !TCL_THREADS
|
||||
# undef TCL_DECLARE_MUTEX
|
||||
# define TCL_DECLARE_MUTEX(name)
|
||||
# undef Tcl_MutexLock
|
||||
# define Tcl_MutexLock(mutexPtr)
|
||||
# undef Tcl_MutexUnlock
|
||||
# define Tcl_MutexUnlock(mutexPtr)
|
||||
# undef Tcl_MutexFinalize
|
||||
# define Tcl_MutexFinalize(mutexPtr)
|
||||
# undef Tcl_ConditionNotify
|
||||
# define Tcl_ConditionNotify(condPtr)
|
||||
# undef Tcl_ConditionWait
|
||||
# define Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
|
||||
# undef Tcl_ConditionFinalize
|
||||
# define Tcl_ConditionFinalize(condPtr)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following procedures allow namespaces to be customized to support
|
||||
* special name resolution rules for commands/variables.
|
||||
@@ -1146,6 +1166,10 @@ typedef struct CallFrame {
|
||||
* field contains an Object reference that has
|
||||
* been confirmed to refer to a class. Part of
|
||||
* TIP#257. */
|
||||
#define FRAME_IS_PRIVATE_DEFINE 0x10
|
||||
/* Marks this frame as being used for private
|
||||
* declarations with [oo::define]. Usually
|
||||
* OR'd with FRAME_IS_OO_DEFINE. TIP#500. */
|
||||
|
||||
/*
|
||||
* TIP #280
|
||||
@@ -2760,6 +2784,10 @@ MODULE_SCOPE long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS];
|
||||
|
||||
MODULE_SCOPE char tclEmptyString;
|
||||
|
||||
enum CheckEmptyStringResult {
|
||||
TCL_EMPTYSTRING_UNKNOWN = -1, TCL_EMPTYSTRING_NO, TCL_EMPTYSTRING_YES
|
||||
};
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------
|
||||
* Procedures shared among Tcl modules but not used by the outside world,
|
||||
@@ -2900,6 +2928,7 @@ MODULE_SCOPE int TclCheckArrayTraces(Tcl_Interp *interp, Var *varPtr,
|
||||
Var *arrayPtr, Tcl_Obj *name, int index);
|
||||
MODULE_SCOPE int TclCheckBadOctal(Tcl_Interp *interp,
|
||||
const char *value);
|
||||
MODULE_SCOPE int TclCheckEmptyString(Tcl_Obj *objPtr);
|
||||
MODULE_SCOPE int TclChanCaughtErrorBypass(Tcl_Interp *interp,
|
||||
Tcl_Channel chan);
|
||||
MODULE_SCOPE Tcl_ObjCmdProc TclChannelNamesCmd;
|
||||
@@ -2915,19 +2944,13 @@ MODULE_SCOPE void TclContinuationsCopy(Tcl_Obj *objPtr,
|
||||
Tcl_Obj *originObjPtr);
|
||||
MODULE_SCOPE int TclConvertElement(const char *src, int length,
|
||||
char *dst, int flags);
|
||||
MODULE_SCOPE Tcl_Command TclCreateObjCommandInNs (
|
||||
Tcl_Interp *interp,
|
||||
const char *cmdName,
|
||||
Tcl_Namespace *nsPtr,
|
||||
Tcl_ObjCmdProc *proc,
|
||||
ClientData clientData,
|
||||
MODULE_SCOPE Tcl_Command TclCreateObjCommandInNs(Tcl_Interp *interp,
|
||||
const char *cmdName, Tcl_Namespace *nsPtr,
|
||||
Tcl_ObjCmdProc *proc, ClientData clientData,
|
||||
Tcl_CmdDeleteProc *deleteProc);
|
||||
MODULE_SCOPE Tcl_Command TclCreateEnsembleInNs(
|
||||
Tcl_Interp *interp,
|
||||
const char *name,
|
||||
Tcl_Namespace *nameNamespacePtr,
|
||||
Tcl_Namespace *ensembleNamespacePtr,
|
||||
int flags);
|
||||
MODULE_SCOPE Tcl_Command TclCreateEnsembleInNs(Tcl_Interp *interp,
|
||||
const char *name, Tcl_Namespace *nameNamespacePtr,
|
||||
Tcl_Namespace *ensembleNamespacePtr, int flags);
|
||||
MODULE_SCOPE void TclDeleteNamespaceVars(Namespace *nsPtr);
|
||||
MODULE_SCOPE int TclFindDictElement(Tcl_Interp *interp,
|
||||
const char *dict, int dictLength,
|
||||
@@ -2954,9 +2977,9 @@ MODULE_SCOPE char * TclDStringAppendObj(Tcl_DString *dsPtr,
|
||||
MODULE_SCOPE char * TclDStringAppendDString(Tcl_DString *dsPtr,
|
||||
Tcl_DString *toAppendPtr);
|
||||
MODULE_SCOPE Tcl_Obj * TclDStringToObj(Tcl_DString *dsPtr);
|
||||
MODULE_SCOPE Tcl_Obj *const * TclFetchEnsembleRoot(Tcl_Interp *interp,
|
||||
MODULE_SCOPE Tcl_Obj *const *TclFetchEnsembleRoot(Tcl_Interp *interp,
|
||||
Tcl_Obj *const *objv, int objc, int *objcPtr);
|
||||
MODULE_SCOPE Tcl_Namespace * TclEnsureNamespace(Tcl_Interp *interp,
|
||||
MODULE_SCOPE Tcl_Namespace *TclEnsureNamespace(Tcl_Interp *interp,
|
||||
Tcl_Namespace *namespacePtr);
|
||||
MODULE_SCOPE void TclFinalizeAllocSubsystem(void);
|
||||
MODULE_SCOPE void TclFinalizeAsync(void);
|
||||
@@ -2984,15 +3007,11 @@ MODULE_SCOPE double TclFloor(const mp_int *a);
|
||||
MODULE_SCOPE void TclFormatNaN(double value, char *buffer);
|
||||
MODULE_SCOPE int TclFSFileAttrIndex(Tcl_Obj *pathPtr,
|
||||
const char *attributeName, int *indexPtr);
|
||||
MODULE_SCOPE Tcl_Command TclNRCreateCommandInNs (
|
||||
Tcl_Interp *interp,
|
||||
const char *cmdName,
|
||||
Tcl_Namespace *nsPtr,
|
||||
Tcl_ObjCmdProc *proc,
|
||||
Tcl_ObjCmdProc *nreProc,
|
||||
MODULE_SCOPE Tcl_Command TclNRCreateCommandInNs(Tcl_Interp *interp,
|
||||
const char *cmdName, Tcl_Namespace *nsPtr,
|
||||
Tcl_ObjCmdProc *proc, Tcl_ObjCmdProc *nreProc,
|
||||
ClientData clientData,
|
||||
Tcl_CmdDeleteProc *deleteProc);
|
||||
|
||||
MODULE_SCOPE int TclNREvalFile(Tcl_Interp *interp, Tcl_Obj *pathPtr,
|
||||
const char *encodingName);
|
||||
MODULE_SCOPE void TclFSUnloadTempFile(Tcl_LoadHandle loadHandle);
|
||||
@@ -3173,7 +3192,8 @@ MODULE_SCOPE void TclSetBgErrorHandler(Tcl_Interp *interp,
|
||||
Tcl_Obj *cmdPrefix);
|
||||
MODULE_SCOPE void TclSetBignumIntRep(Tcl_Obj *objPtr,
|
||||
mp_int *bignumValue);
|
||||
MODULE_SCOPE int TclSetBooleanFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
|
||||
MODULE_SCOPE int TclSetBooleanFromAny(Tcl_Interp *interp,
|
||||
Tcl_Obj *objPtr);
|
||||
MODULE_SCOPE void TclSetCmdNameObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
|
||||
Command *cmdPtr);
|
||||
MODULE_SCOPE void TclSetDuplicateObj(Tcl_Obj *dupPtr, Tcl_Obj *objPtr);
|
||||
@@ -3185,6 +3205,12 @@ MODULE_SCOPE void TclSpellFix(Tcl_Interp *interp,
|
||||
Tcl_Obj *bad, Tcl_Obj *fix);
|
||||
MODULE_SCOPE void * TclStackRealloc(Tcl_Interp *interp, void *ptr,
|
||||
int numBytes);
|
||||
typedef int (*memCmpFn_t)(const void*, const void*, size_t);
|
||||
MODULE_SCOPE int TclStringCmp(Tcl_Obj *value1Ptr, Tcl_Obj *value2Ptr,
|
||||
int checkEq, int nocase, int reqlength);
|
||||
MODULE_SCOPE int TclStringCmpOpts(Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const objv[], int *nocase,
|
||||
int *reqlength);
|
||||
MODULE_SCOPE int TclStringMatch(const char *str, int strLen,
|
||||
const char *pattern, int ptnLen, int flags);
|
||||
MODULE_SCOPE int TclStringMatchObj(Tcl_Obj *stringObj,
|
||||
@@ -3233,8 +3259,8 @@ MODULE_SCOPE void * TclpThreadCreateKey(void);
|
||||
MODULE_SCOPE void TclpThreadDeleteKey(void *keyPtr);
|
||||
MODULE_SCOPE void TclpThreadSetMasterTSD(void *tsdKeyPtr, void *ptr);
|
||||
MODULE_SCOPE void * TclpThreadGetMasterTSD(void *tsdKeyPtr);
|
||||
|
||||
MODULE_SCOPE void TclErrorStackResetIf(Tcl_Interp *interp, const char *msg, int length);
|
||||
MODULE_SCOPE void TclErrorStackResetIf(Tcl_Interp *interp,
|
||||
const char *msg, int length);
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------
|
||||
@@ -4087,7 +4113,7 @@ typedef enum TclProcessWaitStatus {
|
||||
TCL_PROCESS_EXITED = 1, /* Process has exited. */
|
||||
TCL_PROCESS_SIGNALED = 2, /* Child killed because of a signal. */
|
||||
TCL_PROCESS_STOPPED = 3, /* Child suspended because of a signal. */
|
||||
TCL_PROCESS_UNKNOWN_STATUS = 4
|
||||
TCL_PROCESS_UNKNOWN_STATUS = 4
|
||||
/* Child wait status didn't make sense. */
|
||||
} TclProcessWaitStatus;
|
||||
|
||||
@@ -4198,6 +4224,10 @@ typedef const char *TclDTraceStr;
|
||||
} \
|
||||
}
|
||||
|
||||
#if TCL_THREADS && !defined(USE_THREAD_ALLOC)
|
||||
# define USE_THREAD_ALLOC 1
|
||||
#endif
|
||||
|
||||
#if defined(PURIFY)
|
||||
|
||||
/*
|
||||
@@ -4215,7 +4245,7 @@ typedef const char *TclDTraceStr;
|
||||
|
||||
#undef USE_THREAD_ALLOC
|
||||
#undef USE_TCLALLOC
|
||||
#elif defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
|
||||
#elif TCL_THREADS && defined(USE_THREAD_ALLOC)
|
||||
|
||||
/*
|
||||
* The TCL_THREADS mode is like the regular mode but allocates Tcl_Obj's from
|
||||
@@ -4280,7 +4310,7 @@ MODULE_SCOPE void TclpFreeAllocCache(void *);
|
||||
# define USE_TCLALLOC 0
|
||||
#endif
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/* declared in tclObj.c */
|
||||
MODULE_SCOPE Tcl_Mutex tclObjMutex;
|
||||
#endif
|
||||
@@ -4540,6 +4570,9 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file,
|
||||
*/
|
||||
|
||||
MODULE_SCOPE int TclIsPureByteArray(Tcl_Obj *objPtr);
|
||||
#define TclIsPureDict(objPtr) \
|
||||
(((objPtr)->bytes==NULL) && ((objPtr)->typePtr==&tclDictType))
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
#ifndef _TCLINTPLATDECLS
|
||||
#define _TCLINTPLATDECLS
|
||||
|
||||
#ifdef _WIN32
|
||||
# define Tcl_DirEntry void
|
||||
# define DIR void
|
||||
#endif
|
||||
|
||||
#undef TCL_STORAGE_CLASS
|
||||
#ifdef BUILD_tcl
|
||||
# define TCL_STORAGE_CLASS DLLEXPORT
|
||||
@@ -72,7 +67,7 @@ EXTERN int TclUnixWaitForFile(int fd, int mask, int timeout);
|
||||
/* 9 */
|
||||
EXTERN TclFile TclpCreateTempFile(const char *contents);
|
||||
/* 10 */
|
||||
EXTERN Tcl_DirEntry * TclpReaddir(DIR *dir);
|
||||
EXTERN Tcl_DirEntry * TclpReaddir(TclDIR *dir);
|
||||
/* 11 */
|
||||
EXTERN struct tm * TclpLocaltime_unix(const time_t *clock);
|
||||
/* 12 */
|
||||
@@ -129,7 +124,7 @@ EXTERN int TclpGetPid(Tcl_Pid pid);
|
||||
/* 9 */
|
||||
EXTERN int TclWinGetPlatformId(void);
|
||||
/* 10 */
|
||||
EXTERN Tcl_DirEntry * TclpReaddir(DIR *dir);
|
||||
EXTERN Tcl_DirEntry * TclpReaddir(TclDIR *dir);
|
||||
/* 11 */
|
||||
EXTERN void TclGetAndDetachPids(Tcl_Interp *interp,
|
||||
Tcl_Channel chan);
|
||||
@@ -206,7 +201,7 @@ EXTERN int TclUnixWaitForFile(int fd, int mask, int timeout);
|
||||
/* 9 */
|
||||
EXTERN TclFile TclpCreateTempFile(const char *contents);
|
||||
/* 10 */
|
||||
EXTERN Tcl_DirEntry * TclpReaddir(DIR *dir);
|
||||
EXTERN Tcl_DirEntry * TclpReaddir(TclDIR *dir);
|
||||
/* 11 */
|
||||
EXTERN struct tm * TclpLocaltime_unix(const time_t *clock);
|
||||
/* 12 */
|
||||
@@ -269,7 +264,7 @@ typedef struct TclIntPlatStubs {
|
||||
TclFile (*tclpOpenFile) (const char *fname, int mode); /* 7 */
|
||||
int (*tclUnixWaitForFile) (int fd, int mask, int timeout); /* 8 */
|
||||
TclFile (*tclpCreateTempFile) (const char *contents); /* 9 */
|
||||
Tcl_DirEntry * (*tclpReaddir) (DIR *dir); /* 10 */
|
||||
Tcl_DirEntry * (*tclpReaddir) (TclDIR *dir); /* 10 */
|
||||
struct tm * (*tclpLocaltime_unix) (const time_t *clock); /* 11 */
|
||||
struct tm * (*tclpGmtime_unix) (const time_t *clock); /* 12 */
|
||||
char * (*tclpInetNtoa) (struct in_addr addr); /* 13 */
|
||||
@@ -302,7 +297,7 @@ typedef struct TclIntPlatStubs {
|
||||
int (*tclWinSetSockOpt) (SOCKET s, int level, int optname, const char *optval, int optlen); /* 7 */
|
||||
int (*tclpGetPid) (Tcl_Pid pid); /* 8 */
|
||||
int (*tclWinGetPlatformId) (void); /* 9 */
|
||||
Tcl_DirEntry * (*tclpReaddir) (DIR *dir); /* 10 */
|
||||
Tcl_DirEntry * (*tclpReaddir) (TclDIR *dir); /* 10 */
|
||||
void (*tclGetAndDetachPids) (Tcl_Interp *interp, Tcl_Channel chan); /* 11 */
|
||||
int (*tclpCloseFile) (TclFile file); /* 12 */
|
||||
Tcl_Channel (*tclpCreateCommandChannel) (TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr); /* 13 */
|
||||
@@ -335,7 +330,7 @@ typedef struct TclIntPlatStubs {
|
||||
TclFile (*tclpOpenFile) (const char *fname, int mode); /* 7 */
|
||||
int (*tclUnixWaitForFile) (int fd, int mask, int timeout); /* 8 */
|
||||
TclFile (*tclpCreateTempFile) (const char *contents); /* 9 */
|
||||
Tcl_DirEntry * (*tclpReaddir) (DIR *dir); /* 10 */
|
||||
Tcl_DirEntry * (*tclpReaddir) (TclDIR *dir); /* 10 */
|
||||
struct tm * (*tclpLocaltime_unix) (const time_t *clock); /* 11 */
|
||||
struct tm * (*tclpGmtime_unix) (const time_t *clock); /* 12 */
|
||||
char * (*tclpInetNtoa) (struct in_addr addr); /* 13 */
|
||||
|
||||
+67
-8
@@ -31,6 +31,7 @@ static const struct {
|
||||
{"export", TclOODefineExportObjCmd, 0},
|
||||
{"forward", TclOODefineForwardObjCmd, 0},
|
||||
{"method", TclOODefineMethodObjCmd, 0},
|
||||
{"private", TclOODefinePrivateObjCmd, 0},
|
||||
{"renamemethod", TclOODefineRenameMethodObjCmd, 0},
|
||||
{"self", TclOODefineSelfObjCmd, 0},
|
||||
{"unexport", TclOODefineUnexportObjCmd, 0},
|
||||
@@ -41,6 +42,7 @@ static const struct {
|
||||
{"export", TclOODefineExportObjCmd, 1},
|
||||
{"forward", TclOODefineForwardObjCmd, 1},
|
||||
{"method", TclOODefineMethodObjCmd, 1},
|
||||
{"private", TclOODefinePrivateObjCmd, 1},
|
||||
{"renamemethod", TclOODefineRenameMethodObjCmd, 1},
|
||||
{"self", TclOODefineObjSelfObjCmd, 0},
|
||||
{"unexport", TclOODefineUnexportObjCmd, 1},
|
||||
@@ -993,6 +995,7 @@ ReleaseClassContents(
|
||||
Method *mPtr;
|
||||
Foundation *fPtr = oPtr->fPtr;
|
||||
Tcl_Obj *variableObj;
|
||||
PrivateVariableMapping *privateVariable;
|
||||
|
||||
/*
|
||||
* Sanity check!
|
||||
@@ -1099,6 +1102,14 @@ ReleaseClassContents(
|
||||
ckfree(clsPtr->variables.list);
|
||||
}
|
||||
|
||||
FOREACH_STRUCT(privateVariable, clsPtr->privateVariables) {
|
||||
TclDecrRefCount(privateVariable->variableObj);
|
||||
TclDecrRefCount(privateVariable->fullNameObj);
|
||||
}
|
||||
if (i) {
|
||||
ckfree(clsPtr->privateVariables.list);
|
||||
}
|
||||
|
||||
if (IsRootClass(oPtr) && !Deleted(fPtr->objectCls->thisPtr)) {
|
||||
Tcl_DeleteCommandFromToken(interp, fPtr->objectCls->thisPtr->command);
|
||||
}
|
||||
@@ -1128,6 +1139,7 @@ ObjectNamespaceDeleted(
|
||||
Class *mixinPtr;
|
||||
Method *mPtr;
|
||||
Tcl_Obj *filterObj, *variableObj;
|
||||
PrivateVariableMapping *privateVariable;
|
||||
Tcl_Interp *interp = oPtr->fPtr->interp;
|
||||
int i;
|
||||
|
||||
@@ -1162,7 +1174,7 @@ ObjectNamespaceDeleted(
|
||||
|
||||
if (!Tcl_InterpDeleted(interp) && !(oPtr->flags & DESTRUCTOR_CALLED)) {
|
||||
CallContext *contextPtr =
|
||||
TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL);
|
||||
TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL, NULL, NULL);
|
||||
int result;
|
||||
|
||||
Tcl_InterpState state;
|
||||
@@ -1248,6 +1260,14 @@ ObjectNamespaceDeleted(
|
||||
ckfree(oPtr->variables.list);
|
||||
}
|
||||
|
||||
FOREACH_STRUCT(privateVariable, oPtr->privateVariables) {
|
||||
TclDecrRefCount(privateVariable->variableObj);
|
||||
TclDecrRefCount(privateVariable->fullNameObj);
|
||||
}
|
||||
if (i) {
|
||||
ckfree(oPtr->privateVariables.list);
|
||||
}
|
||||
|
||||
if (oPtr->chainCache) {
|
||||
TclOODeleteChainCache(oPtr->chainCache);
|
||||
}
|
||||
@@ -1631,7 +1651,7 @@ Tcl_NewObjectInstance(
|
||||
|
||||
if (objc >= 0) {
|
||||
CallContext *contextPtr =
|
||||
TclOOGetCallContext(oPtr, NULL, CONSTRUCTOR, NULL);
|
||||
TclOOGetCallContext(oPtr, NULL, CONSTRUCTOR, NULL, NULL, NULL);
|
||||
|
||||
if (contextPtr != NULL) {
|
||||
int isRoot, result;
|
||||
@@ -1704,7 +1724,7 @@ TclNRNewObjectInstance(
|
||||
*objectPtr = (Tcl_Object) oPtr;
|
||||
return TCL_OK;
|
||||
}
|
||||
contextPtr = TclOOGetCallContext(oPtr, NULL, CONSTRUCTOR, NULL);
|
||||
contextPtr = TclOOGetCallContext(oPtr, NULL, CONSTRUCTOR, NULL, NULL, NULL);
|
||||
if (contextPtr == NULL) {
|
||||
*objectPtr = (Tcl_Object) oPtr;
|
||||
return TCL_OK;
|
||||
@@ -1884,6 +1904,7 @@ Tcl_CopyObjectInstance(
|
||||
Class *mixinPtr;
|
||||
CallContext *contextPtr;
|
||||
Tcl_Obj *keyPtr, *filterObj, *variableObj, *args[3];
|
||||
PrivateVariableMapping *privateVariable;
|
||||
int i, result;
|
||||
|
||||
/*
|
||||
@@ -1953,7 +1974,7 @@ Tcl_CopyObjectInstance(
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the object's variable resolution list to the new object.
|
||||
* Copy the object's variable resolution lists to the new object.
|
||||
*/
|
||||
|
||||
DUPLICATE(o2Ptr->variables, oPtr->variables, Tcl_Obj *);
|
||||
@@ -1961,6 +1982,13 @@ Tcl_CopyObjectInstance(
|
||||
Tcl_IncrRefCount(variableObj);
|
||||
}
|
||||
|
||||
DUPLICATE(o2Ptr->privateVariables, oPtr->privateVariables,
|
||||
PrivateVariableMapping);
|
||||
FOREACH_STRUCT(privateVariable, o2Ptr->privateVariables) {
|
||||
Tcl_IncrRefCount(privateVariable->variableObj);
|
||||
Tcl_IncrRefCount(privateVariable->fullNameObj);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the object's flags to the new object, clearing those that must be
|
||||
* kept object-local. The duplicate is never deleted at this point, nor is
|
||||
@@ -2049,7 +2077,7 @@ Tcl_CopyObjectInstance(
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the source class's variable resolution list.
|
||||
* Copy the source class's variable resolution lists.
|
||||
*/
|
||||
|
||||
DUPLICATE(cls2Ptr->variables, clsPtr->variables, Tcl_Obj *);
|
||||
@@ -2057,6 +2085,13 @@ Tcl_CopyObjectInstance(
|
||||
Tcl_IncrRefCount(variableObj);
|
||||
}
|
||||
|
||||
DUPLICATE(cls2Ptr->privateVariables, clsPtr->privateVariables,
|
||||
PrivateVariableMapping);
|
||||
FOREACH_STRUCT(privateVariable, cls2Ptr->privateVariables) {
|
||||
Tcl_IncrRefCount(privateVariable->variableObj);
|
||||
Tcl_IncrRefCount(privateVariable->fullNameObj);
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate the source class's mixins (which cannot be circular
|
||||
* references to the duplicate).
|
||||
@@ -2129,7 +2164,8 @@ Tcl_CopyObjectInstance(
|
||||
}
|
||||
|
||||
TclResetRewriteEnsemble(interp, 1);
|
||||
contextPtr = TclOOGetCallContext(o2Ptr, oPtr->fPtr->clonedName, 0, NULL);
|
||||
contextPtr = TclOOGetCallContext(o2Ptr, oPtr->fPtr->clonedName, 0, NULL,
|
||||
NULL, NULL);
|
||||
if (contextPtr) {
|
||||
args[0] = TclOOObjectName(interp, o2Ptr);
|
||||
args[1] = oPtr->fPtr->clonedName;
|
||||
@@ -2526,6 +2562,9 @@ TclOOObjectCmdCore(
|
||||
{
|
||||
CallContext *contextPtr;
|
||||
Tcl_Obj *methodNamePtr;
|
||||
CallFrame *framePtr = ((Interp *) interp)->varFramePtr;
|
||||
Object *callerObjPtr = NULL;
|
||||
Class *callerClsPtr = NULL;
|
||||
int result;
|
||||
|
||||
/*
|
||||
@@ -2539,6 +2578,24 @@ TclOOObjectCmdCore(
|
||||
goto noMapping;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if we're in a context that can see the extra, private methods
|
||||
* in this class.
|
||||
*/
|
||||
|
||||
if (framePtr->isProcCallFrame & FRAME_IS_METHOD) {
|
||||
CallContext *callerContextPtr = framePtr->clientData;
|
||||
Method *callerMethodPtr =
|
||||
callerContextPtr->callPtr->chain[callerContextPtr->index].mPtr;
|
||||
|
||||
if (callerMethodPtr->declaringObjectPtr) {
|
||||
callerObjPtr = callerMethodPtr->declaringObjectPtr;
|
||||
}
|
||||
if (callerMethodPtr->declaringClassPtr) {
|
||||
callerClsPtr = callerMethodPtr->declaringClassPtr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Give plugged in code a chance to remap the method name.
|
||||
*/
|
||||
@@ -2566,7 +2623,8 @@ TclOOObjectCmdCore(
|
||||
|
||||
Tcl_IncrRefCount(mappedMethodName);
|
||||
contextPtr = TclOOGetCallContext(oPtr, mappedMethodName,
|
||||
flags | (oPtr->flags & FILTER_HANDLING), methodNamePtr);
|
||||
flags | (oPtr->flags & FILTER_HANDLING), callerObjPtr,
|
||||
callerClsPtr, methodNamePtr);
|
||||
TclDecrRefCount(mappedMethodName);
|
||||
if (contextPtr == NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
@@ -2583,7 +2641,8 @@ TclOOObjectCmdCore(
|
||||
|
||||
noMapping:
|
||||
contextPtr = TclOOGetCallContext(oPtr, methodNamePtr,
|
||||
flags | (oPtr->flags & FILTER_HANDLING), NULL);
|
||||
flags | (oPtr->flags & FILTER_HANDLING), callerObjPtr,
|
||||
callerClsPtr, NULL);
|
||||
if (contextPtr == NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"impossible to invoke method \"%s\": no defined method or"
|
||||
|
||||
+5
-2
@@ -58,12 +58,12 @@ declare 10 {
|
||||
}
|
||||
declare 11 {
|
||||
Tcl_Method Tcl_NewInstanceMethod(Tcl_Interp *interp, Tcl_Object object,
|
||||
Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr,
|
||||
Tcl_Obj *nameObj, int flags, const Tcl_MethodType *typePtr,
|
||||
ClientData clientData)
|
||||
}
|
||||
declare 12 {
|
||||
Tcl_Method Tcl_NewMethod(Tcl_Interp *interp, Tcl_Class cls,
|
||||
Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr,
|
||||
Tcl_Obj *nameObj, int flags, const Tcl_MethodType *typePtr,
|
||||
ClientData clientData)
|
||||
}
|
||||
declare 13 {
|
||||
@@ -126,6 +126,9 @@ declare 27 {
|
||||
declare 28 {
|
||||
Tcl_Obj *Tcl_GetObjectName(Tcl_Interp *interp, Tcl_Object object)
|
||||
}
|
||||
declare 29 {
|
||||
int Tcl_MethodIsPrivate(Tcl_Method method)
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Private API, exposed to support advanced OO systems that plug in on top of
|
||||
|
||||
@@ -99,6 +99,15 @@ typedef struct {
|
||||
*/
|
||||
|
||||
#define TCL_OO_METHOD_VERSION_CURRENT 1
|
||||
|
||||
/*
|
||||
* Visibility constants for the flags parameter to Tcl_NewMethod and
|
||||
* Tcl_NewInstanceMethod.
|
||||
*/
|
||||
|
||||
#define TCL_OO_METHOD_PUBLIC 1
|
||||
#define TCL_OO_METHOD_UNEXPORTED 0
|
||||
#define TCL_OO_METHOD_PRIVATE 0x20
|
||||
|
||||
/*
|
||||
* The type of some object (or class) metadata. This describes how to delete
|
||||
|
||||
+84
-16
@@ -347,7 +347,8 @@ TclOO_Object_Destroy(
|
||||
}
|
||||
if (!(oPtr->flags & DESTRUCTOR_CALLED)) {
|
||||
oPtr->flags |= DESTRUCTOR_CALLED;
|
||||
contextPtr = TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL);
|
||||
contextPtr = TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL, NULL,
|
||||
NULL);
|
||||
if (contextPtr != NULL) {
|
||||
contextPtr->callPtr->flags |= DESTRUCTOR;
|
||||
contextPtr->skip = 0;
|
||||
@@ -499,9 +500,12 @@ TclOO_Object_Unknown(
|
||||
Tcl_Obj *const *objv) /* The actual arguments. */
|
||||
{
|
||||
CallContext *contextPtr = (CallContext *) context;
|
||||
Object *callerObj = NULL;
|
||||
Class *callerCls = NULL;
|
||||
Object *oPtr = contextPtr->oPtr;
|
||||
const char **methodNames;
|
||||
int numMethodNames, i, skip = Tcl_ObjectContextSkippedArgs(context);
|
||||
CallFrame *framePtr = ((Interp *) interp)->varFramePtr;
|
||||
Tcl_Obj *errorMsg;
|
||||
|
||||
/*
|
||||
@@ -515,11 +519,32 @@ TclOO_Object_Unknown(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if the calling context should know about extra private
|
||||
* methods, and if so, which.
|
||||
*/
|
||||
|
||||
if (framePtr->isProcCallFrame & FRAME_IS_METHOD) {
|
||||
CallContext *callerContext = framePtr->clientData;
|
||||
Method *mPtr = callerContext->callPtr->chain[
|
||||
callerContext->index].mPtr;
|
||||
|
||||
if (mPtr->declaringObjectPtr) {
|
||||
if (oPtr == mPtr->declaringObjectPtr) {
|
||||
callerObj = mPtr->declaringObjectPtr;
|
||||
}
|
||||
} else {
|
||||
if (TclOOIsReachable(mPtr->declaringClassPtr, oPtr->selfCls)) {
|
||||
callerCls = mPtr->declaringClassPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the list of methods that we want to know about.
|
||||
*/
|
||||
|
||||
numMethodNames = TclOOGetSortedMethodList(oPtr,
|
||||
numMethodNames = TclOOGetSortedMethodList(oPtr, callerObj, callerCls,
|
||||
contextPtr->callPtr->flags & PUBLIC_METHOD, &methodNames);
|
||||
|
||||
/*
|
||||
@@ -684,6 +709,7 @@ TclOO_Object_VarName(
|
||||
{
|
||||
Var *varPtr, *aryVar;
|
||||
Tcl_Obj *varNamePtr, *argPtr;
|
||||
CallFrame *framePtr = ((Interp *) interp)->varFramePtr;
|
||||
const char *arg;
|
||||
|
||||
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
|
||||
@@ -709,6 +735,58 @@ TclOO_Object_VarName(
|
||||
Tcl_Namespace *namespacePtr =
|
||||
Tcl_GetObjectNamespace(Tcl_ObjectContextObject(context));
|
||||
|
||||
/*
|
||||
* Private method handling. [TIP 500]
|
||||
*
|
||||
* If we're in a context that can see some private methods of an
|
||||
* object, we may need to precede a variable name with its prefix.
|
||||
* This is a little tricky as we need to check through the inheritance
|
||||
* hierarchy when the method was declared by a class to see if the
|
||||
* current object is an instance of that class.
|
||||
*/
|
||||
|
||||
if (framePtr->isProcCallFrame & FRAME_IS_METHOD) {
|
||||
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
|
||||
CallContext *callerContext = framePtr->clientData;
|
||||
Method *mPtr = callerContext->callPtr->chain[
|
||||
callerContext->index].mPtr;
|
||||
PrivateVariableMapping *pvPtr;
|
||||
int i;
|
||||
|
||||
if (mPtr->declaringObjectPtr == oPtr) {
|
||||
FOREACH_STRUCT(pvPtr, oPtr->privateVariables) {
|
||||
if (!strcmp(Tcl_GetString(pvPtr->variableObj),
|
||||
Tcl_GetString(argPtr))) {
|
||||
argPtr = pvPtr->fullNameObj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (mPtr->declaringClassPtr &&
|
||||
mPtr->declaringClassPtr->privateVariables.num) {
|
||||
Class *clsPtr = mPtr->declaringClassPtr;
|
||||
int isInstance = TclOOIsReachable(clsPtr, oPtr->selfCls);
|
||||
Class *mixinCls;
|
||||
|
||||
if (!isInstance) {
|
||||
FOREACH(mixinCls, oPtr->mixins) {
|
||||
if (TclOOIsReachable(clsPtr, mixinCls)) {
|
||||
isInstance = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isInstance) {
|
||||
FOREACH_STRUCT(pvPtr, clsPtr->privateVariables) {
|
||||
if (!strcmp(Tcl_GetString(pvPtr->variableObj),
|
||||
Tcl_GetString(argPtr))) {
|
||||
argPtr = pvPtr->fullNameObj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
varNamePtr = Tcl_NewStringObj(namespacePtr->fullName, -1);
|
||||
Tcl_AppendToObj(varNamePtr, "::", 2);
|
||||
Tcl_AppendObjToObj(varNamePtr, argPtr);
|
||||
@@ -729,26 +807,16 @@ TclOO_Object_VarName(
|
||||
|
||||
varNamePtr = Tcl_NewObj();
|
||||
if (aryVar != NULL) {
|
||||
Tcl_HashEntry *hPtr;
|
||||
Tcl_HashSearch search;
|
||||
|
||||
Tcl_GetVariableFullName(interp, (Tcl_Var) aryVar, varNamePtr);
|
||||
|
||||
/*
|
||||
* WARNING! This code pokes inside the implementation of hash tables!
|
||||
*/
|
||||
|
||||
hPtr = Tcl_FirstHashEntry((Tcl_HashTable *) aryVar->value.tablePtr,
|
||||
&search);
|
||||
while (hPtr != NULL) {
|
||||
if (varPtr == Tcl_GetHashValue(hPtr)) {
|
||||
Tcl_AppendToObj(varNamePtr, "(", -1);
|
||||
Tcl_AppendObjToObj(varNamePtr, hPtr->key.objPtr);
|
||||
Tcl_AppendToObj(varNamePtr, ")", -1);
|
||||
break;
|
||||
}
|
||||
hPtr = Tcl_NextHashEntry(&search);
|
||||
}
|
||||
Tcl_AppendToObj(varNamePtr, "(", -1);
|
||||
Tcl_AppendObjToObj(varNamePtr, ((VarInHash *)
|
||||
varPtr)->entry.key.objPtr);
|
||||
Tcl_AppendToObj(varNamePtr, ")", -1);
|
||||
} else {
|
||||
Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, varNamePtr);
|
||||
}
|
||||
|
||||
+470
-212
File diff suppressed because it is too large
Load Diff
@@ -59,11 +59,11 @@ TCLAPI Tcl_Obj * Tcl_MethodName(Tcl_Method method);
|
||||
/* 11 */
|
||||
TCLAPI Tcl_Method Tcl_NewInstanceMethod(Tcl_Interp *interp,
|
||||
Tcl_Object object, Tcl_Obj *nameObj,
|
||||
int isPublic, const Tcl_MethodType *typePtr,
|
||||
int flags, const Tcl_MethodType *typePtr,
|
||||
ClientData clientData);
|
||||
/* 12 */
|
||||
TCLAPI Tcl_Method Tcl_NewMethod(Tcl_Interp *interp, Tcl_Class cls,
|
||||
Tcl_Obj *nameObj, int isPublic,
|
||||
Tcl_Obj *nameObj, int flags,
|
||||
const Tcl_MethodType *typePtr,
|
||||
ClientData clientData);
|
||||
/* 13 */
|
||||
@@ -116,6 +116,8 @@ TCLAPI void Tcl_ClassSetDestructor(Tcl_Interp *interp,
|
||||
/* 28 */
|
||||
TCLAPI Tcl_Obj * Tcl_GetObjectName(Tcl_Interp *interp,
|
||||
Tcl_Object object);
|
||||
/* 29 */
|
||||
TCLAPI int Tcl_MethodIsPrivate(Tcl_Method method);
|
||||
|
||||
typedef struct {
|
||||
const struct TclOOIntStubs *tclOOIntStubs;
|
||||
@@ -136,8 +138,8 @@ typedef struct TclOOStubs {
|
||||
int (*tcl_MethodIsPublic) (Tcl_Method method); /* 8 */
|
||||
int (*tcl_MethodIsType) (Tcl_Method method, const Tcl_MethodType *typePtr, ClientData *clientDataPtr); /* 9 */
|
||||
Tcl_Obj * (*tcl_MethodName) (Tcl_Method method); /* 10 */
|
||||
Tcl_Method (*tcl_NewInstanceMethod) (Tcl_Interp *interp, Tcl_Object object, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, ClientData clientData); /* 11 */
|
||||
Tcl_Method (*tcl_NewMethod) (Tcl_Interp *interp, Tcl_Class cls, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, ClientData clientData); /* 12 */
|
||||
Tcl_Method (*tcl_NewInstanceMethod) (Tcl_Interp *interp, Tcl_Object object, Tcl_Obj *nameObj, int flags, const Tcl_MethodType *typePtr, ClientData clientData); /* 11 */
|
||||
Tcl_Method (*tcl_NewMethod) (Tcl_Interp *interp, Tcl_Class cls, Tcl_Obj *nameObj, int flags, const Tcl_MethodType *typePtr, ClientData clientData); /* 12 */
|
||||
Tcl_Object (*tcl_NewObjectInstance) (Tcl_Interp *interp, Tcl_Class cls, const char *nameStr, const char *nsNameStr, int objc, Tcl_Obj *const *objv, int skip); /* 13 */
|
||||
int (*tcl_ObjectDeleted) (Tcl_Object object); /* 14 */
|
||||
int (*tcl_ObjectContextIsFiltering) (Tcl_ObjectContext context); /* 15 */
|
||||
@@ -154,6 +156,7 @@ typedef struct TclOOStubs {
|
||||
void (*tcl_ClassSetConstructor) (Tcl_Interp *interp, Tcl_Class clazz, Tcl_Method method); /* 26 */
|
||||
void (*tcl_ClassSetDestructor) (Tcl_Interp *interp, Tcl_Class clazz, Tcl_Method method); /* 27 */
|
||||
Tcl_Obj * (*tcl_GetObjectName) (Tcl_Interp *interp, Tcl_Object object); /* 28 */
|
||||
int (*tcl_MethodIsPrivate) (Tcl_Method method); /* 29 */
|
||||
} TclOOStubs;
|
||||
|
||||
extern const TclOOStubs *tclOOStubsPtr;
|
||||
@@ -226,6 +229,8 @@ extern const TclOOStubs *tclOOStubsPtr;
|
||||
(tclOOStubsPtr->tcl_ClassSetDestructor) /* 27 */
|
||||
#define Tcl_GetObjectName \
|
||||
(tclOOStubsPtr->tcl_GetObjectName) /* 28 */
|
||||
#define Tcl_MethodIsPrivate \
|
||||
(tclOOStubsPtr->tcl_MethodIsPrivate) /* 29 */
|
||||
|
||||
#endif /* defined(USE_TCLOO_STUBS) */
|
||||
|
||||
|
||||
+284
-100
@@ -16,6 +16,12 @@
|
||||
#include "tclInt.h"
|
||||
#include "tclOOInt.h"
|
||||
|
||||
/*
|
||||
* The actual value used to mark private declaration frames.
|
||||
*/
|
||||
|
||||
#define PRIVATE_FRAME (FRAME_IS_OO_DEFINE | FRAME_IS_PRIVATE_DEFINE)
|
||||
|
||||
/*
|
||||
* The maximum length of fully-qualified object name to use in an errorinfo
|
||||
* message. Longer than this will be curtailed.
|
||||
@@ -118,6 +124,35 @@ static const struct DeclaredSlot slots[] = {
|
||||
SLOT("objdefine::variable", ObjVarsGet, ObjVarsSet),
|
||||
{NULL, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}
|
||||
};
|
||||
|
||||
/*
|
||||
* How to build the in-namespace name of a private variable. This is a pattern
|
||||
* used with Tcl_ObjPrintf().
|
||||
*/
|
||||
|
||||
#define PRIVATE_VARIABLE_PATTERN "%d : %s"
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* IsPrivateDefine --
|
||||
*
|
||||
* Extracts whether the current context is handling private definitions.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static inline int
|
||||
IsPrivateDefine(
|
||||
Tcl_Interp *interp)
|
||||
{
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
|
||||
if (!iPtr->varFramePtr) {
|
||||
return 0;
|
||||
}
|
||||
return iPtr->varFramePtr->isProcCallFrame == PRIVATE_FRAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
@@ -416,6 +451,123 @@ TclOOClassSetMixins(
|
||||
BumpGlobalEpoch(interp, classPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* InstallStandardVariableMapping, InstallPrivateVariableMapping --
|
||||
*
|
||||
* Helpers for installing standard and private variable maps.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
static inline void
|
||||
InstallStandardVariableMapping(
|
||||
VariableNameList *vnlPtr,
|
||||
int varc,
|
||||
Tcl_Obj *const *varv)
|
||||
{
|
||||
Tcl_Obj *variableObj;
|
||||
int i, n, created;
|
||||
Tcl_HashTable uniqueTable;
|
||||
|
||||
for (i=0 ; i<varc ; i++) {
|
||||
Tcl_IncrRefCount(varv[i]);
|
||||
}
|
||||
FOREACH(variableObj, *vnlPtr) {
|
||||
Tcl_DecrRefCount(variableObj);
|
||||
}
|
||||
if (i != varc) {
|
||||
if (varc == 0) {
|
||||
ckfree(vnlPtr->list);
|
||||
} else if (i) {
|
||||
vnlPtr->list = ckrealloc(vnlPtr->list, sizeof(Tcl_Obj *) * varc);
|
||||
} else {
|
||||
vnlPtr->list = ckalloc(sizeof(Tcl_Obj *) * varc);
|
||||
}
|
||||
}
|
||||
vnlPtr->num = 0;
|
||||
if (varc > 0) {
|
||||
Tcl_InitObjHashTable(&uniqueTable);
|
||||
for (i=n=0 ; i<varc ; i++) {
|
||||
Tcl_CreateHashEntry(&uniqueTable, varv[i], &created);
|
||||
if (created) {
|
||||
vnlPtr->list[n++] = varv[i];
|
||||
} else {
|
||||
Tcl_DecrRefCount(varv[i]);
|
||||
}
|
||||
}
|
||||
vnlPtr->num = n;
|
||||
|
||||
/*
|
||||
* Shouldn't be necessary, but maintain num/list invariant.
|
||||
*/
|
||||
|
||||
if (n != varc) {
|
||||
vnlPtr->list = ckrealloc(vnlPtr->list, sizeof(Tcl_Obj *) * n);
|
||||
}
|
||||
Tcl_DeleteHashTable(&uniqueTable);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
InstallPrivateVariableMapping(
|
||||
PrivateVariableList *pvlPtr,
|
||||
int varc,
|
||||
Tcl_Obj *const *varv,
|
||||
int creationEpoch)
|
||||
{
|
||||
PrivateVariableMapping *privatePtr;
|
||||
int i, n, created;
|
||||
Tcl_HashTable uniqueTable;
|
||||
|
||||
for (i=0 ; i<varc ; i++) {
|
||||
Tcl_IncrRefCount(varv[i]);
|
||||
}
|
||||
FOREACH_STRUCT(privatePtr, *pvlPtr) {
|
||||
Tcl_DecrRefCount(privatePtr->variableObj);
|
||||
Tcl_DecrRefCount(privatePtr->fullNameObj);
|
||||
}
|
||||
if (i != varc) {
|
||||
if (varc == 0) {
|
||||
ckfree(pvlPtr->list);
|
||||
} else if (i) {
|
||||
pvlPtr->list = ckrealloc(pvlPtr->list,
|
||||
sizeof(PrivateVariableMapping) * varc);
|
||||
} else {
|
||||
pvlPtr->list = ckalloc(sizeof(PrivateVariableMapping) * varc);
|
||||
}
|
||||
}
|
||||
|
||||
pvlPtr->num = 0;
|
||||
if (varc > 0) {
|
||||
Tcl_InitObjHashTable(&uniqueTable);
|
||||
for (i=n=0 ; i<varc ; i++) {
|
||||
Tcl_CreateHashEntry(&uniqueTable, varv[i], &created);
|
||||
if (created) {
|
||||
privatePtr = &(pvlPtr->list[n++]);
|
||||
privatePtr->variableObj = varv[i];
|
||||
privatePtr->fullNameObj = Tcl_ObjPrintf(
|
||||
PRIVATE_VARIABLE_PATTERN,
|
||||
creationEpoch, Tcl_GetString(varv[i]));
|
||||
Tcl_IncrRefCount(privatePtr->fullNameObj);
|
||||
} else {
|
||||
Tcl_DecrRefCount(varv[i]);
|
||||
}
|
||||
}
|
||||
pvlPtr->num = n;
|
||||
|
||||
/*
|
||||
* Shouldn't be necessary, but maintain num/list invariant.
|
||||
*/
|
||||
|
||||
if (n != varc) {
|
||||
pvlPtr->list = ckrealloc(pvlPtr->list,
|
||||
sizeof(PrivateVariableMapping) * n);
|
||||
}
|
||||
Tcl_DeleteHashTable(&uniqueTable);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
@@ -708,7 +860,8 @@ TclOOGetDefineCmdContext(
|
||||
Tcl_Object object;
|
||||
|
||||
if ((iPtr->varFramePtr == NULL)
|
||||
|| (iPtr->varFramePtr->isProcCallFrame != FRAME_IS_OO_DEFINE)) {
|
||||
|| (iPtr->varFramePtr->isProcCallFrame != FRAME_IS_OO_DEFINE
|
||||
&& iPtr->varFramePtr->isProcCallFrame != PRIVATE_FRAME)) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
"this command may only be called from within the context of"
|
||||
" an ::oo::define or ::oo::objdefine command", -1));
|
||||
@@ -749,7 +902,8 @@ GetClassInOuterContext(
|
||||
Object *oPtr;
|
||||
CallFrame *savedFramePtr = iPtr->varFramePtr;
|
||||
|
||||
while (iPtr->varFramePtr->isProcCallFrame == FRAME_IS_OO_DEFINE) {
|
||||
while (iPtr->varFramePtr->isProcCallFrame == FRAME_IS_OO_DEFINE
|
||||
|| iPtr->varFramePtr->isProcCallFrame == PRIVATE_FRAME) {
|
||||
if (iPtr->varFramePtr->callerVarPtr == NULL) {
|
||||
Tcl_Panic("getting outer context when already in global context");
|
||||
}
|
||||
@@ -1038,7 +1192,7 @@ TclOODefineSelfObjCmd(
|
||||
{
|
||||
Foundation *fPtr = TclOOGetFoundation(interp);
|
||||
Object *oPtr;
|
||||
int result;
|
||||
int result, private;
|
||||
|
||||
oPtr = (Object *) TclOOGetDefineCmdContext(interp);
|
||||
if (oPtr == NULL) {
|
||||
@@ -1050,6 +1204,8 @@ TclOODefineSelfObjCmd(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
private = IsPrivateDefine(interp);
|
||||
|
||||
/*
|
||||
* Make the oo::objdefine namespace the current namespace and evaluate the
|
||||
* command(s).
|
||||
@@ -1058,6 +1214,9 @@ TclOODefineSelfObjCmd(
|
||||
if (InitDefineContext(interp, fPtr->objdefNs, oPtr, objc,objv) != TCL_OK){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (private) {
|
||||
((Interp *) interp)->varFramePtr->isProcCallFrame = PRIVATE_FRAME;
|
||||
}
|
||||
|
||||
AddRef(oPtr);
|
||||
if (objc == 2) {
|
||||
@@ -1065,7 +1224,7 @@ TclOODefineSelfObjCmd(
|
||||
|
||||
Tcl_IncrRefCount(objNameObj);
|
||||
result = TclEvalObjEx(interp, objv[1], 0,
|
||||
((Interp *)interp)->cmdFramePtr, 2);
|
||||
((Interp *)interp)->cmdFramePtr, 1);
|
||||
if (result == TCL_ERROR) {
|
||||
GenerateErrorInfo(interp, oPtr, objNameObj, "class object");
|
||||
}
|
||||
@@ -1117,6 +1276,79 @@ TclOODefineObjSelfObjCmd(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* TclOODefinePrivateObjCmd --
|
||||
*
|
||||
* Implementation of the "private" subcommand of the "oo::define"
|
||||
* and "oo::objdefine" commands.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
TclOODefinePrivateObjCmd(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
int isInstancePrivate = (clientData != NULL);
|
||||
/* Just so that we can generate the correct
|
||||
* error message depending on the context of
|
||||
* usage of this function. */
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
|
||||
int saved; /* The saved flag. We restore it on exit so
|
||||
* that [private private ...] doesn't make
|
||||
* things go weird. */
|
||||
int result;
|
||||
|
||||
if (oPtr == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (objc == 1) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(IsPrivateDefine(interp)));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the frame type flag while evaluating the body.
|
||||
*/
|
||||
|
||||
saved = iPtr->varFramePtr->isProcCallFrame;
|
||||
iPtr->varFramePtr->isProcCallFrame = PRIVATE_FRAME;
|
||||
|
||||
/*
|
||||
* Evaluate the body; standard pattern.
|
||||
*/
|
||||
|
||||
AddRef(oPtr);
|
||||
if (objc == 2) {
|
||||
Tcl_Obj *objNameObj = TclOOObjectName(interp, oPtr);
|
||||
|
||||
Tcl_IncrRefCount(objNameObj);
|
||||
result = TclEvalObjEx(interp, objv[1], 0, iPtr->cmdFramePtr, 1);
|
||||
if (result == TCL_ERROR) {
|
||||
GenerateErrorInfo(interp, oPtr, objNameObj,
|
||||
isInstancePrivate ? "object" : "class");
|
||||
}
|
||||
TclDecrRefCount(objNameObj);
|
||||
} else {
|
||||
result = MagicDefinitionInvoke(interp, TclGetCurrentNamespace(interp),
|
||||
1, objc, objv);
|
||||
}
|
||||
TclOODecrRefCount(oPtr);
|
||||
|
||||
/*
|
||||
* Restore the frame type flag to what it was previously.
|
||||
*/
|
||||
|
||||
iPtr->varFramePtr->isProcCallFrame = saved;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
@@ -1460,8 +1692,9 @@ TclOODefineExportObjCmd(
|
||||
} else {
|
||||
mPtr = Tcl_GetHashValue(hPtr);
|
||||
}
|
||||
if (isNew || !(mPtr->flags & PUBLIC_METHOD)) {
|
||||
if (isNew || !(mPtr->flags & (PUBLIC_METHOD | PRIVATE_METHOD))) {
|
||||
mPtr->flags |= PUBLIC_METHOD;
|
||||
mPtr->flags &= ~TRUE_PRIVATE_METHOD;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
@@ -1521,6 +1754,9 @@ TclOODefineForwardObjCmd(
|
||||
}
|
||||
isPublic = Tcl_StringMatch(TclGetString(objv[1]), "[a-z]*")
|
||||
? PUBLIC_METHOD : 0;
|
||||
if (IsPrivateDefine(interp)) {
|
||||
isPublic = TRUE_PRIVATE_METHOD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the method structure.
|
||||
@@ -1580,6 +1816,9 @@ TclOODefineMethodObjCmd(
|
||||
}
|
||||
isPublic = Tcl_StringMatch(TclGetString(objv[1]), "[a-z]*")
|
||||
? PUBLIC_METHOD : 0;
|
||||
if (IsPrivateDefine(interp)) {
|
||||
isPublic = TRUE_PRIVATE_METHOD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the method by using the right back-end API.
|
||||
@@ -1795,8 +2034,8 @@ TclOODefineUnexportObjCmd(
|
||||
} else {
|
||||
mPtr = Tcl_GetHashValue(hPtr);
|
||||
}
|
||||
if (isNew || mPtr->flags & PUBLIC_METHOD) {
|
||||
mPtr->flags &= ~PUBLIC_METHOD;
|
||||
if (isNew || mPtr->flags & (PUBLIC_METHOD | TRUE_PRIVATE_METHOD)) {
|
||||
mPtr->flags &= ~(PUBLIC_METHOD | TRUE_PRIVATE_METHOD);
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
@@ -2288,7 +2527,7 @@ ClassVarsGet(
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
|
||||
Tcl_Obj *resultObj, *variableObj;
|
||||
Tcl_Obj *resultObj;
|
||||
int i;
|
||||
|
||||
if (Tcl_ObjectContextSkippedArgs(context) != objc) {
|
||||
@@ -2306,8 +2545,18 @@ ClassVarsGet(
|
||||
}
|
||||
|
||||
resultObj = Tcl_NewObj();
|
||||
FOREACH(variableObj, oPtr->classPtr->variables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
|
||||
if (IsPrivateDefine(interp)) {
|
||||
PrivateVariableMapping *privatePtr;
|
||||
|
||||
FOREACH_STRUCT(privatePtr, oPtr->classPtr->privateVariables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, privatePtr->variableObj);
|
||||
}
|
||||
} else {
|
||||
Tcl_Obj *variableObj;
|
||||
|
||||
FOREACH(variableObj, oPtr->classPtr->variables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
|
||||
}
|
||||
}
|
||||
Tcl_SetObjResult(interp, resultObj);
|
||||
return TCL_OK;
|
||||
@@ -2323,7 +2572,7 @@ ClassVarsSet(
|
||||
{
|
||||
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
|
||||
int varc;
|
||||
Tcl_Obj **varv, *variableObj;
|
||||
Tcl_Obj **varv;
|
||||
int i;
|
||||
|
||||
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
|
||||
@@ -2364,49 +2613,11 @@ ClassVarsSet(
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0 ; i<varc ; i++) {
|
||||
Tcl_IncrRefCount(varv[i]);
|
||||
}
|
||||
FOREACH(variableObj, oPtr->classPtr->variables) {
|
||||
Tcl_DecrRefCount(variableObj);
|
||||
}
|
||||
if (i != varc) {
|
||||
if (varc == 0) {
|
||||
ckfree(oPtr->classPtr->variables.list);
|
||||
} else if (i) {
|
||||
oPtr->classPtr->variables.list = (Tcl_Obj **)
|
||||
ckrealloc((char *) oPtr->classPtr->variables.list,
|
||||
sizeof(Tcl_Obj *) * varc);
|
||||
} else {
|
||||
oPtr->classPtr->variables.list = (Tcl_Obj **)
|
||||
ckalloc(sizeof(Tcl_Obj *) * varc);
|
||||
}
|
||||
}
|
||||
|
||||
oPtr->classPtr->variables.num = 0;
|
||||
if (varc > 0) {
|
||||
int created, n;
|
||||
Tcl_HashTable uniqueTable;
|
||||
|
||||
Tcl_InitObjHashTable(&uniqueTable);
|
||||
for (i=n=0 ; i<varc ; i++) {
|
||||
Tcl_CreateHashEntry(&uniqueTable, varv[i], &created);
|
||||
if (created) {
|
||||
oPtr->classPtr->variables.list[n++] = varv[i];
|
||||
} else {
|
||||
Tcl_DecrRefCount(varv[i]);
|
||||
}
|
||||
}
|
||||
oPtr->classPtr->variables.num = n;
|
||||
|
||||
/*
|
||||
* Shouldn't be necessary, but maintain num/list invariant.
|
||||
*/
|
||||
|
||||
oPtr->classPtr->variables.list = (Tcl_Obj **)
|
||||
ckrealloc((char *) oPtr->classPtr->variables.list,
|
||||
sizeof(Tcl_Obj *) * n);
|
||||
Tcl_DeleteHashTable(&uniqueTable);
|
||||
if (IsPrivateDefine(interp)) {
|
||||
InstallPrivateVariableMapping(&oPtr->classPtr->privateVariables,
|
||||
varc, varv, oPtr->classPtr->thisPtr->creationEpoch);
|
||||
} else {
|
||||
InstallStandardVariableMapping(&oPtr->classPtr->variables, varc, varv);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -2585,7 +2796,7 @@ ObjVarsGet(
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
|
||||
Tcl_Obj *resultObj, *variableObj;
|
||||
Tcl_Obj *resultObj;
|
||||
int i;
|
||||
|
||||
if (Tcl_ObjectContextSkippedArgs(context) != objc) {
|
||||
@@ -2597,8 +2808,18 @@ ObjVarsGet(
|
||||
}
|
||||
|
||||
resultObj = Tcl_NewObj();
|
||||
FOREACH(variableObj, oPtr->variables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
|
||||
if (IsPrivateDefine(interp)) {
|
||||
PrivateVariableMapping *privatePtr;
|
||||
|
||||
FOREACH_STRUCT(privatePtr, oPtr->privateVariables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, privatePtr->variableObj);
|
||||
}
|
||||
} else {
|
||||
Tcl_Obj *variableObj;
|
||||
|
||||
FOREACH(variableObj, oPtr->variables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
|
||||
}
|
||||
}
|
||||
Tcl_SetObjResult(interp, resultObj);
|
||||
return TCL_OK;
|
||||
@@ -2614,7 +2835,7 @@ ObjVarsSet(
|
||||
{
|
||||
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
|
||||
int varc, i;
|
||||
Tcl_Obj **varv, *variableObj;
|
||||
Tcl_Obj **varv;
|
||||
|
||||
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
|
||||
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
|
||||
@@ -2647,49 +2868,12 @@ ObjVarsSet(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
for (i=0 ; i<varc ; i++) {
|
||||
Tcl_IncrRefCount(varv[i]);
|
||||
}
|
||||
|
||||
FOREACH(variableObj, oPtr->variables) {
|
||||
Tcl_DecrRefCount(variableObj);
|
||||
}
|
||||
if (i != varc) {
|
||||
if (varc == 0) {
|
||||
ckfree(oPtr->variables.list);
|
||||
} else if (i) {
|
||||
oPtr->variables.list = (Tcl_Obj **)
|
||||
ckrealloc((char *) oPtr->variables.list,
|
||||
sizeof(Tcl_Obj *) * varc);
|
||||
} else {
|
||||
oPtr->variables.list = (Tcl_Obj **)
|
||||
ckalloc(sizeof(Tcl_Obj *) * varc);
|
||||
}
|
||||
}
|
||||
oPtr->variables.num = 0;
|
||||
if (varc > 0) {
|
||||
int created, n;
|
||||
Tcl_HashTable uniqueTable;
|
||||
|
||||
Tcl_InitObjHashTable(&uniqueTable);
|
||||
for (i=n=0 ; i<varc ; i++) {
|
||||
Tcl_CreateHashEntry(&uniqueTable, varv[i], &created);
|
||||
if (created) {
|
||||
oPtr->variables.list[n++] = varv[i];
|
||||
} else {
|
||||
Tcl_DecrRefCount(varv[i]);
|
||||
}
|
||||
}
|
||||
oPtr->variables.num = n;
|
||||
|
||||
/*
|
||||
* Shouldn't be necessary, but maintain num/list invariant.
|
||||
*/
|
||||
|
||||
oPtr->variables.list = (Tcl_Obj **)
|
||||
ckrealloc((char *) oPtr->variables.list,
|
||||
sizeof(Tcl_Obj *) * n);
|
||||
Tcl_DeleteHashTable(&uniqueTable);
|
||||
if (IsPrivateDefine(interp)) {
|
||||
InstallPrivateVariableMapping(&oPtr->privateVariables, varc, varv,
|
||||
oPtr->creationEpoch);
|
||||
} else {
|
||||
InstallStandardVariableMapping(&oPtr->variables, varc, varv);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
+165
-27
@@ -22,6 +22,7 @@ static Tcl_ObjCmdProc InfoObjectClassCmd;
|
||||
static Tcl_ObjCmdProc InfoObjectDefnCmd;
|
||||
static Tcl_ObjCmdProc InfoObjectFiltersCmd;
|
||||
static Tcl_ObjCmdProc InfoObjectForwardCmd;
|
||||
static Tcl_ObjCmdProc InfoObjectIdCmd;
|
||||
static Tcl_ObjCmdProc InfoObjectIsACmd;
|
||||
static Tcl_ObjCmdProc InfoObjectMethodsCmd;
|
||||
static Tcl_ObjCmdProc InfoObjectMethodTypeCmd;
|
||||
@@ -50,6 +51,7 @@ static Tcl_ObjCmdProc InfoClassVariablesCmd;
|
||||
static const EnsembleImplMap infoObjectCmds[] = {
|
||||
{"call", InfoObjectCallCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
|
||||
{"class", InfoObjectClassCmd, TclCompileInfoObjectClassCmd, NULL, NULL, 0},
|
||||
{"creationid", InfoObjectIdCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
|
||||
{"definition", InfoObjectDefnCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
|
||||
{"filters", InfoObjectFiltersCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
|
||||
{"forward", InfoObjectForwardCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
|
||||
@@ -58,7 +60,7 @@ static const EnsembleImplMap infoObjectCmds[] = {
|
||||
{"methodtype", InfoObjectMethodTypeCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
|
||||
{"mixins", InfoObjectMixinsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
|
||||
{"namespace", InfoObjectNsCmd, TclCompileInfoObjectNamespaceCmd, NULL, NULL, 0},
|
||||
{"variables", InfoObjectVariablesCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
|
||||
{"variables", InfoObjectVariablesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
|
||||
{"vars", InfoObjectVarsCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
|
||||
{NULL, NULL, NULL, NULL, NULL, 0}
|
||||
};
|
||||
@@ -80,7 +82,7 @@ static const EnsembleImplMap infoClassCmds[] = {
|
||||
{"mixins", InfoClassMixinsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
|
||||
{"subclasses", InfoClassSubsCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
|
||||
{"superclasses", InfoClassSupersCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
|
||||
{"variables", InfoClassVariablesCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
|
||||
{"variables", InfoClassVariablesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
|
||||
{NULL, NULL, NULL, NULL, NULL, 0}
|
||||
};
|
||||
|
||||
@@ -517,15 +519,22 @@ InfoObjectMethodsCmd(
|
||||
Tcl_Obj *const objv[])
|
||||
{
|
||||
Object *oPtr;
|
||||
int flag = PUBLIC_METHOD, recurse = 0;
|
||||
int flag = PUBLIC_METHOD, recurse = 0, scope = -1;
|
||||
FOREACH_HASH_DECLS;
|
||||
Tcl_Obj *namePtr, *resultObj;
|
||||
Method *mPtr;
|
||||
static const char *const options[] = {
|
||||
"-all", "-localprivate", "-private", NULL
|
||||
"-all", "-localprivate", "-private", "-scope", NULL
|
||||
};
|
||||
enum Options {
|
||||
OPT_ALL, OPT_LOCALPRIVATE, OPT_PRIVATE
|
||||
OPT_ALL, OPT_LOCALPRIVATE, OPT_PRIVATE, OPT_SCOPE
|
||||
};
|
||||
static const char *const scopes[] = {
|
||||
"private", "public", "unexported"
|
||||
};
|
||||
enum Scopes {
|
||||
SCOPE_PRIVATE, SCOPE_PUBLIC, SCOPE_UNEXPORTED,
|
||||
SCOPE_LOCALPRIVATE
|
||||
};
|
||||
|
||||
if (objc < 2) {
|
||||
@@ -554,14 +563,45 @@ InfoObjectMethodsCmd(
|
||||
case OPT_PRIVATE:
|
||||
flag = 0;
|
||||
break;
|
||||
case OPT_SCOPE:
|
||||
if (++i >= objc) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"missing option for -scope"));
|
||||
Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING",
|
||||
NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i], scopes, "scope", 0,
|
||||
&scope) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scope != -1) {
|
||||
recurse = 0;
|
||||
switch (scope) {
|
||||
case SCOPE_PRIVATE:
|
||||
flag = TRUE_PRIVATE_METHOD;
|
||||
break;
|
||||
case SCOPE_PUBLIC:
|
||||
flag = PUBLIC_METHOD;
|
||||
break;
|
||||
case SCOPE_LOCALPRIVATE:
|
||||
flag = PRIVATE_METHOD;
|
||||
break;
|
||||
case SCOPE_UNEXPORTED:
|
||||
flag = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resultObj = Tcl_NewObj();
|
||||
if (recurse) {
|
||||
const char **names;
|
||||
int i, numNames = TclOOGetSortedMethodList(oPtr, flag, &names);
|
||||
int i, numNames = TclOOGetSortedMethodList(oPtr, NULL, NULL, flag,
|
||||
&names);
|
||||
|
||||
for (i=0 ; i<numNames ; i++) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj,
|
||||
@@ -572,7 +612,7 @@ InfoObjectMethodsCmd(
|
||||
}
|
||||
} else if (oPtr->methodsPtr) {
|
||||
FOREACH_HASH(namePtr, mPtr, oPtr->methodsPtr) {
|
||||
if (mPtr->typePtr != NULL && (mPtr->flags & flag) == flag) {
|
||||
if (mPtr->typePtr && (mPtr->flags & SCOPE_FLAGS) == flag) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, namePtr);
|
||||
}
|
||||
}
|
||||
@@ -681,6 +721,38 @@ InfoObjectMixinsCmd(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* InfoObjectIdCmd --
|
||||
*
|
||||
* Implements [info object creationid $objName]
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int
|
||||
InfoObjectIdCmd(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *const objv[])
|
||||
{
|
||||
Object *oPtr;
|
||||
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "objName");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
|
||||
if (oPtr == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(oPtr->creationEpoch));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
@@ -719,7 +791,7 @@ InfoObjectNsCmd(
|
||||
*
|
||||
* InfoObjectVariablesCmd --
|
||||
*
|
||||
* Implements [info object variables $objName]
|
||||
* Implements [info object variables $objName ?-private?]
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -732,21 +804,37 @@ InfoObjectVariablesCmd(
|
||||
Tcl_Obj *const objv[])
|
||||
{
|
||||
Object *oPtr;
|
||||
Tcl_Obj *variableObj, *resultObj;
|
||||
int i;
|
||||
Tcl_Obj *resultObj;
|
||||
int i, private = 0;
|
||||
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "objName");
|
||||
if (objc != 2 && objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "objName ?-private?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (objc == 3) {
|
||||
if (strcmp("-private", Tcl_GetString(objv[2])) != 0) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
private = 1;
|
||||
}
|
||||
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
|
||||
if (oPtr == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
resultObj = Tcl_NewObj();
|
||||
FOREACH(variableObj, oPtr->variables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
|
||||
if (private) {
|
||||
PrivateVariableMapping *privatePtr;
|
||||
|
||||
FOREACH_STRUCT(privatePtr, oPtr->privateVariables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, privatePtr->variableObj);
|
||||
}
|
||||
} else {
|
||||
Tcl_Obj *variableObj;
|
||||
|
||||
FOREACH(variableObj, oPtr->variables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
|
||||
}
|
||||
}
|
||||
Tcl_SetObjResult(interp, resultObj);
|
||||
return TCL_OK;
|
||||
@@ -1128,7 +1216,7 @@ InfoClassInstancesCmd(
|
||||
*
|
||||
* InfoClassMethodsCmd --
|
||||
*
|
||||
* Implements [info class methods $clsName ?-private?]
|
||||
* Implements [info class methods $clsName ?options...?]
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1140,15 +1228,21 @@ InfoClassMethodsCmd(
|
||||
int objc,
|
||||
Tcl_Obj *const objv[])
|
||||
{
|
||||
int flag = PUBLIC_METHOD, recurse = 0;
|
||||
int flag = PUBLIC_METHOD, recurse = 0, scope = -1;
|
||||
Tcl_Obj *namePtr, *resultObj;
|
||||
Method *mPtr;
|
||||
Class *clsPtr;
|
||||
static const char *const options[] = {
|
||||
"-all", "-localprivate", "-private", NULL
|
||||
"-all", "-localprivate", "-private", "-scope", NULL
|
||||
};
|
||||
enum Options {
|
||||
OPT_ALL, OPT_LOCALPRIVATE, OPT_PRIVATE
|
||||
OPT_ALL, OPT_LOCALPRIVATE, OPT_PRIVATE, OPT_SCOPE
|
||||
};
|
||||
static const char *const scopes[] = {
|
||||
"private", "public", "unexported"
|
||||
};
|
||||
enum Scopes {
|
||||
SCOPE_PRIVATE, SCOPE_PUBLIC, SCOPE_UNEXPORTED
|
||||
};
|
||||
|
||||
if (objc < 2) {
|
||||
@@ -1177,9 +1271,36 @@ InfoClassMethodsCmd(
|
||||
case OPT_PRIVATE:
|
||||
flag = 0;
|
||||
break;
|
||||
case OPT_SCOPE:
|
||||
if (++i >= objc) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"missing option for -scope"));
|
||||
Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING",
|
||||
NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i], scopes, "scope", 0,
|
||||
&scope) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scope != -1) {
|
||||
recurse = 0;
|
||||
switch (scope) {
|
||||
case SCOPE_PRIVATE:
|
||||
flag = TRUE_PRIVATE_METHOD;
|
||||
break;
|
||||
case SCOPE_PUBLIC:
|
||||
flag = PUBLIC_METHOD;
|
||||
break;
|
||||
case SCOPE_UNEXPORTED:
|
||||
flag = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resultObj = Tcl_NewObj();
|
||||
if (recurse) {
|
||||
@@ -1197,7 +1318,7 @@ InfoClassMethodsCmd(
|
||||
FOREACH_HASH_DECLS;
|
||||
|
||||
FOREACH_HASH(namePtr, mPtr, &clsPtr->classMethods) {
|
||||
if (mPtr->typePtr != NULL && (mPtr->flags & flag) == flag) {
|
||||
if (mPtr->typePtr && (mPtr->flags & SCOPE_FLAGS) == flag) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, namePtr);
|
||||
}
|
||||
}
|
||||
@@ -1399,7 +1520,7 @@ InfoClassSupersCmd(
|
||||
*
|
||||
* InfoClassVariablesCmd --
|
||||
*
|
||||
* Implements [info class variables $clsName]
|
||||
* Implements [info class variables $clsName ?-private?]
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1412,21 +1533,37 @@ InfoClassVariablesCmd(
|
||||
Tcl_Obj *const objv[])
|
||||
{
|
||||
Class *clsPtr;
|
||||
Tcl_Obj *variableObj, *resultObj;
|
||||
int i;
|
||||
Tcl_Obj *resultObj;
|
||||
int i, private = 0;
|
||||
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "className");
|
||||
if (objc != 2 && objc != 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "className ?-private?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (objc == 3) {
|
||||
if (strcmp("-private", Tcl_GetString(objv[2])) != 0) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
private = 1;
|
||||
}
|
||||
clsPtr = GetClassFromObj(interp, objv[1]);
|
||||
if (clsPtr == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
resultObj = Tcl_NewObj();
|
||||
FOREACH(variableObj, clsPtr->variables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
|
||||
if (private) {
|
||||
PrivateVariableMapping *privatePtr;
|
||||
|
||||
FOREACH_STRUCT(privatePtr, clsPtr->privateVariables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, privatePtr->variableObj);
|
||||
}
|
||||
} else {
|
||||
Tcl_Obj *variableObj;
|
||||
|
||||
FOREACH(variableObj, clsPtr->variables) {
|
||||
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
|
||||
}
|
||||
}
|
||||
Tcl_SetObjResult(interp, resultObj);
|
||||
return TCL_OK;
|
||||
@@ -1465,7 +1602,8 @@ InfoObjectCallCmd(
|
||||
* Get the call context and render its call chain.
|
||||
*/
|
||||
|
||||
contextPtr = TclOOGetCallContext(oPtr, objv[2], PUBLIC_METHOD, NULL);
|
||||
contextPtr = TclOOGetCallContext(oPtr, objv[2], PUBLIC_METHOD, NULL, NULL,
|
||||
NULL);
|
||||
if (contextPtr == NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
"cannot construct any call chain", -1));
|
||||
|
||||
+54
-4
@@ -124,6 +124,18 @@ typedef struct ForwardMethod {
|
||||
* non-empty list. */
|
||||
} ForwardMethod;
|
||||
|
||||
/*
|
||||
* Structure used in private variable mappings. Describes the mapping of a
|
||||
* single variable from the user's local name to the system's storage name.
|
||||
* [TIP #500]
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
Tcl_Obj *variableObj; /* Name used within methods. This is the part
|
||||
* that is properly under user control. */
|
||||
Tcl_Obj *fullNameObj; /* Name used at the instance namespace level. */
|
||||
} PrivateVariableMapping;
|
||||
|
||||
/*
|
||||
* Helper definitions that declare a "list" array. The two varieties are
|
||||
* either optimized for simplicity (in the case that the whole array is
|
||||
@@ -141,6 +153,13 @@ typedef struct ForwardMethod {
|
||||
#define LIST_DYNAMIC(listType_t) \
|
||||
struct { int num, size; listType_t *list; }
|
||||
|
||||
/*
|
||||
* These types are needed in function arguments.
|
||||
*/
|
||||
|
||||
typedef LIST_STATIC(Tcl_Obj *) VariableNameList;
|
||||
typedef LIST_STATIC(PrivateVariableMapping) PrivateVariableList;
|
||||
|
||||
/*
|
||||
* Now, the definition of what an object actually is.
|
||||
*/
|
||||
@@ -186,7 +205,10 @@ typedef struct Object {
|
||||
Tcl_ObjectMapMethodNameProc *mapMethodNameProc;
|
||||
/* Function to allow remapping of method
|
||||
* names. For itcl-ng. */
|
||||
LIST_STATIC(Tcl_Obj *) variables;
|
||||
VariableNameList variables;
|
||||
PrivateVariableList privateVariables;
|
||||
/* Configurations for the variable resolver
|
||||
* used inside methods. */
|
||||
} Object;
|
||||
|
||||
#define OBJECT_DELETED 1 /* Flag to say that an object has been
|
||||
@@ -214,6 +236,10 @@ typedef struct Object {
|
||||
* other spots). */
|
||||
#define FORCE_UNKNOWN 0x10000 /* States that we are *really* looking up the
|
||||
* unknown method handler at that point. */
|
||||
#define HAS_PRIVATE_METHODS 0x20000
|
||||
/* Object/class has (or had) private methods,
|
||||
* and so shouldn't be cached so
|
||||
* aggressively. */
|
||||
|
||||
/*
|
||||
* And the definition of a class. Note that every class also has an associated
|
||||
@@ -268,7 +294,10 @@ typedef struct Class {
|
||||
* object doesn't override with its own mixins
|
||||
* (and filters and method implementations for
|
||||
* when getting method chains). */
|
||||
LIST_STATIC(Tcl_Obj *) variables;
|
||||
VariableNameList variables;
|
||||
PrivateVariableList privateVariables;
|
||||
/* Configurations for the variable resolver
|
||||
* used inside methods. */
|
||||
} Class;
|
||||
|
||||
/*
|
||||
@@ -370,10 +399,15 @@ typedef struct CallContext {
|
||||
|
||||
#define PUBLIC_METHOD 0x01 /* This is a public (exported) method. */
|
||||
#define PRIVATE_METHOD 0x02 /* This is a private (class's direct instances
|
||||
* only) method. */
|
||||
* only) method. Supports itcl. */
|
||||
#define OO_UNKNOWN_METHOD 0x04 /* This is an unknown method. */
|
||||
#define CONSTRUCTOR 0x08 /* This is a constructor. */
|
||||
#define DESTRUCTOR 0x10 /* This is a destructor. */
|
||||
#define TRUE_PRIVATE_METHOD 0x20
|
||||
/* This is a private method only accessible
|
||||
* from other methods defined on this class
|
||||
* or instance. [TIP #500] */
|
||||
#define SCOPE_FLAGS (PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD)
|
||||
|
||||
/*
|
||||
* Structure containing definition information about basic class methods.
|
||||
@@ -431,6 +465,9 @@ MODULE_SCOPE int TclOODefineSelfObjCmd(ClientData clientData,
|
||||
MODULE_SCOPE int TclOODefineObjSelfObjCmd(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const *objv);
|
||||
MODULE_SCOPE int TclOODefinePrivateObjCmd(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const *objv);
|
||||
MODULE_SCOPE int TclOOUnknownDefinition(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const *objv);
|
||||
@@ -504,6 +541,7 @@ MODULE_SCOPE void TclOODeleteContext(CallContext *contextPtr);
|
||||
MODULE_SCOPE void TclOODelMethodRef(Method *method);
|
||||
MODULE_SCOPE CallContext *TclOOGetCallContext(Object *oPtr,
|
||||
Tcl_Obj *methodNameObj, int flags,
|
||||
Object *contextObjPtr, Class *contextClsPtr,
|
||||
Tcl_Obj *cacheInThisObj);
|
||||
MODULE_SCOPE CallChain *TclOOGetStereotypeCallChain(Class *clsPtr,
|
||||
Tcl_Obj *methodNameObj, int flags);
|
||||
@@ -513,7 +551,8 @@ MODULE_SCOPE Proc * TclOOGetProcFromMethod(Method *mPtr);
|
||||
MODULE_SCOPE Tcl_Obj * TclOOGetMethodBody(Method *mPtr);
|
||||
MODULE_SCOPE int TclOOGetSortedClassMethodList(Class *clsPtr,
|
||||
int flags, const char ***stringsPtr);
|
||||
MODULE_SCOPE int TclOOGetSortedMethodList(Object *oPtr, int flags,
|
||||
MODULE_SCOPE int TclOOGetSortedMethodList(Object *oPtr,
|
||||
Object *contextObj, Class *contextCls, int flags,
|
||||
const char ***stringsPtr);
|
||||
MODULE_SCOPE int TclOOInit(Tcl_Interp *interp);
|
||||
MODULE_SCOPE void TclOOInitInfo(Tcl_Interp *interp);
|
||||
@@ -560,11 +599,22 @@ MODULE_SCOPE void TclOOSetupVariableResolver(Tcl_Namespace *nsPtr);
|
||||
continue; \
|
||||
} else if (var = (ary).list[i], 1)
|
||||
|
||||
/*
|
||||
* A variation where the array is an array of structs. There's no issue with
|
||||
* possible NULLs; every element of the array will be iterated over and the
|
||||
* varable set to a pointer to each of those elements in turn.
|
||||
* REQUIRES DECLARATION: int i;
|
||||
*/
|
||||
|
||||
#define FOREACH_STRUCT(var,ary) \
|
||||
for(i=0 ; var=&((ary).list[i]), i<(ary).num; i++)
|
||||
|
||||
/*
|
||||
* Convenience macros for iterating through hash tables. FOREACH_HASH_DECLS
|
||||
* sets up the declarations needed for the main macro, FOREACH_HASH, which
|
||||
* does the actual iteration. FOREACH_HASH_VALUE is a restricted version that
|
||||
* only iterates over values.
|
||||
* REQUIRES DECLARATION: FOREACH_HASH_DECLS;
|
||||
*/
|
||||
|
||||
#define FOREACH_HASH_DECLS \
|
||||
|
||||
+36
-3
@@ -186,7 +186,11 @@ Tcl_NewInstanceMethod(
|
||||
mPtr->declaringObjectPtr = oPtr;
|
||||
mPtr->declaringClassPtr = NULL;
|
||||
if (flags) {
|
||||
mPtr->flags |= flags & (PUBLIC_METHOD | PRIVATE_METHOD);
|
||||
mPtr->flags |= flags &
|
||||
(PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD);
|
||||
if (flags & TRUE_PRIVATE_METHOD) {
|
||||
oPtr->flags |= HAS_PRIVATE_METHODS;
|
||||
}
|
||||
}
|
||||
oPtr->epoch++;
|
||||
return (Tcl_Method) mPtr;
|
||||
@@ -250,7 +254,11 @@ Tcl_NewMethod(
|
||||
mPtr->declaringObjectPtr = NULL;
|
||||
mPtr->declaringClassPtr = clsPtr;
|
||||
if (flags) {
|
||||
mPtr->flags |= flags & (PUBLIC_METHOD | PRIVATE_METHOD);
|
||||
mPtr->flags |= flags &
|
||||
(PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD);
|
||||
if (flags & TRUE_PRIVATE_METHOD) {
|
||||
clsPtr->flags |= HAS_PRIVATE_METHODS;
|
||||
}
|
||||
}
|
||||
|
||||
return (Tcl_Method) mPtr;
|
||||
@@ -928,7 +936,7 @@ PushMethodCallFrame(
|
||||
* variables used in methods. The compiled variable resolver is more
|
||||
* important, but both are needed as it is possible to have a variable
|
||||
* that is only referred to in ways that aren't compilable and we can't
|
||||
* force LVT presence. [TIP #320]
|
||||
* force LVT presence. [TIP #320, #500]
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -986,6 +994,7 @@ ProcedureMethodCompiledVarConnect(
|
||||
CallFrame *framePtr = iPtr->varFramePtr;
|
||||
CallContext *contextPtr;
|
||||
Tcl_Obj *variableObj;
|
||||
PrivateVariableMapping *privateVar;
|
||||
Tcl_HashEntry *hPtr;
|
||||
int i, isNew, cacheIt, varLen, len;
|
||||
const char *match, *varName;
|
||||
@@ -1019,6 +1028,15 @@ ProcedureMethodCompiledVarConnect(
|
||||
varName = TclGetStringFromObj(infoPtr->variableObj, &varLen);
|
||||
if (contextPtr->callPtr->chain[contextPtr->index]
|
||||
.mPtr->declaringClassPtr != NULL) {
|
||||
FOREACH_STRUCT(privateVar, contextPtr->callPtr->chain[contextPtr->index]
|
||||
.mPtr->declaringClassPtr->privateVariables) {
|
||||
match = TclGetStringFromObj(privateVar->variableObj, &len);
|
||||
if ((len == varLen) && !memcmp(match, varName, len)) {
|
||||
variableObj = privateVar->fullNameObj;
|
||||
cacheIt = 0;
|
||||
goto gotMatch;
|
||||
}
|
||||
}
|
||||
FOREACH(variableObj, contextPtr->callPtr->chain[contextPtr->index]
|
||||
.mPtr->declaringClassPtr->variables) {
|
||||
match = TclGetStringFromObj(variableObj, &len);
|
||||
@@ -1028,6 +1046,14 @@ ProcedureMethodCompiledVarConnect(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FOREACH_STRUCT(privateVar, contextPtr->oPtr->privateVariables) {
|
||||
match = TclGetStringFromObj(privateVar->variableObj, &len);
|
||||
if ((len == varLen) && !memcmp(match, varName, len)) {
|
||||
variableObj = privateVar->fullNameObj;
|
||||
cacheIt = 1;
|
||||
goto gotMatch;
|
||||
}
|
||||
}
|
||||
FOREACH(variableObj, contextPtr->oPtr->variables) {
|
||||
match = TclGetStringFromObj(variableObj, &len);
|
||||
if ((len == varLen) && !memcmp(match, varName, len)) {
|
||||
@@ -1673,6 +1699,13 @@ Tcl_MethodIsPublic(
|
||||
{
|
||||
return (((Method *)method)->flags & PUBLIC_METHOD) ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
Tcl_MethodIsPrivate(
|
||||
Tcl_Method method)
|
||||
{
|
||||
return (((Method *)method)->flags & TRUE_PRIVATE_METHOD) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended method construction for itcl-ng.
|
||||
|
||||
@@ -73,6 +73,7 @@ const TclOOStubs tclOOStubs = {
|
||||
Tcl_ClassSetConstructor, /* 26 */
|
||||
Tcl_ClassSetDestructor, /* 27 */
|
||||
Tcl_GetObjectName, /* 28 */
|
||||
Tcl_MethodIsPrivate, /* 29 */
|
||||
};
|
||||
|
||||
/* !END!: Do not edit above this line. */
|
||||
|
||||
+11
-11
@@ -37,7 +37,7 @@ Tcl_Obj *tclFreeObjList = NULL;
|
||||
* TclNewObj macro, however, so must be visible.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
MODULE_SCOPE Tcl_Mutex tclObjMutex;
|
||||
Tcl_Mutex tclObjMutex;
|
||||
#endif
|
||||
@@ -50,7 +50,7 @@ Tcl_Mutex tclObjMutex;
|
||||
|
||||
char tclEmptyString = '\0';
|
||||
|
||||
#if defined(TCL_MEM_DEBUG) && defined(TCL_THREADS)
|
||||
#if TCL_THREADS && defined(TCL_MEM_DEBUG)
|
||||
/*
|
||||
* Structure for tracking the source file and line number where a given
|
||||
* Tcl_Obj was allocated. We also track the pointer to the Tcl_Obj itself,
|
||||
@@ -87,7 +87,7 @@ typedef struct {
|
||||
* tclCompile.h for the definition of this
|
||||
* structure, and for references to all
|
||||
* related places in the core. */
|
||||
#if defined(TCL_MEM_DEBUG) && defined(TCL_THREADS)
|
||||
#if TCL_THREADS && defined(TCL_MEM_DEBUG)
|
||||
Tcl_HashTable *objThreadMap;/* Thread local table that is used to check
|
||||
* that a Tcl_Obj was not allocated by some
|
||||
* other thread. */
|
||||
@@ -156,7 +156,7 @@ typedef struct PendingObjData {
|
||||
/*
|
||||
* Macro to set up the local reference to the deletion context.
|
||||
*/
|
||||
#ifndef TCL_THREADS
|
||||
#if !TCL_THREADS
|
||||
static PendingObjData pendingObjData;
|
||||
#define ObjInitDeletionContext(contextPtr) \
|
||||
PendingObjData *const contextPtr = &pendingObjData
|
||||
@@ -452,7 +452,7 @@ TclInitObjSubsystem(void)
|
||||
void
|
||||
TclFinalizeThreadObjects(void)
|
||||
{
|
||||
#if defined(TCL_MEM_DEBUG) && defined(TCL_THREADS)
|
||||
#if TCL_THREADS && defined(TCL_MEM_DEBUG)
|
||||
Tcl_HashEntry *hPtr;
|
||||
Tcl_HashSearch hSearch;
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
@@ -1009,7 +1009,7 @@ void
|
||||
TclDbDumpActiveObjects(
|
||||
FILE *outFile)
|
||||
{
|
||||
#if defined(TCL_MEM_DEBUG) && defined(TCL_THREADS)
|
||||
#if TCL_THREADS && defined(TCL_MEM_DEBUG)
|
||||
Tcl_HashSearch hSearch;
|
||||
Tcl_HashEntry *hPtr;
|
||||
Tcl_HashTable *tablePtr;
|
||||
@@ -1069,7 +1069,7 @@ TclDbInitNewObj(
|
||||
objPtr->length = 0;
|
||||
objPtr->typePtr = NULL;
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Add entry to a thread local map used to check if a Tcl_Obj was
|
||||
* allocated by the currently executing thread.
|
||||
@@ -1305,7 +1305,7 @@ TclFreeObj(
|
||||
|
||||
ObjInitDeletionContext(context);
|
||||
|
||||
# ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Check to make sure that the Tcl_Obj was allocated by the current
|
||||
* thread. Don't do this check when shutting down since thread local
|
||||
@@ -3598,7 +3598,7 @@ Tcl_DbIncrRefCount(
|
||||
Tcl_Panic("incrementing refCount of previously disposed object");
|
||||
}
|
||||
|
||||
# ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Check to make sure that the Tcl_Obj was allocated by the current
|
||||
* thread. Don't do this check when shutting down since thread local
|
||||
@@ -3661,7 +3661,7 @@ Tcl_DbDecrRefCount(
|
||||
Tcl_Panic("decrementing refCount of previously disposed object");
|
||||
}
|
||||
|
||||
# ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Check to make sure that the Tcl_Obj was allocated by the current
|
||||
* thread. Don't do this check when shutting down since thread local
|
||||
@@ -3726,7 +3726,7 @@ Tcl_DbIsShared(
|
||||
Tcl_Panic("checking whether previously disposed object is shared");
|
||||
}
|
||||
|
||||
# ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Check to make sure that the Tcl_Obj was allocated by the current
|
||||
* thread. Don't do this check when shutting down since thread local
|
||||
|
||||
+3
-2
@@ -23,8 +23,8 @@
|
||||
* procedure.
|
||||
*/
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
static TCL_NORETURN Tcl_PanicProc *panicProc = tclWinDebugPanic;
|
||||
#if defined(__CYGWIN__) || (defined(_WIN32) && (defined(TCL_NO_DEPRECATED) || TCL_MAJOR_VERSION > 8))
|
||||
static TCL_NORETURN1 Tcl_PanicProc *panicProc = tclWinDebugPanic;
|
||||
#else
|
||||
static TCL_NORETURN1 Tcl_PanicProc *panicProc = NULL;
|
||||
#endif
|
||||
@@ -45,6 +45,7 @@ static TCL_NORETURN1 Tcl_PanicProc *panicProc = NULL;
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#undef Tcl_SetPanicProc
|
||||
void
|
||||
Tcl_SetPanicProc(
|
||||
TCL_NORETURN1 Tcl_PanicProc *proc)
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
* configuration information.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
# define CFG_THREADED "1"
|
||||
#else
|
||||
# define CFG_THREADED "0"
|
||||
|
||||
+2
-2
@@ -4543,7 +4543,7 @@ Tcl_InitBignumFromDouble(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
fract = frexp(d,&expt);
|
||||
fract = frexp(d, &expt);
|
||||
if (expt <= 0) {
|
||||
mp_init(b);
|
||||
mp_zero(b);
|
||||
@@ -4883,7 +4883,7 @@ Pow10TimesFrExp(
|
||||
* Multiply by 10**exponent.
|
||||
*/
|
||||
|
||||
retval = frexp(retval * pow10vals[exponent&0xf], &j);
|
||||
retval = frexp(retval * pow10vals[exponent & 0xf], &j);
|
||||
expt += j;
|
||||
for (i=4; i<9; ++i) {
|
||||
if (exponent & (1<<i)) {
|
||||
|
||||
+342
-85
@@ -455,6 +455,48 @@ Tcl_GetCharLength(
|
||||
return numChars;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclCheckEmptyString --
|
||||
*
|
||||
* Determine whether the string value of an object is or would be the
|
||||
* empty string, without generating a string representation.
|
||||
*
|
||||
* Results:
|
||||
* Returns 1 if empty, 0 if not, and -1 if unknown.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
TclCheckEmptyString(
|
||||
Tcl_Obj *objPtr)
|
||||
{
|
||||
int length = -1;
|
||||
|
||||
if (objPtr->bytes == &tclEmptyString) {
|
||||
return TCL_EMPTYSTRING_YES;
|
||||
}
|
||||
|
||||
if (TclListObjIsCanonical(objPtr)) {
|
||||
Tcl_ListObjLength(NULL, objPtr, &length);
|
||||
return length == 0;
|
||||
}
|
||||
|
||||
if (TclIsPureDict(objPtr)) {
|
||||
Tcl_DictObjSize(NULL, objPtr, &length);
|
||||
return length == 0;
|
||||
}
|
||||
|
||||
if (objPtr->bytes == NULL) {
|
||||
return TCL_EMPTYSTRING_UNKNOWN;
|
||||
}
|
||||
return objPtr->length == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -525,20 +567,22 @@ Tcl_GetUniChar(
|
||||
if (index >= stringPtr->numChars) {
|
||||
return -1;
|
||||
}
|
||||
ch = stringPtr->unicode[index];
|
||||
ch = stringPtr->unicode[index];
|
||||
#if TCL_UTF_MAX <= 4
|
||||
/* See: bug [11ae2be95dac9417] */
|
||||
if ((ch&0xF800) == 0xD800) {
|
||||
if (ch&0x400) {
|
||||
if ((index > 0) && ((stringPtr->unicode[index-1]&0xFC00) == 0xD800)) {
|
||||
ch = -1; /* low surrogate preceded by high surrogate */
|
||||
}
|
||||
} else if ((++index < stringPtr->numChars)
|
||||
&& ((stringPtr->unicode[index]&0xFC00) == 0xDC00)) {
|
||||
/* high surrogate followed by low surrogate */
|
||||
ch = (((ch & 0x3FF) << 10) | (stringPtr->unicode[index] & 0x3FF)) + 0x10000;
|
||||
/* See: bug [11ae2be95dac9417] */
|
||||
if ((ch & 0xF800) == 0xD800) {
|
||||
if (ch & 0x400) {
|
||||
if ((index > 0)
|
||||
&& ((stringPtr->unicode[index-1] & 0xFC00) == 0xD800)) {
|
||||
ch = -1; /* low surrogate preceded by high surrogate */
|
||||
}
|
||||
} else if ((++index < stringPtr->numChars)
|
||||
&& ((stringPtr->unicode[index] & 0xFC00) == 0xDC00)) {
|
||||
/* high surrogate followed by low surrogate */
|
||||
ch = (((ch & 0x3FF) << 10) |
|
||||
(stringPtr->unicode[index] & 0x3FF)) + 0x10000;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ch;
|
||||
}
|
||||
@@ -644,7 +688,8 @@ Tcl_GetRange(
|
||||
|
||||
if (first < 0) {
|
||||
first = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Optimize the case where we're really dealing with a bytearray object
|
||||
* we don't need to convert to a string to perform the substring operation.
|
||||
@@ -652,13 +697,14 @@ Tcl_GetRange(
|
||||
|
||||
if (TclIsPureByteArray(objPtr)) {
|
||||
unsigned char *bytes = Tcl_GetByteArrayFromObj(objPtr, &length);
|
||||
|
||||
if (last >= length) {
|
||||
last = length - 1;
|
||||
}
|
||||
if (last < first) {
|
||||
return Tcl_NewObj();
|
||||
}
|
||||
return Tcl_NewByteArrayObj(bytes+first, last-first+1);
|
||||
return Tcl_NewByteArrayObj(bytes + first, last - first + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -697,24 +743,25 @@ Tcl_GetRange(
|
||||
FillUnicodeRep(objPtr);
|
||||
stringPtr = GET_STRING(objPtr);
|
||||
}
|
||||
if (last > stringPtr->numChars) {
|
||||
last = stringPtr->numChars;
|
||||
}
|
||||
if (last < first) {
|
||||
return Tcl_NewObj();
|
||||
}
|
||||
if (last > stringPtr->numChars) {
|
||||
last = stringPtr->numChars;
|
||||
}
|
||||
if (last < first) {
|
||||
return Tcl_NewObj();
|
||||
}
|
||||
#if TCL_UTF_MAX <= 4
|
||||
/* See: bug [11ae2be95dac9417] */
|
||||
if ((first>0) && ((stringPtr->unicode[first]&0xFC00) == 0xDC00)
|
||||
&& ((stringPtr->unicode[first-1]&0xFC00) == 0xD800)) {
|
||||
++first;
|
||||
}
|
||||
if ((last+1<stringPtr->numChars) && ((stringPtr->unicode[last+1]&0xFC00) == 0xDC00)
|
||||
&& ((stringPtr->unicode[last]&0xFC00) == 0xD800)) {
|
||||
++last;
|
||||
}
|
||||
/* See: bug [11ae2be95dac9417] */
|
||||
if ((first > 0) && ((stringPtr->unicode[first] & 0xFC00) == 0xDC00)
|
||||
&& ((stringPtr->unicode[first-1] & 0xFC00) == 0xD800)) {
|
||||
++first;
|
||||
}
|
||||
if ((last + 1 < stringPtr->numChars)
|
||||
&& ((stringPtr->unicode[last+1] & 0xFC00) == 0xDC00)
|
||||
&& ((stringPtr->unicode[last] & 0xFC00) == 0xD800)) {
|
||||
++last;
|
||||
}
|
||||
#endif
|
||||
return Tcl_NewUnicodeObj(stringPtr->unicode + first, last-first+1);
|
||||
return Tcl_NewUnicodeObj(stringPtr->unicode + first, last - first + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1272,45 +1319,51 @@ Tcl_AppendObjToObj(
|
||||
/*
|
||||
* Handle append of one bytearray object to another as a special case.
|
||||
* Note that we only do this when the objects are pure so that the
|
||||
* bytearray faithfully represent the true value; Otherwise
|
||||
* appending the byte arrays together could lose information;
|
||||
* bytearray faithfully represent the true value; Otherwise appending the
|
||||
* byte arrays together could lose information;
|
||||
*/
|
||||
|
||||
if ((TclIsPureByteArray(objPtr) || objPtr->bytes == &tclEmptyString)
|
||||
&& TclIsPureByteArray(appendObjPtr)) {
|
||||
|
||||
/*
|
||||
* You might expect the code here to be
|
||||
*
|
||||
* bytes = Tcl_GetByteArrayFromObj(appendObjPtr, &length);
|
||||
* TclAppendBytesToByteArray(objPtr, bytes, length);
|
||||
*
|
||||
* and essentially all of the time that would be fine. However,
|
||||
* it would run into trouble in the case where objPtr and
|
||||
* appendObjPtr point to the same thing. That may never be a
|
||||
* good idea. It seems to violate Copy On Write, and we don't
|
||||
* have any tests for the situation, since making any Tcl commands
|
||||
* that call Tcl_AppendObjToObj() do that appears impossible
|
||||
* (They honor Copy On Write!). For the sake of extensions that
|
||||
* go off into that realm, though, here's a more complex approach
|
||||
* that can handle all the cases.
|
||||
* and essentially all of the time that would be fine. However, it
|
||||
* would run into trouble in the case where objPtr and appendObjPtr
|
||||
* point to the same thing. That may never be a good idea. It seems to
|
||||
* violate Copy On Write, and we don't have any tests for the
|
||||
* situation, since making any Tcl commands that call
|
||||
* Tcl_AppendObjToObj() do that appears impossible (They honor Copy On
|
||||
* Write!). For the sake of extensions that go off into that realm,
|
||||
* though, here's a more complex approach that can handle all the
|
||||
* cases.
|
||||
*
|
||||
* First, get the lengths.
|
||||
*/
|
||||
|
||||
/* Get lengths */
|
||||
int lengthSrc;
|
||||
|
||||
(void) Tcl_GetByteArrayFromObj(objPtr, &length);
|
||||
(void) Tcl_GetByteArrayFromObj(appendObjPtr, &lengthSrc);
|
||||
|
||||
/* Grow buffer enough for the append */
|
||||
/*
|
||||
* Grow buffer enough for the append.
|
||||
*/
|
||||
|
||||
TclAppendBytesToByteArray(objPtr, NULL, lengthSrc);
|
||||
|
||||
/* Reset objPtr back to the original value */
|
||||
/*
|
||||
* Reset objPtr back to the original value.
|
||||
*/
|
||||
|
||||
Tcl_SetByteArrayLength(objPtr, length);
|
||||
|
||||
/*
|
||||
* Now do the append knowing that buffer growth cannot cause
|
||||
* any trouble.
|
||||
* Now do the append knowing that buffer growth cannot cause any
|
||||
* trouble.
|
||||
*/
|
||||
|
||||
TclAppendBytesToByteArray(objPtr,
|
||||
@@ -1358,6 +1411,7 @@ Tcl_AppendObjToObj(
|
||||
numChars = stringPtr->numChars;
|
||||
if ((numChars >= 0) && (appendObjPtr->typePtr == &tclStringType)) {
|
||||
String *appendStringPtr = GET_STRING(appendObjPtr);
|
||||
|
||||
appendNumChars = appendStringPtr->numChars;
|
||||
}
|
||||
|
||||
@@ -1943,7 +1997,8 @@ Tcl_AppendFormatToObj(
|
||||
format += step;
|
||||
step = TclUtfToUniChar(format, &ch);
|
||||
}
|
||||
} else if ((ch == 't') || (ch == 'z') || (ch == 'q') || (ch == 'j') || (ch == 'L')) {
|
||||
} else if ((ch == 't') || (ch == 'z') || (ch == 'q') || (ch == 'j')
|
||||
|| (ch == 'L')) {
|
||||
format += step;
|
||||
step = TclUtfToUniChar(format, &ch);
|
||||
useBig = 1;
|
||||
@@ -2468,7 +2523,7 @@ Tcl_AppendFormatToObj(
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_Format--
|
||||
* Tcl_Format --
|
||||
*
|
||||
* Results:
|
||||
* A refcount zero Tcl_Obj.
|
||||
@@ -2859,7 +2914,10 @@ TclStringRepeat(
|
||||
Tcl_GetByteArrayFromObj(objResultPtr, NULL),
|
||||
(count - done) * length);
|
||||
} else if (unichar) {
|
||||
/* Efficiently produce a pure Tcl_UniChar array result */
|
||||
/*
|
||||
* Efficiently produce a pure Tcl_UniChar array result.
|
||||
*/
|
||||
|
||||
if (!inPlace || Tcl_IsShared(objPtr)) {
|
||||
objResultPtr = Tcl_NewUnicodeObj(Tcl_GetUnicode(objPtr), length);
|
||||
} else {
|
||||
@@ -2885,7 +2943,10 @@ TclStringRepeat(
|
||||
Tcl_AppendUnicodeToObj(objResultPtr, Tcl_GetUnicode(objResultPtr),
|
||||
(count - done) * length);
|
||||
} else {
|
||||
/* Efficiently concatenate string reps */
|
||||
/*
|
||||
* Efficiently concatenate string reps.
|
||||
*/
|
||||
|
||||
if (!inPlace || Tcl_IsShared(objPtr)) {
|
||||
objResultPtr = Tcl_NewStringObj(Tcl_GetString(objPtr), length);
|
||||
} else {
|
||||
@@ -2969,9 +3030,10 @@ TclStringCat(
|
||||
/* Value has a string rep. */
|
||||
if (objPtr->length) {
|
||||
/*
|
||||
* Non-empty string rep. Not a pure bytearray, so we
|
||||
* won't create a pure bytearray
|
||||
* Non-empty string rep. Not a pure bytearray, so we won't
|
||||
* create a pure bytearray.
|
||||
*/
|
||||
|
||||
binary = 0;
|
||||
if ((objPtr->typePtr) && (objPtr->typePtr != &tclStringType)) {
|
||||
/* Prevent shimmer of non-string types. */
|
||||
@@ -2992,8 +3054,12 @@ TclStringCat(
|
||||
} while (--oc && (binary || allowUniChar));
|
||||
|
||||
if (binary) {
|
||||
/* Result will be pure byte array. Pre-size it */
|
||||
ov = objv; oc = objc;
|
||||
/*
|
||||
* Result will be pure byte array. Pre-size it
|
||||
*/
|
||||
|
||||
ov = objv;
|
||||
oc = objc;
|
||||
do {
|
||||
Tcl_Obj *objPtr = *ov++;
|
||||
|
||||
@@ -3013,8 +3079,12 @@ TclStringCat(
|
||||
}
|
||||
} while (--oc);
|
||||
} else if (allowUniChar && requestUniChar) {
|
||||
/* Result will be pure Tcl_UniChar array. Pre-size it. */
|
||||
ov = objv; oc = objc;
|
||||
/*
|
||||
* Result will be pure Tcl_UniChar array. Pre-size it.
|
||||
*/
|
||||
|
||||
ov = objv;
|
||||
oc = objc;
|
||||
do {
|
||||
Tcl_Obj *objPtr = *ov++;
|
||||
|
||||
@@ -3059,9 +3129,9 @@ TclStringCat(
|
||||
} while (--oc && (length == 0) && (pendingPtr == NULL));
|
||||
|
||||
/*
|
||||
* Either we found a possibly non-empty value, and we
|
||||
* remember this index as the first and last such value so
|
||||
* far seen, or (oc == 0) and all values are known empty,
|
||||
* Either we found a possibly non-empty value, and we remember
|
||||
* this index as the first and last such value so far seen,
|
||||
* or (oc == 0) and all values are known empty,
|
||||
* so first = last = objc - 1 signals the right quick return.
|
||||
*/
|
||||
|
||||
@@ -3073,10 +3143,9 @@ TclStringCat(
|
||||
/* assert ( pendingPtr != NULL ) */
|
||||
|
||||
/*
|
||||
* There's a pending value followed by more values.
|
||||
* Loop over remaining values generating strings until
|
||||
* a non-empty value is found, or the pending value gets
|
||||
* its string generated.
|
||||
* There's a pending value followed by more values. Loop over
|
||||
* remaining values generating strings until a non-empty value
|
||||
* is found, or the pending value gets its string generated.
|
||||
*/
|
||||
|
||||
do {
|
||||
@@ -3132,10 +3201,10 @@ TclStringCat(
|
||||
unsigned char *dst;
|
||||
|
||||
/*
|
||||
* Broken interface! Byte array value routines offer no way
|
||||
* to handle failure to allocate enough space. Following
|
||||
* stanza may panic.
|
||||
* Broken interface! Byte array value routines offer no way to handle
|
||||
* failure to allocate enough space. Following stanza may panic.
|
||||
*/
|
||||
|
||||
if (inPlace && !Tcl_IsShared(*objv)) {
|
||||
int start;
|
||||
|
||||
@@ -3250,6 +3319,7 @@ TclStringCat(
|
||||
if ((objPtr->bytes == NULL) || (objPtr->length)) {
|
||||
int more;
|
||||
char *src = Tcl_GetStringFromObj(objPtr, &more);
|
||||
|
||||
memcpy(dst, src, (size_t) more);
|
||||
dst += more;
|
||||
}
|
||||
@@ -3268,6 +3338,187 @@ TclStringCat(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* TclStringCmp --
|
||||
* Compare two Tcl_Obj values as strings.
|
||||
*
|
||||
* Results:
|
||||
* Like memcmp, return -1, 0, or 1.
|
||||
*
|
||||
* Side effects:
|
||||
* String representations may be generated. Internal representation may
|
||||
* be changed.
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int TclStringCmp(
|
||||
Tcl_Obj *value1Ptr,
|
||||
Tcl_Obj *value2Ptr,
|
||||
int checkEq, /* comparison is only for equality */
|
||||
int nocase, /* comparison is not case sensitive */
|
||||
int reqlength) /* requested length */
|
||||
{
|
||||
char *s1, *s2;
|
||||
int empty, length, match, s1len, s2len;
|
||||
memCmpFn_t memCmpFn;
|
||||
|
||||
if ((reqlength == 0) || (value1Ptr == value2Ptr)) {
|
||||
/*
|
||||
* Always match at 0 chars of if it is the same obj.
|
||||
*/
|
||||
match = 0;
|
||||
} else {
|
||||
|
||||
if (!nocase && TclIsPureByteArray(value1Ptr)
|
||||
&& TclIsPureByteArray(value2Ptr)) {
|
||||
/*
|
||||
* Use binary versions of comparisons since that won't cause undue
|
||||
* type conversions and it is much faster. Only do this if we're
|
||||
* case-sensitive (which is all that really makes sense with byte
|
||||
* arrays anyway, and we have no memcasecmp() for some reason... :^)
|
||||
*/
|
||||
|
||||
s1 = (char *) Tcl_GetByteArrayFromObj(value1Ptr, &s1len);
|
||||
s2 = (char *) Tcl_GetByteArrayFromObj(value2Ptr, &s2len);
|
||||
memCmpFn = memcmp;
|
||||
} else if ((value1Ptr->typePtr == &tclStringType)
|
||||
&& (value2Ptr->typePtr == &tclStringType)) {
|
||||
/*
|
||||
* Do a unicode-specific comparison if both of the args are of
|
||||
* String type. If the char length == byte length, we can do a
|
||||
* memcmp. In benchmark testing this proved the most efficient
|
||||
* check between the unicode and string comparison operations.
|
||||
*/
|
||||
|
||||
if (nocase) {
|
||||
s1 = (char *) Tcl_GetUnicodeFromObj(value1Ptr, &s1len);
|
||||
s2 = (char *) Tcl_GetUnicodeFromObj(value2Ptr, &s2len);
|
||||
memCmpFn = (memCmpFn_t)Tcl_UniCharNcasecmp;
|
||||
} else {
|
||||
s1len = Tcl_GetCharLength(value1Ptr);
|
||||
s2len = Tcl_GetCharLength(value2Ptr);
|
||||
if ((s1len == value1Ptr->length)
|
||||
&& (value1Ptr->bytes != NULL)
|
||||
&& (s2len == value2Ptr->length)
|
||||
&& (value2Ptr->bytes != NULL)) {
|
||||
s1 = value1Ptr->bytes;
|
||||
s2 = value2Ptr->bytes;
|
||||
memCmpFn = memcmp;
|
||||
} else {
|
||||
s1 = (char *) Tcl_GetUnicode(value1Ptr);
|
||||
s2 = (char *) Tcl_GetUnicode(value2Ptr);
|
||||
if (
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
1
|
||||
#else
|
||||
checkEq
|
||||
#endif
|
||||
) {
|
||||
memCmpFn = memcmp;
|
||||
s1len *= sizeof(Tcl_UniChar);
|
||||
s2len *= sizeof(Tcl_UniChar);
|
||||
} else {
|
||||
memCmpFn = (memCmpFn_t) Tcl_UniCharNcmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((empty = TclCheckEmptyString(value1Ptr)) > 0) {
|
||||
switch (TclCheckEmptyString(value2Ptr)) {
|
||||
case -1:
|
||||
s1 = 0;
|
||||
s1len = 0;
|
||||
s2 = TclGetStringFromObj(value2Ptr, &s2len);
|
||||
break;
|
||||
case 0:
|
||||
match = -1;
|
||||
goto matchdone;
|
||||
case 1:
|
||||
default: /* avoid warn: `s2` may be used uninitialized */
|
||||
match = 0;
|
||||
goto matchdone;
|
||||
}
|
||||
} else if (TclCheckEmptyString(value2Ptr) > 0) {
|
||||
switch (empty) {
|
||||
case -1:
|
||||
s2 = 0;
|
||||
s2len = 0;
|
||||
s1 = TclGetStringFromObj(value1Ptr, &s1len);
|
||||
break;
|
||||
case 0:
|
||||
match = 1;
|
||||
goto matchdone;
|
||||
case 1:
|
||||
default: /* avoid warn: `s1` may be used uninitialized */
|
||||
match = 0;
|
||||
goto matchdone;
|
||||
}
|
||||
} else {
|
||||
s1 = TclGetStringFromObj(value1Ptr, &s1len);
|
||||
s2 = TclGetStringFromObj(value2Ptr, &s2len);
|
||||
}
|
||||
if (!nocase && checkEq) {
|
||||
/*
|
||||
* When we have equal-length we can check only for
|
||||
* (in)equality. We can use memcmp in all (n)eq cases because
|
||||
* we don't need to worry about lexical LE/BE variance.
|
||||
*/
|
||||
|
||||
memCmpFn = memcmp;
|
||||
} else {
|
||||
/*
|
||||
* As a catch-all we will work with UTF-8. We cannot use
|
||||
* memcmp() as that is unsafe with any string containing NUL
|
||||
* (\xC0\x80 in Tcl's utf rep). We can use the more efficient
|
||||
* TclpUtfNcmp2 if we are case-sensitive and no specific
|
||||
* length was requested.
|
||||
*/
|
||||
|
||||
if ((reqlength < 0) && !nocase) {
|
||||
memCmpFn = (memCmpFn_t) TclpUtfNcmp2;
|
||||
} else {
|
||||
s1len = Tcl_NumUtfChars(s1, s1len);
|
||||
s2len = Tcl_NumUtfChars(s2, s2len);
|
||||
memCmpFn = (memCmpFn_t)
|
||||
(nocase ? Tcl_UtfNcasecmp : Tcl_UtfNcmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
length = (s1len < s2len) ? s1len : s2len;
|
||||
if (reqlength > 0 && reqlength < length) {
|
||||
length = reqlength;
|
||||
} else if (reqlength < 0) {
|
||||
/*
|
||||
* The requested length is negative, so we ignore it by setting it
|
||||
* to length + 1 so we correct the match var.
|
||||
*/
|
||||
|
||||
reqlength = length + 1;
|
||||
}
|
||||
|
||||
if (checkEq && (s1len != s2len)) {
|
||||
match = 1; /* This will be reversed below. */
|
||||
} else {
|
||||
/*
|
||||
* The comparison function should compare up to the minimum byte
|
||||
* length only.
|
||||
*/
|
||||
|
||||
match = memCmpFn(s1, s2, (size_t) length);
|
||||
}
|
||||
if ((match == 0) && (reqlength > length)) {
|
||||
match = s1len - s2len;
|
||||
}
|
||||
match = (match > 0) ? 1 : (match < 0) ? -1 : 0;
|
||||
}
|
||||
matchdone:
|
||||
return match;
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
@@ -3462,18 +3713,20 @@ static void
|
||||
ReverseBytes(
|
||||
unsigned char *to, /* Copy bytes into here... */
|
||||
unsigned char *from, /* ...from here... */
|
||||
int count) /* Until this many are copied, */
|
||||
int count) /* Until this many are copied, */
|
||||
/* reversing as you go. */
|
||||
{
|
||||
unsigned char *src = from + count;
|
||||
|
||||
if (to == from) {
|
||||
/* Reversing in place */
|
||||
while (--src > to) {
|
||||
unsigned char c = *src;
|
||||
|
||||
*src = *to;
|
||||
*to++ = c;
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
while (--src >= from) {
|
||||
*to++ = *src;
|
||||
}
|
||||
@@ -3522,7 +3775,10 @@ TclStringReverse(
|
||||
*to++ = *src;
|
||||
}
|
||||
} else {
|
||||
/* Reversing in place */
|
||||
/*
|
||||
* Reversing in place.
|
||||
*/
|
||||
|
||||
while (--src > from) {
|
||||
ch = *src;
|
||||
*src = *from;
|
||||
@@ -3546,20 +3802,22 @@ TclStringReverse(
|
||||
/*
|
||||
* Either numChars == -1 and we don't know how many chars are
|
||||
* represented by objPtr->bytes and we need Pass 1 just in case,
|
||||
* or numChars >= 0 and we know we have fewer chars than bytes,
|
||||
* so we know there's a multibyte character needing Pass 1.
|
||||
* or numChars >= 0 and we know we have fewer chars than bytes, so
|
||||
* we know there's a multibyte character needing Pass 1.
|
||||
*
|
||||
* Pass 1. Reverse the bytes of each multi-byte character.
|
||||
*/
|
||||
|
||||
int charCount = 0;
|
||||
int bytesLeft = numBytes;
|
||||
|
||||
while (bytesLeft) {
|
||||
/*
|
||||
* NOTE: We know that the from buffer is NUL-terminated.
|
||||
* It's part of the contract for objPtr->bytes values.
|
||||
* Thus, we can skip calling Tcl_UtfCharComplete() here.
|
||||
* NOTE: We know that the from buffer is NUL-terminated. It's
|
||||
* part of the contract for objPtr->bytes values. Thus, we can
|
||||
* skip calling Tcl_UtfCharComplete() here.
|
||||
*/
|
||||
|
||||
int bytesInChar = TclUtfToUniChar(from, &ch);
|
||||
|
||||
ReverseBytes((unsigned char *)to, (unsigned char *)from,
|
||||
@@ -3589,19 +3847,18 @@ TclStringReverse(
|
||||
*
|
||||
* The result is a concatenation of a prefix from objPtr, characters
|
||||
* 0 through first-1, the insertPtr string value, and a suffix from
|
||||
* objPtr, characters from first + count to the end. The effect is
|
||||
* as if the inner substring of characters first through first+count-1
|
||||
* are removed and replaced with insertPtr.
|
||||
* If insertPtr is NULL, it is treated as an empty string.
|
||||
* When passed the flag TCL_STRING_IN_PLACE, this routine will try
|
||||
* to do the work within objPtr, so long as no sharing forbids it.
|
||||
* Without that request, or as needed, a new Tcl value will be allocated
|
||||
* to be the result.
|
||||
* objPtr, characters from first + count to the end. The effect is as if
|
||||
* the inner substring of characters first through first+count-1 are
|
||||
* removed and replaced with insertPtr. If insertPtr is NULL, it is
|
||||
* treated as an empty string. When passed the flag TCL_STRING_IN_PLACE,
|
||||
* this routine will try to do the work within objPtr, so long as no
|
||||
* sharing forbids it. Without that request, or as needed, a new Tcl
|
||||
* value will be allocated to be the result.
|
||||
*
|
||||
* Results:
|
||||
* A Tcl value that is the result of the substring replacement.
|
||||
* May return NULL in case of an error. When NULL is returned and
|
||||
* interp is non-NULL, error information is left in interp
|
||||
* A Tcl value that is the result of the substring replacement. May
|
||||
* return NULL in case of an error. When NULL is returned and interp is
|
||||
* non-NULL, error information is left in interp
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#undef Tcl_CreateHashEntry
|
||||
#undef Tcl_Panic
|
||||
#undef Tcl_FindExecutable
|
||||
#undef Tcl_SetPanicProc
|
||||
#undef TclpGetPid
|
||||
#undef TclSockMinimumBuffers
|
||||
#undef Tcl_SetIntObj
|
||||
@@ -454,6 +455,15 @@ tellOld(
|
||||
MODULE_SCOPE const TclStubs tclStubs;
|
||||
MODULE_SCOPE const TclTomMathStubs tclTomMathStubs;
|
||||
|
||||
#ifdef __GNUC__
|
||||
/*
|
||||
* The rest of this file shouldn't warn about deprecated functions; they're
|
||||
* there because we intend them to be so and know that this file is OK to
|
||||
* touch those fields.
|
||||
*/
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
/* !BEGIN!: Do not edit below this line. */
|
||||
|
||||
static const TclIntStubs tclIntStubs = {
|
||||
|
||||
+4
-4
@@ -161,7 +161,7 @@ static TestChannel *firstDetached;
|
||||
|
||||
static int AsyncHandlerProc(ClientData clientData,
|
||||
Tcl_Interp *interp, int code);
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
static Tcl_ThreadCreateType AsyncThreadProc(ClientData);
|
||||
#endif
|
||||
static void CleanupTestSetassocdataTests(
|
||||
@@ -722,7 +722,7 @@ Tcltest_Init(
|
||||
if (Procbodytest_Init(interp) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (TclThread_Init(interp) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -902,7 +902,7 @@ TestasyncCmd(
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(argv[3], -1));
|
||||
Tcl_MutexUnlock(&asyncTestMutex);
|
||||
return code;
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
} else if (strcmp(argv[1], "marklater") == 0) {
|
||||
if (argc != 3) {
|
||||
goto wrongNumArgs;
|
||||
@@ -999,7 +999,7 @@ AsyncHandlerProc(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
static Tcl_ThreadCreateType
|
||||
AsyncThreadProc(
|
||||
ClientData clientData) /* Parameter is the id of a
|
||||
|
||||
+10
-25
@@ -40,21 +40,6 @@ static void ForgetSyncObject(void *objPtr, SyncObjRecord *recPtr);
|
||||
static void RememberSyncObject(void *objPtr,
|
||||
SyncObjRecord *recPtr);
|
||||
|
||||
/*
|
||||
* Several functions are #defined to nothing in tcl.h if TCL_THREADS is not
|
||||
* specified. Here we undo that so the functions are defined in the stubs
|
||||
* table.
|
||||
*/
|
||||
|
||||
#ifndef TCL_THREADS
|
||||
#undef Tcl_MutexLock
|
||||
#undef Tcl_MutexUnlock
|
||||
#undef Tcl_MutexFinalize
|
||||
#undef Tcl_ConditionNotify
|
||||
#undef Tcl_ConditionWait
|
||||
#undef Tcl_ConditionFinalize
|
||||
#endif
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -79,7 +64,7 @@ Tcl_GetThreadData(
|
||||
int size) /* Size of storage block */
|
||||
{
|
||||
void *result;
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Initialize the key for this thread.
|
||||
*/
|
||||
@@ -126,7 +111,7 @@ TclThreadDataKeyGet(
|
||||
Tcl_ThreadDataKey *keyPtr) /* Identifier for the data chunk. */
|
||||
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
return TclThreadStorageKeyGet(keyPtr);
|
||||
#else /* TCL_THREADS */
|
||||
return *keyPtr;
|
||||
@@ -269,11 +254,12 @@ TclRememberMutex(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#undef Tcl_MutexFinalize
|
||||
void
|
||||
Tcl_MutexFinalize(
|
||||
Tcl_Mutex *mutexPtr)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
TclpFinalizeMutex(mutexPtr);
|
||||
#endif
|
||||
TclpMasterLock();
|
||||
@@ -322,11 +308,12 @@ TclRememberCondition(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#undef Tcl_ConditionFinalize
|
||||
void
|
||||
Tcl_ConditionFinalize(
|
||||
Tcl_Condition *condPtr)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
TclpFinalizeCondition(condPtr);
|
||||
#endif
|
||||
TclpMasterLock();
|
||||
@@ -356,7 +343,7 @@ void
|
||||
TclFinalizeThreadData(int quick)
|
||||
{
|
||||
TclFinalizeThreadDataThread();
|
||||
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
|
||||
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
|
||||
if (!quick) {
|
||||
/*
|
||||
* Quick exit principle makes it useless to terminate allocators
|
||||
@@ -389,7 +376,7 @@ TclFinalizeSynchronization(void)
|
||||
int i;
|
||||
void *blockPtr;
|
||||
Tcl_ThreadDataKey *keyPtr;
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
Tcl_Mutex *mutexPtr;
|
||||
Tcl_Condition *condPtr;
|
||||
|
||||
@@ -413,7 +400,7 @@ TclFinalizeSynchronization(void)
|
||||
keyRecord.max = 0;
|
||||
keyRecord.num = 0;
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Call thread storage master cleanup.
|
||||
*/
|
||||
@@ -473,12 +460,10 @@ Tcl_ExitThread(
|
||||
int status)
|
||||
{
|
||||
Tcl_FinalizeThread();
|
||||
#ifdef TCL_THREADS
|
||||
TclpThreadExit(status);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef TCL_THREADS
|
||||
#if !TCL_THREADS
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "tclInt.h"
|
||||
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
|
||||
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
|
||||
|
||||
/*
|
||||
* If range checking is enabled, an additional byte will be allocated to store
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "tclInt.h"
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
#include <signal.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#endif
|
||||
#include "tclInt.h"
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Each thread has an single instance of the following structure. There is one
|
||||
* instance of this structure per thread even if that thread contains multiple
|
||||
|
||||
+2
-2
@@ -1034,8 +1034,8 @@ Tcl_UtfToTitle(
|
||||
lowChar = (((lowChar & 0x3ff) << 10) | (ch & 0x3ff)) + 0x10000;
|
||||
}
|
||||
#endif
|
||||
/* Special exception for Gregorian characters, which don't have titlecase */
|
||||
if ((lowChar < 0x1C90) || (lowChar >= 0x1CC0)) {
|
||||
/* Special exception for Georgian Asomtavruli chars, no titlecase. */
|
||||
if ((unsigned)(lowChar - 0x1C90) >= 0x30) {
|
||||
lowChar = Tcl_UniCharToLower(lowChar);
|
||||
}
|
||||
|
||||
|
||||
+174
-143
@@ -60,14 +60,12 @@ VarHashCreateVar(
|
||||
Tcl_Obj *key,
|
||||
int *newPtr)
|
||||
{
|
||||
Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(&tablePtr->table,
|
||||
key, newPtr);
|
||||
Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(&tablePtr->table, key, newPtr);
|
||||
|
||||
if (hPtr) {
|
||||
return VarHashGetValue(hPtr);
|
||||
} else {
|
||||
if (!hPtr) {
|
||||
return NULL;
|
||||
}
|
||||
return VarHashGetValue(hPtr);
|
||||
}
|
||||
|
||||
#define VarHashFindVar(tablePtr, key) \
|
||||
@@ -92,11 +90,10 @@ VarHashFirstVar(
|
||||
{
|
||||
Tcl_HashEntry *hPtr = VarHashFirstEntry(tablePtr, searchPtr);
|
||||
|
||||
if (hPtr) {
|
||||
return VarHashGetValue(hPtr);
|
||||
} else {
|
||||
if (!hPtr) {
|
||||
return NULL;
|
||||
}
|
||||
return VarHashGetValue(hPtr);
|
||||
}
|
||||
|
||||
static inline Var *
|
||||
@@ -105,11 +102,10 @@ VarHashNextVar(
|
||||
{
|
||||
Tcl_HashEntry *hPtr = VarHashNextEntry(searchPtr);
|
||||
|
||||
if (hPtr) {
|
||||
return VarHashGetValue(hPtr);
|
||||
} else {
|
||||
if (!hPtr) {
|
||||
return NULL;
|
||||
}
|
||||
return VarHashGetValue(hPtr);
|
||||
}
|
||||
|
||||
#define VarHashGetKey(varPtr) \
|
||||
@@ -174,10 +170,14 @@ typedef struct ArraySearch {
|
||||
|
||||
static void AppendLocals(Tcl_Interp *interp, Tcl_Obj *listPtr,
|
||||
Tcl_Obj *patternPtr, int includeLinks);
|
||||
static void ArrayPopulateSearch(Tcl_Interp *interp, Tcl_Obj *arrayNameObj, Var *varPtr, ArraySearch *searchPtr);
|
||||
static void ArrayDoneSearch (Interp *iPtr, Var *varPtr, ArraySearch *searchPtr);
|
||||
static void ArrayPopulateSearch(Tcl_Interp *interp,
|
||||
Tcl_Obj *arrayNameObj, Var *varPtr,
|
||||
ArraySearch *searchPtr);
|
||||
static void ArrayDoneSearch(Interp *iPtr, Var *varPtr,
|
||||
ArraySearch *searchPtr);
|
||||
static Tcl_NRPostProc ArrayForLoopCallback;
|
||||
static int ArrayForNRCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv);
|
||||
static int ArrayForNRCmd(ClientData dummy, Tcl_Interp *interp,
|
||||
int objc, Tcl_Obj *const *objv);
|
||||
static void DeleteSearches(Interp *iPtr, Var *arrayVarPtr);
|
||||
static void DeleteArray(Interp *iPtr, Tcl_Obj *arrayNamePtr,
|
||||
Var *varPtr, int flags, int index);
|
||||
@@ -322,7 +322,8 @@ CleanupVar(
|
||||
{
|
||||
if (TclIsVarUndefined(varPtr) && TclIsVarInHash(varPtr)
|
||||
&& !TclIsVarTraced(varPtr)
|
||||
&& (VarHashRefCount(varPtr) == (unsigned)!TclIsVarDeadHash(varPtr))) {
|
||||
&& (VarHashRefCount(varPtr) == (unsigned)
|
||||
!TclIsVarDeadHash(varPtr))) {
|
||||
if (VarHashRefCount(varPtr) == 0) {
|
||||
ckfree(varPtr);
|
||||
} else {
|
||||
@@ -331,7 +332,8 @@ CleanupVar(
|
||||
}
|
||||
if (arrayPtr != NULL && TclIsVarUndefined(arrayPtr) &&
|
||||
TclIsVarInHash(arrayPtr) && !TclIsVarTraced(arrayPtr) &&
|
||||
(VarHashRefCount(arrayPtr) == (unsigned)!TclIsVarDeadHash(arrayPtr))) {
|
||||
(VarHashRefCount(arrayPtr) == (unsigned)
|
||||
!TclIsVarDeadHash(arrayPtr))) {
|
||||
if (VarHashRefCount(arrayPtr) == 0) {
|
||||
ckfree(arrayPtr);
|
||||
} else {
|
||||
@@ -607,7 +609,6 @@ TclObjLookupVarEx(
|
||||
}
|
||||
|
||||
if (!parsed) {
|
||||
|
||||
/*
|
||||
* part1Ptr is possibly an unparsed array element.
|
||||
*/
|
||||
@@ -615,12 +616,11 @@ TclObjLookupVarEx(
|
||||
int len;
|
||||
const char *part1 = TclGetStringFromObj(part1Ptr, &len);
|
||||
|
||||
if (len > 1 && (part1[len - 1] == ')')) {
|
||||
if ((len > 1) && (part1[len - 1] == ')')) {
|
||||
const char *part2 = strchr(part1, '(');
|
||||
|
||||
const char *part2 = strchr(part1, '(');
|
||||
|
||||
if (part2) {
|
||||
Tcl_Obj *arrayPtr;
|
||||
if (part2) {
|
||||
Tcl_Obj *arrayPtr;
|
||||
|
||||
if (part2Ptr != NULL) {
|
||||
if (flags & TCL_LEAVE_ERR_MSG) {
|
||||
@@ -632,19 +632,20 @@ TclObjLookupVarEx(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
arrayPtr = Tcl_NewStringObj(part1, (part2 - part1));
|
||||
part2Ptr = Tcl_NewStringObj(part2 + 1, len - (part2 - part1) - 2);
|
||||
arrayPtr = Tcl_NewStringObj(part1, (part2 - part1));
|
||||
part2Ptr = Tcl_NewStringObj(part2 + 1,
|
||||
len - (part2 - part1) - 2);
|
||||
|
||||
TclFreeIntRep(part1Ptr);
|
||||
TclFreeIntRep(part1Ptr);
|
||||
|
||||
Tcl_IncrRefCount(arrayPtr);
|
||||
part1Ptr->internalRep.twoPtrValue.ptr1 = arrayPtr;
|
||||
Tcl_IncrRefCount(part2Ptr);
|
||||
part1Ptr->internalRep.twoPtrValue.ptr2 = part2Ptr;
|
||||
part1Ptr->typePtr = &tclParsedVarNameType;
|
||||
Tcl_IncrRefCount(arrayPtr);
|
||||
part1Ptr->internalRep.twoPtrValue.ptr1 = arrayPtr;
|
||||
Tcl_IncrRefCount(part2Ptr);
|
||||
part1Ptr->internalRep.twoPtrValue.ptr2 = part2Ptr;
|
||||
part1Ptr->typePtr = &tclParsedVarNameType;
|
||||
|
||||
part1Ptr = arrayPtr;
|
||||
}
|
||||
part1Ptr = arrayPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,6 +675,7 @@ TclObjLookupVarEx(
|
||||
/*
|
||||
* An indexed local variable.
|
||||
*/
|
||||
|
||||
Tcl_Obj *cachedNamePtr = localName(varFramePtr, index);
|
||||
|
||||
part1Ptr->typePtr = &localVarNameType;
|
||||
@@ -682,7 +684,7 @@ TclObjLookupVarEx(
|
||||
Tcl_IncrRefCount(cachedNamePtr);
|
||||
if (cachedNamePtr->typePtr != &localVarNameType
|
||||
|| cachedNamePtr->internalRep.twoPtrValue.ptr1 != NULL) {
|
||||
TclFreeIntRep(cachedNamePtr);
|
||||
TclFreeIntRep(cachedNamePtr);
|
||||
}
|
||||
} else {
|
||||
part1Ptr->internalRep.twoPtrValue.ptr1 = NULL;
|
||||
@@ -877,38 +879,41 @@ TclLookupSimpleVar(
|
||||
if (varPtr == NULL) {
|
||||
Tcl_Obj *tailPtr;
|
||||
|
||||
if (create) { /* Var wasn't found so create it. */
|
||||
TclGetNamespaceForQualName(interp, varName, cxtNsPtr,
|
||||
flags, &varNsPtr, &dummy1Ptr, &dummy2Ptr, &tail);
|
||||
if (varNsPtr == NULL) {
|
||||
*errMsgPtr = badNamespace;
|
||||
return NULL;
|
||||
} else if (tail == NULL) {
|
||||
*errMsgPtr = missingName;
|
||||
return NULL;
|
||||
}
|
||||
if (tail != varName) {
|
||||
tailPtr = Tcl_NewStringObj(tail, -1);
|
||||
} else {
|
||||
tailPtr = varNamePtr;
|
||||
}
|
||||
varPtr = VarHashCreateVar(&varNsPtr->varTable, tailPtr,
|
||||
&isNew);
|
||||
if (lookGlobal) {
|
||||
/*
|
||||
* The variable was created starting from the global
|
||||
* namespace: a global reference is returned even if it
|
||||
* wasn't explicitly requested.
|
||||
*/
|
||||
|
||||
*indexPtr = -1;
|
||||
} else {
|
||||
*indexPtr = -2;
|
||||
}
|
||||
} else { /* Var wasn't found and not to create it. */
|
||||
if (!create) { /* Var wasn't found and not to create it. */
|
||||
*errMsgPtr = noSuchVar;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Var wasn't found so create it.
|
||||
*/
|
||||
|
||||
TclGetNamespaceForQualName(interp, varName, cxtNsPtr, flags,
|
||||
&varNsPtr, &dummy1Ptr, &dummy2Ptr, &tail);
|
||||
if (varNsPtr == NULL) {
|
||||
*errMsgPtr = badNamespace;
|
||||
return NULL;
|
||||
} else if (tail == NULL) {
|
||||
*errMsgPtr = missingName;
|
||||
return NULL;
|
||||
}
|
||||
if (tail != varName) {
|
||||
tailPtr = Tcl_NewStringObj(tail, -1);
|
||||
} else {
|
||||
tailPtr = varNamePtr;
|
||||
}
|
||||
varPtr = VarHashCreateVar(&varNsPtr->varTable, tailPtr, &isNew);
|
||||
if (lookGlobal) {
|
||||
/*
|
||||
* The variable was created starting from the global
|
||||
* namespace: a global reference is returned even if it wasn't
|
||||
* explicitly requested.
|
||||
*/
|
||||
|
||||
*indexPtr = -1;
|
||||
} else {
|
||||
*indexPtr = -2;
|
||||
}
|
||||
}
|
||||
} else { /* Local var: look in frame varFramePtr. */
|
||||
int localLen, localCt = varFramePtr->numCompiledLocals;
|
||||
@@ -2167,7 +2172,6 @@ TclPtrIncrObjVarIdx(
|
||||
} else {
|
||||
/* Unshared - can Incr in place */
|
||||
if (TCL_OK == TclIncrObj(interp, varValuePtr, incrPtr)) {
|
||||
|
||||
/*
|
||||
* This seems dumb to write the incremeted value into the var
|
||||
* after we just adjusted the value in place, but the spec for
|
||||
@@ -2909,27 +2913,24 @@ Tcl_LappendObjCmd(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* ArrayForObjCmd
|
||||
* ArrayForNRCmd
|
||||
* ArrayForLoopCallback
|
||||
* ArrayObjNext
|
||||
* ArrayForObjCmd, ArrayForNRCmd, ArrayForLoopCallback, ArrayObjNext --
|
||||
*
|
||||
* These functions implement the "array for" Tcl command.
|
||||
* array for {k v} a {}
|
||||
* The array for command iterates over the array, setting the
|
||||
* the specified loop variables, and executing the body each iteration.
|
||||
* These functions implement the "array for" Tcl command.
|
||||
* array for {k v} a {}
|
||||
* The array for command iterates over the array, setting the the
|
||||
* specified loop variables, and executing the body each iteration.
|
||||
*
|
||||
* ArrayForObjCmd() is the standard wrapper around ArrayForNRCmd().
|
||||
* ArrayForObjCmd() is the standard wrapper around ArrayForNRCmd().
|
||||
*
|
||||
* ArrayForNRCmd() sets up the ArraySearch structure, sets arrayNamePtr
|
||||
* inside the structure and calls VarHashFirstEntry to start the hash
|
||||
* iteration.
|
||||
* ArrayForNRCmd() sets up the ArraySearch structure, sets arrayNamePtr
|
||||
* inside the structure and calls VarHashFirstEntry to start the hash
|
||||
* iteration.
|
||||
*
|
||||
* ArrayForNRCmd() does not execute the body or set the loop variables,
|
||||
* it only initializes the iterator.
|
||||
* ArrayForNRCmd() does not execute the body or set the loop variables,
|
||||
* it only initializes the iterator.
|
||||
*
|
||||
* ArrayForLoopCallback() iterates over the entire array, executing
|
||||
* the body each time.
|
||||
* ArrayForLoopCallback() iterates over the entire array, executing the
|
||||
* body each time.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -2937,39 +2938,39 @@ Tcl_LappendObjCmd(
|
||||
static int
|
||||
ArrayObjNext(
|
||||
Tcl_Interp *interp,
|
||||
Tcl_Obj *arrayNameObj, /* array */
|
||||
Var *varPtr, /* array */
|
||||
Tcl_Obj *arrayNameObj, /* array */
|
||||
Var *varPtr, /* array */
|
||||
ArraySearch *searchPtr,
|
||||
Tcl_Obj **keyPtrPtr, /* Pointer to a variable to have the key
|
||||
* written into, or NULL. */
|
||||
Tcl_Obj **valuePtrPtr /* Pointer to a variable to have the
|
||||
Tcl_Obj **valuePtrPtr) /* Pointer to a variable to have the
|
||||
* value written into, or NULL.*/
|
||||
)
|
||||
{
|
||||
Tcl_Obj *keyObj;
|
||||
Tcl_Obj *valueObj = NULL;
|
||||
int gotValue;
|
||||
int donerc;
|
||||
int gotValue;
|
||||
int donerc;
|
||||
|
||||
donerc = TCL_BREAK;
|
||||
|
||||
if ((varPtr->flags & VAR_SEARCH_ACTIVE) != VAR_SEARCH_ACTIVE) {
|
||||
donerc = TCL_ERROR;
|
||||
return donerc;
|
||||
donerc = TCL_ERROR;
|
||||
return donerc;
|
||||
}
|
||||
|
||||
gotValue = 0;
|
||||
while (1) {
|
||||
Tcl_HashEntry *hPtr = searchPtr->nextEntry;
|
||||
if (hPtr != NULL) {
|
||||
searchPtr->nextEntry = NULL;
|
||||
} else {
|
||||
hPtr = Tcl_NextHashEntry(&searchPtr->search);
|
||||
if (hPtr == NULL) {
|
||||
gotValue = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hPtr != NULL) {
|
||||
searchPtr->nextEntry = NULL;
|
||||
} else {
|
||||
hPtr = Tcl_NextHashEntry(&searchPtr->search);
|
||||
if (hPtr == NULL) {
|
||||
gotValue = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
varPtr = VarHashGetValue(hPtr);
|
||||
if (!TclIsVarUndefined(varPtr)) {
|
||||
gotValue = 1;
|
||||
@@ -2977,7 +2978,7 @@ ArrayObjNext(
|
||||
}
|
||||
}
|
||||
|
||||
if (! gotValue) {
|
||||
if (!gotValue) {
|
||||
return donerc;
|
||||
}
|
||||
|
||||
@@ -2985,8 +2986,8 @@ ArrayObjNext(
|
||||
|
||||
keyObj = VarHashGetKey(varPtr);
|
||||
*keyPtrPtr = keyObj;
|
||||
valueObj = Tcl_ObjGetVar2(interp, arrayNameObj,
|
||||
keyObj, TCL_LEAVE_ERR_MSG);
|
||||
valueObj = Tcl_ObjGetVar2(interp, arrayNameObj, keyObj,
|
||||
TCL_LEAVE_ERR_MSG);
|
||||
*valuePtrPtr = valueObj;
|
||||
|
||||
return donerc;
|
||||
@@ -3019,8 +3020,7 @@ ArrayForNRCmd(
|
||||
*/
|
||||
|
||||
if (objc != 4) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
"{key value} arrayName script");
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "{key value} arrayName script");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -3054,7 +3054,7 @@ ArrayForNRCmd(
|
||||
*/
|
||||
|
||||
searchPtr = ckalloc(sizeof(ArraySearch));
|
||||
ArrayPopulateSearch (interp, arrayNameObj, varPtr, searchPtr);
|
||||
ArrayPopulateSearch(interp, arrayNameObj, varPtr, searchPtr);
|
||||
|
||||
/*
|
||||
* Make sure that these objects (which we need throughout the body of the
|
||||
@@ -3120,35 +3120,37 @@ ArrayForLoopCallback(
|
||||
varPtr = TclObjLookupVarEx(interp, arrayNameObj, NULL, /*flags*/ 0,
|
||||
/*msg*/ 0, /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
|
||||
if (varPtr == NULL) {
|
||||
done = TCL_ERROR;
|
||||
done = TCL_ERROR;
|
||||
} else {
|
||||
done = ArrayObjNext (interp, arrayNameObj, varPtr,
|
||||
searchPtr, &keyObj, &valueObj);
|
||||
done = ArrayObjNext(interp, arrayNameObj, varPtr, searchPtr, &keyObj,
|
||||
&valueObj);
|
||||
}
|
||||
|
||||
result = TCL_OK;
|
||||
if (done != TCL_CONTINUE) {
|
||||
Tcl_ResetResult(interp);
|
||||
if (done == TCL_ERROR) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
"array changed during iteration", -1));
|
||||
Tcl_SetErrorCode(interp, "TCL", "READ", "array", "for", NULL);
|
||||
varPtr->flags |= TCL_LEAVE_ERR_MSG;
|
||||
result = done;
|
||||
}
|
||||
if (done == TCL_ERROR) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
"array changed during iteration", -1));
|
||||
Tcl_SetErrorCode(interp, "TCL", "READ", "array", "for", NULL);
|
||||
varPtr->flags |= TCL_LEAVE_ERR_MSG;
|
||||
result = done;
|
||||
}
|
||||
goto arrayfordone;
|
||||
}
|
||||
|
||||
Tcl_ListObjGetElements(NULL, varListObj, &varc, &varv);
|
||||
if (Tcl_ObjSetVar2(interp, varv[0], NULL, keyObj, TCL_LEAVE_ERR_MSG) == NULL) {
|
||||
result = TCL_ERROR;
|
||||
goto arrayfordone;
|
||||
if (Tcl_ObjSetVar2(interp, varv[0], NULL, keyObj,
|
||||
TCL_LEAVE_ERR_MSG) == NULL) {
|
||||
result = TCL_ERROR;
|
||||
goto arrayfordone;
|
||||
}
|
||||
if (valueObj != NULL) {
|
||||
if (Tcl_ObjSetVar2(interp, varv[1], NULL, valueObj, TCL_LEAVE_ERR_MSG) == NULL) {
|
||||
result = TCL_ERROR;
|
||||
goto arrayfordone;
|
||||
}
|
||||
if (Tcl_ObjSetVar2(interp, varv[1], NULL, valueObj,
|
||||
TCL_LEAVE_ERR_MSG) == NULL) {
|
||||
result = TCL_ERROR;
|
||||
goto arrayfordone;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3164,13 +3166,15 @@ ArrayForLoopCallback(
|
||||
*/
|
||||
|
||||
arrayfordone:
|
||||
/* if the search was terminated by an array change, the
|
||||
* VAR_SEARCH_ACTIVE flag will no longer be set
|
||||
*/
|
||||
if (done != TCL_ERROR) {
|
||||
ArrayDoneSearch (iPtr, varPtr, searchPtr);
|
||||
/*
|
||||
* If the search was terminated by an array change, the
|
||||
* VAR_SEARCH_ACTIVE flag will no longer be set.
|
||||
*/
|
||||
|
||||
ArrayDoneSearch(iPtr, varPtr, searchPtr);
|
||||
Tcl_DecrRefCount(searchPtr->name);
|
||||
ckfree(searchPtr);
|
||||
ckfree(searchPtr);
|
||||
}
|
||||
|
||||
TclDecrRefCount(varListObj);
|
||||
@@ -3181,14 +3185,15 @@ ArrayForLoopCallback(
|
||||
/*
|
||||
* ArrayPopulateSearch
|
||||
*/
|
||||
|
||||
static void
|
||||
ArrayPopulateSearch(
|
||||
Tcl_Interp *interp,
|
||||
Tcl_Obj *arrayNameObj,
|
||||
Var *varPtr,
|
||||
Tcl_Interp *interp,
|
||||
Tcl_Obj *arrayNameObj,
|
||||
Var *varPtr,
|
||||
ArraySearch *searchPtr)
|
||||
{
|
||||
Interp *iPtr = (Interp *)interp;
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
Tcl_HashEntry *hPtr;
|
||||
int isNew;
|
||||
|
||||
@@ -3206,7 +3211,7 @@ ArrayPopulateSearch(
|
||||
&searchPtr->search);
|
||||
Tcl_SetHashValue(hPtr, searchPtr);
|
||||
searchPtr->name = Tcl_ObjPrintf("s-%d-%s", searchPtr->id,
|
||||
TclGetString(arrayNameObj));
|
||||
TclGetString(arrayNameObj));
|
||||
Tcl_IncrRefCount(searchPtr->name);
|
||||
}
|
||||
/*
|
||||
@@ -3258,7 +3263,7 @@ ArrayStartSearchCmd(
|
||||
*/
|
||||
|
||||
searchPtr = ckalloc(sizeof(ArraySearch));
|
||||
ArrayPopulateSearch (interp, objv[1], varPtr, searchPtr);
|
||||
ArrayPopulateSearch(interp, objv[1], varPtr, searchPtr);
|
||||
Tcl_SetObjResult(interp, searchPtr->name);
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -3268,12 +3273,12 @@ ArrayStartSearchCmd(
|
||||
*
|
||||
* ArrayDoneSearch --
|
||||
*
|
||||
* Removes the search from the hash of active searches.
|
||||
* Removes the search from the hash of active searches.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
ArrayDoneSearch (
|
||||
ArrayDoneSearch(
|
||||
Interp *iPtr,
|
||||
Var *varPtr,
|
||||
ArraySearch *searchPtr)
|
||||
@@ -3288,7 +3293,7 @@ ArrayDoneSearch (
|
||||
|
||||
hPtr = Tcl_FindHashEntry(&iPtr->varSearches, varPtr);
|
||||
if (hPtr == NULL) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
if (searchPtr == Tcl_GetHashValue(hPtr)) {
|
||||
if (searchPtr->nextPtr) {
|
||||
@@ -3522,7 +3527,7 @@ ArrayDoneSearchCmd(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
ArrayDoneSearch (iPtr, varPtr, searchPtr);
|
||||
ArrayDoneSearch(iPtr, varPtr, searchPtr);
|
||||
Tcl_DecrRefCount(searchPtr->name);
|
||||
ckfree(searchPtr);
|
||||
return TCL_OK;
|
||||
@@ -4034,7 +4039,8 @@ ArraySetCmd(
|
||||
|
||||
if ((elemVarPtr == NULL) ||
|
||||
(TclPtrSetVarIdx(interp, elemVarPtr, varPtr, arrayNameObj,
|
||||
elemPtrs[i],elemPtrs[i+1],TCL_LEAVE_ERR_MSG,-1) == NULL)){
|
||||
elemPtrs[i], elemPtrs[i+1], TCL_LEAVE_ERR_MSG,
|
||||
-1) == NULL)) {
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
@@ -6024,7 +6030,7 @@ TclInfoVarsCmd(
|
||||
*/
|
||||
|
||||
if ((nsPtr != globalNsPtr) && !specificNsInPattern) {
|
||||
varPtr = VarHashFirstVar(&globalNsPtr->varTable,&search);
|
||||
varPtr = VarHashFirstVar(&globalNsPtr->varTable, &search);
|
||||
while (varPtr) {
|
||||
if (!TclIsVarUndefined(varPtr)
|
||||
|| TclIsVarNamespaceVar(varPtr)) {
|
||||
@@ -6317,25 +6323,50 @@ AppendLocals(
|
||||
}
|
||||
|
||||
if (iPtr->varFramePtr->isProcCallFrame & FRAME_IS_METHOD) {
|
||||
CallContext *contextPtr = iPtr->varFramePtr->clientData;
|
||||
Method *mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr;
|
||||
Method *mPtr = (Method *)
|
||||
Tcl_ObjectContextMethod(iPtr->varFramePtr->clientData);
|
||||
PrivateVariableMapping *privatePtr;
|
||||
|
||||
if (mPtr->declaringObjectPtr) {
|
||||
FOREACH(objNamePtr, mPtr->declaringObjectPtr->variables) {
|
||||
Object *oPtr = mPtr->declaringObjectPtr;
|
||||
|
||||
FOREACH(objNamePtr, oPtr->variables) {
|
||||
Tcl_CreateHashEntry(&addedTable, objNamePtr, &added);
|
||||
if (added && (!pattern ||
|
||||
Tcl_StringMatch(TclGetString(objNamePtr), pattern))) {
|
||||
Tcl_ListObjAppendElement(interp, listPtr, objNamePtr);
|
||||
}
|
||||
}
|
||||
FOREACH_STRUCT(privatePtr, oPtr->privateVariables) {
|
||||
Tcl_CreateHashEntry(&addedTable, privatePtr->variableObj,
|
||||
&added);
|
||||
if (added && (!pattern ||
|
||||
Tcl_StringMatch(TclGetString(privatePtr->variableObj),
|
||||
pattern))) {
|
||||
Tcl_ListObjAppendElement(interp, listPtr,
|
||||
privatePtr->variableObj);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FOREACH(objNamePtr, mPtr->declaringClassPtr->variables) {
|
||||
Class *clsPtr = mPtr->declaringClassPtr;
|
||||
|
||||
FOREACH(objNamePtr, clsPtr->variables) {
|
||||
Tcl_CreateHashEntry(&addedTable, objNamePtr, &added);
|
||||
if (added && (!pattern ||
|
||||
Tcl_StringMatch(TclGetString(objNamePtr), pattern))) {
|
||||
Tcl_ListObjAppendElement(interp, listPtr, objNamePtr);
|
||||
}
|
||||
}
|
||||
FOREACH_STRUCT(privatePtr, clsPtr->privateVariables) {
|
||||
Tcl_CreateHashEntry(&addedTable, privatePtr->variableObj,
|
||||
&added);
|
||||
if (added && (!pattern ||
|
||||
Tcl_StringMatch(TclGetString(privatePtr->variableObj),
|
||||
pattern))) {
|
||||
Tcl_ListObjAppendElement(interp, listPtr,
|
||||
privatePtr->variableObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Tcl_DeleteHashTable(&addedTable);
|
||||
@@ -6408,9 +6439,9 @@ CompareVarKeys(
|
||||
/*
|
||||
* If the object pointers are the same then they match.
|
||||
* OPT: this comparison was moved to the caller
|
||||
|
||||
if (objPtr1 == objPtr2) return 1;
|
||||
*/
|
||||
*
|
||||
* if (objPtr1 == objPtr2) return 1;
|
||||
*/
|
||||
|
||||
/*
|
||||
* Don't use Tcl_GetStringFromObj as it would prevent l1 and l2 being in a
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@ ${objdir}/Makefile: ${UNIX_DIR}/Makefile.in ${UNIX_DIR}/configure \
|
||||
mkdir -p "${OBJ_DIR}" && cd "${OBJ_DIR}" && \
|
||||
if [ ${UNIX_DIR}/configure -nt config.status ]; then ${UNIX_DIR}/configure -C \
|
||||
--prefix="${PREFIX}" --bindir="${BINDIR}" --libdir="${LIBDIR}" \
|
||||
--mandir="${MANDIR}" --enable-threads --enable-framework --enable-dtrace \
|
||||
--mandir="${MANDIR}" --enable-framework --enable-dtrace \
|
||||
${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS}; else ./config.status; fi
|
||||
|
||||
build-${PROJECT}: ${objdir}/Makefile
|
||||
|
||||
@@ -30,7 +30,7 @@ MANDIR = $(PREFIX)/man
|
||||
PER_ARCH_CFLAGS_ppc = -mcpu=G3 -mtune=G4 $(PER_ARCH_CFLAGS_ppc)
|
||||
PER_ARCH_CFLAGS_ppc64 = -mcpu=G5 -mpowerpc64 $(PER_ARCH_CFLAGS_ppc64)
|
||||
PREFIX = /usr/local
|
||||
TCL_CONFIGURE_ARGS = --enable-threads --enable-dtrace
|
||||
TCL_CONFIGURE_ARGS = --enable-dtrace
|
||||
TCL_LIBRARY = $(LIBDIR)/tcl$(VERSION)
|
||||
TCL_PACKAGE_PATH = "$(LIBDIR)"
|
||||
TCL_DEFS = HAVE_TCL_CONFIG_H
|
||||
|
||||
+3
-4
@@ -20,7 +20,6 @@ if {[lsearch [namespace children] ::tcltest] == -1} {
|
||||
catch [list package require -exact Tcltest [info patchlevel]]
|
||||
|
||||
testConstraint testasync [llength [info commands testasync]]
|
||||
testConstraint threaded [::tcl::pkgconfig get threaded]
|
||||
|
||||
proc async1 {result code} {
|
||||
global aresult acode
|
||||
@@ -149,7 +148,7 @@ test async-3.1 {deleting handlers} testasync {
|
||||
} {3 del2 {0 0 0 del1 del2}}
|
||||
|
||||
test async-4.1 {async interrupting bytecode sequence} -constraints {
|
||||
testasync threaded
|
||||
testasync
|
||||
} -setup {
|
||||
set hm [testasync create async3]
|
||||
proc nothing {} {
|
||||
@@ -171,7 +170,7 @@ test async-4.1 {async interrupting bytecode sequence} -constraints {
|
||||
testasync delete $hm
|
||||
}
|
||||
test async-4.2 {async interrupting straight bytecode sequence} -constraints {
|
||||
testasync threaded
|
||||
testasync
|
||||
} -setup {
|
||||
set hm [testasync create async3]
|
||||
} -body {
|
||||
@@ -188,7 +187,7 @@ test async-4.2 {async interrupting straight bytecode sequence} -constraints {
|
||||
testasync delete $hm
|
||||
}
|
||||
test async-4.3 {async interrupting loop-less bytecode sequence} -constraints {
|
||||
testasync threaded
|
||||
testasync
|
||||
} -setup {
|
||||
set hm [testasync create async3]
|
||||
} -body {
|
||||
|
||||
@@ -264,6 +264,12 @@ removeDirectory dir.dir
|
||||
test filesystem-1.30 {normalisation of nonexistent user} -body {
|
||||
file normalize ~noonewiththisname
|
||||
} -returnCodes error -result {user "noonewiththisname" doesn't exist}
|
||||
test filesystem-1.30.1 {normalisation of existing user} -body {
|
||||
catch {file normalize ~$::tcl_platform(user)}
|
||||
} -result {0}
|
||||
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.31 {link normalisation: link near filesystem root} {testsetplatform} {
|
||||
testsetplatform unix
|
||||
file normalize /foo/../bar
|
||||
|
||||
+744
-1
@@ -2202,7 +2202,7 @@ test oo-16.2 {OO: object introspection} -body {
|
||||
} -returnCodes 1 -result {NOTANOBJECT does not refer to an object}
|
||||
test oo-16.3 {OO: object introspection} -body {
|
||||
info object gorp oo::object
|
||||
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be call, class, definition, filters, forward, isa, methods, methodtype, mixins, namespace, variables, or vars}
|
||||
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be call, class, creationid, definition, filters, forward, isa, methods, methodtype, mixins, namespace, variables, or vars}
|
||||
test oo-16.4 {OO: object introspection} -setup {
|
||||
oo::class create meta { superclass oo::class }
|
||||
[meta create instance1] create instance2
|
||||
@@ -2332,6 +2332,73 @@ test oo-16.14 {OO: object introspection: TIP #436} -setup {
|
||||
} -cleanup {
|
||||
meta destroy
|
||||
} -result {class {0 0} meta {0 0 0} type {0 0 0 0 0 0} mix {0 0 0 0 0 0}}
|
||||
test oo-16.15 {OO: object introspection: creationid #500} -setup {
|
||||
oo::class create cls
|
||||
} -body {
|
||||
info object creationid [cls new]
|
||||
} -cleanup {
|
||||
cls destroy
|
||||
} -result {^\d+$} -match regexp
|
||||
test oo-16.16 {OO: object introspection: creationid #500} -setup {
|
||||
oo::class create cls
|
||||
} -body {
|
||||
set obj [cls new]
|
||||
set id [info object creationid $obj]
|
||||
rename $obj gorp
|
||||
set id2 [info object creationid gorp]
|
||||
list $id $id2
|
||||
} -cleanup {
|
||||
cls destroy
|
||||
} -result {^(\d+) \1$} -match regexp
|
||||
test oo-16.17 {OO: object introspection: creationid #500} -body {
|
||||
info object creationid nosuchobject
|
||||
} -returnCodes error -result {nosuchobject does not refer to an object}
|
||||
test oo-16.18 {OO: object introspection: creationid #500} -body {
|
||||
info object creationid
|
||||
} -returnCodes error -result {wrong # args: should be "info object creationid objName"}
|
||||
test oo-16.18 {OO: object introspection: creationid #500} -body {
|
||||
info object creationid oo::object gorp
|
||||
} -returnCodes error -result {wrong # args: should be "info object creationid objName"}
|
||||
test oo-16.19 {OO: object introspection: creationid #500} -setup {
|
||||
oo::class create cls
|
||||
} -body {
|
||||
set id1 [info object creationid [set o1 [cls new]]]
|
||||
set id2 [info object creationid [set o2 [cls new]]]
|
||||
if {$id1 == $id2} {
|
||||
format "objects %s and %s have same creation id: %d" $o1 $o2 $id1
|
||||
} else {
|
||||
string cat not-equal
|
||||
}
|
||||
} -cleanup {
|
||||
cls destroy
|
||||
} -result not-equal
|
||||
test oo-16.20 {OO: object introspection: creationid #500} -setup {
|
||||
oo::class create cls
|
||||
} -body {
|
||||
set id1 [info object creationid [set o1 [cls new]]]
|
||||
$o1 destroy
|
||||
set id2 [info object creationid [set o2 [cls new]]]
|
||||
if {$id1 == $id2} {
|
||||
format "objects %s and %s have same creation id: %d" $o1 $o2 $id1
|
||||
} else {
|
||||
string cat not-equal
|
||||
}
|
||||
} -cleanup {
|
||||
cls destroy
|
||||
} -result not-equal
|
||||
test oo-16.21 {OO: object introspection: creationid #500} -setup {
|
||||
oo::class create cls
|
||||
} -body {
|
||||
set id1 [info object creationid [set o1 [cls new]]]
|
||||
set id2 [info object creationid [set o2 [oo::copy $o1]]]
|
||||
if {$id1 == $id2} {
|
||||
format "objects %s and %s have same creation id: %d" $o1 $o2 $id1
|
||||
} else {
|
||||
string cat not-equal
|
||||
}
|
||||
} -cleanup {
|
||||
cls destroy
|
||||
} -result not-equal
|
||||
|
||||
test oo-17.1 {OO: class introspection} -body {
|
||||
info class
|
||||
@@ -4102,6 +4169,682 @@ test oo-36.10 {TIP #470: introspection within oo::define} -setup {
|
||||
Cls destroy
|
||||
catch {rename oo::objdefine::testself {}}
|
||||
} -result {{} {1 {this command may only be called from within the context of an ::oo::define or ::oo::objdefine command} 0 ::obj}}
|
||||
|
||||
test oo-37.1 {TIP 500: private command propagates errors} -setup {
|
||||
oo::class create cls
|
||||
} -body {
|
||||
oo::define cls {
|
||||
private ::error "this is an error"
|
||||
}
|
||||
} -cleanup {
|
||||
cls destroy
|
||||
} -returnCodes error -result {this is an error}
|
||||
test oo-37.2 {TIP 500: private command propagates errors} -setup {
|
||||
oo::class create cls
|
||||
} -body {
|
||||
oo::define cls {
|
||||
private {
|
||||
::error "this is an error"
|
||||
}
|
||||
}
|
||||
} -cleanup {
|
||||
cls destroy
|
||||
} -returnCodes error -result {this is an error}
|
||||
test oo-37.3 {TIP 500: private command propagates errors} -setup {
|
||||
oo::object create obj
|
||||
} -body {
|
||||
oo::objdefine obj {
|
||||
private ::error "this is an error"
|
||||
}
|
||||
} -cleanup {
|
||||
obj destroy
|
||||
} -returnCodes error -result {this is an error}
|
||||
test oo-37.4 {TIP 500: private command propagates errors} -setup {
|
||||
oo::object create obj
|
||||
} -body {
|
||||
oo::objdefine obj {
|
||||
private {
|
||||
::error "this is an error"
|
||||
}
|
||||
}
|
||||
} -cleanup {
|
||||
obj destroy
|
||||
} -returnCodes error -result {this is an error}
|
||||
test oo-37.5 {TIP 500: private command can't be used outside definitions} -body {
|
||||
oo::define::private error "xyz"
|
||||
} -returnCodes error -result {this command may only be called from within the context of an ::oo::define or ::oo::objdefine command}
|
||||
test oo-37.6 {TIP 500: private command can't be used outside definitions} -body {
|
||||
oo::objdefine::private error "xyz"
|
||||
} -returnCodes error -result {this command may only be called from within the context of an ::oo::define or ::oo::objdefine command}
|
||||
|
||||
test oo-38.1 {TIP 500: private variables don't cross-interfere with each other or normal ones} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create clsA {
|
||||
superclass parent
|
||||
private variable x
|
||||
constructor {} {
|
||||
set x 1
|
||||
}
|
||||
method getA {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
oo::class create clsB {
|
||||
superclass clsA
|
||||
private {
|
||||
variable x
|
||||
}
|
||||
constructor {} {
|
||||
set x 2
|
||||
next
|
||||
}
|
||||
method getB {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
oo::class create clsC {
|
||||
superclass clsB
|
||||
variable x
|
||||
constructor {} {
|
||||
set x 3
|
||||
next
|
||||
}
|
||||
method getC {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
clsC create obj
|
||||
oo::objdefine obj {
|
||||
private {
|
||||
variable x
|
||||
}
|
||||
method setup {} {
|
||||
set x 4
|
||||
}
|
||||
method getO {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
obj setup
|
||||
list [obj getA] [obj getB] [obj getC] [obj getO] \
|
||||
[lsort [string map [list [info object creationid clsA] CLASS-A \
|
||||
[info object creationid clsB] CLASS-B \
|
||||
[info object creationid obj] OBJ] \
|
||||
[info object vars obj]]]
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {1 2 3 4 {{CLASS-A : x} {CLASS-B : x} {OBJ : x} x}}
|
||||
test oo-38.2 {TIP 500: private variables introspection} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls {
|
||||
superclass parent
|
||||
private {
|
||||
variable x1
|
||||
variable x2
|
||||
}
|
||||
variable y1 y2
|
||||
}
|
||||
cls create obj
|
||||
oo::objdefine obj {
|
||||
private variable a1 a2
|
||||
variable b1 b2
|
||||
}
|
||||
list [lsort [info class variables cls]] \
|
||||
[lsort [info class variables cls -private]] \
|
||||
[lsort [info object variables obj]] \
|
||||
[lsort [info object variables obj -private]]
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {{y1 y2} {x1 x2} {b1 b2} {a1 a2}}
|
||||
test oo-38.3 {TIP 500: private variables and oo::object·varname} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create clsA {
|
||||
superclass parent
|
||||
private {
|
||||
variable x
|
||||
}
|
||||
method getx {} {
|
||||
set x 1
|
||||
my varname x
|
||||
}
|
||||
method readx {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
oo::class create clsB {
|
||||
superclass clsA
|
||||
variable x
|
||||
method gety {} {
|
||||
set x 1
|
||||
my varname x
|
||||
}
|
||||
method ready {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
clsB create obj
|
||||
set [obj getx] 2
|
||||
set [obj gety] 3
|
||||
list [obj readx] [obj ready]
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {2 3}
|
||||
test oo-38.4 {TIP 500: private variables introspection} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls {
|
||||
superclass parent
|
||||
private {
|
||||
variable x1 x2
|
||||
}
|
||||
variable y1 y2
|
||||
constructor {} {
|
||||
variable z boo
|
||||
set x1 a
|
||||
set y1 c
|
||||
}
|
||||
method list {} {
|
||||
variable z
|
||||
set ok 1
|
||||
list [info locals] [lsort [info vars]] [info exist x2]
|
||||
}
|
||||
}
|
||||
cls create obj
|
||||
oo::objdefine obj {
|
||||
private variable a1 a2
|
||||
variable b1 b2
|
||||
method init {} {
|
||||
# Because we don't have a constructor to do this setup for us
|
||||
set a1 p
|
||||
set b1 r
|
||||
}
|
||||
method list {} {
|
||||
variable z
|
||||
set yes 1
|
||||
list {*}[next] [info locals] [lsort [info vars]] [info exist a2]
|
||||
}
|
||||
}
|
||||
obj init
|
||||
obj list
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {ok {ok x1 x2 y1 y2 z} 0 yes {a1 a2 b1 b2 yes z} 0}
|
||||
test oo-38.5 {TIP 500: private variables and oo::object·variable} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls1 {
|
||||
superclass parent
|
||||
private variable x
|
||||
method abc val {
|
||||
my variable x
|
||||
set x $val
|
||||
}
|
||||
method def val {
|
||||
my variable y
|
||||
set y $val
|
||||
}
|
||||
method get1 {} {
|
||||
my variable x y
|
||||
return [list $x $y]
|
||||
}
|
||||
}
|
||||
oo::class create cls2 {
|
||||
superclass cls1
|
||||
private variable x
|
||||
method x-exists {} {
|
||||
return [info exists x],[uplevel 1 {info exists x}]
|
||||
}
|
||||
method ghi x {
|
||||
# Additional instrumentation to show that we're not using the
|
||||
# resolved variable until we ask for it; the argument nixed that
|
||||
# happening by default.
|
||||
set val $x
|
||||
set before [my x-exists]
|
||||
unset x
|
||||
set x $val
|
||||
set mid [my x-exists]
|
||||
unset x
|
||||
set mid2 [my x-exists]
|
||||
my variable x
|
||||
set x $val
|
||||
set after [my x-exists]
|
||||
return "$before;$mid;$mid2;$after"
|
||||
}
|
||||
method jkl val {
|
||||
my variable y
|
||||
set y $val
|
||||
}
|
||||
method get2 {} {
|
||||
my variable x y
|
||||
return [list $x $y]
|
||||
}
|
||||
}
|
||||
cls2 create a
|
||||
a abc 123
|
||||
a def 234
|
||||
set tmp [a ghi 345]
|
||||
a jkl 456
|
||||
list $tmp [a get1] [a get2]
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {{0,1;0,1;0,0;1,1} {123 456} {345 456}}
|
||||
|
||||
test oo-39.1 {TIP 500: private methods internal call; class private} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create clsA {
|
||||
superclass parent
|
||||
variable x
|
||||
constructor {} {
|
||||
set x 1
|
||||
}
|
||||
method act {} {
|
||||
my step
|
||||
my step
|
||||
my step
|
||||
return
|
||||
}
|
||||
private {
|
||||
method step {} {
|
||||
incr x 2
|
||||
}
|
||||
}
|
||||
method x {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
clsA create obj
|
||||
obj act
|
||||
list [obj x] [catch {obj step} msg] $msg
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {7 1 {unknown method "step": must be act, destroy or x}}
|
||||
test oo-39.2 {TIP 500: private methods internal call; class private} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create clsA {
|
||||
superclass parent
|
||||
variable x
|
||||
constructor {} {
|
||||
set x 1
|
||||
}
|
||||
method act {} {
|
||||
my step
|
||||
my step
|
||||
my step
|
||||
return
|
||||
}
|
||||
private {
|
||||
method step {} {
|
||||
incr x 2
|
||||
}
|
||||
}
|
||||
method x {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
oo::class create clsB {
|
||||
superclass clsA
|
||||
variable x
|
||||
method step {} {
|
||||
incr x 5
|
||||
}
|
||||
}
|
||||
clsB create obj
|
||||
obj act
|
||||
list [obj x] [obj step]
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {7 12}
|
||||
test oo-39.3 {TIP 500: private methods internal call; class private} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create clsA {
|
||||
superclass parent
|
||||
variable x
|
||||
constructor {} {
|
||||
set x 1
|
||||
}
|
||||
method act {} {
|
||||
my Step
|
||||
my Step
|
||||
my Step
|
||||
return
|
||||
}
|
||||
method x {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
oo::class create clsB {
|
||||
superclass clsA
|
||||
variable x
|
||||
method Step {} {
|
||||
incr x 5
|
||||
}
|
||||
}
|
||||
clsB create obj
|
||||
obj act
|
||||
set result [obj x]
|
||||
oo::define clsA {
|
||||
private {
|
||||
method Step {} {
|
||||
incr x 2
|
||||
}
|
||||
}
|
||||
}
|
||||
obj act
|
||||
lappend result [obj x]
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {16 22}
|
||||
test oo-39.4 {TIP 500: private methods internal call; instance private} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create clsA {
|
||||
superclass parent
|
||||
variable x
|
||||
constructor {} {
|
||||
set x 1
|
||||
}
|
||||
method act {} {
|
||||
my step
|
||||
return
|
||||
}
|
||||
method step {} {
|
||||
incr x
|
||||
}
|
||||
method x {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
clsA create obj
|
||||
obj act
|
||||
set result [obj x]
|
||||
oo::objdefine obj {
|
||||
variable x
|
||||
private {
|
||||
method step {} {
|
||||
incr x 2
|
||||
}
|
||||
}
|
||||
}
|
||||
obj act
|
||||
lappend result [obj x]
|
||||
oo::objdefine obj {
|
||||
method act {} {
|
||||
my step
|
||||
next
|
||||
}
|
||||
}
|
||||
obj act
|
||||
lappend result [obj x]
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {2 3 6}
|
||||
test oo-39.5 {TIP 500: private methods internal call; cross object} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls {
|
||||
superclass parent
|
||||
variable x
|
||||
constructor {val} {
|
||||
set x $val
|
||||
}
|
||||
private method x {} {
|
||||
return $x
|
||||
}
|
||||
method equal {other} {
|
||||
expr {$x == [$other x]}
|
||||
}
|
||||
}
|
||||
cls create a 1
|
||||
cls create b 2
|
||||
cls create c 1
|
||||
list [a equal b] [b equal c] [c equal a] [catch {a x} msg] $msg
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {0 0 1 1 {unknown method "x": must be destroy or equal}}
|
||||
test oo-39.6 {TIP 500: private methods internal call; error reporting} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls {
|
||||
superclass parent
|
||||
variable x
|
||||
constructor {val} {
|
||||
set x $val
|
||||
}
|
||||
private method x {} {
|
||||
return $x
|
||||
}
|
||||
method equal {other} {
|
||||
expr {$x == [$other y]}
|
||||
}
|
||||
}
|
||||
cls create a 1
|
||||
cls create b 2
|
||||
a equal b
|
||||
} -returnCodes error -cleanup {
|
||||
parent destroy
|
||||
} -result {unknown method "y": must be destroy, equal or x}
|
||||
test oo-39.7 {TIP 500: private methods internal call; error reporting} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls {
|
||||
superclass parent
|
||||
variable x
|
||||
constructor {val} {
|
||||
set x $val
|
||||
}
|
||||
private method x {} {
|
||||
return $x
|
||||
}
|
||||
method equal {other} {
|
||||
expr {[[self] y] == [$other x]}
|
||||
}
|
||||
}
|
||||
cls create a 1
|
||||
cls create b 2
|
||||
a equal b
|
||||
} -returnCodes error -cleanup {
|
||||
parent destroy
|
||||
} -result {unknown method "y": must be destroy, equal or x}
|
||||
test oo-39.8 {TIP 500: private methods internal call; error reporting} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls {
|
||||
superclass parent
|
||||
variable x
|
||||
constructor {val} {
|
||||
set x $val
|
||||
}
|
||||
private method x {} {
|
||||
return $x
|
||||
}
|
||||
method equal {other} {
|
||||
expr {[my y] == [$other x]}
|
||||
}
|
||||
}
|
||||
cls create a 1
|
||||
cls create b 2
|
||||
a equal b
|
||||
} -returnCodes error -cleanup {
|
||||
parent destroy
|
||||
} -result {unknown method "y": must be <cloned>, destroy, equal, eval, unknown, variable, varname or x}
|
||||
test oo-39.9 {TIP 500: private methods internal call; error reporting} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls {
|
||||
superclass parent
|
||||
variable x
|
||||
constructor {val} {
|
||||
set x $val
|
||||
}
|
||||
private method x {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
oo::class create cls2 {
|
||||
superclass cls
|
||||
method equal {other} {
|
||||
expr {[my y] == [$other x]}
|
||||
}
|
||||
}
|
||||
cls2 create a 1
|
||||
cls2 create b 2
|
||||
a equal b
|
||||
} -returnCodes error -cleanup {
|
||||
parent destroy
|
||||
} -result {unknown method "y": must be <cloned>, destroy, equal, eval, unknown, variable or varname}
|
||||
test oo-39.10 {TIP 500: private methods internal call; error reporting} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls {
|
||||
superclass parent
|
||||
variable x
|
||||
constructor {val} {
|
||||
set x $val
|
||||
}
|
||||
private method x {} {
|
||||
return $x
|
||||
}
|
||||
}
|
||||
oo::class create cls2 {
|
||||
superclass cls
|
||||
method equal {other} {
|
||||
expr {[my x] == [$other x]}
|
||||
}
|
||||
}
|
||||
cls2 create a 1
|
||||
cls2 create b 2
|
||||
a equal b
|
||||
} -returnCodes error -cleanup {
|
||||
parent destroy
|
||||
} -result {unknown method "x": must be <cloned>, destroy, equal, eval, unknown, variable or varname}
|
||||
test oo-39.11 {TIP 500: private methods; call chain caching and reporting} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls {
|
||||
superclass parent
|
||||
method chain {} {
|
||||
return [self call]
|
||||
}
|
||||
}
|
||||
oo::class create cls2 {
|
||||
superclass cls
|
||||
private method chain {} {
|
||||
next
|
||||
}
|
||||
method chain2 {} {
|
||||
my chain
|
||||
}
|
||||
method chain3 {} {
|
||||
[self] chain
|
||||
}
|
||||
}
|
||||
cls create a
|
||||
cls2 create b
|
||||
list [a chain] [b chain] [b chain2] [b chain3]
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {{{{method chain ::cls method}} 0} {{{method chain ::cls method}} 0} {{{private chain ::cls2 method} {method chain ::cls method}} 1} {{{private chain ::cls2 method} {method chain ::cls method}} 1}}
|
||||
test oo-39.12 {TIP 500: private methods; introspection} -setup {
|
||||
oo::class create parent
|
||||
} -body {
|
||||
oo::class create cls {
|
||||
superclass parent
|
||||
method chain {} {
|
||||
return [self call]
|
||||
}
|
||||
private method abc {} {}
|
||||
}
|
||||
oo::class create cls2 {
|
||||
superclass cls
|
||||
method chain2 {} {
|
||||
my chain
|
||||
}
|
||||
method chain3 {} {
|
||||
[self] chain
|
||||
}
|
||||
private method def {} {}
|
||||
unexport chain3
|
||||
}
|
||||
cls create a
|
||||
cls2 create b
|
||||
oo::objdefine b {
|
||||
private method ghi {} {}
|
||||
method ABC {} {}
|
||||
method foo {} {}
|
||||
}
|
||||
set scopes {public unexported private}
|
||||
list a: [lmap s $scopes {info object methods a -scope $s}] \
|
||||
b: [lmap s $scopes {info object methods b -scope $s}] \
|
||||
cls: [lmap s $scopes {info class methods cls -scope $s}] \
|
||||
cls2: [lmap s $scopes {info class methods cls2 -scope $s}] \
|
||||
} -cleanup {
|
||||
parent destroy
|
||||
} -result {a: {{} {} {}} b: {foo ABC ghi} cls: {chain {} abc} cls2: {chain2 chain3 def}}
|
||||
|
||||
test oo-40.1 {TIP 500: private and self} -setup {
|
||||
oo::class create cls
|
||||
} -body {
|
||||
oo::define cls {
|
||||
self {
|
||||
private {
|
||||
variable a
|
||||
}
|
||||
variable b
|
||||
}
|
||||
private {
|
||||
self {
|
||||
variable c
|
||||
}
|
||||
variable d
|
||||
}
|
||||
variable e
|
||||
}
|
||||
list \
|
||||
[lsort [info class variables cls]] \
|
||||
[lsort [info class variables cls -private]] \
|
||||
[lsort [info object variables cls]] \
|
||||
[lsort [info object variables cls -private]]
|
||||
} -cleanup {
|
||||
cls destroy
|
||||
} -result {e d b {a c}}
|
||||
test oo-40.2 {TIP 500: private and export} -setup {
|
||||
oo::class create cls
|
||||
} -body {
|
||||
oo::define cls {
|
||||
private method foo {} {}
|
||||
}
|
||||
set result [lmap s {public unexported private} {
|
||||
info class methods cls -scope $s}]
|
||||
oo::define cls {
|
||||
export foo
|
||||
}
|
||||
lappend result {*}[lmap s {public unexported private} {
|
||||
info class methods cls -scope $s}]
|
||||
} -cleanup {
|
||||
cls destroy
|
||||
} -result {{} {} foo foo {} {}}
|
||||
test oo-40.3 {TIP 500: private and unexport} -setup {
|
||||
oo::class create cls
|
||||
} -body {
|
||||
oo::define cls {
|
||||
private method foo {} {}
|
||||
}
|
||||
set result [lmap s {public unexported private} {
|
||||
info class methods cls -scope $s}]
|
||||
oo::define cls {
|
||||
unexport foo
|
||||
}
|
||||
lappend result {*}[lmap s {public unexported private} {
|
||||
info class methods cls -scope $s}]
|
||||
} -cleanup {
|
||||
cls destroy
|
||||
} -result {{} {} foo {} foo {}}
|
||||
|
||||
cleanupTests
|
||||
return
|
||||
|
||||
+259
-6
@@ -13,19 +13,272 @@ if {[lsearch [namespace children] ::tcltest] == -1} {
|
||||
namespace import -force ::tcltest::*
|
||||
}
|
||||
|
||||
# Utilities
|
||||
set path(sleep) [makeFile {
|
||||
after [expr $argv*1000]
|
||||
exit
|
||||
} sleep]
|
||||
set path(exit) [makeFile {
|
||||
exit $argv
|
||||
} exit]
|
||||
|
||||
# Basic syntax checking
|
||||
test process-1.1 {tcl::process command basic syntax} -returnCodes error -body {
|
||||
tcl::process
|
||||
} -result {wrong # args: should be "tcl::process subcommand ?arg ...?"}
|
||||
test process-1.2 {tcl::process command basic syntax} -returnCodes error -body {
|
||||
test process-1.2 {tcl::process subcommands} -returnCodes error -body {
|
||||
tcl::process ?
|
||||
} -match glob -result {unknown or ambiguous subcommand "?": must be autopurge, list, purge, or status}
|
||||
|
||||
test process-2.1 {tcl::process autopurge get} {tcl::process autopurge} {1}
|
||||
test process-2.2 {tcl::process autopurge set true} {
|
||||
# Autopurge flag
|
||||
# - Default state
|
||||
test process-2.1 {autopurge default} -body {
|
||||
tcl::process autopurge
|
||||
} -result {1}
|
||||
# - Enabling autopurge
|
||||
test process-2.2 {enable autopurge} -body {
|
||||
tcl::process autopurge true
|
||||
tcl::process autopurge
|
||||
} {1}
|
||||
test process-2.3 {tcl::process autopurge set false} {
|
||||
} -result {1}
|
||||
# - Disabling autopurge
|
||||
test process-2.3 {disable autopurge} -body {
|
||||
tcl::process autopurge false
|
||||
tcl::process autopurge
|
||||
} {0}
|
||||
} -result {0} -cleanup {tcl::process autopurge true}
|
||||
|
||||
# Subprocess list & status
|
||||
test process-3.1 {empty subprocess list} -body {
|
||||
llength [tcl::process list]
|
||||
} -result {0}
|
||||
test process-3.2 {empty subprocess status} -body {
|
||||
dict size [tcl::process status]
|
||||
} -result {0}
|
||||
|
||||
# Spawn subprocesses using [exec]
|
||||
# - One child
|
||||
test process-4.1 {exec one child} -body {
|
||||
tcl::process autopurge 0
|
||||
set pid [exec [interpreter] $path(exit) 0 &]
|
||||
set list [tcl::process list]
|
||||
set statuses [tcl::process status -wait]
|
||||
set status [lindex [tcl::process status $pid] 1]
|
||||
expr {
|
||||
[llength $list] eq 1
|
||||
&& [lindex $list 0] eq $pid
|
||||
&& [dict size $statuses] eq 1
|
||||
&& [dict get $statuses $pid] eq $status
|
||||
&& $status eq 0
|
||||
}
|
||||
} -result {1} -cleanup {
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
# - Two children
|
||||
test process-4.2 {exec two children in parallel} -body {
|
||||
tcl::process autopurge 0
|
||||
set pid1 [exec [interpreter] $path(exit) 0 &]
|
||||
set pid2 [exec [interpreter] $path(exit) 0 &]
|
||||
set list [tcl::process list]
|
||||
set statuses [tcl::process status -wait]
|
||||
set status1 [lindex [tcl::process status $pid1] 1]
|
||||
set status2 [lindex [tcl::process status $pid2] 1]
|
||||
expr {
|
||||
[llength $list] eq 2
|
||||
&& [lsearch $list $pid1] >= 0
|
||||
&& [lsearch $list $pid2] >= 0
|
||||
&& [dict size $statuses] eq 2
|
||||
&& [dict get $statuses $pid1] eq $status1
|
||||
&& [dict get $statuses $pid2] eq $status2
|
||||
&& $status1 eq 0
|
||||
&& $status2 eq 0
|
||||
}
|
||||
} -result {1} -cleanup {
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
# - 3-stage pipe
|
||||
test process-4.3 {exec 3-stage pipe} -body {
|
||||
tcl::process autopurge 0
|
||||
set pids [exec \
|
||||
[interpreter] $path(exit) 0 \
|
||||
| [interpreter] $path(exit) 0 \
|
||||
| [interpreter] $path(exit) 0 \
|
||||
&]
|
||||
lassign $pids pid1 pid2 pid3
|
||||
set list [tcl::process list]
|
||||
set statuses [tcl::process status -wait]
|
||||
set status1 [lindex [tcl::process status $pid1] 1]
|
||||
set status2 [lindex [tcl::process status $pid2] 1]
|
||||
set status3 [lindex [tcl::process status $pid3] 1]
|
||||
expr {
|
||||
[llength $pids] eq 3
|
||||
&& [llength $list] eq 3
|
||||
&& [lsearch $list $pid1] >= 0
|
||||
&& [lsearch $list $pid2] >= 0
|
||||
&& [lsearch $list $pid3] >= 0
|
||||
&& [dict size $statuses] eq 3
|
||||
&& [dict get $statuses $pid1] eq $status1
|
||||
&& [dict get $statuses $pid2] eq $status2
|
||||
&& [dict get $statuses $pid3] eq $status3
|
||||
&& $status1 eq 0
|
||||
&& $status2 eq 0
|
||||
&& $status3 eq 0
|
||||
}
|
||||
} -result {1} -cleanup {
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
|
||||
# Spawn subprocesses using [open "|"]
|
||||
# - One child
|
||||
test process-5.1 {exec one child} -body {
|
||||
tcl::process autopurge 0
|
||||
set f [open "|\"[interpreter]\" \"$path(exit)\" 0"]
|
||||
set pid [pid $f]
|
||||
set list [tcl::process list]
|
||||
set statuses [tcl::process status -wait]
|
||||
set status [lindex [tcl::process status $pid] 1]
|
||||
expr {
|
||||
[llength $list] eq 1
|
||||
&& [lindex $list 0] eq $pid
|
||||
&& [dict size $statuses] eq 1
|
||||
&& [dict get $statuses $pid] eq $status
|
||||
&& $status eq 0
|
||||
}
|
||||
} -result {1} -cleanup {
|
||||
close $f
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
# - Two children
|
||||
test process-5.2 {exec two children in parallel} -body {
|
||||
tcl::process autopurge 0
|
||||
set f1 [open "|\"[interpreter]\" \"$path(exit)\" 0"]
|
||||
set f2 [open "|\"[interpreter]\" \"$path(exit)\" 0"]
|
||||
set pid1 [pid $f1]
|
||||
set pid2 [pid $f2]
|
||||
set list [tcl::process list]
|
||||
set statuses [tcl::process status -wait]
|
||||
set status1 [lindex [tcl::process status $pid1] 1]
|
||||
set status2 [lindex [tcl::process status $pid2] 1]
|
||||
expr {
|
||||
[llength $list] eq 2
|
||||
&& [lsearch $list $pid1] >= 0
|
||||
&& [lsearch $list $pid2] >= 0
|
||||
&& [dict size $statuses] eq 2
|
||||
&& [dict get $statuses $pid1] eq $status1
|
||||
&& [dict get $statuses $pid2] eq $status2
|
||||
&& $status1 eq 0
|
||||
&& $status2 eq 0
|
||||
}
|
||||
} -result {1} -cleanup {
|
||||
close $f1
|
||||
close $f2
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
# - 3-stage pipe
|
||||
test process-5.3 {exec 3-stage pipe} -body {
|
||||
tcl::process autopurge 0
|
||||
set f [open "|
|
||||
\"[interpreter]\" \"$path(exit)\" 0
|
||||
| \"[interpreter]\" \"$path(exit)\" 0
|
||||
| \"[interpreter]\" \"$path(exit)\" 0
|
||||
"]
|
||||
set pids [pid $f]
|
||||
lassign $pids pid1 pid2 pid3
|
||||
set list [tcl::process list]
|
||||
set statuses [tcl::process status -wait]
|
||||
set status1 [lindex [tcl::process status $pid1] 1]
|
||||
set status2 [lindex [tcl::process status $pid2] 1]
|
||||
set status3 [lindex [tcl::process status $pid3] 1]
|
||||
expr {
|
||||
[llength $pids] eq 3
|
||||
&& [llength $list] eq 3
|
||||
&& [lsearch $list $pid1] >= 0
|
||||
&& [lsearch $list $pid2] >= 0
|
||||
&& [lsearch $list $pid3] >= 0
|
||||
&& [dict size $statuses] eq 3
|
||||
&& [dict get $statuses $pid1] eq $status1
|
||||
&& [dict get $statuses $pid2] eq $status2
|
||||
&& [dict get $statuses $pid3] eq $status3
|
||||
&& $status1 eq 0
|
||||
&& $status2 eq 0
|
||||
&& $status3 eq 0
|
||||
}
|
||||
} -result {1} -cleanup {
|
||||
close $f
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
|
||||
# Async child status
|
||||
test process-6.1 {async status} -body {
|
||||
tcl::process autopurge 0
|
||||
set pid [exec [interpreter] $path(sleep) 1 &]
|
||||
set status1 [lindex [tcl::process status $pid] 1]
|
||||
set status2 [lindex [tcl::process status -wait $pid] 1]
|
||||
expr {
|
||||
$status1 eq {}
|
||||
&& $status2 eq 0
|
||||
}
|
||||
} -result {1} -cleanup {
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
test process-6.2 {selective wait} -body {
|
||||
tcl::process autopurge 0
|
||||
# Child 1 sleeps 1s
|
||||
set pid1 [exec [interpreter] $path(sleep) 1 &]
|
||||
# Child 2 sleeps 1s
|
||||
set pid2 [exec [interpreter] $path(sleep) 2 &]
|
||||
# Initial status
|
||||
set status1_1 [lindex [tcl::process status $pid1] 1]
|
||||
set status1_2 [lindex [tcl::process status $pid2] 1]
|
||||
# Wait until child 1 termination
|
||||
set status2_1 [lindex [tcl::process status -wait $pid1] 1]
|
||||
set status2_2 [lindex [tcl::process status $pid2] 1]
|
||||
# Wait until child 2 termination
|
||||
set status3_2 [lindex [tcl::process status -wait $pid2] 1]
|
||||
set status3_1 [lindex [tcl::process status $pid1] 1]
|
||||
expr {
|
||||
$status1_1 eq {}
|
||||
&& $status1_2 eq {}
|
||||
&& $status2_1 eq 0
|
||||
&& $status2_2 eq {}
|
||||
&& $status3_1 eq 0
|
||||
&& $status3_2 eq 0
|
||||
}
|
||||
} -result {1} -cleanup {
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
|
||||
# Error codes
|
||||
test process-7.1 {normal exit} -body {
|
||||
tcl::process autopurge 0
|
||||
set pid [exec [interpreter] $path(exit) 0 &]
|
||||
lindex [tcl::process status -wait $pid] 1
|
||||
} -result {0} -cleanup {
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
test process-7.2 {abnormal exit} -body {
|
||||
tcl::process autopurge 0
|
||||
set pid [exec [interpreter] $path(exit) 1 &]
|
||||
lindex [tcl::process status -wait $pid] 1
|
||||
} -match glob -result {1 {child process exited abnormally} {CHILDSTATUS * 1}} -cleanup {
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
test process-7.3 {child killed} -constraints {win} -body {
|
||||
tcl::process autopurge 0
|
||||
set pid [exec [interpreter] $path(exit) -1 &]
|
||||
lindex [tcl::process status -wait $pid] 1
|
||||
} -match glob -result {1 {child killed: unknown signal} {CHILDKILLED * {unknown signal} {unknown signal}}} -cleanup {
|
||||
tcl::process purge
|
||||
tcl::process autopurge 1
|
||||
}
|
||||
|
||||
::tcltest::cleanupTests
|
||||
return
|
||||
|
||||
@@ -18,16 +18,11 @@ if {[lsearch [namespace children] ::tcltest] == -1} {
|
||||
# When run in a Tk shell, these tests hang.
|
||||
testConstraint noTk [expr {0 != [catch {package present Tk}]}]
|
||||
testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}]
|
||||
# Darwin always uses a threaded notifier
|
||||
testConstraint unthreaded [expr {
|
||||
![::tcl::pkgconfig get threaded]
|
||||
&& $tcl_platform(os) ne "Darwin"
|
||||
}]
|
||||
|
||||
# The next two tests will hang if threads are enabled because the notifier
|
||||
# will not necessarily wait for ever in this case, so it does not generate
|
||||
# an error.
|
||||
test unixNotfy-1.1 {Tcl_DeleteFileHandler} -constraints {noTk unix unthreaded} -body {
|
||||
test unixNotfy-1.1 {Tcl_DeleteFileHandler} -constraints nonPortable -body {
|
||||
catch {vwait x}
|
||||
set f [open [makeFile "" foo] w]
|
||||
fileevent $f writable {set x 1}
|
||||
@@ -38,7 +33,7 @@ test unixNotfy-1.1 {Tcl_DeleteFileHandler} -constraints {noTk unix unthreaded} -
|
||||
catch { close $f }
|
||||
catch { removeFile foo }
|
||||
}
|
||||
test unixNotfy-1.2 {Tcl_DeleteFileHandler} -constraints {noTk unix unthreaded} -body {
|
||||
test unixNotfy-1.2 {Tcl_DeleteFileHandler} -constraints nonPortable -body {
|
||||
catch {vwait x}
|
||||
set f1 [open [makeFile "" foo] w]
|
||||
set f2 [open [makeFile "" foo2] w]
|
||||
|
||||
+8
-10
@@ -41,7 +41,7 @@ test utf-1.5 {Tcl_UniCharToUtf: overflowed Tcl_UniChar} testbytestring {
|
||||
test utf-1.6 {Tcl_UniCharToUtf: negative Tcl_UniChar} testbytestring {
|
||||
expr {[format %c -1] eq [testbytestring "\xef\xbf\xbd"]}
|
||||
} 1
|
||||
test utf-1.7 {Tcl_UniCharToUtf: 4 byte sequences} -constraints {tip389 testbytestring} -body {
|
||||
test utf-1.7 {Tcl_UniCharToUtf: 4 byte sequences} -constraints testbytestring -body {
|
||||
expr {"\U014e4e" eq [testbytestring "\xf0\x94\xb9\x8e"]}
|
||||
} -result 1
|
||||
|
||||
@@ -228,15 +228,13 @@ bsCheck \U4e21 20001
|
||||
bsCheck \U004e21 20001
|
||||
bsCheck \U00004e21 20001
|
||||
bsCheck \U0000004e21 78
|
||||
if {[testConstraint tip389]} {
|
||||
bsCheck \U00110000 69632
|
||||
bsCheck \U01100000 69632
|
||||
bsCheck \U11000000 69632
|
||||
bsCheck \U0010FFFF 1114111
|
||||
bsCheck \U010FFFF0 1114111
|
||||
bsCheck \U10FFFF00 1114111
|
||||
bsCheck \UFFFFFFFF 1048575
|
||||
}
|
||||
bsCheck \U00110000 69632
|
||||
bsCheck \U01100000 69632
|
||||
bsCheck \U11000000 69632
|
||||
bsCheck \U0010FFFF 1114111
|
||||
bsCheck \U010FFFF0 1114111
|
||||
bsCheck \U10FFFF00 1114111
|
||||
bsCheck \UFFFFFFFF 1048575
|
||||
|
||||
test utf-11.1 {Tcl_UtfToUpper} {
|
||||
string toupper {}
|
||||
|
||||
+1
-1
@@ -1061,7 +1061,7 @@ test winFCmd-12.6.2 {ConvertFileNameFormat: absolute path with drive (in temp fo
|
||||
} -constraints {win} -body {
|
||||
createfile $::env(TEMP)/td1 {}
|
||||
string equal [string tolower [file attributes $::env(TEMP)/td1 -longname]] \
|
||||
[string tolower [file normalize $::env(TEMP)]/td1]]
|
||||
[string tolower [file normalize $::env(TEMP)]/td1]
|
||||
} -cleanup {
|
||||
file delete -force -- $::env(TEMP)/td1
|
||||
} -result 1
|
||||
|
||||
+1
-1
@@ -1759,7 +1759,7 @@ configure-packages:
|
||||
$$i/configure --with-tcl=../.. \
|
||||
--with-tclinclude=$(GENERIC_DIR) \
|
||||
$(PKG_CFG_ARGS) --libdir=$(PACKAGE_DIR) \
|
||||
--enable-shared --enable-threads; ) || exit $$?; \
|
||||
--enable-shared; ) || exit $$?; \
|
||||
fi; \
|
||||
fi; \
|
||||
fi; \
|
||||
|
||||
@@ -45,8 +45,6 @@ How To Compile And Install Tcl:
|
||||
refer to the autoconf documentation (not included here). Tcl's "configure"
|
||||
supports the following special switches in addition to the standard ones:
|
||||
|
||||
--enable-threads If this switch is set, Tcl will compile itself
|
||||
with multithreading support.
|
||||
--disable-load If this switch is specified then Tcl will
|
||||
configure itself not to allow dynamic loading,
|
||||
even if your system appears to support it.
|
||||
|
||||
Vendored
+301
-382
@@ -699,7 +699,6 @@ ZLIB_INCLUDE
|
||||
ZLIB_SRCS
|
||||
ZLIB_OBJS
|
||||
TCLSH_PROG
|
||||
TCL_THREADS
|
||||
EGREP
|
||||
GREP
|
||||
CPP
|
||||
@@ -755,7 +754,6 @@ enable_option_checking
|
||||
enable_man_symlinks
|
||||
enable_man_compression
|
||||
enable_man_suffix
|
||||
enable_threads
|
||||
with_encoding
|
||||
enable_shared
|
||||
enable_64bit
|
||||
@@ -1395,7 +1393,6 @@ Optional Features:
|
||||
use STRING as a suffix to manpage file names
|
||||
(default: no, tcl if enabled without
|
||||
specifying STRING)
|
||||
--enable-threads build with threads (default: on)
|
||||
--enable-shared build and link with shared libraries (default: on)
|
||||
--enable-64bit enable 64bit support (default: off)
|
||||
--enable-64bit-vis enable 64bit Sparc VIS support (default: off)
|
||||
@@ -3910,323 +3907,6 @@ $as_echo "$tcl_cv_cc_pipe" >&6; }
|
||||
fi
|
||||
fi
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# Threads support
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Check whether --enable-threads was given.
|
||||
if test "${enable_threads+set}" = set; then :
|
||||
enableval=$enable_threads; tcl_ok=$enableval
|
||||
else
|
||||
tcl_ok=yes
|
||||
fi
|
||||
|
||||
|
||||
if test "${TCL_THREADS}" = 1; then
|
||||
tcl_threaded_core=1;
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then
|
||||
TCL_THREADS=1
|
||||
# USE_THREAD_ALLOC tells us to try the special thread-based
|
||||
# allocator that significantly reduces lock contention
|
||||
|
||||
$as_echo "#define USE_THREAD_ALLOC 1" >>confdefs.h
|
||||
|
||||
|
||||
$as_echo "#define _REENTRANT 1" >>confdefs.h
|
||||
|
||||
if test "`uname -s`" = "SunOS" ; then
|
||||
|
||||
$as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
$as_echo "#define _THREAD_SAFE 1" >>confdefs.h
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5
|
||||
$as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; }
|
||||
if ${ac_cv_lib_pthread_pthread_mutex_init+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lpthread $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char pthread_mutex_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return pthread_mutex_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_pthread_pthread_mutex_init=yes
|
||||
else
|
||||
ac_cv_lib_pthread_pthread_mutex_init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5
|
||||
$as_echo "$ac_cv_lib_pthread_pthread_mutex_init" >&6; }
|
||||
if test "x$ac_cv_lib_pthread_pthread_mutex_init" = xyes; then :
|
||||
tcl_ok=yes
|
||||
else
|
||||
tcl_ok=no
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "no"; then
|
||||
# Check a little harder for __pthread_mutex_init in the same
|
||||
# library, as some systems hide it there until pthread.h is
|
||||
# defined. We could alternatively do an AC_TRY_COMPILE with
|
||||
# pthread.h, but that will work with libpthread really doesn't
|
||||
# exist, like AIX 4.2. [Bug: 4359]
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5
|
||||
$as_echo_n "checking for __pthread_mutex_init in -lpthread... " >&6; }
|
||||
if ${ac_cv_lib_pthread___pthread_mutex_init+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lpthread $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char __pthread_mutex_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return __pthread_mutex_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_pthread___pthread_mutex_init=yes
|
||||
else
|
||||
ac_cv_lib_pthread___pthread_mutex_init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5
|
||||
$as_echo "$ac_cv_lib_pthread___pthread_mutex_init" >&6; }
|
||||
if test "x$ac_cv_lib_pthread___pthread_mutex_init" = xyes; then :
|
||||
tcl_ok=yes
|
||||
else
|
||||
tcl_ok=no
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -lpthread"
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5
|
||||
$as_echo_n "checking for pthread_mutex_init in -lpthreads... " >&6; }
|
||||
if ${ac_cv_lib_pthreads_pthread_mutex_init+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lpthreads $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char pthread_mutex_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return pthread_mutex_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_pthreads_pthread_mutex_init=yes
|
||||
else
|
||||
ac_cv_lib_pthreads_pthread_mutex_init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5
|
||||
$as_echo "$ac_cv_lib_pthreads_pthread_mutex_init" >&6; }
|
||||
if test "x$ac_cv_lib_pthreads_pthread_mutex_init" = xyes; then :
|
||||
tcl_ok=yes
|
||||
else
|
||||
tcl_ok=no
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -lpthreads"
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5
|
||||
$as_echo_n "checking for pthread_mutex_init in -lc... " >&6; }
|
||||
if ${ac_cv_lib_c_pthread_mutex_init+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lc $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char pthread_mutex_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return pthread_mutex_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_c_pthread_mutex_init=yes
|
||||
else
|
||||
ac_cv_lib_c_pthread_mutex_init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_pthread_mutex_init" >&5
|
||||
$as_echo "$ac_cv_lib_c_pthread_mutex_init" >&6; }
|
||||
if test "x$ac_cv_lib_c_pthread_mutex_init" = xyes; then :
|
||||
tcl_ok=yes
|
||||
else
|
||||
tcl_ok=no
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "no"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5
|
||||
$as_echo_n "checking for pthread_mutex_init in -lc_r... " >&6; }
|
||||
if ${ac_cv_lib_c_r_pthread_mutex_init+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lc_r $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char pthread_mutex_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return pthread_mutex_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_c_r_pthread_mutex_init=yes
|
||||
else
|
||||
ac_cv_lib_c_r_pthread_mutex_init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5
|
||||
$as_echo "$ac_cv_lib_c_r_pthread_mutex_init" >&6; }
|
||||
if test "x$ac_cv_lib_c_r_pthread_mutex_init" = xyes; then :
|
||||
tcl_ok=yes
|
||||
else
|
||||
tcl_ok=no
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -pthread"
|
||||
else
|
||||
TCL_THREADS=0
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Don't know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile..." >&5
|
||||
$as_echo "$as_me: WARNING: Don't know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile..." >&2;}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Does the pthread-implementation provide
|
||||
# 'pthread_attr_setstacksize' ?
|
||||
|
||||
ac_saved_libs=$LIBS
|
||||
LIBS="$LIBS $THREADS_LIBS"
|
||||
for ac_func in pthread_attr_setstacksize pthread_atfork
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
LIBS=$ac_saved_libs
|
||||
else
|
||||
TCL_THREADS=0
|
||||
fi
|
||||
# Do checking message here to not mess up interleaved configure output
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5
|
||||
$as_echo_n "checking for building with threads... " >&6; }
|
||||
if test "${TCL_THREADS}" = 1; then
|
||||
|
||||
$as_echo "#define TCL_THREADS 1" >>confdefs.h
|
||||
|
||||
if test "${tcl_threaded_core}" = 1; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (threaded core)" >&5
|
||||
$as_echo "yes (threaded core)" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
fi
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# Embedded configuration information, encoding to use for the values, TIP #59
|
||||
#------------------------------------------------------------------------
|
||||
@@ -4454,6 +4134,269 @@ fi
|
||||
|
||||
|
||||
|
||||
$as_echo "#define _REENTRANT 1" >>confdefs.h
|
||||
|
||||
|
||||
$as_echo "#define _THREAD_SAFE 1" >>confdefs.h
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5
|
||||
$as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; }
|
||||
if ${ac_cv_lib_pthread_pthread_mutex_init+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lpthread $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char pthread_mutex_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return pthread_mutex_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_pthread_pthread_mutex_init=yes
|
||||
else
|
||||
ac_cv_lib_pthread_pthread_mutex_init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5
|
||||
$as_echo "$ac_cv_lib_pthread_pthread_mutex_init" >&6; }
|
||||
if test "x$ac_cv_lib_pthread_pthread_mutex_init" = xyes; then :
|
||||
tcl_ok=yes
|
||||
else
|
||||
tcl_ok=no
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "no"; then
|
||||
# Check a little harder for __pthread_mutex_init in the same
|
||||
# library, as some systems hide it there until pthread.h is
|
||||
# defined. We could alternatively do an AC_TRY_COMPILE with
|
||||
# pthread.h, but that will work with libpthread really doesn't
|
||||
# exist, like AIX 4.2. [Bug: 4359]
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5
|
||||
$as_echo_n "checking for __pthread_mutex_init in -lpthread... " >&6; }
|
||||
if ${ac_cv_lib_pthread___pthread_mutex_init+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lpthread $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char __pthread_mutex_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return __pthread_mutex_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_pthread___pthread_mutex_init=yes
|
||||
else
|
||||
ac_cv_lib_pthread___pthread_mutex_init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5
|
||||
$as_echo "$ac_cv_lib_pthread___pthread_mutex_init" >&6; }
|
||||
if test "x$ac_cv_lib_pthread___pthread_mutex_init" = xyes; then :
|
||||
tcl_ok=yes
|
||||
else
|
||||
tcl_ok=no
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -lpthread"
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5
|
||||
$as_echo_n "checking for pthread_mutex_init in -lpthreads... " >&6; }
|
||||
if ${ac_cv_lib_pthreads_pthread_mutex_init+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lpthreads $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char pthread_mutex_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return pthread_mutex_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_pthreads_pthread_mutex_init=yes
|
||||
else
|
||||
ac_cv_lib_pthreads_pthread_mutex_init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5
|
||||
$as_echo "$ac_cv_lib_pthreads_pthread_mutex_init" >&6; }
|
||||
if test "x$ac_cv_lib_pthreads_pthread_mutex_init" = xyes; then :
|
||||
_ok=yes
|
||||
else
|
||||
tcl_ok=no
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -lpthreads"
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5
|
||||
$as_echo_n "checking for pthread_mutex_init in -lc... " >&6; }
|
||||
if ${ac_cv_lib_c_pthread_mutex_init+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lc $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char pthread_mutex_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return pthread_mutex_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_c_pthread_mutex_init=yes
|
||||
else
|
||||
ac_cv_lib_c_pthread_mutex_init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_pthread_mutex_init" >&5
|
||||
$as_echo "$ac_cv_lib_c_pthread_mutex_init" >&6; }
|
||||
if test "x$ac_cv_lib_c_pthread_mutex_init" = xyes; then :
|
||||
tcl_ok=yes
|
||||
else
|
||||
tcl_ok=no
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "no"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5
|
||||
$as_echo_n "checking for pthread_mutex_init in -lc_r... " >&6; }
|
||||
if ${ac_cv_lib_c_r_pthread_mutex_init+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lc_r $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char pthread_mutex_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return pthread_mutex_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_c_r_pthread_mutex_init=yes
|
||||
else
|
||||
ac_cv_lib_c_r_pthread_mutex_init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5
|
||||
$as_echo "$ac_cv_lib_c_r_pthread_mutex_init" >&6; }
|
||||
if test "x$ac_cv_lib_c_r_pthread_mutex_init" = xyes; then :
|
||||
tcl_ok=yes
|
||||
else
|
||||
tcl_ok=no
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -pthread"
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Don't know how to find pthread lib on your system - you must edit the LIBS in the Makefile..." >&5
|
||||
$as_echo "$as_me: WARNING: Don't know how to find pthread lib on your system - you must edit the LIBS in the Makefile..." >&2;}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Does the pthread-implementation provide
|
||||
# 'pthread_attr_setstacksize' ?
|
||||
|
||||
ac_saved_libs=$LIBS
|
||||
LIBS="$LIBS $THREADS_LIBS"
|
||||
for ac_func in pthread_attr_setstacksize pthread_atfork
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
LIBS=$ac_saved_libs
|
||||
|
||||
|
||||
# Add the threads support libraries
|
||||
LIBS="$LIBS$THREADS_LIBS"
|
||||
|
||||
@@ -5033,7 +4976,7 @@ fi
|
||||
fi
|
||||
case $system in
|
||||
AIX-*)
|
||||
if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"; then :
|
||||
if test "$GCC" != "yes"; then :
|
||||
|
||||
# AIX requires the _r compiler when gcc isn't being used
|
||||
case "${CC}" in
|
||||
@@ -5235,9 +5178,6 @@ $as_echo "$ac_cv_cygwin" >&6; }
|
||||
if test "$ac_cv_cygwin" = "no"; then
|
||||
as_fn_error $? "${CC} is not a cygwin compiler." "$LINENO" 5
|
||||
fi
|
||||
if test "x${TCL_THREADS}" = "x0"; then
|
||||
as_fn_error $? "CYGWIN compile is only supported with --enable-threads" "$LINENO" 5
|
||||
fi
|
||||
do64bit_ok=yes
|
||||
if test "x${SHARED_BUILD}" = "x1"; then
|
||||
echo "running cd ../win; ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args"
|
||||
@@ -5684,14 +5624,10 @@ fi
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
|
||||
LDFLAGS="-Wl,-export-dynamic"
|
||||
CFLAGS_OPTIMIZE="-O2"
|
||||
if test "${TCL_THREADS}" = "1"; then :
|
||||
|
||||
# On OpenBSD: Compile with -pthread
|
||||
# Don't link with -lpthread
|
||||
LIBS=`echo $LIBS | sed s/-lpthread//`
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
|
||||
fi
|
||||
# On OpenBSD: Compile with -pthread
|
||||
# Don't link with -lpthread
|
||||
LIBS=`echo $LIBS | sed s/-lpthread//`
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
# OpenBSD doesn't do version numbers with dots.
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
@@ -5709,14 +5645,10 @@ fi
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
|
||||
fi
|
||||
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
|
||||
if test "${TCL_THREADS}" = "1"; then :
|
||||
|
||||
# The -pthread needs to go in the CFLAGS, not LIBS
|
||||
LIBS=`echo $LIBS | sed s/-pthread//`
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
|
||||
fi
|
||||
# The -pthread needs to go in the CFLAGS, not LIBS
|
||||
LIBS=`echo $LIBS | sed s/-pthread//`
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
;;
|
||||
FreeBSD-*)
|
||||
# This configuration from FreeBSD Ports.
|
||||
@@ -5732,13 +5664,10 @@ fi
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
|
||||
LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
|
||||
fi
|
||||
if test "${TCL_THREADS}" = "1"; then :
|
||||
|
||||
# The -pthread needs to go in the LDFLAGS, not LIBS
|
||||
LIBS=`echo $LIBS | sed s/-pthread//`
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LDFLAGS="$LDFLAGS $PTHREAD_LIBS"
|
||||
fi
|
||||
# The -pthread needs to go in the LDFLAGS, not LIBS
|
||||
LIBS=`echo $LIBS | sed s/-pthread//`
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LDFLAGS="$LDFLAGS $PTHREAD_LIBS"
|
||||
case $system in
|
||||
FreeBSD-3.*)
|
||||
# Version numbers are dot-stripped by system policy.
|
||||
@@ -6100,21 +6029,17 @@ else
|
||||
CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"
|
||||
fi
|
||||
# see pthread_intro(3) for pthread support on osf1, k.furukawa
|
||||
if test "${TCL_THREADS}" = 1; then :
|
||||
CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
|
||||
CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"
|
||||
LIBS=`echo $LIBS | sed s/-lpthreads//`
|
||||
if test "$GCC" = yes; then :
|
||||
|
||||
CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
|
||||
CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"
|
||||
LIBS=`echo $LIBS | sed s/-lpthreads//`
|
||||
if test "$GCC" = yes; then :
|
||||
|
||||
LIBS="$LIBS -lpthread -lmach -lexc"
|
||||
LIBS="$LIBS -lpthread -lmach -lexc"
|
||||
|
||||
else
|
||||
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
|
||||
fi
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
|
||||
fi
|
||||
;;
|
||||
@@ -7373,7 +7298,7 @@ $as_echo "#define NO_UNAME 1" >>confdefs.h
|
||||
fi
|
||||
|
||||
|
||||
if test "`uname -s`" = "Darwin" && test "${TCL_THREADS}" = 1 && \
|
||||
if test "`uname -s`" = "Darwin" && \
|
||||
test "`uname -r | awk -F. '{print $1}'`" -lt 7; then
|
||||
# prior to Darwin 7, realpath is not threadsafe, so don't
|
||||
# use it when threads are enabled, c.f. bug # 711232
|
||||
@@ -7496,8 +7421,7 @@ fi
|
||||
# Look for thread-safe variants of some library functions.
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
if test "${TCL_THREADS}" = 1; then
|
||||
ac_fn_c_check_func "$LINENO" "getpwuid_r" "ac_cv_func_getpwuid_r"
|
||||
ac_fn_c_check_func "$LINENO" "getpwuid_r" "ac_cv_func_getpwuid_r"
|
||||
if test "x$ac_cv_func_getpwuid_r" = xyes; then :
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpwuid_r with 5 args" >&5
|
||||
@@ -7593,7 +7517,7 @@ $as_echo "#define HAVE_GETPWUID_R 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "getpwnam_r" "ac_cv_func_getpwnam_r"
|
||||
ac_fn_c_check_func "$LINENO" "getpwnam_r" "ac_cv_func_getpwnam_r"
|
||||
if test "x$ac_cv_func_getpwnam_r" = xyes; then :
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpwnam_r with 5 args" >&5
|
||||
@@ -7689,7 +7613,7 @@ $as_echo "#define HAVE_GETPWNAM_R 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "getgrgid_r" "ac_cv_func_getgrgid_r"
|
||||
ac_fn_c_check_func "$LINENO" "getgrgid_r" "ac_cv_func_getgrgid_r"
|
||||
if test "x$ac_cv_func_getgrgid_r" = xyes; then :
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getgrgid_r with 5 args" >&5
|
||||
@@ -7785,7 +7709,7 @@ $as_echo "#define HAVE_GETGRGID_R 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "getgrnam_r" "ac_cv_func_getgrnam_r"
|
||||
ac_fn_c_check_func "$LINENO" "getgrnam_r" "ac_cv_func_getgrnam_r"
|
||||
if test "x$ac_cv_func_getgrnam_r" = xyes; then :
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getgrnam_r with 5 args" >&5
|
||||
@@ -7881,11 +7805,11 @@ $as_echo "#define HAVE_GETGRNAM_R 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
if test "`uname -s`" = "Darwin" && \
|
||||
test "`uname -r | awk -F. '{print $1}'`" -gt 5; then
|
||||
# Starting with Darwin 6 (Mac OSX 10.2), gethostbyX
|
||||
# are actually MT-safe as they always return pointers
|
||||
# from TSD instead of static storage.
|
||||
if test "`uname -s`" = "Darwin" && \
|
||||
test "`uname -r | awk -F. '{print $1}'`" -gt 5; then
|
||||
# Starting with Darwin 6 (Mac OSX 10.2), gethostbyX
|
||||
# are actually MT-safe as they always return pointers
|
||||
# from TSD instead of static storage.
|
||||
|
||||
$as_echo "#define HAVE_MTSAFE_GETHOSTBYNAME 1" >>confdefs.h
|
||||
|
||||
@@ -7893,11 +7817,11 @@ $as_echo "#define HAVE_MTSAFE_GETHOSTBYNAME 1" >>confdefs.h
|
||||
$as_echo "#define HAVE_MTSAFE_GETHOSTBYADDR 1" >>confdefs.h
|
||||
|
||||
|
||||
elif test "`uname -s`" = "HP-UX" && \
|
||||
test "`uname -r|sed -e 's|B\.||' -e 's|\..*$||'`" -gt 10; then
|
||||
# Starting with HPUX 11.00 (we believe), gethostbyX
|
||||
# are actually MT-safe as they always return pointers
|
||||
# from TSD instead of static storage.
|
||||
elif test "`uname -s`" = "HP-UX" && \
|
||||
test "`uname -r|sed -e 's|B\.||' -e 's|\..*$||'`" -gt 10; then
|
||||
# Starting with HPUX 11.00 (we believe), gethostbyX
|
||||
# are actually MT-safe as they always return pointers
|
||||
# from TSD instead of static storage.
|
||||
|
||||
$as_echo "#define HAVE_MTSAFE_GETHOSTBYNAME 1" >>confdefs.h
|
||||
|
||||
@@ -7905,8 +7829,8 @@ $as_echo "#define HAVE_MTSAFE_GETHOSTBYNAME 1" >>confdefs.h
|
||||
$as_echo "#define HAVE_MTSAFE_GETHOSTBYADDR 1" >>confdefs.h
|
||||
|
||||
|
||||
else
|
||||
ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r"
|
||||
else
|
||||
ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r"
|
||||
if test "x$ac_cv_func_gethostbyname_r" = xyes; then :
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname_r with 6 args" >&5
|
||||
@@ -8043,7 +7967,7 @@ $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "gethostbyaddr_r" "ac_cv_func_gethostbyaddr_r"
|
||||
ac_fn_c_check_func "$LINENO" "gethostbyaddr_r" "ac_cv_func_gethostbyaddr_r"
|
||||
if test "x$ac_cv_func_gethostbyaddr_r" = xyes; then :
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyaddr_r with 7 args" >&5
|
||||
@@ -8145,7 +8069,6 @@ $as_echo "#define HAVE_GETHOSTBYADDR_R 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -8337,10 +8260,6 @@ fi;;
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: OSX" >&5
|
||||
$as_echo "OSX" >&6; };;
|
||||
*)
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define NOTIFIER_SELECT 1
|
||||
_ACEOF
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
|
||||
$as_echo "none" >&6; };;
|
||||
esac
|
||||
|
||||
+26
-35
@@ -119,12 +119,6 @@ if test -z "$no_pipe" && test -n "$GCC"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# Threads support
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
SC_ENABLE_THREADS
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# Embedded configuration information, encoding to use for the values, TIP #59
|
||||
#------------------------------------------------------------------------
|
||||
@@ -215,7 +209,7 @@ AC_CHECK_FUNC(getwd, , [AC_DEFINE(NO_GETWD, 1, [Do we have getwd()])])
|
||||
AC_CHECK_FUNC(wait3, , [AC_DEFINE(NO_WAIT3, 1, [Do we have wait3()])])
|
||||
AC_CHECK_FUNC(uname, , [AC_DEFINE(NO_UNAME, 1, [Do we have uname()])])
|
||||
|
||||
if test "`uname -s`" = "Darwin" && test "${TCL_THREADS}" = 1 && \
|
||||
if test "`uname -s`" = "Darwin" && \
|
||||
test "`uname -r | awk -F. '{print [$]1}'`" -lt 7; then
|
||||
# prior to Darwin 7, realpath is not threadsafe, so don't
|
||||
# use it when threads are enabled, c.f. bug # 711232
|
||||
@@ -229,35 +223,33 @@ SC_TCL_IPV6
|
||||
# Look for thread-safe variants of some library functions.
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
if test "${TCL_THREADS}" = 1; then
|
||||
SC_TCL_GETPWUID_R
|
||||
SC_TCL_GETPWNAM_R
|
||||
SC_TCL_GETGRGID_R
|
||||
SC_TCL_GETGRNAM_R
|
||||
if test "`uname -s`" = "Darwin" && \
|
||||
test "`uname -r | awk -F. '{print [$]1}'`" -gt 5; then
|
||||
# Starting with Darwin 6 (Mac OSX 10.2), gethostbyX
|
||||
# are actually MT-safe as they always return pointers
|
||||
# from TSD instead of static storage.
|
||||
AC_DEFINE(HAVE_MTSAFE_GETHOSTBYNAME, 1,
|
||||
[Do we have MT-safe gethostbyname() ?])
|
||||
AC_DEFINE(HAVE_MTSAFE_GETHOSTBYADDR, 1,
|
||||
[Do we have MT-safe gethostbyaddr() ?])
|
||||
SC_TCL_GETPWUID_R
|
||||
SC_TCL_GETPWNAM_R
|
||||
SC_TCL_GETGRGID_R
|
||||
SC_TCL_GETGRNAM_R
|
||||
if test "`uname -s`" = "Darwin" && \
|
||||
test "`uname -r | awk -F. '{print [$]1}'`" -gt 5; then
|
||||
# Starting with Darwin 6 (Mac OSX 10.2), gethostbyX
|
||||
# are actually MT-safe as they always return pointers
|
||||
# from TSD instead of static storage.
|
||||
AC_DEFINE(HAVE_MTSAFE_GETHOSTBYNAME, 1,
|
||||
[Do we have MT-safe gethostbyname() ?])
|
||||
AC_DEFINE(HAVE_MTSAFE_GETHOSTBYADDR, 1,
|
||||
[Do we have MT-safe gethostbyaddr() ?])
|
||||
|
||||
elif test "`uname -s`" = "HP-UX" && \
|
||||
test "`uname -r|sed -e 's|B\.||' -e 's|\..*$||'`" -gt 10; then
|
||||
# Starting with HPUX 11.00 (we believe), gethostbyX
|
||||
# are actually MT-safe as they always return pointers
|
||||
# from TSD instead of static storage.
|
||||
AC_DEFINE(HAVE_MTSAFE_GETHOSTBYNAME, 1,
|
||||
[Do we have MT-safe gethostbyname() ?])
|
||||
AC_DEFINE(HAVE_MTSAFE_GETHOSTBYADDR, 1,
|
||||
[Do we have MT-safe gethostbyaddr() ?])
|
||||
elif test "`uname -s`" = "HP-UX" && \
|
||||
test "`uname -r|sed -e 's|B\.||' -e 's|\..*$||'`" -gt 10; then
|
||||
# Starting with HPUX 11.00 (we believe), gethostbyX
|
||||
# are actually MT-safe as they always return pointers
|
||||
# from TSD instead of static storage.
|
||||
AC_DEFINE(HAVE_MTSAFE_GETHOSTBYNAME, 1,
|
||||
[Do we have MT-safe gethostbyname() ?])
|
||||
AC_DEFINE(HAVE_MTSAFE_GETHOSTBYADDR, 1,
|
||||
[Do we have MT-safe gethostbyaddr() ?])
|
||||
|
||||
else
|
||||
SC_TCL_GETHOSTBYNAME_R
|
||||
SC_TCL_GETHOSTBYADDR_R
|
||||
fi
|
||||
else
|
||||
SC_TCL_GETHOSTBYNAME_R
|
||||
SC_TCL_GETHOSTBYADDR_R
|
||||
fi
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -327,7 +319,6 @@ case x`uname -s` in
|
||||
# of wider impact).
|
||||
AC_MSG_RESULT([OSX]);;
|
||||
*)
|
||||
AC_DEFINE_UNQUOTED(NOTIFIER_SELECT)
|
||||
AC_MSG_RESULT([none]);;
|
||||
esac
|
||||
|
||||
|
||||
+75
-139
@@ -592,113 +592,6 @@ AC_DEFUN([SC_ENABLE_FRAMEWORK], [
|
||||
fi
|
||||
])
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# SC_ENABLE_THREADS --
|
||||
#
|
||||
# Specify if thread support should be enabled
|
||||
#
|
||||
# Arguments:
|
||||
# none
|
||||
#
|
||||
# Results:
|
||||
#
|
||||
# Adds the following arguments to configure:
|
||||
# --enable-threads
|
||||
#
|
||||
# Sets the following vars:
|
||||
# THREADS_LIBS Thread library(s)
|
||||
#
|
||||
# Defines the following vars:
|
||||
# TCL_THREADS
|
||||
# _REENTRANT
|
||||
# _THREAD_SAFE
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([SC_ENABLE_THREADS], [
|
||||
AC_ARG_ENABLE(threads,
|
||||
AC_HELP_STRING([--enable-threads],
|
||||
[build with threads (default: on)]),
|
||||
[tcl_ok=$enableval], [tcl_ok=yes])
|
||||
|
||||
if test "${TCL_THREADS}" = 1; then
|
||||
tcl_threaded_core=1;
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then
|
||||
TCL_THREADS=1
|
||||
# USE_THREAD_ALLOC tells us to try the special thread-based
|
||||
# allocator that significantly reduces lock contention
|
||||
AC_DEFINE(USE_THREAD_ALLOC, 1,
|
||||
[Do we want to use the threaded memory allocator?])
|
||||
AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?])
|
||||
if test "`uname -s`" = "SunOS" ; then
|
||||
AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1,
|
||||
[Do we really want to follow the standard? Yes we do!])
|
||||
fi
|
||||
AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?])
|
||||
AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no)
|
||||
if test "$tcl_ok" = "no"; then
|
||||
# Check a little harder for __pthread_mutex_init in the same
|
||||
# library, as some systems hide it there until pthread.h is
|
||||
# defined. We could alternatively do an AC_TRY_COMPILE with
|
||||
# pthread.h, but that will work with libpthread really doesn't
|
||||
# exist, like AIX 4.2. [Bug: 4359]
|
||||
AC_CHECK_LIB(pthread, __pthread_mutex_init,
|
||||
tcl_ok=yes, tcl_ok=no)
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -lpthread"
|
||||
else
|
||||
AC_CHECK_LIB(pthreads, pthread_mutex_init,
|
||||
tcl_ok=yes, tcl_ok=no)
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -lpthreads"
|
||||
else
|
||||
AC_CHECK_LIB(c, pthread_mutex_init,
|
||||
tcl_ok=yes, tcl_ok=no)
|
||||
if test "$tcl_ok" = "no"; then
|
||||
AC_CHECK_LIB(c_r, pthread_mutex_init,
|
||||
tcl_ok=yes, tcl_ok=no)
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -pthread"
|
||||
else
|
||||
TCL_THREADS=0
|
||||
AC_MSG_WARN([Don't know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile...])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Does the pthread-implementation provide
|
||||
# 'pthread_attr_setstacksize' ?
|
||||
|
||||
ac_saved_libs=$LIBS
|
||||
LIBS="$LIBS $THREADS_LIBS"
|
||||
AC_CHECK_FUNCS(pthread_attr_setstacksize pthread_atfork)
|
||||
LIBS=$ac_saved_libs
|
||||
else
|
||||
TCL_THREADS=0
|
||||
fi
|
||||
# Do checking message here to not mess up interleaved configure output
|
||||
AC_MSG_CHECKING([for building with threads])
|
||||
if test "${TCL_THREADS}" = 1; then
|
||||
AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?])
|
||||
if test "${tcl_threaded_core}" = 1; then
|
||||
AC_MSG_RESULT([yes (threaded core)])
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
AC_SUBST(TCL_THREADS)
|
||||
])
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# SC_ENABLE_SYMBOLS --
|
||||
#
|
||||
@@ -1101,7 +994,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
|
||||
AS_IF([test "x${SHLIB_VERSION}" = x], [SHLIB_VERSION="1.0"])
|
||||
case $system in
|
||||
AIX-*)
|
||||
AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [
|
||||
AS_IF([test "$GCC" != "yes"], [
|
||||
# AIX requires the _r compiler when gcc isn't being used
|
||||
case "${CC}" in
|
||||
*_r|*_r\ *)
|
||||
@@ -1222,9 +1115,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
|
||||
if test "$ac_cv_cygwin" = "no"; then
|
||||
AC_MSG_ERROR([${CC} is not a cygwin compiler.])
|
||||
fi
|
||||
if test "x${TCL_THREADS}" = "x0"; then
|
||||
AC_MSG_ERROR([CYGWIN compile is only supported with --enable-threads])
|
||||
fi
|
||||
do64bit_ok=yes
|
||||
if test "x${SHARED_BUILD}" = "x1"; then
|
||||
echo "running cd ../win; ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args"
|
||||
@@ -1454,12 +1344,10 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
|
||||
SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
|
||||
LDFLAGS="-Wl,-export-dynamic"
|
||||
CFLAGS_OPTIMIZE="-O2"
|
||||
AS_IF([test "${TCL_THREADS}" = "1"], [
|
||||
# On OpenBSD: Compile with -pthread
|
||||
# Don't link with -lpthread
|
||||
LIBS=`echo $LIBS | sed s/-lpthread//`
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
])
|
||||
# On OpenBSD: Compile with -pthread
|
||||
# Don't link with -lpthread
|
||||
LIBS=`echo $LIBS | sed s/-lpthread//`
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
# OpenBSD doesn't do version numbers with dots.
|
||||
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
|
||||
TCL_LIB_VERSIONS_OK=nodots
|
||||
@@ -1475,12 +1363,10 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
|
||||
AS_IF([test $doRpath = yes], [
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
|
||||
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
|
||||
AS_IF([test "${TCL_THREADS}" = "1"], [
|
||||
# The -pthread needs to go in the CFLAGS, not LIBS
|
||||
LIBS=`echo $LIBS | sed s/-pthread//`
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
])
|
||||
# The -pthread needs to go in the CFLAGS, not LIBS
|
||||
LIBS=`echo $LIBS | sed s/-pthread//`
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
;;
|
||||
FreeBSD-*)
|
||||
# This configuration from FreeBSD Ports.
|
||||
@@ -1494,11 +1380,10 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
|
||||
AS_IF([test $doRpath = yes], [
|
||||
CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
|
||||
LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
|
||||
AS_IF([test "${TCL_THREADS}" = "1"], [
|
||||
# The -pthread needs to go in the LDFLAGS, not LIBS
|
||||
LIBS=`echo $LIBS | sed s/-pthread//`
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LDFLAGS="$LDFLAGS $PTHREAD_LIBS"])
|
||||
# The -pthread needs to go in the LDFLAGS, not LIBS
|
||||
LIBS=`echo $LIBS | sed s/-pthread//`
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LDFLAGS="$LDFLAGS $PTHREAD_LIBS"
|
||||
case $system in
|
||||
FreeBSD-3.*)
|
||||
# Version numbers are dot-stripped by system policy.
|
||||
@@ -1670,16 +1555,14 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
|
||||
AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [
|
||||
CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"])
|
||||
# see pthread_intro(3) for pthread support on osf1, k.furukawa
|
||||
AS_IF([test "${TCL_THREADS}" = 1], [
|
||||
CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
|
||||
CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"
|
||||
LIBS=`echo $LIBS | sed s/-lpthreads//`
|
||||
AS_IF([test "$GCC" = yes], [
|
||||
LIBS="$LIBS -lpthread -lmach -lexc"
|
||||
], [
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
])
|
||||
CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
|
||||
CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"
|
||||
LIBS=`echo $LIBS | sed s/-lpthreads//`
|
||||
AS_IF([test "$GCC" = yes], [
|
||||
LIBS="$LIBS -lpthread -lmach -lexc"
|
||||
], [
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
])
|
||||
;;
|
||||
QNX-6*)
|
||||
@@ -2350,13 +2233,20 @@ AC_DEFUN([SC_BUGGY_STRTOD], [
|
||||
#
|
||||
# Search for the libraries needed to link the Tcl shell.
|
||||
# Things like the math library (-lm) and socket stuff (-lsocket vs.
|
||||
# -lnsl) are dealt with here.
|
||||
# -lnsl) or thread library (-lpthread) are dealt with here.
|
||||
#
|
||||
# Arguments:
|
||||
# None.
|
||||
#
|
||||
# Results:
|
||||
#
|
||||
# Sets the following vars:
|
||||
# THREADS_LIBS Thread library(s)
|
||||
#
|
||||
# Defines the following vars:
|
||||
# _REENTRANT
|
||||
# _THREAD_SAFE
|
||||
#
|
||||
# Might append to the following vars:
|
||||
# LIBS
|
||||
# MATH_LIBS
|
||||
@@ -2414,6 +2304,52 @@ AC_DEFUN([SC_TCL_LINK_LIBS], [
|
||||
fi
|
||||
AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname,
|
||||
[LIBS="$LIBS -lnsl"])])
|
||||
|
||||
AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?])
|
||||
AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?])
|
||||
AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no)
|
||||
if test "$tcl_ok" = "no"; then
|
||||
# Check a little harder for __pthread_mutex_init in the same
|
||||
# library, as some systems hide it there until pthread.h is
|
||||
# defined. We could alternatively do an AC_TRY_COMPILE with
|
||||
# pthread.h, but that will work with libpthread really doesn't
|
||||
# exist, like AIX 4.2. [Bug: 4359]
|
||||
AC_CHECK_LIB(pthread, __pthread_mutex_init,
|
||||
tcl_ok=yes, tcl_ok=no)
|
||||
fi
|
||||
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -lpthread"
|
||||
else
|
||||
AC_CHECK_LIB(pthreads, pthread_mutex_init,
|
||||
_ok=yes, tcl_ok=no)
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -lpthreads"
|
||||
else
|
||||
AC_CHECK_LIB(c, pthread_mutex_init,
|
||||
tcl_ok=yes, tcl_ok=no)
|
||||
if test "$tcl_ok" = "no"; then
|
||||
AC_CHECK_LIB(c_r, pthread_mutex_init,
|
||||
tcl_ok=yes, tcl_ok=no)
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
# The space is needed
|
||||
THREADS_LIBS=" -pthread"
|
||||
else
|
||||
AC_MSG_WARN([Don't know how to find pthread lib on your system - you must edit the LIBS in the Makefile...])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Does the pthread-implementation provide
|
||||
# 'pthread_attr_setstacksize' ?
|
||||
|
||||
ac_saved_libs=$LIBS
|
||||
LIBS="$LIBS $THREADS_LIBS"
|
||||
AC_CHECK_FUNCS(pthread_attr_setstacksize pthread_atfork)
|
||||
LIBS=$ac_saved_libs
|
||||
])
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
@@ -385,9 +385,6 @@
|
||||
/* What is the default extension for shared libraries? */
|
||||
#undef TCL_SHLIB_EXT
|
||||
|
||||
/* Are we building with threads enabled? */
|
||||
#undef TCL_THREADS
|
||||
|
||||
/* Do we allow unloading of shared libraries? */
|
||||
#undef TCL_UNLOAD_DLLS
|
||||
|
||||
|
||||
@@ -164,6 +164,3 @@ TCL_BUILD_STUB_LIB_PATH='@TCL_BUILD_STUB_LIB_PATH@'
|
||||
|
||||
# Path to the Tcl stub library in the install directory.
|
||||
TCL_STUB_LIB_PATH='@TCL_STUB_LIB_PATH@'
|
||||
|
||||
# Flag, 1: we built Tcl with threads enabled, 0 we didn't
|
||||
TCL_THREADS=@TCL_THREADS@
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
|
||||
#ifdef NOTIFIER_EPOLL
|
||||
#include "tclInt.h"
|
||||
#if defined(NOTIFIER_EPOLL) && TCL_THREADS
|
||||
|
||||
#define _GNU_SOURCE /* For pipe2(2) */
|
||||
#include "tclInt.h"
|
||||
#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is
|
||||
* in tclMacOSXNotify.c */
|
||||
#include <fcntl.h>
|
||||
@@ -88,6 +88,7 @@ typedef struct {
|
||||
|
||||
LIST_HEAD(PlatformReadyFileHandlerList, FileHandler);
|
||||
typedef struct ThreadSpecificData {
|
||||
FileHandler *triggerFilePtr;
|
||||
FileHandler *firstFileHandlerPtr;
|
||||
/* Pointer to head of file handler list. */
|
||||
struct PlatformReadyFileHandlerList firstReadyFileHandlerPtr;
|
||||
@@ -306,6 +307,8 @@ PlatformEventsFinalize(
|
||||
tsdPtr->triggerPipe[1] = -1;
|
||||
}
|
||||
#endif /* HAVE_EVENTFD */
|
||||
ckfree(tsdPtr->triggerFilePtr->pedPtr);
|
||||
ckfree(tsdPtr->triggerFilePtr);
|
||||
if (tsdPtr->eventsFd > 0) {
|
||||
close(tsdPtr->eventsFd);
|
||||
tsdPtr->eventsFd = 0;
|
||||
@@ -368,6 +371,7 @@ PlatformEventsInit(
|
||||
}
|
||||
filePtr->fd = tsdPtr->triggerPipe[0];
|
||||
#endif
|
||||
tsdPtr->triggerFilePtr = filePtr;
|
||||
if ((tsdPtr->eventsFd = epoll_create1(EPOLL_CLOEXEC)) == -1) {
|
||||
Tcl_Panic("epoll_create1: %s", strerror(errno));
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
|
||||
#ifdef NOTIFIER_KQUEUE
|
||||
|
||||
#include "tclInt.h"
|
||||
#if defined(NOTIFIER_KQUEUE) && TCL_THREADS
|
||||
|
||||
#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is
|
||||
* in tclMacOSXNotify.c */
|
||||
#include <signal.h>
|
||||
|
||||
+14
-14
@@ -11,9 +11,9 @@
|
||||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
|
||||
#if !defined(NOTIFIER_EPOLL) && !defined(NOTIFIER_KQUEUE)
|
||||
|
||||
#include "tclInt.h"
|
||||
#if (!defined(NOTIFIER_EPOLL) && !defined(NOTIFIER_KQUEUE)) || !TCL_THREADS
|
||||
|
||||
#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is
|
||||
* in tclMacOSXNotify.c */
|
||||
#include <signal.h>
|
||||
@@ -81,7 +81,7 @@ typedef struct ThreadSpecificData {
|
||||
int numFdBits; /* Number of valid bits in checkMasks (one
|
||||
* more than highest fd for which
|
||||
* Tcl_WatchFile has been called). */
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
int onList; /* True if it is in this list */
|
||||
unsigned int pollState; /* pollState is used to implement a polling
|
||||
* handshake between each thread and the
|
||||
@@ -112,7 +112,7 @@ typedef struct ThreadSpecificData {
|
||||
|
||||
static Tcl_ThreadDataKey dataKey;
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* The following static indicates the number of threads that have initialized
|
||||
* notifiers.
|
||||
@@ -193,7 +193,7 @@ static Tcl_ThreadId notifierThread;
|
||||
* Static routines defined in this file.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
static TCL_NORETURN void NotifierThreadProc(ClientData clientData);
|
||||
#if defined(HAVE_PTHREAD_ATFORK)
|
||||
static int atForkInit = 0;
|
||||
@@ -206,7 +206,7 @@ static int FileHandlerEventProc(Tcl_Event *evPtr, int flags);
|
||||
* Import of Windows API when building threaded with Cygwin.
|
||||
*/
|
||||
|
||||
#if defined(TCL_THREADS) && defined(__CYGWIN__)
|
||||
#if defined(__CYGWIN__)
|
||||
typedef struct {
|
||||
void *hwnd;
|
||||
unsigned int *message;
|
||||
@@ -285,7 +285,7 @@ Tcl_InitNotifier(void)
|
||||
} else {
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
tsdPtr->eventReady = 0;
|
||||
|
||||
/*
|
||||
@@ -370,7 +370,7 @@ Tcl_FinalizeNotifier(
|
||||
tclNotifierHooks.finalizeNotifierProc(clientData);
|
||||
return;
|
||||
} else {
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
|
||||
pthread_mutex_lock(¬ifierInitMutex);
|
||||
@@ -587,7 +587,7 @@ Tcl_DeleteFileHandler(
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TCL_THREADS) && defined(__CYGWIN__)
|
||||
#if defined(__CYGWIN__)
|
||||
|
||||
static DWORD __stdcall
|
||||
NotifierProc(
|
||||
@@ -640,7 +640,7 @@ Tcl_WaitForEvent(
|
||||
FileHandler *filePtr;
|
||||
int mask;
|
||||
Tcl_Time vTime;
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
int waitForFiles;
|
||||
# ifdef __CYGWIN__
|
||||
MSG msg;
|
||||
@@ -675,7 +675,7 @@ Tcl_WaitForEvent(
|
||||
tclScaleTimeProcPtr(&vTime, tclTimeClientData);
|
||||
timePtr = &vTime;
|
||||
}
|
||||
#ifndef TCL_THREADS
|
||||
#if !TCL_THREADS
|
||||
timeout.tv_sec = timePtr->sec;
|
||||
timeout.tv_usec = timePtr->usec;
|
||||
timeoutPtr = &timeout;
|
||||
@@ -694,7 +694,7 @@ Tcl_WaitForEvent(
|
||||
#endif /* !TCL_THREADS */
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Start notifier thread and place this thread on the list of
|
||||
* interested threads, signal the notifier thread, and wait for a
|
||||
@@ -885,14 +885,14 @@ Tcl_WaitForEvent(
|
||||
}
|
||||
filePtr->readyMask = mask;
|
||||
}
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
pthread_mutex_unlock(¬ifierMutex);
|
||||
#endif /* TCL_THREADS */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
* library calls.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
|
||||
typedef struct {
|
||||
struct passwd pwd;
|
||||
@@ -182,7 +182,7 @@ struct passwd *
|
||||
TclpGetPwNam(
|
||||
const char *name)
|
||||
{
|
||||
#if !defined(TCL_THREADS)
|
||||
#if !TCL_THREADS
|
||||
return getpwnam(name);
|
||||
#else
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
@@ -262,7 +262,7 @@ struct passwd *
|
||||
TclpGetPwUid(
|
||||
uid_t uid)
|
||||
{
|
||||
#if !defined(TCL_THREADS)
|
||||
#if !TCL_THREADS
|
||||
return getpwuid(uid);
|
||||
#else
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
@@ -365,7 +365,7 @@ struct group *
|
||||
TclpGetGrNam(
|
||||
const char *name)
|
||||
{
|
||||
#if !defined(TCL_THREADS)
|
||||
#if !TCL_THREADS
|
||||
return getgrnam(name);
|
||||
#else
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
@@ -445,7 +445,7 @@ struct group *
|
||||
TclpGetGrGid(
|
||||
gid_t gid)
|
||||
{
|
||||
#if !defined(TCL_THREADS)
|
||||
#if !TCL_THREADS
|
||||
return getgrgid(gid);
|
||||
#else
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
@@ -548,7 +548,7 @@ struct hostent *
|
||||
TclpGetHostByName(
|
||||
const char *name)
|
||||
{
|
||||
#if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYNAME)
|
||||
#if !TCL_THREADS || defined(HAVE_MTSAFE_GETHOSTBYNAME)
|
||||
return gethostbyname(name);
|
||||
#else
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
@@ -618,7 +618,7 @@ TclpGetHostByAddr(
|
||||
int length,
|
||||
int type)
|
||||
{
|
||||
#if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYADDR)
|
||||
#if !TCL_THREADS || defined(HAVE_MTSAFE_GETHOSTBYADDR)
|
||||
return gethostbyaddr(addr, length, type);
|
||||
#else
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
|
||||
+16
-16
@@ -256,7 +256,7 @@ Realpath(
|
||||
#endif /* PURIFY */
|
||||
|
||||
#ifndef NO_REALPATH
|
||||
#if defined(__APPLE__) && defined(TCL_THREADS) && \
|
||||
#if defined(__APPLE__) && TCL_THREADS && \
|
||||
defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
|
||||
MAC_OS_X_VERSION_MIN_REQUIRED < 1030
|
||||
/*
|
||||
@@ -369,13 +369,13 @@ DoRenameFile(
|
||||
|
||||
if (errno == EINVAL && haveRealpath) {
|
||||
char srcPath[MAXPATHLEN], dstPath[MAXPATHLEN];
|
||||
DIR *dirPtr;
|
||||
TclDIR *dirPtr;
|
||||
Tcl_DirEntry *dirEntPtr;
|
||||
|
||||
if ((Realpath((char *) src, srcPath) != NULL) /* INTL: Native. */
|
||||
&& (Realpath((char *) dst, dstPath) != NULL) /* INTL: Native */
|
||||
&& (strncmp(srcPath, dstPath, strlen(srcPath)) != 0)) {
|
||||
dirPtr = opendir(dst); /* INTL: Native. */
|
||||
dirPtr = TclOSopendir(dst); /* INTL: Native. */
|
||||
if (dirPtr != NULL) {
|
||||
while (1) {
|
||||
dirEntPtr = TclOSreaddir(dirPtr); /* INTL: Native. */
|
||||
@@ -385,11 +385,11 @@ DoRenameFile(
|
||||
if ((strcmp(dirEntPtr->d_name, ".") != 0) &&
|
||||
(strcmp(dirEntPtr->d_name, "..") != 0)) {
|
||||
errno = EEXIST;
|
||||
closedir(dirPtr);
|
||||
TclOSclosedir(dirPtr);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
closedir(dirPtr);
|
||||
TclOSclosedir(dirPtr);
|
||||
}
|
||||
}
|
||||
errno = EINVAL;
|
||||
@@ -965,7 +965,7 @@ TraverseUnixTree(
|
||||
#ifndef HAVE_FTS
|
||||
int numProcessed = 0;
|
||||
Tcl_DirEntry *dirEntPtr;
|
||||
DIR *dirPtr;
|
||||
TclDIR *dirPtr;
|
||||
#else
|
||||
const char *paths[2] = {NULL, NULL};
|
||||
FTS *fts = NULL;
|
||||
@@ -990,7 +990,7 @@ TraverseUnixTree(
|
||||
errorPtr);
|
||||
}
|
||||
#ifndef HAVE_FTS
|
||||
dirPtr = opendir(source); /* INTL: Native. */
|
||||
dirPtr = TclOSopendir(source); /* INTL: Native. */
|
||||
if (dirPtr == NULL) {
|
||||
/*
|
||||
* Can't read directory
|
||||
@@ -1002,7 +1002,7 @@ TraverseUnixTree(
|
||||
result = traverseProc(sourcePtr, targetPtr, &statBuf, DOTREE_PRED,
|
||||
errorPtr);
|
||||
if (result != TCL_OK) {
|
||||
closedir(dirPtr);
|
||||
TclOSclosedir(dirPtr);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1052,11 +1052,11 @@ TraverseUnixTree(
|
||||
* NULL-return that may a symptom of a buggy readdir.
|
||||
*/
|
||||
|
||||
rewinddir(dirPtr);
|
||||
TclOSrewinddir(dirPtr);
|
||||
numProcessed = 0;
|
||||
}
|
||||
}
|
||||
closedir(dirPtr);
|
||||
TclOSclosedir(dirPtr);
|
||||
|
||||
/*
|
||||
* Strip off the trailing slash we added
|
||||
@@ -2302,7 +2302,8 @@ winPathFromObj(
|
||||
}
|
||||
|
||||
static const int attributeArray[] = {
|
||||
0x20, 0, 2, 0, 0, 1, 4};
|
||||
0x20, 0, 2, 0, 0, 1, 4
|
||||
};
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -2339,8 +2340,8 @@ GetUnixFileAttributes(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
*attributePtrPtr = Tcl_NewIntObj((fileAttributes&attributeArray[objIndex])!=0);
|
||||
|
||||
*attributePtrPtr = Tcl_NewIntObj(
|
||||
(fileAttributes & attributeArray[objIndex]) != 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -2397,7 +2398,7 @@ SetUnixFileAttributes(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
ckfree(winPath);
|
||||
ckfree(winPath);
|
||||
return TCL_OK;
|
||||
}
|
||||
#elif defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE)
|
||||
@@ -2439,8 +2440,7 @@ GetUnixFileAttributes(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
*attributePtrPtr = Tcl_NewBooleanObj(statBuf.st_flags&UF_IMMUTABLE);
|
||||
|
||||
*attributePtrPtr = Tcl_NewBooleanObj(statBuf.st_flags & UF_IMMUTABLE);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -259,7 +259,7 @@ TclpMatchInDirectory(
|
||||
Tcl_DecrRefCount(tailPtr);
|
||||
Tcl_DecrRefCount(fileNamePtr);
|
||||
} else {
|
||||
DIR *d;
|
||||
TclDIR *d;
|
||||
Tcl_DirEntry *entryPtr;
|
||||
const char *dirName;
|
||||
size_t dirLength, nativeDirLen;
|
||||
@@ -310,7 +310,7 @@ TclpMatchInDirectory(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
d = opendir(native); /* INTL: Native. */
|
||||
d = TclOSopendir(native); /* INTL: Native. */
|
||||
if (d == NULL) {
|
||||
Tcl_DStringFree(&ds);
|
||||
if (interp != NULL) {
|
||||
@@ -388,7 +388,7 @@ TclpMatchInDirectory(
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
TclOSclosedir(d);
|
||||
Tcl_DStringFree(&ds);
|
||||
Tcl_DStringFree(&dsOrig);
|
||||
Tcl_DecrRefCount(fileNamePtr);
|
||||
|
||||
+1
-1
@@ -316,7 +316,7 @@ static int MacOSXGetLibraryPath(Tcl_Interp *interp,
|
||||
#endif /* HAVE_COREFOUNDATION */
|
||||
#if defined(__APPLE__) && (defined(TCL_LOAD_FROM_MEMORY) || ( \
|
||||
defined(MAC_OS_X_VERSION_MIN_REQUIRED) && ( \
|
||||
(defined(TCL_THREADS) && MAC_OS_X_VERSION_MIN_REQUIRED < 1030) || \
|
||||
(TCL_THREADS && MAC_OS_X_VERSION_MIN_REQUIRED < 1030) || \
|
||||
(defined(__LP64__) && MAC_OS_X_VERSION_MIN_REQUIRED < 1050) || \
|
||||
(defined(HAVE_COREFOUNDATION) && MAC_OS_X_VERSION_MIN_REQUIRED < 1050)\
|
||||
)))
|
||||
|
||||
+14
-14
@@ -12,29 +12,30 @@
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
#include "tclInt.h"
|
||||
|
||||
/*
|
||||
* Static routines defined in this file.
|
||||
*/
|
||||
|
||||
#ifdef NOTIFIER_SELECT
|
||||
#ifdef TCL_THREADS
|
||||
static TCL_NORETURN void NotifierThreadProc(ClientData clientData);
|
||||
#if defined(HAVE_PTHREAD_ATFORK)
|
||||
static void AtForkChild(void);
|
||||
#endif /* HAVE_PTHREAD_ATFORK */
|
||||
#endif /* TCL_THREADS */
|
||||
#endif /* NOTIFIER_SELECT */
|
||||
static int FileHandlerEventProc(Tcl_Event *evPtr, int flags);
|
||||
#if !TCL_THREADS
|
||||
# undef NOTIFIER_EPOLL
|
||||
# undef NOTIFIER_KQUEUE
|
||||
# define NOTIFIER_SELECT
|
||||
#elif !defined(NOTIFIER_EPOLL) && !defined(NOTIFIER_KQUEUE)
|
||||
# define NOTIFIER_SELECT
|
||||
static TCL_NORETURN void NotifierThreadProc(ClientData clientData);
|
||||
# if defined(HAVE_PTHREAD_ATFORK)
|
||||
static void AtForkChild(void);
|
||||
# endif /* HAVE_PTHREAD_ATFORK */
|
||||
|
||||
#ifdef NOTIFIER_SELECT
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* StartNotifierThread --
|
||||
*
|
||||
* Start a notfier thread and wait for the notifier pipe to be created.
|
||||
* Start a notifier thread and wait for the notifier pipe to be created.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
@@ -70,7 +71,6 @@ StartNotifierThread(const char *proc)
|
||||
pthread_mutex_unlock(¬ifierInitMutex);
|
||||
}
|
||||
}
|
||||
#endif /* TCL_THREADS */
|
||||
#endif /* NOTIFIER_SELECT */
|
||||
|
||||
/*
|
||||
@@ -107,7 +107,7 @@ Tcl_AlertNotifier(
|
||||
return;
|
||||
} else {
|
||||
#ifdef NOTIFIER_SELECT
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
ThreadSpecificData *tsdPtr = clientData;
|
||||
|
||||
pthread_mutex_lock(¬ifierMutex);
|
||||
@@ -280,7 +280,7 @@ FileHandlerEventProc(
|
||||
}
|
||||
|
||||
#ifdef NOTIFIER_SELECT
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
+11
-5
@@ -57,11 +57,19 @@
|
||||
*/
|
||||
|
||||
#ifdef HAVE_STRUCT_DIRENT64
|
||||
typedef DIR64 TclDIR;
|
||||
typedef struct dirent64 Tcl_DirEntry;
|
||||
# define TclOSreaddir readdir64
|
||||
# define TclOSopendir opendir64
|
||||
# define TclOSrewinddir rewinddir64
|
||||
# define TclOSclosedir closedir64
|
||||
#else
|
||||
typedef DIR TclDIR;
|
||||
typedef struct dirent Tcl_DirEntry;
|
||||
# define TclOSreaddir readdir
|
||||
# define TclOSopendir opendir
|
||||
# define TclOSrewinddir rewinddir
|
||||
# define TclOSclosedir closedir
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TYPE_OFF64_T
|
||||
@@ -602,10 +610,8 @@ extern char ** environ;
|
||||
# undef HAVE_COPYFILE
|
||||
# endif
|
||||
# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030
|
||||
# ifdef TCL_THREADS
|
||||
/* prior to 10.3, realpath is not threadsafe, c.f. bug 711232 */
|
||||
# define NO_REALPATH 1
|
||||
# endif
|
||||
/* prior to 10.3, realpath is not threadsafe, c.f. bug 711232 */
|
||||
# define NO_REALPATH 1
|
||||
# undef HAVE_LANGINFO
|
||||
# endif
|
||||
# endif /* MAC_OS_X_VERSION_MAX_ALLOWED */
|
||||
@@ -678,7 +684,7 @@ typedef int socklen_t;
|
||||
|
||||
#define TclpExit exit
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if !defined(TCL_THREADS) || TCL_THREADS
|
||||
# include <pthread.h>
|
||||
#endif /* TCL_THREADS */
|
||||
|
||||
|
||||
+18
-16
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "tclInt.h"
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
|
||||
#ifndef TCL_NO_DEPRECATED
|
||||
typedef struct {
|
||||
@@ -74,7 +74,7 @@ TclpThreadCreate(
|
||||
int flags) /* Flags controlling behaviour of the new
|
||||
* thread. */
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
pthread_attr_t attr;
|
||||
pthread_t theThread;
|
||||
int result;
|
||||
@@ -152,7 +152,7 @@ Tcl_JoinThread(
|
||||
* thread we wait upon will be written into.
|
||||
* May be NULL. */
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
int result;
|
||||
unsigned long retcode, *retcodePtr = &retcode;
|
||||
|
||||
@@ -166,7 +166,6 @@ Tcl_JoinThread(
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -187,9 +186,12 @@ void
|
||||
TclpThreadExit(
|
||||
int status)
|
||||
{
|
||||
#if TCL_THREADS
|
||||
pthread_exit(INT2PTR(status));
|
||||
}
|
||||
#else /* TCL_THREADS */
|
||||
exit(status);
|
||||
#endif /* TCL_THREADS */
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -210,7 +212,7 @@ TclpThreadExit(
|
||||
Tcl_ThreadId
|
||||
Tcl_GetCurrentThread(void)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
return (Tcl_ThreadId) pthread_self();
|
||||
#else
|
||||
return (Tcl_ThreadId) 0;
|
||||
@@ -239,7 +241,7 @@ Tcl_GetCurrentThread(void)
|
||||
void
|
||||
TclpInitLock(void)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
pthread_mutex_lock(&initLock);
|
||||
#endif
|
||||
}
|
||||
@@ -265,7 +267,7 @@ TclpInitLock(void)
|
||||
void
|
||||
TclFinalizeLock(void)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* You do not need to destroy mutexes that were created with the
|
||||
* PTHREAD_MUTEX_INITIALIZER macro. These mutexes do not need any
|
||||
@@ -296,7 +298,7 @@ TclFinalizeLock(void)
|
||||
void
|
||||
TclpInitUnlock(void)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
pthread_mutex_unlock(&initLock);
|
||||
#endif
|
||||
}
|
||||
@@ -325,7 +327,7 @@ TclpInitUnlock(void)
|
||||
void
|
||||
TclpMasterLock(void)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
pthread_mutex_lock(&masterLock);
|
||||
#endif
|
||||
}
|
||||
@@ -351,7 +353,7 @@ TclpMasterLock(void)
|
||||
void
|
||||
TclpMasterUnlock(void)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
pthread_mutex_unlock(&masterLock);
|
||||
#endif
|
||||
}
|
||||
@@ -378,7 +380,7 @@ TclpMasterUnlock(void)
|
||||
Tcl_Mutex *
|
||||
Tcl_GetAllocMutex(void)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
pthread_mutex_t **allocLockPtrPtr = &allocLockPtr;
|
||||
return (Tcl_Mutex *) allocLockPtrPtr;
|
||||
#else
|
||||
@@ -386,7 +388,7 @@ Tcl_GetAllocMutex(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -649,7 +651,7 @@ TclpFinalizeCondition(
|
||||
#ifndef TCL_NO_DEPRECATED
|
||||
Tcl_DirEntry *
|
||||
TclpReaddir(
|
||||
DIR * dir)
|
||||
TclDIR * dir)
|
||||
{
|
||||
return TclOSreaddir(dir);
|
||||
}
|
||||
@@ -659,7 +661,7 @@ char *
|
||||
TclpInetNtoa(
|
||||
struct in_addr addr)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
unsigned char *b = (unsigned char*) &addr.s_addr;
|
||||
|
||||
@@ -671,7 +673,7 @@ TclpInetNtoa(
|
||||
}
|
||||
#endif /* TCL_NO_DEPRECATED */
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
* Additions by AOL for specialized thread memory allocator.
|
||||
*/
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* tclUnixThrd.h --
|
||||
*
|
||||
* This header file defines things for thread support.
|
||||
*
|
||||
* Copyright (c) 1998 Sun Microsystems, Inc.
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution
|
||||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
|
||||
#ifndef _TCLUNIXTHRD
|
||||
#define _TCLUNIXTHRD
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
|
||||
|
||||
#endif /* TCL_THREADS */
|
||||
#endif /* _TCLUNIXTHRD */
|
||||
+6
-2
@@ -401,7 +401,8 @@ REG_OBJS = tclWinReg.$(OBJEXT)
|
||||
STUB_OBJS = \
|
||||
tclStubLib.$(OBJEXT) \
|
||||
tclTomMathStubLib.$(OBJEXT) \
|
||||
tclOOStubLib.$(OBJEXT)
|
||||
tclOOStubLib.$(OBJEXT) \
|
||||
tclWinPanic.$(OBJEXT)
|
||||
|
||||
TCLSH_OBJS = tclAppInit.$(OBJEXT)
|
||||
|
||||
@@ -538,6 +539,9 @@ tclTomMathStubLib.${OBJEXT}: tclTomMathStubLib.c
|
||||
tclOOStubLib.${OBJEXT}: tclOOStubLib.c
|
||||
$(CC) -c $(CC_SWITCHES) -DSTATIC_BUILD @DEPARG@ $(CC_OBJNAME)
|
||||
|
||||
tclWinPanic.${OBJEXT}: tclWinPanic.c
|
||||
$(CC) -c $(CC_SWITCHES) -DSTATIC_BUILD @DEPARG@ $(CC_OBJNAME)
|
||||
|
||||
# Implicit rule for all object files that will end up in the Tcl library
|
||||
|
||||
%.${OBJEXT}: %.c
|
||||
@@ -770,7 +774,7 @@ packages:
|
||||
if [ ! -f $(PKG_DIR)/$$pkg/Makefile ]; then \
|
||||
( cd $(PKG_DIR)/$$pkg; \
|
||||
echo "Configuring package '$$i' wd = `$(CYGPATH) $$(pwd -P)`"; \
|
||||
$$i/configure --with-tcl=$$builddir --with-tclinclude=$(GENERIC_DIR_NATIVE) $(PKG_CFG_ARGS) --enable-shared --enable-threads; ) \
|
||||
$$i/configure --with-tcl=$$builddir --with-tclinclude=$(GENERIC_DIR_NATIVE) $(PKG_CFG_ARGS) --enable-shared; ) \
|
||||
fi ; \
|
||||
echo "Building package '$$pkg'"; \
|
||||
( cd $(PKG_DIR)/$$pkg; $(MAKE); ) \
|
||||
|
||||
Vendored
-36
@@ -707,7 +707,6 @@ CFLAGS_OPTIMIZE
|
||||
CFLAGS_DEBUG
|
||||
DL_LIBS
|
||||
CYGPATH
|
||||
TCL_THREADS
|
||||
SET_MAKE
|
||||
RC
|
||||
RANLIB
|
||||
@@ -763,7 +762,6 @@ SHELL'
|
||||
ac_subst_files=''
|
||||
ac_user_opts='
|
||||
enable_option_checking
|
||||
enable_threads
|
||||
with_encoding
|
||||
enable_shared
|
||||
enable_64bit
|
||||
@@ -1386,7 +1384,6 @@ Optional Features:
|
||||
--disable-option-checking ignore unrecognized --enable/--with options
|
||||
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
|
||||
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
||||
--enable-threads build with threads (default: on)
|
||||
--enable-shared build and link with shared libraries (default: on)
|
||||
--enable-64bit enable 64bit support (where applicable)
|
||||
--enable-symbols build with debugging symbols (default: off)
|
||||
@@ -3673,39 +3670,6 @@ fi
|
||||
|
||||
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check whether --enable-threads or --disable-threads was given.
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5
|
||||
$as_echo_n "checking for building with threads... " >&6; }
|
||||
# Check whether --enable-threads was given.
|
||||
if test "${enable_threads+set}" = set; then :
|
||||
enableval=$enable_threads; tcl_ok=$enableval
|
||||
else
|
||||
tcl_ok=yes
|
||||
fi
|
||||
|
||||
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5
|
||||
$as_echo "yes (default)" >&6; }
|
||||
TCL_THREADS=1
|
||||
$as_echo "#define TCL_THREADS 1" >>confdefs.h
|
||||
|
||||
# USE_THREAD_ALLOC tells us to try the special thread-based
|
||||
# allocator that significantly reduces lock contention
|
||||
$as_echo "#define USE_THREAD_ALLOC 1" >>confdefs.h
|
||||
|
||||
else
|
||||
TCL_THREADS=0
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# Embedded configuration information, encoding to use for the values, TIP #59
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
@@ -78,12 +78,6 @@ AC_PROG_MAKE_SET
|
||||
AC_OBJEXT
|
||||
AC_EXEEXT
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check whether --enable-threads or --disable-threads was given.
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
SC_ENABLE_THREADS
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# Embedded configuration information, encoding to use for the values, TIP #59
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
+7
-4
@@ -350,7 +350,8 @@ TCLOBJS = $(COREOBJS) $(ZLIBOBJS) $(TOMMATHOBJS) $(PLATFORMOBJS)
|
||||
TCLSTUBOBJS = \
|
||||
$(TMP_DIR)\tclStubLib.obj \
|
||||
$(TMP_DIR)\tclTomMathStubLib.obj \
|
||||
$(TMP_DIR)\tclOOStubLib.obj
|
||||
$(TMP_DIR)\tclOOStubLib.obj \
|
||||
$(TMP_DIR)\tclWinPanic.obj
|
||||
|
||||
### The following paths CANNOT have spaces in them as they appear on
|
||||
### the left side of implicit rules.
|
||||
@@ -581,7 +582,6 @@ $(OUT_DIR)\tcl.nmake:
|
||||
@type << >$@
|
||||
CORE_MACHINE = $(MACHINE)
|
||||
CORE_DEBUG = $(DEBUG)
|
||||
CORE_TCL_THREADS = $(TCL_THREADS)
|
||||
CORE_USE_THREAD_ALLOC = $(USE_THREAD_ALLOC)
|
||||
CORE_USE_WIDECHAR_API = $(USE_WIDECHAR_API)
|
||||
<<
|
||||
@@ -637,7 +637,6 @@ $(OUT_DIR)\tclConfig.sh: $(WINDIR)\tclConfig.sh.in
|
||||
@TCL_STUB_LIB_FILE@ $(TCLSTUBLIBNAME)
|
||||
@TCL_STUB_LIB_FLAG@ $(TCLSTUBLIBNAME)
|
||||
@TCL_STUB_LIB_SPEC@ -L$(LIB_INSTALL_DIR) $(TCLSTUBLIBNAME)
|
||||
@TCL_THREADS@ $(TCL_THREADS)
|
||||
@TCL_BUILD_STUB_LIB_SPEC@ -L$(OUT_DIR) $(TCLSTUBLIBNAME)
|
||||
@TCL_BUILD_STUB_LIB_PATH@ $(TCLSTUBLIB)
|
||||
@TCL_STUB_LIB_PATH@ $(LIB_INSTALL_DIR)\$(TCLSTUBLIBNAME)
|
||||
@@ -710,7 +709,6 @@ $(TMP_DIR)\tclAppInit.obj: $(WINDIR)\tclAppInit.c
|
||||
-Fo$@ $?
|
||||
|
||||
### The following objects should be built using the stub interfaces
|
||||
### *ALL* extensions need to built with -DTCL_THREADS=1
|
||||
|
||||
$(TMP_DIR)\tclWinReg.obj: $(WINDIR)\tclWinReg.c
|
||||
!if $(STATIC_BUILD)
|
||||
@@ -741,6 +739,9 @@ $(TMP_DIR)\tclTomMathStubLib.obj: $(GENERICDIR)\tclTomMathStubLib.c
|
||||
$(TMP_DIR)\tclOOStubLib.obj: $(GENERICDIR)\tclOOStubLib.c
|
||||
$(cc32) $(stubscflags) -Fo$@ $?
|
||||
|
||||
$(TMP_DIR)\tclWinPanic.obj: $(WINDIR)\tclWinPanic.c
|
||||
$(cc32) $(stubscflags) -Fo$@ $?
|
||||
|
||||
$(TMP_DIR)\tclsh.exe.manifest: $(WINDIR)\tclsh.exe.manifest.in
|
||||
@nmakehlp -s << $** >$@
|
||||
@MACHINE@ $(MACHINE:IX86=X86)
|
||||
@@ -832,6 +833,8 @@ install-libraries: tclConfig tcl-nmake install-msgs install-tzdata
|
||||
$(MKDIR) "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.5"
|
||||
@if not exist "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.6" \
|
||||
$(MKDIR) "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.6"
|
||||
@if not exist "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.7" \
|
||||
$(MKDIR) "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.7"
|
||||
@if not exist "$(LIB_INSTALL_DIR)\nmake" \
|
||||
$(MKDIR) "$(LIB_INSTALL_DIR)\nmake"
|
||||
@echo Installing header files
|
||||
|
||||
+12
-36
@@ -24,7 +24,7 @@ _RULES_VC = 1
|
||||
# For modifications that are not backward-compatible, you *must* change
|
||||
# the major version.
|
||||
RULES_VERSION_MAJOR = 1
|
||||
RULES_VERSION_MINOR = 2
|
||||
RULES_VERSION_MINOR = 3
|
||||
|
||||
# The PROJECT macro must be defined by parent makefile.
|
||||
!if "$(PROJECT)" == ""
|
||||
@@ -730,15 +730,6 @@ TCL_USE_STATIC_PACKAGES = 1
|
||||
TCL_USE_STATIC_PACKAGES = 0
|
||||
!endif
|
||||
|
||||
!if [nmakehlp -f $(OPTS) "nothreads"]
|
||||
!message *** Compile explicitly for non-threaded tcl
|
||||
TCL_THREADS = 0
|
||||
USE_THREAD_ALLOC= 0
|
||||
!else
|
||||
TCL_THREADS = 1
|
||||
USE_THREAD_ALLOC= 1
|
||||
!endif
|
||||
|
||||
!if [nmakehlp -f $(OPTS) "symbols"]
|
||||
!message *** Doing symbols
|
||||
DEBUG = 1
|
||||
@@ -774,12 +765,6 @@ PGO = 0
|
||||
!message *** Warning: ignoring option "loimpact" - deprecated on modern Windows.
|
||||
!endif
|
||||
|
||||
# TBD - should get rid of this option
|
||||
!if [nmakehlp -f $(OPTS) "thrdalloc"]
|
||||
!message *** Doing thrdalloc
|
||||
USE_THREAD_ALLOC = 1
|
||||
!endif
|
||||
|
||||
!if [nmakehlp -f $(OPTS) "tclalloc"]
|
||||
USE_THREAD_ALLOC = 0
|
||||
!endif
|
||||
@@ -970,7 +955,7 @@ VERSION = $(DOTVERSION:.=)
|
||||
# different compilers, build configurations etc.,
|
||||
#
|
||||
# Naming convention (suffixes):
|
||||
# t = full thread support.
|
||||
# t = full thread support. (Not used for Tcl >= 8.7)
|
||||
# s = static library (as opposed to an import library)
|
||||
# g = linked to the debug enabled C run-time.
|
||||
# x = special static build when it links to the dynamic C run-time.
|
||||
@@ -1028,7 +1013,7 @@ SUFX = $(SUFX:x=)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!if !$(TCL_THREADS)
|
||||
!if !$(TCL_THREADS) || $(TCL_VERSION) > 86
|
||||
TMP_DIRFULL = $(TMP_DIRFULL:Threaded=)
|
||||
SUFX = $(SUFX:t=)
|
||||
!endif
|
||||
@@ -1078,20 +1063,17 @@ TCL_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)"
|
||||
# When building extensions, we need to locate tclsh. Depending on version
|
||||
# of Tcl we are building against, this may or may not have a "t" suffix.
|
||||
# Try various possibilities in turn.
|
||||
TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe
|
||||
!if !exist("$(TCLSH)") && $(TCL_THREADS)
|
||||
TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX).exe
|
||||
!endif
|
||||
TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX:t=).exe
|
||||
!if !exist("$(TCLSH)")
|
||||
TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX:t=).exe
|
||||
TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX:t=).exe
|
||||
!endif
|
||||
|
||||
TCLSTUBLIB = $(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib
|
||||
TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib
|
||||
TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX:t=).lib
|
||||
# When building extensions, may be linking against Tcl that does not add
|
||||
# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility.
|
||||
!if !exist("$(TCLIMPLIB)")
|
||||
TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX:t=).lib
|
||||
TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)t$(SUFX:t=).lib
|
||||
!endif
|
||||
TCL_LIBRARY = $(_TCLDIR)\lib
|
||||
TCLREGLIB = $(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib
|
||||
@@ -1101,19 +1083,16 @@ TCL_INCLUDES = -I"$(_TCLDIR)\include"
|
||||
|
||||
!else # Building against Tcl sources
|
||||
|
||||
TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe
|
||||
!if !exist($(TCLSH)) && $(TCL_THREADS)
|
||||
TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX).exe
|
||||
!endif
|
||||
!if !exist($(TCLSH))
|
||||
TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX:t=).exe
|
||||
!if !exist($(TCLSH))
|
||||
TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX:t=).exe
|
||||
!endif
|
||||
TCLSTUBLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib
|
||||
TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib
|
||||
TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX:t=).lib
|
||||
# When building extensions, may be linking against Tcl that does not add
|
||||
# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility.
|
||||
!if !exist("$(TCLIMPLIB)")
|
||||
TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX:t=).lib
|
||||
TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)t$(SUFX:t=).lib
|
||||
!endif
|
||||
TCL_LIBRARY = $(_TCLDIR)\library
|
||||
TCLREGLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib
|
||||
@@ -1264,7 +1243,7 @@ OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG
|
||||
!if $(TCL_COMPILE_DEBUG)
|
||||
OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS
|
||||
!endif
|
||||
!if $(TCL_THREADS)
|
||||
!if $(TCL_THREADS) && $(TCL_VERSION) < 86
|
||||
OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1
|
||||
!if $(USE_THREAD_ALLOC)
|
||||
OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1
|
||||
@@ -1708,9 +1687,6 @@ TCLNMAKECONFIG = "$(OUT_DIR)\tcl.nmake"
|
||||
!if defined(CORE_MACHINE) && "$(CORE_MACHINE)" != "$(MACHINE)"
|
||||
!error ERROR: Build target ($(MACHINE)) does not match the Tcl library architecture ($(CORE_MACHINE)).
|
||||
!endif
|
||||
!if defined(CORE_USE_THREAD_ALLOC) && $(CORE_USE_THREAD_ALLOC) != $(USE_THREAD_ALLOC)
|
||||
!message WARNING: Value of USE_THREAD_ALLOC ($(USE_THREAD_ALLOC)) does not match its Tcl core value ($(CORE_USE_THREAD_ALLOC)).
|
||||
!endif
|
||||
!if defined(CORE_DEBUG) && $(CORE_DEBUG) != $(DEBUG)
|
||||
!message WARNING: Value of DEBUG ($(DEBUG)) does not match its Tcl library configuration ($(DEBUG)).
|
||||
!endif
|
||||
|
||||
@@ -1528,6 +1528,10 @@ SOURCE=.\tclWinNotify.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tclWinPanic.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tclWinPipe.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
-36
@@ -382,42 +382,6 @@ AC_DEFUN([SC_ENABLE_SHARED], [
|
||||
fi
|
||||
])
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# SC_ENABLE_THREADS --
|
||||
#
|
||||
# Specify if thread support should be enabled
|
||||
#
|
||||
# Arguments:
|
||||
# none
|
||||
#
|
||||
# Results:
|
||||
#
|
||||
# Adds the following arguments to configure:
|
||||
# --enable-threads=yes|no
|
||||
#
|
||||
# Defines the following vars:
|
||||
# TCL_THREADS
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([SC_ENABLE_THREADS], [
|
||||
AC_MSG_CHECKING(for building with threads)
|
||||
AC_ARG_ENABLE(threads, [ --enable-threads build with threads (default: on)],
|
||||
[tcl_ok=$enableval], [tcl_ok=yes])
|
||||
|
||||
if test "$tcl_ok" = "yes"; then
|
||||
AC_MSG_RESULT([yes (default)])
|
||||
TCL_THREADS=1
|
||||
AC_DEFINE(TCL_THREADS)
|
||||
# USE_THREAD_ALLOC tells us to try the special thread-based
|
||||
# allocator that significantly reduces lock contention
|
||||
AC_DEFINE(USE_THREAD_ALLOC)
|
||||
else
|
||||
TCL_THREADS=0
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
AC_SUBST(TCL_THREADS)
|
||||
])
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# SC_ENABLE_SYMBOLS --
|
||||
#
|
||||
|
||||
+1
-7
@@ -7,19 +7,13 @@
|
||||
//
|
||||
// build-up the name suffix that defines the type of build this is.
|
||||
//
|
||||
#if TCL_THREADS
|
||||
#define SUFFIX_THREADS "t"
|
||||
#else
|
||||
#define SUFFIX_THREADS ""
|
||||
#endif
|
||||
|
||||
#if DEBUG && !UNCHECKED
|
||||
#define SUFFIX_DEBUG "g"
|
||||
#else
|
||||
#define SUFFIX_DEBUG ""
|
||||
#endif
|
||||
|
||||
#define SUFFIX SUFFIX_THREADS SUFFIX_DEBUG
|
||||
#define SUFFIX SUFFIX_DEBUG
|
||||
|
||||
|
||||
LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */
|
||||
|
||||
@@ -175,7 +175,3 @@ TCL_BUILD_STUB_LIB_PATH='@TCL_BUILD_STUB_LIB_PATH@'
|
||||
|
||||
# Path to the Tcl stub library in the install directory.
|
||||
TCL_STUB_LIB_PATH='@TCL_STUB_LIB_PATH@'
|
||||
|
||||
# Flag, 1: we built Tcl with threads enabled, 0 we didn't
|
||||
TCL_THREADS=@TCL_THREADS@
|
||||
|
||||
|
||||
@@ -406,6 +406,9 @@ tclWinDebugPanic(
|
||||
}
|
||||
OutputDebugStringW(msgString);
|
||||
} else {
|
||||
if (!isatty(fileno(stderr))) {
|
||||
fprintf(stderr, "\xef\xbb\xbf");
|
||||
}
|
||||
vfprintf(stderr, format, argList);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
|
||||
+49
-18
@@ -867,6 +867,7 @@ TclpFindExecutable(
|
||||
*/
|
||||
|
||||
if (argv0 == NULL) {
|
||||
# undef Tcl_SetPanicProc
|
||||
Tcl_SetPanicProc(tclWinDebugPanic);
|
||||
}
|
||||
|
||||
@@ -1436,48 +1437,78 @@ TclpGetUserHome(
|
||||
Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
|
||||
* name of user's home directory. */
|
||||
{
|
||||
const char *result = NULL;
|
||||
USER_INFO_1 *uiPtr, **uiPtrPtr = &uiPtr;
|
||||
char *result = NULL;
|
||||
USER_INFO_1 *uiPtr;
|
||||
Tcl_DString ds;
|
||||
int nameLen = -1;
|
||||
int badDomain = 0;
|
||||
char *domain;
|
||||
WCHAR *wName, *wHomeDir, *wDomain, **wDomainPtr = &wDomain;
|
||||
int rc = 0;
|
||||
const char *domain;
|
||||
WCHAR *wName, *wHomeDir, *wDomain;
|
||||
WCHAR buf[MAX_PATH];
|
||||
|
||||
Tcl_DStringInit(bufferPtr);
|
||||
|
||||
wDomain = NULL;
|
||||
domain = strchr(name, '@');
|
||||
if (domain != NULL) {
|
||||
domain = Tcl_UtfFindFirst(name, '@');
|
||||
if (domain == NULL) {
|
||||
const char *ptr;
|
||||
|
||||
/* no domain - firstly check it's the current user */
|
||||
if ( (ptr = TclpGetUserName(&ds)) != 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);
|
||||
}
|
||||
}
|
||||
Tcl_DStringFree(&ds);
|
||||
} else {
|
||||
Tcl_DStringInit(&ds);
|
||||
wName = Tcl_UtfToUniCharDString(domain + 1, -1, &ds);
|
||||
badDomain = NetGetDCName(NULL, wName, (LPBYTE *) wDomainPtr);
|
||||
rc = NetGetDCName(NULL, wName, (LPBYTE *) &wDomain);
|
||||
Tcl_DStringFree(&ds);
|
||||
nameLen = domain - name;
|
||||
}
|
||||
if (badDomain == 0) {
|
||||
if (rc == 0) {
|
||||
Tcl_DStringInit(&ds);
|
||||
wName = Tcl_UtfToUniCharDString(name, nameLen, &ds);
|
||||
if (NetUserGetInfo(wDomain, wName, 1, (LPBYTE *) uiPtrPtr) == 0) {
|
||||
while (NetUserGetInfo(wDomain, wName, 1, (LPBYTE *) &uiPtr) != 0) {
|
||||
/*
|
||||
* user does not exists - if domain was not specified,
|
||||
* try again using current domain.
|
||||
*/
|
||||
rc = 1;
|
||||
if (domain != NULL) break;
|
||||
/* get current domain */
|
||||
rc = NetGetDCName(NULL, NULL, (LPBYTE *) &wDomain);
|
||||
if (rc != 0) break;
|
||||
domain = INT2PTR(-1); /* repeat once */
|
||||
}
|
||||
if (rc == 0) {
|
||||
DWORD i, size = MAX_PATH;
|
||||
wHomeDir = uiPtr->usri1_home_dir;
|
||||
if ((wHomeDir != NULL) && (wHomeDir[0] != L'\0')) {
|
||||
Tcl_UniCharToUtfDString(wHomeDir, lstrlenW(wHomeDir),
|
||||
bufferPtr);
|
||||
size = lstrlenW(wHomeDir);
|
||||
Tcl_UniCharToUtfDString(wHomeDir, size, bufferPtr);
|
||||
} else {
|
||||
/*
|
||||
* User exists but has no home dir. Return
|
||||
* "{GetProfilesDirectory}/<user>".
|
||||
*/
|
||||
DWORD i, size = MAX_PATH;
|
||||
GetProfilesDirectoryW(buf, &size);
|
||||
for (i = 0; i < size; ++i){
|
||||
if (buf[i] == '\\') buf[i] = '/';
|
||||
}
|
||||
Tcl_UniCharToUtfDString(buf, size-1, bufferPtr);
|
||||
Tcl_DStringAppend(bufferPtr, "/", -1);
|
||||
Tcl_DStringAppend(bufferPtr, name, -1);
|
||||
Tcl_DStringAppend(bufferPtr, "/", 1);
|
||||
Tcl_DStringAppend(bufferPtr, name, nameLen);
|
||||
}
|
||||
result = Tcl_DStringValue(bufferPtr);
|
||||
/* be sure we returns normalized path */
|
||||
for (i = 0; i < size; ++i){
|
||||
if (result[i] == '\\') result[i] = '/';
|
||||
}
|
||||
NetApiBufferFree((void *) uiPtr);
|
||||
}
|
||||
Tcl_DStringFree(&ds);
|
||||
|
||||
+23
-11
@@ -503,6 +503,27 @@ Tcl_GetEncodingNameFromEnvironment(
|
||||
return Tcl_DStringValue(bufPtr);
|
||||
}
|
||||
|
||||
const char *
|
||||
TclpGetUserName(
|
||||
Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
|
||||
* the name of user. */
|
||||
{
|
||||
Tcl_DStringInit(bufferPtr);
|
||||
|
||||
if (TclGetEnv("USERNAME", bufferPtr) == NULL) {
|
||||
TCHAR szUserName[UNLEN+1];
|
||||
DWORD cchUserNameLen = UNLEN;
|
||||
|
||||
if (!GetUserName(szUserName, &cchUserNameLen)) {
|
||||
return NULL;
|
||||
}
|
||||
cchUserNameLen--;
|
||||
cchUserNameLen *= sizeof(TCHAR);
|
||||
Tcl_WinTCharToUtf(szUserName, cchUserNameLen, bufferPtr);
|
||||
}
|
||||
return Tcl_DStringValue(bufferPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
@@ -533,8 +554,6 @@ TclpSetVariables(
|
||||
static OSVERSIONINFOW osInfo;
|
||||
static int osInfoInitialized = 0;
|
||||
Tcl_DString ds;
|
||||
TCHAR szUserName[UNLEN+1];
|
||||
DWORD cchUserNameLen = UNLEN;
|
||||
|
||||
Tcl_SetVar2Ex(interp, "tclDefaultLibrary", NULL,
|
||||
TclGetProcessGlobalValue(&defaultLibraryDir), TCL_GLOBAL_ONLY);
|
||||
@@ -609,15 +628,8 @@ TclpSetVariables(
|
||||
* Note: cchUserNameLen is number of characters including nul terminator.
|
||||
*/
|
||||
|
||||
Tcl_DStringInit(&ds);
|
||||
if (TclGetEnv("USERNAME", &ds) == NULL) {
|
||||
if (GetUserName(szUserName, &cchUserNameLen) != 0) {
|
||||
int cbUserNameLen = cchUserNameLen - 1;
|
||||
cbUserNameLen *= sizeof(TCHAR);
|
||||
Tcl_WinTCharToUtf(szUserName, cbUserNameLen, &ds);
|
||||
}
|
||||
}
|
||||
Tcl_SetVar2(interp, "tcl_platform", "user", Tcl_DStringValue(&ds),
|
||||
ptr = TclpGetUserName(&ds);
|
||||
Tcl_SetVar2(interp, "tcl_platform", "user", ptr ? ptr : "",
|
||||
TCL_GLOBAL_ONLY);
|
||||
Tcl_DStringFree(&ds);
|
||||
|
||||
|
||||
+2
-7
@@ -63,13 +63,8 @@ MODULE_SCOPE int TclWinSymLinkCopyDirectory(const TCHAR *LinkOriginal,
|
||||
MODULE_SCOPE int TclWinSymLinkDelete(const TCHAR *LinkOriginal,
|
||||
int linkOnly);
|
||||
MODULE_SCOPE int TclWinFileOwned(Tcl_Obj *);
|
||||
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
|
||||
MODULE_SCOPE void TclWinFreeAllocCache(void);
|
||||
MODULE_SCOPE void TclFreeAllocCache(void *);
|
||||
MODULE_SCOPE Tcl_Mutex *TclpNewAllocMutex(void);
|
||||
MODULE_SCOPE void * TclpGetAllocCache(void);
|
||||
MODULE_SCOPE void TclpSetAllocCache(void *);
|
||||
#endif /* TCL_THREADS */
|
||||
|
||||
MODULE_SCOPE const char*TclpGetUserName(Tcl_DString *bufferPtr);
|
||||
|
||||
/* Needed by tclWinFile.c and tclWinFCmd.c */
|
||||
#ifndef FILE_ATTRIBUTE_REPARSE_POINT
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* tclWinPanic.c --
|
||||
*
|
||||
* Contains the Windows-specific command-line panic proc.
|
||||
*
|
||||
* Copyright (c) 2013 by Jan Nijtmans.
|
||||
* All rights reserved.
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution of
|
||||
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
|
||||
#include "tclInt.h"
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_ConsolePanic --
|
||||
*
|
||||
* Display a message. If a debugger is present, present it directly to
|
||||
* the debugger, otherwise send it to stderr.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
Tcl_ConsolePanic(
|
||||
const char *format, ...)
|
||||
{
|
||||
#define TCL_MAX_WARN_LEN 26000
|
||||
va_list argList;
|
||||
WCHAR msgString[TCL_MAX_WARN_LEN];
|
||||
char buf[TCL_MAX_WARN_LEN * TCL_UTF_MAX];
|
||||
HANDLE handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
DWORD dummy;
|
||||
|
||||
va_start(argList, format);
|
||||
vsnprintf(buf+3, sizeof(buf)-3, format, argList);
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
msgString[TCL_MAX_WARN_LEN-1] = L'\0';
|
||||
MultiByteToWideChar(CP_UTF8, 0, buf+3, -1, msgString, TCL_MAX_WARN_LEN);
|
||||
|
||||
/*
|
||||
* Truncate MessageBox string if it is too long to not overflow the buffer.
|
||||
*/
|
||||
|
||||
if (msgString[TCL_MAX_WARN_LEN-1] != L'\0') {
|
||||
memcpy(msgString + (TCL_MAX_WARN_LEN - 5), L" ...", 5 * sizeof(WCHAR));
|
||||
}
|
||||
|
||||
if (IsDebuggerPresent()) {
|
||||
OutputDebugStringW(msgString);
|
||||
} else if (_isatty(2)) {
|
||||
WriteConsoleW(handle, msgString, wcslen(msgString), &dummy, 0);
|
||||
} else {
|
||||
buf[0] = 0xEF; buf[1] = 0xBB; buf[2] = 0xBF; /* UTF-8 bom */
|
||||
WriteFile(handle, buf, strlen(buf), &dummy, 0);
|
||||
WriteFile(handle, "\n", 1, &dummy, 0);
|
||||
FlushFileBuffers(handle);
|
||||
}
|
||||
# if defined(__GNUC__)
|
||||
__builtin_trap();
|
||||
# elif defined(_WIN64)
|
||||
__debugbreak();
|
||||
# elif defined(_MSC_VER)
|
||||
_asm {int 3}
|
||||
# else
|
||||
DebugBreak();
|
||||
# endif
|
||||
#if defined(_WIN32)
|
||||
ExitProcess(1);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: c
|
||||
* c-basic-offset: 4
|
||||
* fill-column: 78
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -568,4 +568,7 @@ typedef DWORD_PTR * PDWORD_PTR;
|
||||
# define LABEL_SECURITY_INFORMATION (0x00000010L)
|
||||
#endif
|
||||
|
||||
#define Tcl_DirEntry void
|
||||
#define TclDIR void
|
||||
|
||||
#endif /* _TCLWINPORT */
|
||||
|
||||
+5
-5
@@ -41,7 +41,7 @@ static CRITICAL_SECTION initLock;
|
||||
* obvious reasons, cannot use any dyamically allocated storage.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
|
||||
static struct Tcl_Mutex_ {
|
||||
CRITICAL_SECTION crit;
|
||||
@@ -76,7 +76,7 @@ static CRITICAL_SECTION joinLock;
|
||||
* The per-thread event and queue pointers.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
|
||||
typedef struct ThreadSpecificData {
|
||||
HANDLE condEvent; /* Per-thread condition event */
|
||||
@@ -474,7 +474,7 @@ TclpMasterUnlock(void)
|
||||
Tcl_Mutex *
|
||||
Tcl_GetAllocMutex(void)
|
||||
{
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (!allocOnce) {
|
||||
InitializeCriticalSection(&allocLock.crit);
|
||||
allocOnce = 1;
|
||||
@@ -516,7 +516,7 @@ TclFinalizeLock(void)
|
||||
DeleteCriticalSection(&masterLock);
|
||||
initialized = 0;
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (allocOnce) {
|
||||
DeleteCriticalSection(&allocLock.crit);
|
||||
allocOnce = 0;
|
||||
@@ -532,7 +532,7 @@ TclFinalizeLock(void)
|
||||
DeleteCriticalSection(&initLock);
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
|
||||
/* locally used prototype */
|
||||
static void FinalizeConditionEvent(ClientData data);
|
||||
|
||||
+1
-7
@@ -8,12 +8,6 @@
|
||||
//
|
||||
// build-up the name suffix that defines the type of build this is.
|
||||
//
|
||||
#if TCL_THREADS
|
||||
#define SUFFIX_THREADS "t"
|
||||
#else
|
||||
#define SUFFIX_THREADS ""
|
||||
#endif
|
||||
|
||||
#if STATIC_BUILD
|
||||
#define SUFFIX_STATIC "s"
|
||||
#else
|
||||
@@ -26,7 +20,7 @@
|
||||
#define SUFFIX_DEBUG ""
|
||||
#endif
|
||||
|
||||
#define SUFFIX SUFFIX_THREADS SUFFIX_STATIC SUFFIX_DEBUG
|
||||
#define SUFFIX SUFFIX_STATIC SUFFIX_DEBUG
|
||||
|
||||
|
||||
LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */
|
||||
|
||||
Reference in New Issue
Block a user