Compare commits
708
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af4318b18f | ||
|
|
243ea5f7a3 | ||
|
|
6d3aeef45e | ||
|
|
f244391aa4 | ||
|
|
fbdc68b6a2 | ||
|
|
6a8b110ddc | ||
|
|
9f9a9e291d | ||
|
|
31b9d1f712 | ||
|
|
25ac7e62ba | ||
|
|
854cf964d2 | ||
|
|
63ef0e3d26 | ||
|
|
df89a7f211 | ||
|
|
8f54520a20 | ||
|
|
39318d91b7 | ||
|
|
395353bfdb | ||
|
|
c3afc3b93f | ||
|
|
d24a3eb2ba | ||
|
|
bd42171094 | ||
|
|
c5943ec574 | ||
|
|
f11320b6b0 | ||
|
|
1775284940 | ||
|
|
3200ec75ef | ||
|
|
9b45aaa5b0 | ||
|
|
1a3cef4874 | ||
|
|
0babbf966b | ||
|
|
945b10776d | ||
|
|
9a15a1b586 | ||
|
|
4b7caf2e4a | ||
|
|
95db69f27b | ||
|
|
e94df65350 | ||
|
|
b8d2426e1b | ||
|
|
e80eaec4d3 | ||
|
|
b9577c0641 | ||
|
|
6269e32c3b | ||
|
|
3e7ffcaf4b | ||
|
|
5c9968a001 | ||
|
|
fdf1df3b29 | ||
|
|
2f2b7f6ac7 | ||
|
|
5f1bd2f2e3 | ||
|
|
0787b1d152 | ||
|
|
cb9f3f9268 | ||
|
|
6d88b01d1e | ||
|
|
6dfe3f5de6 | ||
|
|
77a26f5c95 | ||
|
|
9cec6bac27 | ||
|
|
2f19b0f346 | ||
|
|
265c9d416f | ||
|
|
db610f91eb | ||
|
|
afb5bf5583 | ||
|
|
9b7ce068fe | ||
|
|
d4d1014e7d | ||
|
|
820a737a2f | ||
|
|
c2d61d8dbc | ||
|
|
fb0bf9d1b9 | ||
|
|
01dd016ad8 | ||
|
|
d660b325b5 | ||
|
|
26b477b907 | ||
|
|
89ff80fbdd | ||
|
|
b3993adcfb | ||
|
|
90afac281e | ||
|
|
aed158b518 | ||
|
|
9b285dde85 | ||
|
|
e5270637c0 | ||
|
|
f5efc84600 | ||
|
|
245151ad96 | ||
|
|
65f3d0f56b | ||
|
|
18c102aa70 | ||
|
|
e53f3cf9c6 | ||
|
|
6c78bf0adc | ||
|
|
12647cc4fb | ||
|
|
8346cad0dd | ||
|
|
620b4d531d | ||
|
|
ed3e9c60ba | ||
|
|
d87884d51b | ||
|
|
de5637f853 | ||
|
|
40947c7d3e | ||
|
|
cff4a9d980 | ||
|
|
c1ae69114b | ||
|
|
ad757b50dc | ||
|
|
5902889825 | ||
|
|
04c687936c | ||
|
|
304b569170 | ||
|
|
2133e40e58 | ||
|
|
c7cdc550c4 | ||
|
|
7633450128 | ||
|
|
7e727bed70 | ||
|
|
164a7f04c0 | ||
|
|
54fbd7dbcb | ||
|
|
772d2da10b | ||
|
|
0ae1df9bfc | ||
|
|
814c867db4 | ||
|
|
6667ddcb54 | ||
|
|
d00a212e82 | ||
|
|
7fb72851e8 | ||
|
|
4a3f32b84a | ||
|
|
77aceb5c5f | ||
|
|
8a7c004dbc | ||
|
|
a1790a1683 | ||
|
|
885a163b3c | ||
|
|
87e508c590 | ||
|
|
a76637248c | ||
|
|
2a46a48670 | ||
|
|
51aecf205d | ||
|
|
d0f8889c8f | ||
|
|
27110774bd | ||
|
|
5a06fd4bcf | ||
|
|
969f9f571c | ||
|
|
64cbe6e187 | ||
|
|
367ce9ad48 | ||
|
|
6982ae0ca7 | ||
|
|
da7eafc83b | ||
|
|
414bcee273 | ||
|
|
d11660acfe | ||
|
|
5c7ba37901 | ||
|
|
1d1e95e779 | ||
|
|
bffb982059 | ||
|
|
0978bd50ce | ||
|
|
3f8c7d5d40 | ||
|
|
4c24e60418 | ||
|
|
8219fb2632 | ||
|
|
082e8c6d7a | ||
|
|
7a9d97826e | ||
|
|
9683822257 | ||
|
|
9da2aebeae | ||
|
|
bf884c9bc9 | ||
|
|
ed5ed756bc | ||
|
|
fdee46ab16 | ||
|
|
0839047d8b | ||
|
|
94f9cf81ed | ||
|
|
e2a79c2604 | ||
|
|
05209c57d3 | ||
|
|
6cbfdcc4a3 | ||
|
|
94ec3d9431 | ||
|
|
6c1e9f2b0c | ||
|
|
563bd6e4dd | ||
|
|
b418ff1759 | ||
|
|
56ca35e8a9 | ||
|
|
107fb1eb33 | ||
|
|
c911dc937f | ||
|
|
645241afc1 | ||
|
|
03a3c09b1f | ||
|
|
5c87050dd8 | ||
|
|
3c57d80efe | ||
|
|
04004f3abc | ||
|
|
155e8a1ad5 | ||
|
|
625aca976a | ||
|
|
e9c0ec1219 | ||
|
|
8e696a5e5d | ||
|
|
9e511d7874 | ||
|
|
5af99f55b2 | ||
|
|
8047a470ef | ||
|
|
1f91c778bb | ||
|
|
2b739c838a | ||
|
|
dd713ee96e | ||
|
|
983854ad7b | ||
|
|
7bf68c2335 | ||
|
|
41a6159754 | ||
|
|
c9802b0230 | ||
|
|
df97278634 | ||
|
|
06fc5fb636 | ||
|
|
15f804e04e | ||
|
|
e5de25734f | ||
|
|
e393000b1d | ||
|
|
83d92bd747 | ||
|
|
33b8401436 | ||
|
|
d62033b7e2 | ||
|
|
1b3a0a73ae | ||
|
|
9e3e0498e7 | ||
|
|
b5e61d9f54 | ||
|
|
5a05e0d782 | ||
|
|
9c8f784329 | ||
|
|
bae4992913 | ||
|
|
1efbaebb6a | ||
|
|
ac47e6953d | ||
|
|
400feb302b | ||
|
|
9c9b3d93f9 | ||
|
|
04d1270786 | ||
|
|
f8b9cb869d | ||
|
|
4755be8f41 | ||
|
|
c2e16d9b1f | ||
|
|
3b14a4b0ed | ||
|
|
a3fdad2b4f | ||
|
|
b89a3efc56 | ||
|
|
240e6b50d2 | ||
|
|
38be8d3de6 | ||
|
|
ddd37fb237 | ||
|
|
63be474164 | ||
|
|
754bb107b4 | ||
|
|
fa47c96ac2 | ||
|
|
5e3ca11761 | ||
|
|
6ab540f5ff | ||
|
|
63b0fef31a | ||
|
|
bb503004b6 | ||
|
|
267cdaec03 | ||
|
|
a2ce3dab9b | ||
|
|
6a4d06759e | ||
|
|
6966f0a2b1 | ||
|
|
89a84af271 | ||
|
|
bb5d24622f | ||
|
|
813979693c | ||
|
|
c8da3bbfaf | ||
|
|
35f5b82868 | ||
|
|
5e7a1545a6 | ||
|
|
f4651a5660 | ||
|
|
a0290b85c5 | ||
|
|
8145564d30 | ||
|
|
66ef201ad7 | ||
|
|
6d943ef7b5 | ||
|
|
1c13d543f4 | ||
|
|
263de53394 | ||
|
|
a410c0d8d5 | ||
|
|
ecec1703aa | ||
|
|
1ab67324ca | ||
|
|
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 | ||
|
|
c744824995 | ||
|
|
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 | ||
|
|
5238a999d5 | ||
|
|
ab49bdfd12 | ||
|
|
227db01958 | ||
|
|
41954059c4 | ||
|
|
b169c964e6 | ||
|
|
3771e638b0 | ||
|
|
f44e7c1795 | ||
|
|
04604552b2 | ||
|
|
b5d6b4f138 | ||
|
|
ad02c0b532 | ||
|
|
28e500cbf9 | ||
|
|
637c7dbc7e | ||
|
|
4588d7300e | ||
|
|
d690b84738 | ||
|
|
49879791f4 | ||
|
|
8262e514d0 | ||
|
|
5a8d06b076 | ||
|
|
6bc8c27b7f | ||
|
|
6a58a0cab2 | ||
|
|
1357172367 | ||
|
|
466fd1d930 | ||
|
|
008f1c98d0 | ||
|
|
42a2b87f32 | ||
|
|
441e4f6796 | ||
|
|
3117af219f | ||
|
|
a0e1b18138 | ||
|
|
70af5c2b82 | ||
|
|
d38ae8f974 | ||
|
|
0d887fa465 | ||
|
|
e9bb0992b0 | ||
|
|
f35c0dc2ed | ||
|
|
e80e214673 | ||
|
|
731f40c6d9 | ||
|
|
767cf6314a | ||
|
|
b00317d174 | ||
|
|
a8408767a4 | ||
|
|
4f8b177250 | ||
|
|
25aad1ab18 | ||
|
|
3b48db4a90 | ||
|
|
58eff8f224 | ||
|
|
97721e9675 | ||
|
|
d88d33f74d | ||
|
|
0a9706f48f | ||
|
|
45f91441a5 | ||
|
|
38781266d3 | ||
|
|
383c53f80e | ||
|
|
ba9cf35aa3 | ||
|
|
db41a49d9c | ||
|
|
cbbab84b71 | ||
|
|
55a65632d0 | ||
|
|
47152d94c1 | ||
|
|
f52d25e68a | ||
|
|
6de6ee8aa9 | ||
|
|
5b5bd699ff | ||
|
|
69868ee129 | ||
|
|
e16df96d28 | ||
|
|
608373fcb1 | ||
|
|
a866c42f19 | ||
|
|
3502aebe10 | ||
|
|
9947048fbd | ||
|
|
37b48e808c | ||
|
|
3fc7771456 | ||
|
|
7aa147800f | ||
|
|
b533731c50 | ||
|
|
983b089edb | ||
|
|
47c7771af1 | ||
|
|
1dd89810eb | ||
|
|
53795bd199 | ||
|
|
72af38dd32 | ||
|
|
7f1c241ea2 | ||
|
|
45a3c74a04 | ||
|
|
71cf0dba40 | ||
|
|
603e23c2a9 | ||
|
|
3f03f8189e | ||
|
|
c576cbec93 | ||
|
|
5c4f8d88b5 | ||
|
|
9c5c1a721f | ||
|
|
2756d01872 | ||
|
|
bf868c1c56 | ||
|
|
a69614b432 | ||
|
|
9b22762d4c | ||
|
|
0951ca5344 | ||
|
|
bb48fae153 | ||
|
|
ae2707f558 | ||
|
|
99dc87a51d | ||
|
|
7154cc9c47 | ||
|
|
b3ff8cc20c | ||
|
|
2fcfa34fcf | ||
|
|
2d811a0adf | ||
|
|
09f849cabd | ||
|
|
d997aa477d | ||
|
|
8225859a93 | ||
|
|
35adf8c728 | ||
|
|
334149646f | ||
|
|
d8a921174e | ||
|
|
d7b40297d2 | ||
|
|
9ef614086a | ||
|
|
6b40a5dc5a | ||
|
|
3cd8b86e50 | ||
|
|
d2fc7a6ed5 | ||
|
|
12a14f4954 | ||
|
|
1f34b918b9 | ||
|
|
4a8bb308e8 | ||
|
|
3640513caf | ||
|
|
4e97c16367 | ||
|
|
280b6aa62e | ||
|
|
fe346634a7 | ||
|
|
1d444f5610 | ||
|
|
30938251a2 | ||
|
|
157e55c7bc | ||
|
|
d8a0c08bbc | ||
|
|
3730061388 | ||
|
|
b171f5cc41 | ||
|
|
02a019458f | ||
|
|
b59255450b | ||
|
|
c6d82079ea | ||
|
|
52d32b1033 | ||
|
|
f85da9c9fd | ||
|
|
f20b58c6a9 | ||
|
|
9513859f8c | ||
|
|
f81c2ae724 | ||
|
|
7c1f63bb60 | ||
|
|
4515103846 | ||
|
|
87d37d3101 | ||
|
|
da76cd286c | ||
|
|
3c532f6336 | ||
|
|
ded3368d3c | ||
|
|
e84763748b | ||
|
|
8079a467a7 | ||
|
|
be47788793 | ||
|
|
62fbfd89d7 | ||
|
|
932afb0105 | ||
|
|
b2722c42b1 | ||
|
|
c2dfae0758 | ||
|
|
23440fcbd7 | ||
|
|
399ff79e21 | ||
|
|
338e92cb28 | ||
|
|
433dff0c14 | ||
|
|
ef7ea2c390 | ||
|
|
5470f13299 | ||
|
|
c0effc5b46 | ||
|
|
fc947a1ad4 | ||
|
|
54bc992b81 | ||
|
|
e55f59bd83 | ||
|
|
15f27ca8f2 | ||
|
|
c55b8ed591 | ||
|
|
522456ba98 | ||
|
|
ecdbabf93a | ||
|
|
1f92397dcd | ||
|
|
3a6415e294 | ||
|
|
427c619d34 | ||
|
|
298d32b5d7 | ||
|
|
00fcfb6e96 | ||
|
|
17f324a745 | ||
|
|
75f156016e | ||
|
|
5dd0e19ea5 | ||
|
|
f421f7e202 | ||
|
|
8d199f0272 | ||
|
|
74a1c4a153 | ||
|
|
112bdec4bb | ||
|
|
7dfab1a0f6 | ||
|
|
94f182e0d3 | ||
|
|
5178daa9a7 | ||
|
|
b5273bc1fa | ||
|
|
627f0a4d6a | ||
|
|
b645469c95 | ||
|
|
e295641767 | ||
|
|
c3a18ac8f4 | ||
|
|
f9dda45e97 | ||
|
|
a5c310f993 | ||
|
|
80d9aa777b | ||
|
|
c745f44e3a | ||
|
|
21d4596064 | ||
|
|
5f738db586 | ||
|
|
76bb4d1ea4 | ||
|
|
4db368d595 | ||
|
|
9dfe53af4a | ||
|
|
e58a9dabbe | ||
|
|
3e0c5c6c90 | ||
|
|
e9e40f5f02 | ||
|
|
a4dbdda700 | ||
|
|
5bf83d86b6 | ||
|
|
3c85e6e0ef | ||
|
|
58ab27bf86 | ||
|
|
824b71f959 | ||
|
|
c3c935369d | ||
|
|
e14a1e9e3d | ||
|
|
5c93243c18 | ||
|
|
bd1370959e | ||
|
|
a852495cf6 | ||
|
|
9a7f1bd48c | ||
|
|
47cb19c83f | ||
|
|
f4cc5617a6 | ||
|
|
e48602d674 | ||
|
|
e9a8c42972 | ||
|
|
5bcc7fa342 | ||
|
|
b0c45c3ad0 | ||
|
|
e1e49c9dd1 | ||
|
|
18ba46bf37 | ||
|
|
5b719a2281 | ||
|
|
edbf30e23a | ||
|
|
395d0889b0 | ||
|
|
ba0d107038 | ||
|
|
763f9dff55 | ||
|
|
bbcef5b648 | ||
|
|
b3b6f6ff99 | ||
|
|
71b97d16f3 | ||
|
|
25d1f4aa03 | ||
|
|
22f5c55560 | ||
|
|
3cf33e9e9f | ||
|
|
a288c5e54a | ||
|
|
c3e9d3205f | ||
|
|
227fbec0fc | ||
|
|
dc21089720 | ||
|
|
f6bb864fc7 | ||
|
|
bd7d14f293 | ||
|
|
982211da16 | ||
|
|
a1740d9766 | ||
|
|
e9795fb407 | ||
|
|
299924e512 | ||
|
|
a03e74efc1 | ||
|
|
3c03a492f9 | ||
|
|
56c5833c4a | ||
|
|
63b07461da | ||
|
|
1c3288f038 | ||
|
|
8ecd6aeb5b | ||
|
|
4d00715902 | ||
|
|
95aeb2a3d6 | ||
|
|
b0a98f480d | ||
|
|
cb73551e8d | ||
|
|
4d946107e7 | ||
|
|
c795f44ea5 | ||
|
|
ecd9567624 | ||
|
|
d6fdfa4624 | ||
|
|
58ace2b1dc | ||
|
|
8f6089f225 | ||
|
|
19627fed47 | ||
|
|
83145e2bb1 | ||
|
|
621c76324a | ||
|
|
e961e1c08a | ||
|
|
e740674cb8 | ||
|
|
23ced66a6b | ||
|
|
b637222a5d | ||
|
|
9a0f7dd2c8 | ||
|
|
440e5fc7dc | ||
|
|
74ed7238b0 | ||
|
|
38d734ddcf | ||
|
|
cbeed9da92 | ||
|
|
a369d46795 | ||
|
|
1956f4b66b | ||
|
|
90b38da321 | ||
|
|
4594b4f27a | ||
|
|
ff3f0131bd | ||
|
|
5b793fef99 | ||
|
|
13aa1642ac | ||
|
|
d905cc4737 | ||
|
|
d954f3c4ee | ||
|
|
c770024ce1 | ||
|
|
c1f95640c4 | ||
|
|
48ef2b50eb | ||
|
|
071aa09c6e | ||
|
|
10cd3c906d | ||
|
|
0fca37f803 | ||
|
|
9dd94f7396 | ||
|
|
ce65c7b396 | ||
|
|
a80a084de9 | ||
|
|
ddc625f2fe | ||
|
|
842b15b839 | ||
|
|
4506b4536b | ||
|
|
dbe627594e | ||
|
|
130fe11f2b | ||
|
|
3bce1ab6f2 | ||
|
|
fe773c0a46 | ||
|
|
ecc90e3787 | ||
|
|
6e0d4b6761 | ||
|
|
53ad2ab17d | ||
|
|
a2a59dfb75 | ||
|
|
829af34165 | ||
|
|
1579eae899 | ||
|
|
6fcdce9c74 | ||
|
|
ac785323be | ||
|
|
d68207f7ca | ||
|
|
ddc615491d | ||
|
|
b1031c0d07 | ||
|
|
cdba31b9d5 | ||
|
|
83da0d6374 | ||
|
|
bb504b06b4 | ||
|
|
55717aeaea | ||
|
|
e886aae69e | ||
|
|
adceea62b6 | ||
|
|
348f13ad57 | ||
|
|
e448db56ee | ||
|
|
dd60d52814 | ||
|
|
428c3163c5 | ||
|
|
339d4879a0 | ||
|
|
ded95f89d3 | ||
|
|
5949095693 | ||
|
|
410178bb88 | ||
|
|
9cbfbd034e | ||
|
|
3b50f8bcd6 | ||
|
|
85442c797c | ||
|
|
3e723b7f5e | ||
|
|
6b423f0d9e | ||
|
|
bdc43f8241 | ||
|
|
9171dde346 | ||
|
|
6826dbab46 | ||
|
|
b2164040ac | ||
|
|
307bb5f72d | ||
|
|
963de5ae2a | ||
|
|
2b022e6979 | ||
|
|
cfd9edb0fe | ||
|
|
74b45809d1 | ||
|
|
507bab4b21 | ||
|
|
f45b6c1066 | ||
|
|
ebebb29be9 | ||
|
|
2e0b2484a9 | ||
|
|
ff7a13136d | ||
|
|
4b8398a6ed | ||
|
|
a684c1a281 | ||
|
|
b25f4f5272 | ||
|
|
c003b95ed4 | ||
|
|
0cbfed0c55 | ||
|
|
ee30b1c0ab | ||
|
|
b3362b7dfd | ||
|
|
99d72ae892 | ||
|
|
39145d45d1 | ||
|
|
627a5bfa73 | ||
|
|
ab35383fda | ||
|
|
9f12483ed2 | ||
|
|
4e331e27f8 | ||
|
|
71e02d5298 | ||
|
|
0008ed9ea4 | ||
|
|
3bd1370dbc | ||
|
|
a426ba29d5 | ||
|
|
a813938bef | ||
|
|
295272b73c | ||
|
|
703177e26a | ||
|
|
b992e62207 | ||
|
|
4691bea988 | ||
|
|
fce753c3d5 | ||
|
|
670a31f84f | ||
|
|
25358e0ba4 | ||
|
|
b6f9bc7ca8 | ||
|
|
79ccab2fd2 | ||
|
|
8d1d673760 | ||
|
|
6c2512bc35 | ||
|
|
2c1a55d314 | ||
|
|
e88bbb7296 | ||
|
|
06547a29be | ||
|
|
8ca1a78b1a | ||
|
|
6c59decfba | ||
|
|
732a963e04 | ||
|
|
cd9922f497 | ||
|
|
9554b52dba | ||
|
|
8c90b3ae99 | ||
|
|
811d367c49 | ||
|
|
1d9824ec60 | ||
|
|
5c6730bd0f | ||
|
|
78b3c04320 | ||
|
|
0ce217e309 | ||
|
|
d1536b7378 | ||
|
|
eb664a3d72 | ||
|
|
96dd5baf98 | ||
|
|
18eed1d727 | ||
|
|
ce72e40607 | ||
|
|
8615597984 | ||
|
|
a333bbaa12 | ||
|
|
2bc847ac57 | ||
|
|
9283692888 | ||
|
|
017b8b10b6 | ||
|
|
4ddfe70ae2 | ||
|
|
53dc25e532 | ||
|
|
542b57cf21 | ||
|
|
e36fd891e4 | ||
|
|
954b241f34 | ||
|
|
f038b7fc3d | ||
|
|
3f56494834 | ||
|
|
6a811b97b9 | ||
|
|
30dbc0a75b | ||
|
|
1900da6d24 | ||
|
|
8f38d12eee | ||
|
|
3f5f45f002 | ||
|
|
e6528cb48d | ||
|
|
041184928d | ||
|
|
b108063f75 | ||
|
|
9ce336b3d1 | ||
|
|
b5da760544 | ||
|
|
7e520e2089 | ||
|
|
07af7d5337 | ||
|
|
696a9ba3f9 | ||
|
|
9db6776dbe | ||
|
|
1c6a242b2e | ||
|
|
a58db736cf | ||
|
|
449ea43718 | ||
|
|
260c2634b9 | ||
|
|
6d0db57c02 | ||
|
|
11593d64b8 | ||
|
|
e4a0b9dbfd | ||
|
|
bb770e33f8 | ||
|
|
d048128004 | ||
|
|
eecece2afe | ||
|
|
74c7068a25 | ||
|
|
59360240b3 | ||
|
|
57d33c5027 | ||
|
|
e1c5526cb2 | ||
|
|
290c2ef84f | ||
|
|
91ba235b3c | ||
|
|
d13fe1e431 | ||
|
|
f361c1805c | ||
|
|
52b8ad45d1 | ||
|
|
9b6c85d82e | ||
|
|
88b8fc30a2 | ||
|
|
1a0463ea04 | ||
|
|
cab91124b4 | ||
|
|
8d9ea7c132 | ||
|
|
c5558280d7 | ||
|
|
3913f5f7ae | ||
|
|
e8c69aa654 | ||
|
|
b2b37d97cf | ||
|
|
4796adf5cb | ||
|
|
2c02c2ae5d | ||
|
|
ef824b7395 | ||
|
|
2930daf68c | ||
|
|
0481e3ca74 | ||
|
|
073618d375 | ||
|
|
5ddf03d324 | ||
|
|
ac98be85ce | ||
|
|
048fae9de6 | ||
|
|
81735df1fa | ||
|
|
9c32ab0d8b | ||
|
|
861e75f503 | ||
|
|
e891120584 | ||
|
|
2045bb3c21 | ||
|
|
a498488c59 | ||
|
|
dd43ee3dbf | ||
|
|
39ad9eb8f3 | ||
|
|
b30ba5a92b |
@@ -4,6 +4,7 @@ compat/zlib/win64/zdll.lib
|
||||
compat/zlib/win64/zlib1.dll
|
||||
compat/zlib/win64/libz.dll.a
|
||||
compat/zlib/zlib.3.pdf
|
||||
tools/empty.zip
|
||||
*.bmp
|
||||
*.gif
|
||||
*.png
|
||||
@@ -0,0 +1,3 @@
|
||||
Important Note
|
||||
==========
|
||||
Please do not file issues with Tcl on Github. They are unlikely to be noticed in a timely fashion. Tcl issues are hosted in the [tcl fossil repository on core.tcl.tk](https://core.tcl.tk/tcl/tktnew); please post them there.
|
||||
@@ -0,0 +1,3 @@
|
||||
Important Note
|
||||
==========
|
||||
Please do not file pull requests with Tcl on Github. They are unlikely to be noticed in a timely fashion. Tcl issues (including patches) are hosted in the [tcl fossil repository on core.tcl.tk](https://core.tcl.tk/tcl/tktnew); please post them there.
|
||||
@@ -12,7 +12,6 @@
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
*/
|
||||
|
||||
|
||||
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
|
||||
#ifndef __USE_FILE_OFFSET64
|
||||
#define __USE_FILE_OFFSET64
|
||||
@@ -39,8 +38,7 @@
|
||||
#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include "tinydir.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -172,6 +170,7 @@ void do_banner()
|
||||
void do_help()
|
||||
{
|
||||
printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \
|
||||
" -r Scan directories recursively\n" \
|
||||
" -o Overwrite existing file.zip\n" \
|
||||
" -a Append to existing file.zip\n" \
|
||||
" -0 Store only\n" \
|
||||
@@ -243,12 +242,153 @@ int isLargeFile(const char* filename)
|
||||
return largeFile;
|
||||
}
|
||||
|
||||
void addFileToZip(zipFile zf, const char *filenameinzip, const char *password, int opt_exclude_path,int opt_compress_level) {
|
||||
FILE * fin;
|
||||
int size_read;
|
||||
const char *savefilenameinzip;
|
||||
zip_fileinfo zi;
|
||||
unsigned long crcFile=0;
|
||||
int zip64 = 0;
|
||||
int err=0;
|
||||
int size_buf=WRITEBUFFERSIZE;
|
||||
unsigned char buf[WRITEBUFFERSIZE];
|
||||
zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
|
||||
zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
|
||||
zi.dosDate = 0;
|
||||
zi.internal_fa = 0;
|
||||
zi.external_fa = 0;
|
||||
filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
|
||||
|
||||
/*
|
||||
err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
|
||||
NULL,0,NULL,0,NULL / * comment * /,
|
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0,
|
||||
opt_compress_level);
|
||||
*/
|
||||
if ((password != NULL) && (err==ZIP_OK))
|
||||
err = getFileCrc(filenameinzip,buf,size_buf,&crcFile);
|
||||
|
||||
zip64 = isLargeFile(filenameinzip);
|
||||
|
||||
/* The path name saved, should not include a leading slash. */
|
||||
/*if it did, windows/xp and dynazip couldn't read the zip file. */
|
||||
savefilenameinzip = filenameinzip;
|
||||
while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' )
|
||||
{
|
||||
savefilenameinzip++;
|
||||
}
|
||||
|
||||
/*should the zip file contain any path at all?*/
|
||||
if( opt_exclude_path )
|
||||
{
|
||||
const char *tmpptr;
|
||||
const char *lastslash = 0;
|
||||
for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++)
|
||||
{
|
||||
if( *tmpptr == '\\' || *tmpptr == '/')
|
||||
{
|
||||
lastslash = tmpptr;
|
||||
}
|
||||
}
|
||||
if( lastslash != NULL )
|
||||
{
|
||||
savefilenameinzip = lastslash+1; // base filename follows last slash.
|
||||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi,
|
||||
NULL,0,NULL,0,NULL /* comment*/,
|
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0,
|
||||
opt_compress_level,0,
|
||||
/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
|
||||
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
|
||||
password,crcFile, zip64);
|
||||
|
||||
if (err != ZIP_OK)
|
||||
printf("error in opening %s in zipfile\n",filenameinzip);
|
||||
else
|
||||
{
|
||||
fin = FOPEN_FUNC(filenameinzip,"rb");
|
||||
if (fin==NULL)
|
||||
{
|
||||
err=ZIP_ERRNO;
|
||||
printf("error in opening %s for reading\n",filenameinzip);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ZIP_OK)
|
||||
do
|
||||
{
|
||||
err = ZIP_OK;
|
||||
size_read = (int)fread(buf,1,size_buf,fin);
|
||||
if (size_read < size_buf)
|
||||
if (feof(fin)==0)
|
||||
{
|
||||
printf("error in reading %s\n",filenameinzip);
|
||||
err = ZIP_ERRNO;
|
||||
}
|
||||
|
||||
if (size_read>0)
|
||||
{
|
||||
err = zipWriteInFileInZip (zf,buf,size_read);
|
||||
if (err<0)
|
||||
{
|
||||
printf("error in writing %s in the zipfile\n",
|
||||
filenameinzip);
|
||||
}
|
||||
|
||||
}
|
||||
} while ((err == ZIP_OK) && (size_read>0));
|
||||
|
||||
if (fin)
|
||||
fclose(fin);
|
||||
|
||||
if (err<0)
|
||||
err=ZIP_ERRNO;
|
||||
else
|
||||
{
|
||||
err = zipCloseFileInZip(zf);
|
||||
if (err!=ZIP_OK)
|
||||
printf("error in closing %s in the zipfile\n",
|
||||
filenameinzip);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void addPathToZip(zipFile zf, const char *filenameinzip, const char *password, int opt_exclude_path,int opt_compress_level) {
|
||||
tinydir_dir dir;
|
||||
int i;
|
||||
char *newname[512];
|
||||
|
||||
tinydir_open_sorted(&dir, filenameinzip);
|
||||
|
||||
for (i = 0; i < dir.n_files; i++)
|
||||
{
|
||||
tinydir_file file;
|
||||
tinydir_readfile_n(&dir, &file, i);
|
||||
if(strcmp(file.name,".")==0) continue;
|
||||
if(strcmp(file.name,"..")==0) continue;
|
||||
sprintf(newname,"%s/%s",dir.path,file.name);
|
||||
if (file.is_dir)
|
||||
{
|
||||
addPathToZip(zf,newname,password,opt_exclude_path,opt_compress_level);
|
||||
} else {
|
||||
addFileToZip(zf,newname,password,opt_exclude_path,opt_compress_level);
|
||||
}
|
||||
}
|
||||
|
||||
tinydir_close(&dir);
|
||||
}
|
||||
|
||||
|
||||
int main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i;
|
||||
int opt_overwrite=0;
|
||||
int opt_recursive=0;
|
||||
int opt_overwrite=1;
|
||||
int opt_compress_level=Z_DEFAULT_COMPRESSION;
|
||||
int opt_exclude_path=0;
|
||||
int zipfilenamearg = 0;
|
||||
@@ -285,7 +425,8 @@ int main(argc,argv)
|
||||
opt_compress_level = c-'0';
|
||||
if ((c=='j') || (c=='J'))
|
||||
opt_exclude_path = 1;
|
||||
|
||||
if ((c=='r') || (c=='R'))
|
||||
opt_recursive = 1;
|
||||
if (((c=='p') || (c=='P')) && (i+1<argc))
|
||||
{
|
||||
password=argv[i+1];
|
||||
@@ -392,117 +533,14 @@ int main(argc,argv)
|
||||
((argv[i][1]=='o') || (argv[i][1]=='O') ||
|
||||
(argv[i][1]=='a') || (argv[i][1]=='A') ||
|
||||
(argv[i][1]=='p') || (argv[i][1]=='P') ||
|
||||
(argv[i][1]=='r') || (argv[i][1]=='R') ||
|
||||
((argv[i][1]>='0') || (argv[i][1]<='9'))) &&
|
||||
(strlen(argv[i]) == 2)))
|
||||
{
|
||||
FILE * fin;
|
||||
int size_read;
|
||||
const char* filenameinzip = argv[i];
|
||||
const char *savefilenameinzip;
|
||||
zip_fileinfo zi;
|
||||
unsigned long crcFile=0;
|
||||
int zip64 = 0;
|
||||
|
||||
zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
|
||||
zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
|
||||
zi.dosDate = 0;
|
||||
zi.internal_fa = 0;
|
||||
zi.external_fa = 0;
|
||||
filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
|
||||
|
||||
/*
|
||||
err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
|
||||
NULL,0,NULL,0,NULL / * comment * /,
|
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0,
|
||||
opt_compress_level);
|
||||
*/
|
||||
if ((password != NULL) && (err==ZIP_OK))
|
||||
err = getFileCrc(filenameinzip,buf,size_buf,&crcFile);
|
||||
|
||||
zip64 = isLargeFile(filenameinzip);
|
||||
|
||||
/* The path name saved, should not include a leading slash. */
|
||||
/*if it did, windows/xp and dynazip couldn't read the zip file. */
|
||||
savefilenameinzip = filenameinzip;
|
||||
while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' )
|
||||
{
|
||||
savefilenameinzip++;
|
||||
}
|
||||
|
||||
/*should the zip file contain any path at all?*/
|
||||
if( opt_exclude_path )
|
||||
{
|
||||
const char *tmpptr;
|
||||
const char *lastslash = 0;
|
||||
for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++)
|
||||
{
|
||||
if( *tmpptr == '\\' || *tmpptr == '/')
|
||||
{
|
||||
lastslash = tmpptr;
|
||||
}
|
||||
}
|
||||
if( lastslash != NULL )
|
||||
{
|
||||
savefilenameinzip = lastslash+1; // base filename follows last slash.
|
||||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi,
|
||||
NULL,0,NULL,0,NULL /* comment*/,
|
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0,
|
||||
opt_compress_level,0,
|
||||
/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
|
||||
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
|
||||
password,crcFile, zip64);
|
||||
|
||||
if (err != ZIP_OK)
|
||||
printf("error in opening %s in zipfile\n",filenameinzip);
|
||||
else
|
||||
{
|
||||
fin = FOPEN_FUNC(filenameinzip,"rb");
|
||||
if (fin==NULL)
|
||||
{
|
||||
err=ZIP_ERRNO;
|
||||
printf("error in opening %s for reading\n",filenameinzip);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ZIP_OK)
|
||||
do
|
||||
{
|
||||
err = ZIP_OK;
|
||||
size_read = (int)fread(buf,1,size_buf,fin);
|
||||
if (size_read < size_buf)
|
||||
if (feof(fin)==0)
|
||||
{
|
||||
printf("error in reading %s\n",filenameinzip);
|
||||
err = ZIP_ERRNO;
|
||||
}
|
||||
|
||||
if (size_read>0)
|
||||
{
|
||||
err = zipWriteInFileInZip (zf,buf,size_read);
|
||||
if (err<0)
|
||||
{
|
||||
printf("error in writing %s in the zipfile\n",
|
||||
filenameinzip);
|
||||
}
|
||||
|
||||
}
|
||||
} while ((err == ZIP_OK) && (size_read>0));
|
||||
|
||||
if (fin)
|
||||
fclose(fin);
|
||||
|
||||
if (err<0)
|
||||
err=ZIP_ERRNO;
|
||||
else
|
||||
{
|
||||
err = zipCloseFileInZip(zf);
|
||||
if (err!=ZIP_OK)
|
||||
printf("error in closing %s in the zipfile\n",
|
||||
filenameinzip);
|
||||
if(opt_recursive) {
|
||||
addPathToZip(zf,argv[i],password,opt_exclude_path,opt_compress_level);
|
||||
} else {
|
||||
addFileToZip(zf,argv[i],password,opt_exclude_path,opt_compress_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+816
@@ -0,0 +1,816 @@
|
||||
/*
|
||||
Copyright (c) 2013-2017, tinydir authors:
|
||||
- Cong Xu
|
||||
- Lautis Sun
|
||||
- Baudouin Feildel
|
||||
- Andargor <andargor@yahoo.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef TINYDIR_H
|
||||
#define TINYDIR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if ((defined _UNICODE) && !(defined UNICODE))
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#if ((defined UNICODE) && !(defined _UNICODE))
|
||||
#define _UNICODE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# pragma warning(push)
|
||||
# pragma warning (disable : 4996)
|
||||
#else
|
||||
# include <dirent.h>
|
||||
# include <libgen.h>
|
||||
# include <sys/stat.h>
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
#ifdef __MINGW32__
|
||||
# include <tchar.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* types */
|
||||
|
||||
/* Windows UNICODE wide character support */
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
# define _tinydir_char_t TCHAR
|
||||
# define TINYDIR_STRING(s) _TEXT(s)
|
||||
# define _tinydir_strlen _tcslen
|
||||
# define _tinydir_strcpy _tcscpy
|
||||
# define _tinydir_strcat _tcscat
|
||||
# define _tinydir_strcmp _tcscmp
|
||||
# define _tinydir_strrchr _tcsrchr
|
||||
# define _tinydir_strncmp _tcsncmp
|
||||
#else
|
||||
# define _tinydir_char_t char
|
||||
# define TINYDIR_STRING(s) s
|
||||
# define _tinydir_strlen strlen
|
||||
# define _tinydir_strcpy strcpy
|
||||
# define _tinydir_strcat strcat
|
||||
# define _tinydir_strcmp strcmp
|
||||
# define _tinydir_strrchr strrchr
|
||||
# define _tinydir_strncmp strncmp
|
||||
#endif
|
||||
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
# include <windows.h>
|
||||
# define _TINYDIR_PATH_MAX MAX_PATH
|
||||
#elif defined __linux__
|
||||
# include <limits.h>
|
||||
# define _TINYDIR_PATH_MAX PATH_MAX
|
||||
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
# include <sys/param.h>
|
||||
# if defined(BSD)
|
||||
# include <limits.h>
|
||||
# define _TINYDIR_PATH_MAX PATH_MAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _TINYDIR_PATH_MAX
|
||||
#define _TINYDIR_PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* extra chars for the "\\*" mask */
|
||||
# define _TINYDIR_PATH_EXTRA 2
|
||||
#else
|
||||
# define _TINYDIR_PATH_EXTRA 0
|
||||
#endif
|
||||
|
||||
#define _TINYDIR_FILENAME_MAX 256
|
||||
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
#define _TINYDIR_DRIVE_MAX 3
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define _TINYDIR_FUNC static __inline
|
||||
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||
# define _TINYDIR_FUNC static __inline__
|
||||
#else
|
||||
# define _TINYDIR_FUNC static inline
|
||||
#endif
|
||||
|
||||
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
|
||||
#ifdef TINYDIR_USE_READDIR_R
|
||||
|
||||
/* readdir_r is a POSIX-only function, and may not be available under various
|
||||
* environments/settings, e.g. MinGW. Use readdir fallback */
|
||||
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
|
||||
_POSIX_SOURCE
|
||||
# define _TINYDIR_HAS_READDIR_R
|
||||
#endif
|
||||
#if _POSIX_C_SOURCE >= 200112L
|
||||
# define _TINYDIR_HAS_FPATHCONF
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#if _BSD_SOURCE || _SVID_SOURCE || \
|
||||
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
|
||||
# define _TINYDIR_HAS_DIRFD
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
|
||||
defined _PC_NAME_MAX
|
||||
# define _TINYDIR_USE_FPATHCONF
|
||||
#endif
|
||||
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
|
||||
!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
|
||||
# define _TINYDIR_USE_READDIR
|
||||
#endif
|
||||
|
||||
/* Use readdir by default */
|
||||
#else
|
||||
# define _TINYDIR_USE_READDIR
|
||||
#endif
|
||||
|
||||
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
|
||||
#ifndef _MSC_VER
|
||||
#if (defined __MINGW32__) && (defined _UNICODE)
|
||||
#define _TINYDIR_DIR _WDIR
|
||||
#define _tinydir_dirent _wdirent
|
||||
#define _tinydir_opendir _wopendir
|
||||
#define _tinydir_readdir _wreaddir
|
||||
#define _tinydir_closedir _wclosedir
|
||||
#else
|
||||
#define _TINYDIR_DIR DIR
|
||||
#define _tinydir_dirent dirent
|
||||
#define _tinydir_opendir opendir
|
||||
#define _tinydir_readdir readdir
|
||||
#define _tinydir_closedir closedir
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
|
||||
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
|
||||
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
|
||||
#else
|
||||
#error "Either define both alloc and free or none of them!"
|
||||
#endif
|
||||
|
||||
#if !defined(_TINYDIR_MALLOC)
|
||||
#define _TINYDIR_MALLOC(_size) malloc(_size)
|
||||
#define _TINYDIR_FREE(_ptr) free(_ptr)
|
||||
#endif /* !defined(_TINYDIR_MALLOC) */
|
||||
|
||||
typedef struct tinydir_file
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
|
||||
_tinydir_char_t *extension;
|
||||
int is_dir;
|
||||
int is_reg;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifdef __MINGW32__
|
||||
struct _stat _s;
|
||||
#else
|
||||
struct stat _s;
|
||||
#endif
|
||||
#endif
|
||||
} tinydir_file;
|
||||
|
||||
typedef struct tinydir_dir
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
int has_next;
|
||||
size_t n_files;
|
||||
|
||||
tinydir_file *_files;
|
||||
#ifdef _MSC_VER
|
||||
HANDLE _h;
|
||||
WIN32_FIND_DATA _f;
|
||||
#else
|
||||
_TINYDIR_DIR *_d;
|
||||
struct _tinydir_dirent *_e;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
struct _tinydir_dirent *_ep;
|
||||
#endif
|
||||
#endif
|
||||
} tinydir_dir;
|
||||
|
||||
|
||||
/* declarations */
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
void tinydir_close(tinydir_dir *dir);
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_next(tinydir_dir *dir);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
void _tinydir_get_ext(tinydir_file *file);
|
||||
_TINYDIR_FUNC
|
||||
int _tinydir_file_cmp(const void *a, const void *b);
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
_TINYDIR_FUNC
|
||||
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* definitions*/
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
int error;
|
||||
int size; /* using int size */
|
||||
#endif
|
||||
#else
|
||||
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
|
||||
#endif
|
||||
_tinydir_char_t *pathp;
|
||||
|
||||
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* initialise dir */
|
||||
dir->_files = NULL;
|
||||
#ifdef _MSC_VER
|
||||
dir->_h = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
dir->_d = NULL;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
dir->_ep = NULL;
|
||||
#endif
|
||||
#endif
|
||||
tinydir_close(dir);
|
||||
|
||||
_tinydir_strcpy(dir->path, path);
|
||||
/* Remove trailing slashes */
|
||||
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
|
||||
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
|
||||
{
|
||||
*pathp = TINYDIR_STRING('\0');
|
||||
pathp++;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
_tinydir_strcpy(path_buf, dir->path);
|
||||
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
|
||||
#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
|
||||
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
|
||||
#else
|
||||
dir->_h = FindFirstFile(path_buf, &dir->_f);
|
||||
#endif
|
||||
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = ENOENT;
|
||||
#else
|
||||
dir->_d = _tinydir_opendir(path);
|
||||
if (dir->_d == NULL)
|
||||
{
|
||||
#endif
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* read first file */
|
||||
dir->has_next = 1;
|
||||
#ifndef _MSC_VER
|
||||
#ifdef _TINYDIR_USE_READDIR
|
||||
dir->_e = _tinydir_readdir(dir->_d);
|
||||
#else
|
||||
/* allocate dirent buffer for readdir_r */
|
||||
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
|
||||
if (size == -1) return -1;
|
||||
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
|
||||
if (dir->_ep == NULL) return -1;
|
||||
|
||||
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
|
||||
if (error != 0) return -1;
|
||||
#endif
|
||||
if (dir->_e == NULL)
|
||||
{
|
||||
dir->has_next = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
tinydir_close(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||
{
|
||||
/* Count the number of files first, to pre-allocate the files array */
|
||||
size_t n_files = 0;
|
||||
if (tinydir_open(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
while (dir->has_next)
|
||||
{
|
||||
n_files++;
|
||||
if (tinydir_next(dir) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
tinydir_close(dir);
|
||||
|
||||
if (tinydir_open(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir->n_files = 0;
|
||||
dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
|
||||
if (dir->_files == NULL)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
while (dir->has_next)
|
||||
{
|
||||
tinydir_file *p_file;
|
||||
dir->n_files++;
|
||||
|
||||
p_file = &dir->_files[dir->n_files - 1];
|
||||
if (tinydir_readfile(dir, p_file) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (tinydir_next(dir) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Just in case the number of files has changed between the first and
|
||||
second reads, terminate without writing into unallocated memory */
|
||||
if (dir->n_files == n_files)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
tinydir_close(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
void tinydir_close(tinydir_dir *dir)
|
||||
{
|
||||
if (dir == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(dir->path, 0, sizeof(dir->path));
|
||||
dir->has_next = 0;
|
||||
dir->n_files = 0;
|
||||
_TINYDIR_FREE(dir->_files);
|
||||
dir->_files = NULL;
|
||||
#ifdef _MSC_VER
|
||||
if (dir->_h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(dir->_h);
|
||||
}
|
||||
dir->_h = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
if (dir->_d)
|
||||
{
|
||||
_tinydir_closedir(dir->_d);
|
||||
}
|
||||
dir->_d = NULL;
|
||||
dir->_e = NULL;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
_TINYDIR_FREE(dir->_ep);
|
||||
dir->_ep = NULL;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_next(tinydir_dir *dir)
|
||||
{
|
||||
if (dir == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!dir->has_next)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
if (FindNextFile(dir->_h, &dir->_f) == 0)
|
||||
#else
|
||||
#ifdef _TINYDIR_USE_READDIR
|
||||
dir->_e = _tinydir_readdir(dir->_d);
|
||||
#else
|
||||
if (dir->_ep == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if (dir->_e == NULL)
|
||||
#endif
|
||||
{
|
||||
dir->has_next = 0;
|
||||
#ifdef _MSC_VER
|
||||
if (GetLastError() != ERROR_SUCCESS &&
|
||||
GetLastError() != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
tinydir_close(dir);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
|
||||
{
|
||||
if (dir == NULL || file == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||
#else
|
||||
if (dir->_e == NULL)
|
||||
#endif
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(dir->path) +
|
||||
_tinydir_strlen(
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
) + 1 + _TINYDIR_PATH_EXTRA >=
|
||||
_TINYDIR_PATH_MAX)
|
||||
{
|
||||
/* the path for the file will be too long */
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
) >= _TINYDIR_FILENAME_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_tinydir_strcpy(file->path, dir->path);
|
||||
_tinydir_strcat(file->path, TINYDIR_STRING("/"));
|
||||
_tinydir_strcpy(file->name,
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
);
|
||||
_tinydir_strcat(file->path, file->name);
|
||||
#ifndef _MSC_VER
|
||||
#ifdef __MINGW32__
|
||||
if (_tstat(
|
||||
#else
|
||||
if (stat(
|
||||
#endif
|
||||
file->path, &file->_s) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
_tinydir_get_ext(file);
|
||||
|
||||
file->is_dir =
|
||||
#ifdef _MSC_VER
|
||||
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
S_ISDIR(file->_s.st_mode);
|
||||
#endif
|
||||
file->is_reg =
|
||||
#ifdef _MSC_VER
|
||||
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
|
||||
(
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
|
||||
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
|
||||
#endif
|
||||
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
|
||||
#endif
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
|
||||
#else
|
||||
S_ISREG(file->_s.st_mode);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
|
||||
{
|
||||
if (dir == NULL || file == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (i >= dir->n_files)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
|
||||
_tinydir_get_ext(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
if (dir == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (i >= dir->n_files || !dir->_files[i].is_dir)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_tinydir_strcpy(path, dir->_files[i].path);
|
||||
tinydir_close(dir);
|
||||
if (tinydir_open_sorted(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open a single file given its path */
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
|
||||
{
|
||||
tinydir_dir dir;
|
||||
int result = 0;
|
||||
int found = 0;
|
||||
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
|
||||
_tinydir_char_t *dir_name;
|
||||
_tinydir_char_t *base_name;
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
|
||||
#endif
|
||||
|
||||
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the parent path */
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
|
||||
_tsplitpath_s(
|
||||
path,
|
||||
drive_buf, _TINYDIR_DRIVE_MAX,
|
||||
dir_name_buf, _TINYDIR_FILENAME_MAX,
|
||||
file_name_buf, _TINYDIR_FILENAME_MAX,
|
||||
ext_buf, _TINYDIR_FILENAME_MAX);
|
||||
#else
|
||||
_tsplitpath(
|
||||
path,
|
||||
drive_buf,
|
||||
dir_name_buf,
|
||||
file_name_buf,
|
||||
ext_buf);
|
||||
#endif
|
||||
|
||||
/* _splitpath_s not work fine with only filename and widechar support */
|
||||
#ifdef _UNICODE
|
||||
if (drive_buf[0] == L'\xFEFE')
|
||||
drive_buf[0] = '\0';
|
||||
if (dir_name_buf[0] == L'\xFEFE')
|
||||
dir_name_buf[0] = '\0';
|
||||
#endif
|
||||
|
||||
if (errno)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Emulate the behavior of dirname by returning "." for dir name if it's
|
||||
empty */
|
||||
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
|
||||
{
|
||||
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
|
||||
}
|
||||
/* Concatenate the drive letter and dir name to form full dir name */
|
||||
_tinydir_strcat(drive_buf, dir_name_buf);
|
||||
dir_name = drive_buf;
|
||||
/* Concatenate the file name and extension to form base name */
|
||||
_tinydir_strcat(file_name_buf, ext_buf);
|
||||
base_name = file_name_buf;
|
||||
#else
|
||||
_tinydir_strcpy(dir_name_buf, path);
|
||||
dir_name = dirname(dir_name_buf);
|
||||
_tinydir_strcpy(file_name_buf, path);
|
||||
base_name =basename(file_name_buf);
|
||||
#endif
|
||||
|
||||
/* Open the parent directory */
|
||||
if (tinydir_open(&dir, dir_name) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read through the parent directory and look for the file */
|
||||
while (dir.has_next)
|
||||
{
|
||||
if (tinydir_readfile(&dir, file) == -1)
|
||||
{
|
||||
result = -1;
|
||||
goto bail;
|
||||
}
|
||||
if (_tinydir_strcmp(file->name, base_name) == 0)
|
||||
{
|
||||
/* File found */
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
tinydir_next(&dir);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
result = -1;
|
||||
errno = ENOENT;
|
||||
}
|
||||
|
||||
bail:
|
||||
tinydir_close(&dir);
|
||||
return result;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
void _tinydir_get_ext(tinydir_file *file)
|
||||
{
|
||||
_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
|
||||
if (period == NULL)
|
||||
{
|
||||
file->extension = &(file->name[_tinydir_strlen(file->name)]);
|
||||
}
|
||||
else
|
||||
{
|
||||
file->extension = period + 1;
|
||||
}
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int _tinydir_file_cmp(const void *a, const void *b)
|
||||
{
|
||||
const tinydir_file *fa = (const tinydir_file *)a;
|
||||
const tinydir_file *fb = (const tinydir_file *)b;
|
||||
if (fa->is_dir != fb->is_dir)
|
||||
{
|
||||
return -(fa->is_dir - fb->is_dir);
|
||||
}
|
||||
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
/*
|
||||
The following authored by Ben Hutchings <ben@decadent.org.uk>
|
||||
from https://womble.decadent.org.uk/readdir_r-advisory.html
|
||||
*/
|
||||
/* Calculate the required buffer size (in bytes) for directory *
|
||||
* entries read from the given directory handle. Return -1 if this *
|
||||
* this cannot be done. *
|
||||
* *
|
||||
* This code does not trust values of NAME_MAX that are less than *
|
||||
* 255, since some systems (including at least HP-UX) incorrectly *
|
||||
* define it to be a smaller value. */
|
||||
_TINYDIR_FUNC
|
||||
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
|
||||
{
|
||||
long name_max;
|
||||
size_t name_end;
|
||||
/* parameter may be unused */
|
||||
(void)dirp;
|
||||
|
||||
#if defined _TINYDIR_USE_FPATHCONF
|
||||
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
|
||||
if (name_max == -1)
|
||||
#if defined(NAME_MAX)
|
||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||
#else
|
||||
return (size_t)(-1);
|
||||
#endif
|
||||
#elif defined(NAME_MAX)
|
||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||
#else
|
||||
#error "buffer size for readdir_r cannot be determined"
|
||||
#endif
|
||||
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
|
||||
return (name_end > sizeof(struct _tinydir_dirent) ?
|
||||
name_end : sizeof(struct _tinydir_dirent));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
# if defined (_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
Executable → Regular
+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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2008 by Kevin B. Kenny.
|
||||
.\" Copyright (c) 2018 by Nathan Coulter.
|
||||
.\" Copyright (c) 2018 by Nathan Coulter.
|
||||
.\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
|
||||
+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:
|
||||
|
||||
+36
-71
@@ -1,6 +1,7 @@
|
||||
'\"
|
||||
'\" Copyright (c) 1997 by Sun Microsystems, Inc.
|
||||
'\" Contributions from Don Porter, NIST, 2004. (not subject to US copyright)
|
||||
'\" Copyright (c) 2018 Nathan Coulter.
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
@@ -9,7 +10,9 @@
|
||||
.so man.macros
|
||||
.BS
|
||||
.SH NAME
|
||||
Tcl_SaveInterpState, Tcl_RestoreInterpState, Tcl_DiscardInterpState, Tcl_SaveResult, Tcl_RestoreResult, Tcl_DiscardResult \- save and restore an interpreter's state
|
||||
Tcl_SaveInterpState, Tcl_RestoreInterpState, Tcl_DiscardInterpState,
|
||||
Tcl_SaveResult, Tcl_RestoreResult, Tcl_DiscardResult \- Save and restore the
|
||||
state of an an interpreter.
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fB#include <tcl.h>\fR
|
||||
@@ -30,91 +33,53 @@ int
|
||||
.SH ARGUMENTS
|
||||
.AS Tcl_InterpState savedPtr
|
||||
.AP Tcl_Interp *interp in
|
||||
Interpreter for which state should be saved.
|
||||
The interpreter for the operation.
|
||||
.AP int status in
|
||||
Return code value to save as part of interpreter state.
|
||||
The return code for the state.
|
||||
.AP Tcl_InterpState state in
|
||||
Saved state token to be restored or discarded.
|
||||
A token for saved state.
|
||||
.AP Tcl_SavedResult *savedPtr in
|
||||
Pointer to location where interpreter result should be saved or restored.
|
||||
A pointer to storage for saved state.
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
These routines allows a C procedure to take a snapshot of the current
|
||||
state of an interpreter so that it can be restored after a call
|
||||
to \fBTcl_Eval\fR or some other routine that modifies the interpreter
|
||||
state. There are two triplets of routines meant to work together.
|
||||
These routines save the state of an interpreter before a call to a routine such
|
||||
as \fBTcl_Eval\fR, and restore the state afterwards.
|
||||
.PP
|
||||
The first triplet stores the snapshot of interpreter state in
|
||||
an opaque token returned by \fBTcl_SaveInterpState\fR. That token
|
||||
value may then be passed back to one of \fBTcl_RestoreInterpState\fR
|
||||
or \fBTcl_DiscardInterpState\fR, depending on whether the interp
|
||||
state is to be restored. So long as one of the latter two routines
|
||||
is called, Tcl will take care of memory management.
|
||||
\fBTcl_SaveInterpState\fR saves the parts of \fIinterp\fR that comprise the
|
||||
result of a script, including the resulting value, the return code passed as
|
||||
\fIstatus\fR, and any options such as \fB\-errorinfo\fR and \fB\-errorcode\fR.
|
||||
It returns a token for the saved state. The interpreter result is not reset
|
||||
and no interpreter state is changed.
|
||||
.PP
|
||||
The second triplet stores the snapshot of only the interpreter
|
||||
result (not its complete state) in memory allocated by the caller.
|
||||
These routines are passed a pointer to \fBTcl_SavedResult\fR
|
||||
that is used to store enough information to restore the interpreter result.
|
||||
\fBTcl_SavedResult\fR can be allocated on the stack of the calling
|
||||
procedure. These routines do not save the state of any error
|
||||
information in the interpreter (e.g. the \fB\-errorcode\fR or
|
||||
\fB\-errorinfo\fR return options, when an error is in progress).
|
||||
\fBTcl_RestoreInterpState\fR restores the state indicated by \fIstate\fR and
|
||||
returns the \fIstatus\fR originally passed in the corresponding call to
|
||||
\fBTcl_SaveInterpState\fR.
|
||||
.PP
|
||||
Because the routines \fBTcl_SaveInterpState\fR,
|
||||
\fBTcl_RestoreInterpState\fR, and \fBTcl_DiscardInterpState\fR perform
|
||||
a superset of the functions provided by the other routines,
|
||||
any new code should only make use of the more powerful routines.
|
||||
The older, weaker routines \fBTcl_SaveResult\fR, \fBTcl_RestoreResult\fR,
|
||||
and \fBTcl_DiscardResult\fR continue to exist only for the sake
|
||||
of existing programs that may already be using them.
|
||||
If a saved state is not restored, \fBTcl_DiscardInterpState\fR must be called
|
||||
to release it. A token used to discard or restore state must not be used
|
||||
again.
|
||||
.PP
|
||||
\fBTcl_SaveInterpState\fR takes a snapshot of those portions of
|
||||
interpreter state that make up the full result of script evaluation.
|
||||
This include the interpreter result, the return code (passed in
|
||||
as the \fIstatus\fR argument, and any return options, including
|
||||
\fB\-errorinfo\fR and \fB\-errorcode\fR when an error is in progress.
|
||||
This snapshot is returned as an opaque token of type \fBTcl_InterpState\fR.
|
||||
The call to \fBTcl_SaveInterpState\fR does not itself change the
|
||||
state of the interpreter. Unlike \fBTcl_SaveResult\fR, it does
|
||||
not reset the interpreter.
|
||||
\fBTcl_SaveResult\fR, \fBTcl_RestoreResult\fR, and \fBTcl_DiscardResult\fR are
|
||||
deprecated. Instead use \fBTcl_SaveInterpState\fR,
|
||||
\fBTcl_RestoreInterpState\fR, and \fBTcl_DiscardInterpState\fR, which are more
|
||||
capable.
|
||||
.PP
|
||||
\fBTcl_RestoreInterpState\fR accepts a \fBTcl_InterpState\fR token
|
||||
previously returned by \fBTcl_SaveInterpState\fR and restores the
|
||||
state of the interp to the state held in that snapshot. The return
|
||||
value of \fBTcl_RestoreInterpState\fR is the status value originally
|
||||
passed to \fBTcl_SaveInterpState\fR when the snapshot token was
|
||||
created.
|
||||
\fBTcl_SaveResult\fR moves the result of \fIinterp\fR to the location
|
||||
\fIstatePtr\fR points to and returns the interpreter result to its initial
|
||||
state. It does not save options such as \fB\-errorcode\fR or
|
||||
\fB\-errorinfo\fR.
|
||||
.PP
|
||||
\fBTcl_DiscardInterpState\fR is called to release a \fBTcl_InterpState\fR
|
||||
token previously returned by \fBTcl_SaveInterpState\fR when that
|
||||
snapshot is not to be restored to an interp.
|
||||
.PP
|
||||
The \fBTcl_InterpState\fR token returned by \fBTcl_SaveInterpState\fR
|
||||
must eventually be passed to either \fBTcl_RestoreInterpState\fR
|
||||
or \fBTcl_DiscardInterpState\fR to avoid a memory leak. Once
|
||||
the \fBTcl_InterpState\fR token is passed to one of them, the
|
||||
token is no longer valid and should not be used anymore.
|
||||
.PP
|
||||
\fBTcl_SaveResult\fR moves the string and value results
|
||||
of \fIinterp\fR into the location specified by \fIstatePtr\fR.
|
||||
\fBTcl_SaveResult\fR clears the result for \fIinterp\fR and
|
||||
leaves the result in its normal empty initialized state.
|
||||
.PP
|
||||
\fBTcl_RestoreResult\fR moves the string and value results from
|
||||
\fIstatePtr\fR back into \fIinterp\fR. Any result or error that was
|
||||
already in the interpreter will be cleared. The \fIstatePtr\fR is left
|
||||
in an uninitialized state and cannot be used until another call to
|
||||
\fBTcl_RestoreResult\fR clears any existing result or error in \fIinterp\fR and
|
||||
moves the result from \fIstatePtr\fR back to \fIinterp\fR. \fIstatePtr\fR is
|
||||
then in an undefined state and must not be used until passed again to
|
||||
\fBTcl_SaveResult\fR.
|
||||
.PP
|
||||
\fBTcl_DiscardResult\fR releases the saved interpreter state
|
||||
stored at \fBstatePtr\fR. The state structure is left in an
|
||||
uninitialized state and cannot be used until another call to
|
||||
\fBTcl_DiscardResult\fR releases the state stored at \fBstatePtr\fR, which is
|
||||
then in an undefined state and must not be used until passed again to
|
||||
\fBTcl_SaveResult\fR.
|
||||
.PP
|
||||
Once \fBTcl_SaveResult\fR is called to save the interpreter
|
||||
result, either \fBTcl_RestoreResult\fR or
|
||||
\fBTcl_DiscardResult\fR must be called to properly clean up the
|
||||
memory associated with the saved state.
|
||||
If a saved result is not restored, \fBTcl_DiscardResult\fR must be called to
|
||||
release it.
|
||||
.SH KEYWORDS
|
||||
result, state, interp
|
||||
|
||||
@@ -121,8 +121,8 @@ case-insensitive (1).
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
These routines convert between UTF-8 strings and Tcl_UniChars. A
|
||||
Tcl_UniChar is a Unicode character represented as an unsigned, fixed-size
|
||||
These routines convert between UTF-8 strings and Unicode characters. An
|
||||
Unicode character represented as an unsigned, fixed-size
|
||||
quantity. A UTF-8 character is a Unicode character represented as
|
||||
a varying-length sequence of up to \fBTCL_UTF_MAX\fR bytes. A multibyte UTF-8
|
||||
sequence consists of a lead byte followed by some number of trail bytes.
|
||||
@@ -130,9 +130,12 @@ sequence consists of a lead byte followed by some number of trail bytes.
|
||||
\fBTCL_UTF_MAX\fR is the maximum number of bytes that it takes to
|
||||
represent one Unicode character in the UTF-8 representation.
|
||||
.PP
|
||||
\fBTcl_UniCharToUtf\fR stores the Tcl_UniChar \fIch\fR as a UTF-8 string
|
||||
\fBTcl_UniCharToUtf\fR stores the character \fIch\fR as a UTF-8 string
|
||||
in starting at \fIbuf\fR. The return value is the number of bytes stored
|
||||
in \fIbuf\fR.
|
||||
in \fIbuf\fR. If ch is an upper surrogate (range U+D800 - U+DBFF), then
|
||||
the return value will be 0 and nothing will be stored. If you still
|
||||
want to produce UTF-8 output for it (even though knowing it's an illegal
|
||||
code-point on its own), just call \fBTcl_UniCharToUtf\fR again using ch = -1.
|
||||
.PP
|
||||
\fBTcl_UtfToUniChar\fR reads one UTF-8 character starting at \fIsrc\fR
|
||||
and stores it as a Tcl_UniChar in \fI*chPtr\fR. The return value is the
|
||||
@@ -203,7 +206,7 @@ of \fIlength\fR bytes is long enough to be decoded by
|
||||
\fBTcl_UtfToUniChar\fR, or 0 otherwise. This function does not guarantee
|
||||
that the UTF-8 string is properly formed. This routine is used by
|
||||
procedures that are operating on a byte at a time and need to know if a
|
||||
full Tcl_UniChar has been seen.
|
||||
full Unicode character has been seen.
|
||||
.PP
|
||||
\fBTcl_NumUtfChars\fR corresponds to \fBstrlen\fR for UTF-8 strings. It
|
||||
returns the number of Tcl_UniChars that are represented by the UTF-8 string
|
||||
@@ -211,12 +214,12 @@ returns the number of Tcl_UniChars that are represented by the UTF-8 string
|
||||
length is negative, all bytes up to the first null byte are used.
|
||||
.PP
|
||||
\fBTcl_UtfFindFirst\fR corresponds to \fBstrchr\fR for UTF-8 strings. It
|
||||
returns a pointer to the first occurrence of the Tcl_UniChar \fIch\fR
|
||||
returns a pointer to the first occurrence of the Unicode character \fIch\fR
|
||||
in the null-terminated UTF-8 string \fIsrc\fR. The null terminator is
|
||||
considered part of the UTF-8 string.
|
||||
.PP
|
||||
\fBTcl_UtfFindLast\fR corresponds to \fBstrrchr\fR for UTF-8 strings. It
|
||||
returns a pointer to the last occurrence of the Tcl_UniChar \fIch\fR
|
||||
returns a pointer to the last occurrence of the Unicode character \fIch\fR
|
||||
in the null-terminated UTF-8 string \fIsrc\fR. The null terminator is
|
||||
considered part of the UTF-8 string.
|
||||
.PP
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2018 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH abstract n 0.3 TclOO "TclOO Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
oo::abstract \- a class that does not allow direct instances of itself
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBoo::abstract\fI method \fR?\fIarg ...\fR?
|
||||
.fi
|
||||
.SH "CLASS HIERARCHY"
|
||||
.nf
|
||||
\fBoo::object\fR
|
||||
\(-> \fBoo::class\fR
|
||||
\(-> \fBoo::abstract\fR
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
Abstract classes are classes that can contain definitions, but which cannot be
|
||||
directly manufactured; they are intended to only ever be inherited from and
|
||||
instantiated indirectly. The characteristic methods of \fBoo::class\fR
|
||||
(\fBcreate\fR and \fBnew\fR) are not exported by an instance of
|
||||
\fBoo::abstract\fR.
|
||||
.PP
|
||||
Note that \fBoo::abstract\fR is not itself an instance of \fBoo::abstract\fR.
|
||||
.SS CONSTRUCTOR
|
||||
The \fBoo::abstract\fR class does not define an explicit constructor; this
|
||||
means that it is effectively the same as the constructor of the
|
||||
\fBoo::class\fR class.
|
||||
.SS DESTRUCTOR
|
||||
The \fBoo::abstract\fR class does not define an explicit destructor;
|
||||
destroying an instance of it is just like destroying an ordinary class (and
|
||||
will destroy all its subclasses).
|
||||
.SS "EXPORTED METHODS"
|
||||
The \fBoo::abstract\fR class defines no new exported methods.
|
||||
.SS "NON-EXPORTED METHODS"
|
||||
The \fBoo::abstract\fR class explicitly states that \fBcreate\fR,
|
||||
\fBcreateWithNamespace\fR, and \fBnew\fR are unexported.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
This example defines a simple class hierarchy and creates a new instance of
|
||||
it. It then invokes a method of the object before destroying the hierarchy and
|
||||
showing that the destruction is transitive.
|
||||
.PP
|
||||
.CS
|
||||
\fBoo::abstract\fR create fruit {
|
||||
method eat {} {
|
||||
puts "yummy!"
|
||||
}
|
||||
}
|
||||
oo::class create banana {
|
||||
superclass fruit
|
||||
method peel {} {
|
||||
puts "skin now off"
|
||||
}
|
||||
}
|
||||
set b [banana \fBnew\fR]
|
||||
$b peel \fI\(-> prints 'skin now off'\fR
|
||||
$b eat \fI\(-> prints 'yummy!'\fR
|
||||
set f [fruit new] \fI\(-> error 'unknown method "new"...'\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
oo::define(n), oo::object(n)
|
||||
.SH KEYWORDS
|
||||
abstract class, class, metaclass, object
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
@@ -0,0 +1,88 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2018 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH callback n 0.3 TclOO "TclOO Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
callback, mymethod \- generate callbacks to methods
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBcallback\fR \fImethodName\fR ?\fIarg ...\fR?
|
||||
\fBmymethod\fR \fImethodName\fR ?\fIarg ...\fR?
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
The \fBcallback\fR command,
|
||||
'\" Based on notes in the tcllib docs, we know the provenance of mymethod
|
||||
also called \fBmymethod\fR for compatibility with the ooutil and snit packages
|
||||
of Tcllib,
|
||||
and which should only be used from within the context of a call to a method
|
||||
(i.e. inside a method, constructor or destructor body) is used to generate a
|
||||
script fragment that will invoke the method, \fImethodName\fR, on the current
|
||||
object (as reported by \fBself\fR) when executed. Any additional arguments
|
||||
provided will be provided as leading arguments to the callback. The resulting
|
||||
script fragment shall be a proper list.
|
||||
.PP
|
||||
Note that it is up to the caller to ensure that the current object is able to
|
||||
handle the call of \fImethodName\fR; this command does not check that.
|
||||
\fImethodName\fR may refer to any exported or unexported method, but may not
|
||||
refer to a private method as those can only be invoked directly from within
|
||||
methods. If there is no such method present at the point when the callback is
|
||||
invoked, the standard \fBunknown\fR method handler will be called.
|
||||
.SH EXAMPLE
|
||||
This is a simple echo server class. The \fBcallback\fR command is used in two
|
||||
places, to arrange for the incoming socket connections to be handled by the
|
||||
\fIAccept\fR method, and to arrange for the incoming bytes on those
|
||||
connections to be handled by the \fIReceive\fR method.
|
||||
.PP
|
||||
.CS
|
||||
oo::class create EchoServer {
|
||||
variable server clients
|
||||
constructor {port} {
|
||||
set server [socket -server [\fBcallback\fR Accept] $port]
|
||||
set clients {}
|
||||
}
|
||||
destructor {
|
||||
chan close $server
|
||||
foreach client [dict keys $clients] {
|
||||
chan close $client
|
||||
}
|
||||
}
|
||||
|
||||
method Accept {channel clientAddress clientPort} {
|
||||
dict set clients $channel [dict create \e
|
||||
address $clientAddress port $clientPort]
|
||||
chan event $channel readable [\fBcallback\fR Receive $channel]
|
||||
}
|
||||
method Receive {channel} {
|
||||
if {[chan gets $channel line] >= 0} {
|
||||
my echo $channel $line
|
||||
} else {
|
||||
chan close $channel
|
||||
dict unset clients $channel
|
||||
}
|
||||
}
|
||||
|
||||
method echo {channel line} {
|
||||
dict with clients $channel {
|
||||
chan puts $channel \e
|
||||
[format {[%s:%d] %s} $address $port $line]
|
||||
}
|
||||
}
|
||||
}
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
chan(n), fileevent(n), my(n), self(n), socket(n), trace(n)
|
||||
.SH KEYWORDS
|
||||
callback, object
|
||||
.\" Local Variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
@@ -0,0 +1,78 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2011-2015 Andreas Kupries
|
||||
'\" Copyright (c) 2018 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH classvariable n 0.3 TclOO "TclOO Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
classvariable \- create link from local variable to variable in class
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBclassvariable\fR \fIvariableName\fR ?\fI...\fR?
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
The \fBclassvariable\fR command is available within methods. It takes a series
|
||||
of one or more variable names and makes them available in the method's scope;
|
||||
those variable names must not be qualified and must not refer to array
|
||||
elements. The originating scope for the variables is the namespace of the
|
||||
class that the method was defined by. In other words, the referenced variables
|
||||
are shared between all instances of that class.
|
||||
.PP
|
||||
Note: This command is equivalent to the command \fBtypevariable\fR provided by
|
||||
the snit package in tcllib for approximately the same purpose. If used in a
|
||||
method defined directly on a class instance (e.g., through the
|
||||
\fBoo::objdefine\fR \fBmethod\fR definition) this is very much like just
|
||||
using:
|
||||
.PP
|
||||
.CS
|
||||
namespace upvar [namespace current] $var $var
|
||||
.CE
|
||||
.PP
|
||||
for each variable listed to \fBclassvariable\fR.
|
||||
.SH EXAMPLE
|
||||
This class counts how many instances of it have been made.
|
||||
.PP
|
||||
.CS
|
||||
oo::class create Counted {
|
||||
initialise {
|
||||
variable count 0
|
||||
}
|
||||
|
||||
variable number
|
||||
constructor {} {
|
||||
\fBclassvariable\fR count
|
||||
set number [incr count]
|
||||
}
|
||||
|
||||
method report {} {
|
||||
\fBclassvariable\fR count
|
||||
puts "This is instance $number of $count"
|
||||
}
|
||||
}
|
||||
|
||||
set a [Counted new]
|
||||
set b [Counted new]
|
||||
$a report
|
||||
\fI\(-> This is instance 1 of 2\fR
|
||||
set c [Counted new]
|
||||
$b report
|
||||
\fI\(-> This is instance 2 of 3\fR
|
||||
$c report
|
||||
\fI\(-> This is instance 3 of 3\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
global(n), namespace(n), oo::class(n), oo::define(n), upvar(n), variable(n)
|
||||
.SH KEYWORDS
|
||||
class, class variable, variable
|
||||
.\" Local Variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
+13
@@ -452,6 +452,19 @@ If this situation occurs, the first occurrence of the time is chosen.
|
||||
(For this reason, it is wise to have the input string contain the
|
||||
time zone when converting local times. This caveat does not apply to
|
||||
UTC times.)
|
||||
.PP
|
||||
If the interpretation of the groups yields an impossible time because
|
||||
a field is out of range, enough of that field's unit will be added to
|
||||
or subtracted from the time to bring it in range. Thus, if attempting to
|
||||
scan or format day 0 of the month, one day will be subtracted from day
|
||||
1 of the month, yielding the last day of the previous month.
|
||||
.PP
|
||||
If the interpretation of the groups yields an impossible time because
|
||||
a Daylight Saving Time change skips over that time, or an ambiguous
|
||||
time because a Daylight Saving Time change skips back so that the clock
|
||||
observes the given time twice, and no time zone specifier (\fB%z\fR
|
||||
or \fB%Z\fR) is present in the format, the time is interpreted as
|
||||
if the clock had not changed.
|
||||
.SH "FORMAT GROUPS"
|
||||
.PP
|
||||
The following format groups are recognized by the \fBclock scan\fR and
|
||||
|
||||
+233
-38
@@ -1,5 +1,5 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2007 Donal K. Fellows
|
||||
'\" Copyright (c) 2007-2018 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
@@ -39,6 +39,27 @@ used as the \fIdefScript\fR argument.
|
||||
The following commands are supported in the \fIdefScript\fR for
|
||||
\fBoo::define\fR, each of which may also be used in the \fIsubcommand\fR form:
|
||||
.TP
|
||||
\fBclassmethod\fI name\fR ?\fIargList bodyScrip\fR?
|
||||
.VS TIP478
|
||||
This creates a class method, or (if \fIargList\fR and \fIbodyScript\fR are
|
||||
omitted) promotes an existing method on the class object to be a class
|
||||
method. The \fIname\fR, \fIargList\fR and \fIbodyScript\fR arguments are as in
|
||||
the \fBmethod\fR definition, below.
|
||||
.RS
|
||||
.PP
|
||||
Class methods can be called on either the class itself or on the instances of
|
||||
that class. When they are called, the current object (see the \fBself\R and
|
||||
\fBmy\fR commands) is the class on which they are called or the class of the
|
||||
instance on which they are called, depending on whether they are called on the
|
||||
class or an instance of the class, respectively. If called on a subclass or
|
||||
instance of the subclass, the current object is the subclass.
|
||||
.PP
|
||||
In a private definition context, the methods as invoked on classes are
|
||||
\fInot\fR private, but the methods as invoked on instances of classes are
|
||||
private.
|
||||
.RE
|
||||
.VE TIP478
|
||||
.TP
|
||||
\fBconstructor\fI argList bodyScript\fR
|
||||
.
|
||||
This creates or updates the constructor for a class. The formal arguments to
|
||||
@@ -82,17 +103,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 +123,22 @@ 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
|
||||
\fBinitialise\fI script\fR
|
||||
.TP
|
||||
\fBinitialize\fI script\fR
|
||||
.VS TIP478
|
||||
This evaluates \fIscript\fR in a context which supports local variables and
|
||||
where the current namespace is the instance namespace of the class object
|
||||
itself. This is useful for setting up, e.g., class-scoped variables.
|
||||
.VE TIP478
|
||||
.TP
|
||||
\fBmethod\fI name argList bodyScript\fR
|
||||
.
|
||||
@@ -117,17 +151,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 +216,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 +244,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 +295,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 +313,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 +330,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 +372,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 +385,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 +428,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 +451,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 +470,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
|
||||
@@ -409,6 +526,84 @@ oo::class create B {
|
||||
inst m1 \fI\(-> prints "red brick"\fR
|
||||
inst m2 \fI\(-> prints "blue brick"\fR
|
||||
.CE
|
||||
.PP
|
||||
.VS TIP478
|
||||
This example shows how to create and use class variables. It is a class that
|
||||
counts how many instances of itself have been made.
|
||||
.PP
|
||||
.CS
|
||||
oo::class create Counted
|
||||
\fBoo::define\fR Counted {
|
||||
\fBinitialise\fR {
|
||||
variable count 0
|
||||
}
|
||||
|
||||
\fBvariable\fR number
|
||||
\fBconstructor\fR {} {
|
||||
classvariable count
|
||||
set number [incr count]
|
||||
}
|
||||
|
||||
\fBmethod\fR report {} {
|
||||
classvariable count
|
||||
puts "This is instance $number of $count"
|
||||
}
|
||||
}
|
||||
|
||||
set a [Counted new]
|
||||
set b [Counted new]
|
||||
$a report
|
||||
\fI\(-> This is instance 1 of 2\fR
|
||||
set c [Counted new]
|
||||
$b report
|
||||
\fI\(-> This is instance 2 of 3\fR
|
||||
$c report
|
||||
\fI\(-> This is instance 3 of 3\fR
|
||||
.CE
|
||||
.PP
|
||||
This example demonstrates how to use class methods. (Note that the constructor
|
||||
for \fBoo::class\fR calls \fBoo::define\fR on the class.)
|
||||
.PP
|
||||
.CS
|
||||
oo::class create DBTable {
|
||||
\fBclassmethod\fR find {description} {
|
||||
puts "DB: locate row from [self] matching $description"
|
||||
return [my new]
|
||||
}
|
||||
\fBclassmethod\fR insert {description} {
|
||||
puts "DB: create row in [self] matching $description"
|
||||
return [my new]
|
||||
}
|
||||
\fBmethod\fR update {description} {
|
||||
puts "DB: update row [self] with $description"
|
||||
}
|
||||
\fBmethod\fR delete {} {
|
||||
puts "DB: delete row [self]"
|
||||
my destroy; # Just delete the object, not the DB row
|
||||
}
|
||||
}
|
||||
|
||||
oo::class create Users {
|
||||
\fBsuperclass\fR DBTable
|
||||
}
|
||||
oo::class create Groups {
|
||||
\fBsuperclass\fR DBTable
|
||||
}
|
||||
|
||||
set u1 [Users insert "username=abc"]
|
||||
\fI\(-> DB: create row from ::Users matching username=abc\fR
|
||||
set u2 [Users insert "username=def"]
|
||||
\fI\(-> DB: create row from ::Users matching username=def\fR
|
||||
$u2 update "group=NULL"
|
||||
\fI\(-> DB: update row ::oo::Obj124 with group=NULL\fR
|
||||
$u1 delete
|
||||
\fI\(-> DB: delete row ::oo::Obj123\fR
|
||||
set g [Group find "groupname=webadmins"]
|
||||
\fI\(-> DB: locate row ::Group with groupname=webadmins\fR
|
||||
$g update "emailaddress=admins"
|
||||
\fI\(-> DB: update row ::oo::Obj125 with emailaddress=admins\fR
|
||||
.CE
|
||||
.VE TIP478
|
||||
.SH "SEE ALSO"
|
||||
next(n), oo::class(n), oo::object(n)
|
||||
.SH KEYWORDS
|
||||
|
||||
+17
@@ -217,6 +217,19 @@ information is instead sent to the console, if one is present, or is
|
||||
discarded.
|
||||
.RS
|
||||
.PP
|
||||
Note that the current escape resp. quoting of arguments for windows works only
|
||||
with executables using CommandLineToArgv, CRT-library or similar, as well as
|
||||
with the windows batch files (excepting the newline, see below).
|
||||
Although it is the common escape algorithm, but, in fact, the way how the
|
||||
executable parses the command-line (resp. splits it into single arguments)
|
||||
is decisive.
|
||||
.PP
|
||||
Unfortunately, there is currently no way to supply newline character within
|
||||
an argument to the batch files (\fB.cmd\fR or \fB.bat\fR) or to the command
|
||||
processor (\fBcmd.exe /c\fR), because this causes truncation of command-line
|
||||
(also the argument chain) on the first newline character.
|
||||
But it works properly with an executable (using CommandLineToArgv, etc).
|
||||
.PP
|
||||
The Tk console text widget does not provide real standard IO capabilities.
|
||||
Under Tk, when redirecting from standard input, all applications will see an
|
||||
immediate end-of-file; information redirected to standard output or standard
|
||||
@@ -409,6 +422,10 @@ that sometimes pop up:
|
||||
With the file \fIcmp.bat\fR looking something like:
|
||||
.PP
|
||||
.CS
|
||||
@gcc %*
|
||||
.CE
|
||||
or like another variant using single parameters:
|
||||
.CS
|
||||
@gcc %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
.CE
|
||||
.SS "WORKING WITH COMMAND BUILT-INS"
|
||||
|
||||
+178
-9
@@ -6,14 +6,14 @@
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH "http" n 2.7 http "Tcl Bundled Packages"
|
||||
.TH "http" n 2.9 http "Tcl Bundled Packages"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
http \- Client-side implementation of the HTTP/1.1 protocol
|
||||
.SH SYNOPSIS
|
||||
\fBpackage require http ?2.7?\fR
|
||||
\fBpackage require http ?2.8?\fR
|
||||
.\" See Also -useragent option documentation in body!
|
||||
.sp
|
||||
\fB::http::config ?\fI\-option value\fR ...?
|
||||
@@ -22,6 +22,9 @@ http \- Client-side implementation of the HTTP/1.1 protocol
|
||||
.sp
|
||||
\fB::http::formatQuery\fR \fIkey value\fR ?\fIkey value\fR ...?
|
||||
.sp
|
||||
\fB::http::quoteString\fR \fIvalue\fR
|
||||
.sp
|
||||
\fB::http::quoteString\fR \fIvalue\fR
|
||||
\fB::http::reset\fR \fItoken\fR ?\fIwhy\fR?
|
||||
.sp
|
||||
\fB::http::wait \fItoken\fR
|
||||
@@ -44,12 +47,14 @@ http \- Client-side implementation of the HTTP/1.1 protocol
|
||||
.sp
|
||||
\fB::http::register \fIproto port command\fR
|
||||
.sp
|
||||
\fB::http::registerError \fIport\fR ?\fImessage\fR?
|
||||
.sp
|
||||
\fB::http::unregister \fIproto\fR
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The \fBhttp\fR package provides the client side of the HTTP/1.1
|
||||
protocol, as defined in RFC 2616.
|
||||
protocol, as defined in RFC 7230 to RFC 7235, which supersede RFC 2616.
|
||||
The package implements the GET, POST, and HEAD operations
|
||||
of HTTP/1.1. It allows configuration of a proxy host to get through
|
||||
firewalls. The package is compatible with the \fBSafesock\fR security
|
||||
@@ -95,6 +100,19 @@ comma-separated list of mime type patterns that you are
|
||||
willing to receive. For example,
|
||||
.QW "image/gif, image/jpeg, text/*" .
|
||||
.TP
|
||||
\fB\-pipeline\fR \fIboolean\fR
|
||||
.
|
||||
Specifies whether HTTP/1.1 transactions on a persistent socket will be
|
||||
pipelined. See the \fBPERSISTENT SOCKETS\fR section for details. The default
|
||||
is 1.
|
||||
.TP
|
||||
\fB\-postfresh\fR \fIboolean\fR
|
||||
.
|
||||
Specifies whether requests that use the \fBPOST\fR method will always use a
|
||||
fresh socket, overriding the \fB-keepalive\fR option of
|
||||
command \fBhttp::geturl\fR. See the \fBPERSISTENT SOCKETS\fR section for details.
|
||||
The default is 0.
|
||||
.TP
|
||||
\fB\-proxyhost\fR \fIhostname\fR
|
||||
.
|
||||
The name of the proxy host, if any. If this value is the
|
||||
@@ -116,20 +134,47 @@ an empty list. The default filter returns the values of the
|
||||
\fB\-proxyhost\fR and \fB\-proxyport\fR settings if they are
|
||||
non-empty.
|
||||
.TP
|
||||
\fB\-repost\fR \fIboolean\fR
|
||||
.
|
||||
Specifies what to do if a POST request over a persistent connection fails
|
||||
because the server has half-closed the connection. If boolean \fBtrue\fR, the
|
||||
request
|
||||
will be automatically retried; if boolean \fBfalse\fR it will not, and the
|
||||
application
|
||||
that uses \fBhttp::geturl\fR is expected to seek user confirmation before
|
||||
retrying the POST. The value \fBtrue\fR should be used only under certain
|
||||
conditions. See the \fBPERSISTENT SOCKETS\fR section for details. The
|
||||
default is 0.
|
||||
.TP
|
||||
\fB\-urlencoding\fR \fIencoding\fR
|
||||
.
|
||||
The \fIencoding\fR used for creating the x-url-encoded URLs with
|
||||
\fB::http::formatQuery\fR. The default is \fButf-8\fR, as specified by RFC
|
||||
\fB::http::formatQuery\fR and \fB::http::quoteString\fR.
|
||||
The default is \fButf-8\fR, as specified by RFC
|
||||
2718. Prior to http 2.5 this was unspecified, and that behavior can be
|
||||
returned by specifying the empty string (\fB{}\fR), although
|
||||
\fIiso8859-1\fR is recommended to restore similar behavior but without the
|
||||
\fB::http::formatQuery\fR throwing an error processing non-latin-1
|
||||
characters.
|
||||
\fB::http::formatQuery\fR or \fB::http::quoteString\fR
|
||||
throwing an error processing non-latin-1 characters.
|
||||
.TP
|
||||
\fB\-useragent\fR \fIstring\fR
|
||||
.
|
||||
The value of the User-Agent header in the HTTP request. The default is
|
||||
.QW "\fBTcl http client package 2.7\fR" .
|
||||
The value of the User-Agent header in the HTTP request. In an unsafe
|
||||
interpreter, the default value depends upon the operating system, and
|
||||
the version numbers of \fBhttp\fR and \fBTcl\fR, and is (for example)
|
||||
.QW "\fBMozilla/5.0 (Windows; U; Windows NT 10.0) http/2.8.12 Tcl/8.6.8\fR" .
|
||||
A safe interpreter cannot determine its operating system, and so the default
|
||||
in a safe interpreter is to use a Windows 10 value with the current version
|
||||
numbers of \fBhttp\fR and \fBTcl\fR.
|
||||
.TP
|
||||
\fB\-zip\fR \fIboolean\fR
|
||||
.
|
||||
If the value is boolean \fBtrue\fR, then by default requests will send a header
|
||||
.QW "\fBAccept-Encoding: gzip,deflate,compress\fR" .
|
||||
If the value is boolean \fBfalse\fR, then by default this header will not be sent.
|
||||
In either case the default can be overridden for an individual request by
|
||||
supplying a custom \fBAccept-Encoding\fR header in the \fB-headers\fR option
|
||||
of \fBhttp::geturl\fR. The default is 1.
|
||||
.RE
|
||||
.TP
|
||||
\fB::http::geturl\fR \fIurl\fR ?\fIoptions\fR?
|
||||
@@ -227,7 +272,7 @@ Pragma: no-cache
|
||||
.TP
|
||||
\fB\-keepalive\fR \fIboolean\fR
|
||||
.
|
||||
If true, attempt to keep the connection open for servicing
|
||||
If boolean \fBtrue\fR, attempt to keep the connection open for servicing
|
||||
multiple requests. Default is 0.
|
||||
.TP
|
||||
\fB\-method\fR \fItype\fR
|
||||
@@ -334,6 +379,11 @@ encodes the keys and values, and generates one string that has the
|
||||
proper & and = separators. The result is suitable for the
|
||||
\fB\-query\fR value passed to \fB::http::geturl\fR.
|
||||
.TP
|
||||
\fB::http::quoteString\fR \fIvalue\fR
|
||||
.
|
||||
This procedure does x-url-encoding of string. It takes a single argument and
|
||||
encodes it.
|
||||
.TP
|
||||
\fB::http::reset\fR \fItoken\fR ?\fIwhy\fR?
|
||||
.
|
||||
This command resets the HTTP transaction identified by \fItoken\fR, if any.
|
||||
@@ -415,6 +465,17 @@ set token [::http::geturl https://my.secure.site/]
|
||||
.CE
|
||||
.RE
|
||||
.TP
|
||||
\fB::http::registerError\fR \fIport\fR ?\fImessage\fR?
|
||||
.
|
||||
This procedure allows a registered protocol handler to deliver an error
|
||||
message for use by \fBhttp\fR. Calling this command does not raise an
|
||||
error. The command is useful when a registered protocol detects an problem
|
||||
(for example, an invalid TLS certificate) that will cause an error to
|
||||
propagate to \fBhttp\fR. The command allows \fBhttp\fR to provide a
|
||||
precise error message rather than a general one. The command returns the
|
||||
value provided by the last call with argument \fImessage\fR, or the empty
|
||||
string if no such call has been made.
|
||||
.TP
|
||||
\fB::http::unregister\fR \fIproto\fR
|
||||
.
|
||||
This procedure unregisters a protocol handler that was previously
|
||||
@@ -504,6 +565,14 @@ The following elements of
|
||||
the array are supported:
|
||||
.RS
|
||||
.TP
|
||||
\fBbinary\fR
|
||||
.
|
||||
This is boolean \fBtrue\fR if (after decoding any compression specified
|
||||
by the
|
||||
.QW "Content-Encoding"
|
||||
response header) the HTTP response is binary. It is boolean \fBfalse\fR
|
||||
if the HTTP response is text.
|
||||
.TP
|
||||
\fBbody\fR
|
||||
.
|
||||
The contents of the URL. This will be empty if the \fB\-channel\fR
|
||||
@@ -602,6 +671,106 @@ A copy of the \fBContent-Type\fR meta-data value.
|
||||
.
|
||||
The requested URL.
|
||||
.RE
|
||||
.SH "PERSISTENT CONNECTIONS"
|
||||
.PP
|
||||
.SS "BASICS"
|
||||
.PP
|
||||
See RFC 7230 Sec 6, which supersedes RFC 2616 Sec 8.1.
|
||||
.PP
|
||||
A persistent connection allows multiple HTTP/1.1 transactions to be
|
||||
carried over the same TCP connection. Pipelining allows a
|
||||
client to make multiple requests over a persistent connection without
|
||||
waiting for each response. The server sends responses in the same order
|
||||
that the requests were received.
|
||||
.PP
|
||||
If a POST request fails to complete, typically user confirmation is
|
||||
needed before sending the request again. The user may wish to verify
|
||||
whether the server was modified by the failed POST request, before
|
||||
sending the same request again.
|
||||
.PP
|
||||
A HTTP request will use a persistent socket if the call to
|
||||
\fBhttp::geturl\fR has the option \fB-keepalive true\fR. It will use
|
||||
pipelining where permitted if the \fBhttp::config\fR option
|
||||
\fB-pipeline\fR is boolean \fBtrue\fR (its default value).
|
||||
.PP
|
||||
The http package maintains no more than one persistent connection to each
|
||||
server (i.e. each value of
|
||||
.QW "domain:port" ).
|
||||
If \fBhttp::geturl\fR is called to make a request over a persistent
|
||||
connection while the connection is busy with another request, the new
|
||||
request will be held in a queue until the connection is free.
|
||||
.PP
|
||||
The http package does not support HTTP/1.0 persistent connections
|
||||
controlled by the \fBKeep-Alive\fR header.
|
||||
.SS "SPECIAL CASES"
|
||||
.PP
|
||||
This subsection discusses issues related to closure of the
|
||||
persistent connection by the server, automatic retry of failed requests,
|
||||
the special treatment necessary for POST requests, and the options for
|
||||
dealing with these cases.
|
||||
.PP
|
||||
In accordance with RFC 7230, \fBhttp::geturl\fR does not pipeline
|
||||
requests that use the POST method. If a POST uses a persistent
|
||||
connection and is not the first request on that connection,
|
||||
\fBhttp::geturl\fR waits until it has received the response for the previous
|
||||
request; or (if \fBhttp::config\fR option \fB-postfresh\fR is boolean \fBtrue\fR) it
|
||||
uses a new connection for each POST.
|
||||
.PP
|
||||
If the server is processing a number of pipelined requests, and sends a
|
||||
response header
|
||||
.QW "\fBConnection: close\fR"
|
||||
with one of the responses (other than the last), then subsequent responses
|
||||
are unfulfilled. \fBhttp::geturl\fR will send the unfulfilled requests again
|
||||
over a new connection.
|
||||
.PP
|
||||
A difficulty arises when a HTTP client sends a request over a persistent
|
||||
connection that has been idle for a while. The HTTP server may
|
||||
half-close an apparently idle connection while the client is sending a
|
||||
request, but before the request arrives at the server: in this case (an
|
||||
.QW "asynchronous close event" )
|
||||
the request will fail. The difficulty arises because the client cannot
|
||||
be certain whether the POST modified the state of the server. For HEAD or
|
||||
GET requests, \fBhttp::geturl\fR opens another connection and retransmits
|
||||
the failed request. However, if the request was a POST, RFC 7230 forbids
|
||||
automatic retry by default, suggesting either user confirmation, or
|
||||
confirmation by user-agent software that has semantic understanding of
|
||||
the application. The \fBhttp::config\fR option \fB-repost\fR allows for
|
||||
either possibility.
|
||||
.PP
|
||||
Asynchronous close events can occur only in a short interval of time. The
|
||||
\fBhttp\fR package monitors each persistent connection for closure by the
|
||||
server. Upon detection, the connection is also closed at the client end,
|
||||
and subsequent requests will use a fresh connection.
|
||||
.PP
|
||||
If the \fBhttp::geturl\fR command is called with option \fB-keepalive true\fR,
|
||||
then it will both try to use an existing persistent connection
|
||||
(if one is available), and it will send the server a
|
||||
.QW "\fBConnection: keep-alive\fR"
|
||||
request header asking to keep the connection open for future requests.
|
||||
.PP
|
||||
The \fBhttp::config\fR options \fB-pipeline\fR, \fB-postfresh\fR, and
|
||||
\fB-repost\fR relate to persistent connections.
|
||||
.PP
|
||||
Option \fB-pipeline\fR, if boolean \fBtrue\fR, will pipeline GET and HEAD requests
|
||||
made
|
||||
over a persistent connection. POST requests will not be pipelined - if the
|
||||
POST is not the first transaction on the connection, its request will not
|
||||
be sent until the previous response has finished. GET and HEAD requests
|
||||
made after a POST will not be sent until the POST response has been
|
||||
delivered, and will not be sent if the POST fails.
|
||||
.PP
|
||||
Option \fB-postfresh\fR, if boolean \fBtrue\fR, will override the \fBhttp::geturl\fR option
|
||||
\fB-keepalive\fR, and always open a fresh connection for a POST request.
|
||||
.PP
|
||||
Option \fB-repost\fR, if \fBtrue\fR, permits automatic retry of a POST request
|
||||
that fails because it uses a persistent connection that the server has
|
||||
half-closed (an
|
||||
.QW "asynchronous close event" ).
|
||||
Subsequent GET and HEAD requests in a failed pipeline will also be retried.
|
||||
\fIThe -repost option should be used only if the application understands
|
||||
that the retry is appropriate\fR - specifically, the application must know
|
||||
that if the failed POST successfully modified the state of the server, a repeat POST
|
||||
would have no adverse effect.
|
||||
.SH EXAMPLE
|
||||
.PP
|
||||
This example creates a procedure to copy a URL to a file while printing a
|
||||
|
||||
+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
|
||||
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2011-2015 Andreas Kupries
|
||||
'\" Copyright (c) 2018 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH link n 0.3 TclOO "TclOO Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
link \- create link from command to method of object
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBlink\fR \fImethodName\fR ?\fI...\fR?
|
||||
\fBlink\fR \fB{\fIcommandName methodName\fB}\fR ?\fI...\fR?
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
The \fBlink\fR command is available within methods. It takes a series of one
|
||||
or more method names (\fImethodName ...\fR) and/or pairs of command- and
|
||||
method-name (\fB{\fIcommandName methodName\fB}\fR) and makes the named methods
|
||||
available as commands without requiring the explicit use of the name of the
|
||||
object or the \fBmy\fR command. The method does not need to exist at the time
|
||||
that the link is made; if the link command is invoked when the method does not
|
||||
exist, the standard \fBunknown\fR method handling system is used.
|
||||
.PP
|
||||
The command name under which the method becomes available defaults to the
|
||||
method name, except where explicitly specified through an alias/method pair.
|
||||
Formally, every argument must be a list; if the list has two elements, the
|
||||
first element is the name of the command to create and the second element is
|
||||
the name of the method of the current object to which the command links;
|
||||
otherwise, the name of the command and the name of the method are the same
|
||||
string (the first element of the list).
|
||||
.PP
|
||||
If the name of the command is not a fully-qualified command name, it will be
|
||||
resolved with respect to the current namespace (i.e., the object namespace).
|
||||
.SH EXAMPLES
|
||||
This demonstrates linking a single method in various ways. First it makes a
|
||||
simple link, then a renamed link, then an external link. Note that the method
|
||||
itself is unexported, but that it can still be called directly from outside
|
||||
the class.
|
||||
.PP
|
||||
.CS
|
||||
oo::class create ABC {
|
||||
method Foo {} {
|
||||
puts "This is Foo in [self]"
|
||||
}
|
||||
|
||||
constructor {} {
|
||||
\fBlink\fR Foo
|
||||
# The method foo is now directly accessible as foo here
|
||||
\fBlink\fR {bar Foo}
|
||||
# The method foo is now directly accessible as bar
|
||||
\fBlink\fR {::ExternalCall Foo}
|
||||
# The method foo is now directly accessible in the global
|
||||
# namespace as ExternalCall
|
||||
}
|
||||
|
||||
method grill {} {
|
||||
puts "Step 1:"
|
||||
Foo
|
||||
puts "Step 2:"
|
||||
bar
|
||||
}
|
||||
}
|
||||
|
||||
ABC create abc
|
||||
abc grill
|
||||
\fI\(-> Step 1:\fR
|
||||
\fI\(-> This is foo in ::abc\fR
|
||||
\fI\(-> Step 2:\fR
|
||||
\fI\(-> This is foo in ::abc\fR
|
||||
# Direct access via the linked command
|
||||
puts "Step 3:"; ExternalCall
|
||||
\fI\(-> Step 3:\fR
|
||||
\fI\(-> This is foo in ::abc\fR
|
||||
.CE
|
||||
.PP
|
||||
This example shows that multiple linked commands can be made in a call to
|
||||
\fBlink\fR, and that they can handle arguments.
|
||||
.PP
|
||||
.CS
|
||||
oo::class create Ex {
|
||||
constructor {} {
|
||||
\fBlink\fR a b c
|
||||
# The methods a, b, and c (defined below) are all now
|
||||
# directly acessible within methods under their own names.
|
||||
}
|
||||
|
||||
method a {} {
|
||||
puts "This is a"
|
||||
}
|
||||
method b {x} {
|
||||
puts "This is b($x)"
|
||||
}
|
||||
method c {y z} {
|
||||
puts "This is c($y,$z)"
|
||||
}
|
||||
|
||||
method call {p q r} {
|
||||
a
|
||||
b $p
|
||||
c $q $r
|
||||
}
|
||||
}
|
||||
|
||||
set o [Ex new]
|
||||
$o 3 5 7
|
||||
\fI\(-> This is a\fR
|
||||
\fI\(-> This is b(3)\fR
|
||||
\fI\(-> This is c(5,7)\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
interp(n), my(n), oo::class(n), oo::define(n)
|
||||
.SH KEYWORDS
|
||||
command, method, object
|
||||
.\" Local Variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
@@ -9,25 +9,45 @@
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
my \- invoke any method of current object
|
||||
my, myclass \- invoke any method of current object or its class
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBmy\fI methodName\fR ?\fIarg ...\fR?
|
||||
\fBmyclass\fI methodName\fR ?\fIarg ...\fR?
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The \fBmy\fR command is used to allow methods of objects to invoke any method
|
||||
of the object (or its class). In particular, the set of valid values for
|
||||
The \fBmy\fR command is used to allow methods of objects to invoke methods
|
||||
of the object (or its class),
|
||||
.VS TIP478
|
||||
and he \fBmyclass\fR command is used to allow methods of objects to invoke
|
||||
methods of the current class of the object \fIas an object\fR.
|
||||
.VE TIP478
|
||||
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
|
||||
.PP
|
||||
Each object has its own \fBmy\fR command, contained in its instance namespace.
|
||||
The object upon which the method is invoked via \fBmy\fR 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.
|
||||
.VS TIP478
|
||||
Similarly, the object on which the method is invoked via \fBmyclass\fR is the
|
||||
object that is the current class of the object that owns the namespace that
|
||||
the \fBmyclass\fR command is contained in initially. As with \fBmy\fR, the
|
||||
link remains even if the command is renamed into another namespace, and
|
||||
defaults to being the manufacturing class of the current object.
|
||||
.VE TIP478
|
||||
.PP
|
||||
Each object has its own \fBmy\fR and \fBmyclass\fR commands, contained in its
|
||||
instance namespace.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
This example shows basic use of \fBmy\fR to use the \fBvariables\fR method of
|
||||
@@ -40,16 +60,71 @@ 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. (See the \fBcallback\fR
|
||||
command for the recommended way of doing this.)
|
||||
.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
|
||||
.PP
|
||||
.VS TIP478
|
||||
This example shows how to access a private method of a class from an instance
|
||||
of that class. (See the \fBclassmethod\fR declaration in \fBoo::define\fR for
|
||||
a higher level interface for doing this.)
|
||||
.PP
|
||||
.CS
|
||||
oo::class create CountedSteps {
|
||||
self {
|
||||
variable count
|
||||
method Count {} {
|
||||
return [incr count]
|
||||
}
|
||||
}
|
||||
method advanceTwice {} {
|
||||
puts "in [self] step A: [\fBmyclass\fR Count]"
|
||||
puts "in [self] step B: [\fBmyclass\fR Count]"
|
||||
}
|
||||
}
|
||||
|
||||
CountedSteps create x
|
||||
CountedSteps create y
|
||||
x advanceTwice \fI\(-> prints "in ::x step A: 1"\fR
|
||||
\fI\(-> prints "in ::x step B: 2"\fR
|
||||
y advanceTwice \fI\(-> prints "in ::y step A: 3"\fR
|
||||
\fI\(-> prints "in ::y step B: 4"\fR
|
||||
x advanceTwice \fI\(-> prints "in ::x step A: 5"\fR
|
||||
\fI\(-> prints "in ::x step B: 6"\fR
|
||||
y advanceTwice \fI\(-> prints "in ::y step A: 7"\fR
|
||||
\fI\(-> prints "in ::y step B: 8"\fR
|
||||
.CE
|
||||
.VE TIP478
|
||||
.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
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2018 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH singleton n 0.3 TclOO "TclOO Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
oo::singleton \- a class that does only allows one instance of itself
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBoo::singleton\fI method \fR?\fIarg ...\fR?
|
||||
.fi
|
||||
.SH "CLASS HIERARCHY"
|
||||
.nf
|
||||
\fBoo::object\fR
|
||||
\(-> \fBoo::class\fR
|
||||
\(-> \fBoo::singleton\fR
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
Singleton classes are classes that only permit at most one instance of
|
||||
themselves to exist. They unexport the \fBcreate\fR and
|
||||
\fBcreateWithNamespace\fR methods entirely, and override the \fBnew\fR method
|
||||
so that it only makes a new instance if there is no existing instance. It is
|
||||
not recommended to inherit from a singleton class; singleton-ness is \fInot\fR
|
||||
inherited. It is not recommended that a singleton class's constructor take any
|
||||
arguments.
|
||||
.PP
|
||||
Instances have their\fB destroy\fR method overridden with a method that always
|
||||
returns an error in order to discourage destruction of the object, but
|
||||
destruction remains possible if strictly necessary (e.g., by destroying the
|
||||
class or using \fBrename\fR to delete it). They also have a (non-exported)
|
||||
\fB<cloned>\fR method defined on them that similarly always returns errors to
|
||||
make attempts to use the singleton instance with \fBoo::copy\fR fail.
|
||||
.SS CONSTRUCTOR
|
||||
The \fBoo::singleton\fR class does not define an explicit constructor; this
|
||||
means that it is effectively the same as the constructor of the
|
||||
\fBoo::class\fR class.
|
||||
.SS DESTRUCTOR
|
||||
The \fBoo::singleton\fR class does not define an explicit destructor;
|
||||
destroying an instance of it is just like destroying an ordinary class (and
|
||||
will destroy the singleton object).
|
||||
.SS "EXPORTED METHODS"
|
||||
.TP
|
||||
\fIcls \fBnew \fR?\fIarg ...\fR?
|
||||
.
|
||||
This returns the current instance of the singleton class, if one exists, and
|
||||
creates a new instance only if there is no existing instance. The additional
|
||||
arguments, \fIarg ...\fR, are only used if a new instance is actually
|
||||
manufactured; that construction is via the \fBoo::class\fR class's \fBnew\fR
|
||||
method.
|
||||
.RS
|
||||
.PP
|
||||
This is an override of the behaviour of a superclass's method with an
|
||||
identical call signature to the superclass's implementation.
|
||||
.RE
|
||||
.SS "NON-EXPORTED METHODS"
|
||||
The \fBoo::singleton\fR class explicitly states that \fBcreate\fR and
|
||||
\fBcreateWithNamespace\fR are unexported; callers should not assume that they
|
||||
have control over either the name or the namespace name of the singleton instance.
|
||||
.SH EXAMPLE
|
||||
.PP
|
||||
This example demonstrates that there is only one instance even though the
|
||||
\fBnew\fR method is called three times.
|
||||
.PP
|
||||
.CS
|
||||
\fBoo::singleton\fR create Highlander {
|
||||
method say {} {
|
||||
puts "there can be only one"
|
||||
}
|
||||
}
|
||||
|
||||
set h1 [Highlander new]
|
||||
set h2 [Highlander new]
|
||||
if {$h1 eq $h2} {
|
||||
puts "equal objects" \fI\(-> prints "equal objects"\fR
|
||||
}
|
||||
set h3 [Highlander new]
|
||||
if {$h1 eq $h3} {
|
||||
puts "equal objects" \fI\(-> prints "equal objects"\fR
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
Note that the name of the instance of the singleton is not guaranteed to be
|
||||
anything in particular.
|
||||
.SH "SEE ALSO"
|
||||
oo::class(n)
|
||||
.SH KEYWORDS
|
||||
class, metaclass, object, single instance
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
@@ -143,6 +143,15 @@ incomplete commands.
|
||||
.SH "STANDARD CHANNELS"
|
||||
.PP
|
||||
See \fBTcl_StandardChannels\fR for more explanations.
|
||||
.SH ZIPVFS
|
||||
.PP
|
||||
When a zipfile is concatenated to the end of a \fBtclsh\fR, on
|
||||
startup the contents of the zip archive will be mounted as the
|
||||
virtual file system /zvfs. If a top level directory tcl8.6 is
|
||||
present in the zip archive, it will become the directory loaded
|
||||
as env(TCL_LIBRARY). If a file named \fBmain.tcl\fR is present
|
||||
in the top level directory of the zip archive, it will be sourced
|
||||
instead of the shell's normal command line handing.
|
||||
.SH "SEE ALSO"
|
||||
auto_path(n), encoding(n), env(n), fconfigure(n)
|
||||
.SH KEYWORDS
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2015 Jan Nijtmans <jan.nijtmans@gmail.com>
|
||||
'\" Copyright (c) 2015 Christian Werner <chw@ch-werner.de>
|
||||
'\" Copyright (c) 2017 Sean Woods <yoda@etoyoc.com>
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH Tclzipfs 3 8.7 Tcl "Tcl Library Procedures"
|
||||
.so man.macros
|
||||
.BS
|
||||
.SH NAME
|
||||
TclZipfs_AppHook, Tclzipfs_Mount, Tclzipfs_Unmount, \- handle ZIP files as VFS
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.sp
|
||||
int
|
||||
\fBTclZipfs_AppHook(\fIint *argc, char ***argv\fR)
|
||||
.sp
|
||||
int
|
||||
\fBTclzipfs_Mount\fR(\fIinterp, mntpt, zipname, passwd\fR)
|
||||
.sp
|
||||
int
|
||||
\fBTclzipfs_Unmount\fR(\fIinterp, zipname\fR)
|
||||
.SH ARGUMENTS
|
||||
.AP "int" *argc in
|
||||
Number of command line arguments from main()
|
||||
.AP "char" ***argv in
|
||||
Pointer to an array of strings containing the command
|
||||
line arguments to main()
|
||||
.AS Tcl_Interp **termPtr
|
||||
.AP Tcl_Interp *interp in
|
||||
Interpreter in which the zip file system is mounted. The interpreter's result is
|
||||
modified to hold the result or error message from the script.
|
||||
.AP "const char" *zipname in
|
||||
Name of a zipfile.
|
||||
.AP "const char" *mntpt in
|
||||
Name of a mount point.
|
||||
.AP "const char" *passwd in
|
||||
An (optional) password.
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
\fBTclZipfs_AppHook()\fR is a utility function to perform standard
|
||||
application initialization procedures. If the current application has
|
||||
a mountable zip file system, that file system is mounted under \fIZIPROOT\fR\fB/app\fR.
|
||||
If a file named \fBmain.tcl\fR is located in that file system, it is treated
|
||||
as the startup script for the process. If the file \fIZIPROOT\fR\fB/app/tcl_library/init.tcl\fR
|
||||
is present, \fBtcl_library\fR is set to \fIZIPROOT\fR\fB/app/tcl_library.
|
||||
.PP
|
||||
If the \fBtcl_library\fR was not found in the application, the system will then search for it
|
||||
as either a VFS attached to the application dynamic library, or as a zip archive named
|
||||
libtcl_\fIMAJOR\fR_\fIMINOR\fR_\fIpatchLevel\fR.zip either in the present working directory
|
||||
or in the standard tcl install location.
|
||||
.PP
|
||||
\fBTclzipfs_Mount()\fR mount the ZIP archive \fIzipname\fR on the mount
|
||||
point given in \fImntpt\fR using the optional ZIP password \fIpasswd\fR.
|
||||
Errors during that process are reported in the interpreter \fIinterp\fR.
|
||||
If \fImountpoint\fR is a NULL pointer, information on all currently mounted
|
||||
ZIP file systems is written into \fIinterp\fR's result as a sequence of
|
||||
mount points and ZIP file names.
|
||||
.PP
|
||||
\fBTclzipfs_Unmount()\fR undoes the effect of \fBTclzipfs_Mount()\fR,
|
||||
i.e. it unmounts the mounted ZIP file system at \fImountpoint\fR. Errors are
|
||||
reported in the interpreter \fIinterp\fR.
|
||||
.SH KEYWORDS
|
||||
compress, filesystem, zip
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2015 Jan Nijtmans <jan.nijtmans@gmail.com>
|
||||
'\" Copyright (c) 2015 Christian Werner <chw@ch-werner.de>
|
||||
'\" Copyright (c) 2015 Sean Woods <yoda@etoyoc.com>
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH zipfs n 1.0 Zipfs "zipfs Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
zipfs \- Mount and work with ZIP files within Tcl
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fBpackage require zipfs \fR?\fB1.0\fR?
|
||||
.sp
|
||||
\fBzipfs exists\fR \fIfilename\fR
|
||||
\fBzipfs find\fR \fIdir\fR
|
||||
\fBzipfs info\fR \fIfilename\fR
|
||||
\fBzipfs list\fR \fB?(-glob|-regexp)?\fR \fI?pattern?\fR
|
||||
\fBzipfs mkimg\fR \fIoutfile\fR \fIindir\fR \fI?strip?\fR \fI?password?\fR \fI?infile?\fR
|
||||
\fBzipfs mkkey\fR \fIpassword\fR
|
||||
\fBzipfs mkzip\fR \fIoutfile\fR \fIindir\fR \fI?strip?\fR \fI?password?\fR
|
||||
\fBzipfs mount\fR \fI?mountpoint?\fR \fI?zipfile?\fR \fI?password?\fR
|
||||
\fBzipfs root\fR
|
||||
\fBzipfs unmount\fR \fImountpoint\fR
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The \fBzipfs\fR package provides tcl with the ability to mount
|
||||
the contents of a zip file as a virtual file system.
|
||||
.TP
|
||||
\fBzipfs exists\fR \fIfilename\fR
|
||||
.
|
||||
Return 1 if the given filename exists in the mounted zipfs and 0 if it does not.
|
||||
.TP
|
||||
\fBzipfs find\fR \fIdir\fR
|
||||
.
|
||||
Recursively lists files including and below the directory \fIdir\fR.
|
||||
The result list consists of relative path names starting from the
|
||||
given directory. This command is also used by the \fBzipfs mkzip\fR
|
||||
and \fBzipfs mkimg\fR commands.
|
||||
.TP
|
||||
\fBzipfs info\fR \fIfile\fR
|
||||
.
|
||||
Return information about the given file in the mounted zipfs. The information
|
||||
consists of (1) the name of the ZIP archive file that contains the file,
|
||||
(2) the size of the file after decompressions, (3) the compressed size of
|
||||
the file, and (4) the offset of the compressed data in the ZIP archive file.
|
||||
.RS
|
||||
.PP
|
||||
Note: querying the mount point gives the start of zip data offset in (4),
|
||||
which can be used to truncate the zip info off an executable.
|
||||
.RE
|
||||
.TP
|
||||
\fBzipfs list\fR \fB?(-glob|-regexp)?\fR \fI?pattern?\fR
|
||||
.
|
||||
Return a list of all files in the mounted zipfs. The order of the names
|
||||
in the list is arbitrary.
|
||||
.TP
|
||||
\fBzipfs mkimg\fR \fIoutfile\fR \fIindir\fR \fI?strip?\fR \fI?password?\fR \fI?infile?\fR
|
||||
.
|
||||
Creates an image (potentially a new executable file) similar to
|
||||
\fBzipfs mkzip\fR. If the \fIinfile\fR parameter is specified,
|
||||
this file is prepended in front of the ZIP archive, otherwise the file
|
||||
returned by \fBTcl_NameOfExecutable(3)\fR (i.e. the executable file of
|
||||
the running process) is used. If the \fIpassword\fR parameter is not empty,
|
||||
an obfuscated version of that password is placed between the image and ZIP
|
||||
chunks of the output file and the contents of the ZIP chunk are protected
|
||||
with that password.
|
||||
.RS
|
||||
.PP
|
||||
Caution: highly experimental, not usable on Android, only partially tested
|
||||
on Linux and Windows.
|
||||
.RE
|
||||
.TP
|
||||
\fBzipfs mkkey\fR \fIpassword\fR
|
||||
.
|
||||
For the clear text \fIpassword\fR argument an obfuscated string version
|
||||
is returned with the same format used in the \fBzipfs mkimg\fR command.
|
||||
.TP
|
||||
\fBzipfs mkzip\fR \fIoutfile\fR \fIindir\fR \fI?strip?\fR \fI?password?\fR
|
||||
.
|
||||
Creates a ZIP archive file named \fIoutfile\fR from the contents of the input
|
||||
directory \fIindir\fR (contained regular files only) with optional ZIP
|
||||
password \fIpassword\fR. While processing the files below \fIindir\fR the
|
||||
optional file name prefix given in \fIstrip\fR is stripped off the beginning
|
||||
of the respective file name.
|
||||
.RS
|
||||
.PP
|
||||
Caution: the choice of the \fIindir\fR parameter
|
||||
(less the optional stripped prefix) determines the later root name of the
|
||||
archive's content.
|
||||
.RE
|
||||
.TP
|
||||
\fBzipfs mount ?\fImountpoint\fR? ?\fIzipfile\fR? ?\fIpassword\fR?
|
||||
.
|
||||
The \fBzipfs mount\fR command mounts a ZIP archive file as a VFS.
|
||||
After this command executes, files contained in \fIzipfile\fR
|
||||
will appear to Tcl to be regular files at the mount point.
|
||||
.RS
|
||||
.PP
|
||||
With no \fIzipfile\fR, returns the zipfile mounted at \fImountpoint\fR.
|
||||
With no \fImountpoint\fR, return all zipfile/mount pairs.
|
||||
If \fImountpoint\fR is specified as an empty string, mount on file path.
|
||||
.RE
|
||||
.TP
|
||||
\fBzipfs root\fR
|
||||
Returns a constant string which indicates the mount point for zipfs volumes
|
||||
for the current platform. On Windows, this value is zipfs:/. On Unux, //zipfs:/
|
||||
.RE
|
||||
.TP
|
||||
\fBzipfs unmount \fImountpoint\fR
|
||||
.
|
||||
Unmounts a previously mounted ZIP archive mounted to \fImountpoint\fR.
|
||||
.SH "SEE ALSO"
|
||||
tclsh(1), file(n), zlib(n)
|
||||
.SH "KEYWORDS"
|
||||
compress, filesystem, zip
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" End:
|
||||
+57
-27
@@ -104,7 +104,7 @@ declare 20 {
|
||||
declare 21 {
|
||||
int Tcl_DbIsShared(Tcl_Obj *objPtr, const char *file, int line)
|
||||
}
|
||||
declare 22 {
|
||||
declare 22 {deprecated {No longer in use, changed to macro}} {
|
||||
Tcl_Obj *Tcl_DbNewBooleanObj(int boolValue, const char *file, int line)
|
||||
}
|
||||
declare 23 {
|
||||
@@ -119,7 +119,7 @@ declare 25 {
|
||||
Tcl_Obj *Tcl_DbNewListObj(int objc, Tcl_Obj *const *objv,
|
||||
const char *file, int line)
|
||||
}
|
||||
declare 26 {
|
||||
declare 26 {deprecated {No longer in use, changed to macro}} {
|
||||
Tcl_Obj *Tcl_DbNewLongObj(long longValue, const char *file, int line)
|
||||
}
|
||||
declare 27 {
|
||||
@@ -152,7 +152,7 @@ declare 35 {
|
||||
int Tcl_GetDoubleFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
|
||||
double *doublePtr)
|
||||
}
|
||||
declare 36 {
|
||||
declare 36 {deprecated {No longer in use, changed to macro}} {
|
||||
int Tcl_GetIndexFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
|
||||
const char *const *tablePtr, const char *msg, int flags, int *indexPtr)
|
||||
}
|
||||
@@ -198,7 +198,7 @@ declare 48 {
|
||||
int Tcl_ListObjReplace(Tcl_Interp *interp, Tcl_Obj *listPtr, int first,
|
||||
int count, int objc, Tcl_Obj *const objv[])
|
||||
}
|
||||
declare 49 {
|
||||
declare 49 {deprecated {No longer in use, changed to macro}} {
|
||||
Tcl_Obj *Tcl_NewBooleanObj(int boolValue)
|
||||
}
|
||||
declare 50 {
|
||||
@@ -207,13 +207,13 @@ declare 50 {
|
||||
declare 51 {
|
||||
Tcl_Obj *Tcl_NewDoubleObj(double doubleValue)
|
||||
}
|
||||
declare 52 {
|
||||
declare 52 {deprecated {No longer in use, changed to macro}} {
|
||||
Tcl_Obj *Tcl_NewIntObj(int intValue)
|
||||
}
|
||||
declare 53 {
|
||||
Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[])
|
||||
}
|
||||
declare 54 {
|
||||
declare 54 {deprecated {No longer in use, changed to macro}} {
|
||||
Tcl_Obj *Tcl_NewLongObj(long longValue)
|
||||
}
|
||||
declare 55 {
|
||||
@@ -222,7 +222,7 @@ declare 55 {
|
||||
declare 56 {
|
||||
Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length)
|
||||
}
|
||||
declare 57 {
|
||||
declare 57 {deprecated {No longer in use, changed to macro}} {
|
||||
void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue)
|
||||
}
|
||||
declare 58 {
|
||||
@@ -235,13 +235,13 @@ declare 59 {
|
||||
declare 60 {
|
||||
void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue)
|
||||
}
|
||||
declare 61 {
|
||||
declare 61 {deprecated {No longer in use, changed to macro}} {
|
||||
void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue)
|
||||
}
|
||||
declare 62 {
|
||||
void Tcl_SetListObj(Tcl_Obj *objPtr, int objc, Tcl_Obj *const objv[])
|
||||
}
|
||||
declare 63 {
|
||||
declare 63 {deprecated {No longer in use, changed to macro}} {
|
||||
void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue)
|
||||
}
|
||||
declare 64 {
|
||||
@@ -250,10 +250,10 @@ declare 64 {
|
||||
declare 65 {
|
||||
void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes, int length)
|
||||
}
|
||||
declare 66 {
|
||||
declare 66 {deprecated {No longer in use, changed to macro}} {
|
||||
void Tcl_AddErrorInfo(Tcl_Interp *interp, const char *message)
|
||||
}
|
||||
declare 67 {
|
||||
declare 67 {deprecated {No longer in use, changed to macro}} {
|
||||
void Tcl_AddObjErrorInfo(Tcl_Interp *interp, const char *message,
|
||||
int length)
|
||||
}
|
||||
@@ -472,7 +472,7 @@ declare 129 {
|
||||
declare 130 {
|
||||
int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName)
|
||||
}
|
||||
declare 131 {
|
||||
declare 131 {deprecated {No longer in use, changed to macro}} {
|
||||
int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr)
|
||||
}
|
||||
declare 132 {
|
||||
@@ -624,7 +624,7 @@ declare 173 {
|
||||
declare 174 {
|
||||
const char *Tcl_GetStringResult(Tcl_Interp *interp)
|
||||
}
|
||||
declare 175 {
|
||||
declare 175 {deprecated {No longer in use, changed to macro}} {
|
||||
const char *Tcl_GetVar(Tcl_Interp *interp, const char *varName,
|
||||
int flags)
|
||||
}
|
||||
@@ -635,7 +635,7 @@ declare 176 {
|
||||
declare 177 {
|
||||
int Tcl_GlobalEval(Tcl_Interp *interp, const char *command)
|
||||
}
|
||||
declare 178 {
|
||||
declare 178 {deprecated {No longer in use, changed to macro}} {
|
||||
int Tcl_GlobalEvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr)
|
||||
}
|
||||
declare 179 {
|
||||
@@ -834,7 +834,7 @@ declare 235 {
|
||||
declare 236 {
|
||||
void Tcl_SetStdChannel(Tcl_Channel channel, int type)
|
||||
}
|
||||
declare 237 {
|
||||
declare 237 {deprecated {No longer in use, changed to macro}} {
|
||||
const char *Tcl_SetVar(Tcl_Interp *interp, const char *varName,
|
||||
const char *newValue, int flags)
|
||||
}
|
||||
@@ -869,7 +869,7 @@ declare 245 {
|
||||
declare 246 {deprecated {}} {
|
||||
int Tcl_TellOld(Tcl_Channel chan)
|
||||
}
|
||||
declare 247 {
|
||||
declare 247 {deprecated {No longer in use, changed to macro}} {
|
||||
int Tcl_TraceVar(Tcl_Interp *interp, const char *varName, int flags,
|
||||
Tcl_VarTraceProc *proc, ClientData clientData)
|
||||
}
|
||||
@@ -890,14 +890,14 @@ declare 251 {
|
||||
declare 252 {
|
||||
int Tcl_UnregisterChannel(Tcl_Interp *interp, Tcl_Channel chan)
|
||||
}
|
||||
declare 253 {
|
||||
declare 253 {deprecated {No longer in use, changed to macro}} {
|
||||
int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName, int flags)
|
||||
}
|
||||
declare 254 {
|
||||
int Tcl_UnsetVar2(Tcl_Interp *interp, const char *part1, const char *part2,
|
||||
int flags)
|
||||
}
|
||||
declare 255 {
|
||||
declare 255 {deprecated {No longer in use, changed to macro}} {
|
||||
void Tcl_UntraceVar(Tcl_Interp *interp, const char *varName, int flags,
|
||||
Tcl_VarTraceProc *proc, ClientData clientData)
|
||||
}
|
||||
@@ -909,7 +909,7 @@ declare 256 {
|
||||
declare 257 {
|
||||
void Tcl_UpdateLinkedVar(Tcl_Interp *interp, const char *varName)
|
||||
}
|
||||
declare 258 {
|
||||
declare 258 {deprecated {No longer in use, changed to macro}} {
|
||||
int Tcl_UpVar(Tcl_Interp *interp, const char *frameName,
|
||||
const char *varName, const char *localName, int flags)
|
||||
}
|
||||
@@ -920,7 +920,7 @@ declare 259 {
|
||||
declare 260 {
|
||||
int Tcl_VarEval(Tcl_Interp *interp, ...)
|
||||
}
|
||||
declare 261 {
|
||||
declare 261 {deprecated {No longer in use, changed to macro}} {
|
||||
ClientData Tcl_VarTraceInfo(Tcl_Interp *interp, const char *varName,
|
||||
int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData)
|
||||
}
|
||||
@@ -955,7 +955,7 @@ declare 270 {
|
||||
const char *Tcl_ParseVar(Tcl_Interp *interp, const char *start,
|
||||
const char **termPtr)
|
||||
}
|
||||
declare 271 {
|
||||
declare 271 {deprecated {No longer in use, changed to macro}} {
|
||||
const char *Tcl_PkgPresent(Tcl_Interp *interp, const char *name,
|
||||
const char *version, int exact)
|
||||
}
|
||||
@@ -964,12 +964,12 @@ declare 272 {
|
||||
const char *name, const char *version, int exact,
|
||||
void *clientDataPtr)
|
||||
}
|
||||
declare 273 {
|
||||
declare 273 {deprecated {No longer in use, changed to macro}} {
|
||||
int Tcl_PkgProvide(Tcl_Interp *interp, const char *name,
|
||||
const char *version)
|
||||
}
|
||||
# TIP #268: The internally used new Require function is in slot 573.
|
||||
declare 274 {
|
||||
declare 274 {deprecated {No longer in use, changed to macro}} {
|
||||
const char *Tcl_PkgRequire(Tcl_Interp *interp, const char *name,
|
||||
const char *version, int exact)
|
||||
}
|
||||
@@ -1350,7 +1350,7 @@ declare 380 {
|
||||
declare 381 {
|
||||
int Tcl_GetUniChar(Tcl_Obj *objPtr, int index)
|
||||
}
|
||||
declare 382 {
|
||||
declare 382 {deprecated {No longer in use, changed to macro}} {
|
||||
Tcl_UniChar *Tcl_GetUnicode(Tcl_Obj *objPtr)
|
||||
}
|
||||
declare 383 {
|
||||
@@ -2330,10 +2330,31 @@ declare 631 {
|
||||
ClientData callbackData)
|
||||
}
|
||||
|
||||
# TIP #430
|
||||
declare 632 {
|
||||
int TclZipfs_Mount(
|
||||
Tcl_Interp *interp,
|
||||
const char *mntpt,
|
||||
const char *zipname,
|
||||
const char *passwd)
|
||||
}
|
||||
declare 633 {
|
||||
int TclZipfs_Unmount(Tcl_Interp *interp, const char *zipname)
|
||||
}
|
||||
declare 634 {
|
||||
Tcl_Obj *TclZipfs_TclLibrary(void)
|
||||
}
|
||||
declare 635 {
|
||||
int TclZipfs_Mount_Buffer(
|
||||
Tcl_Interp *interp,
|
||||
const char *mntpt,
|
||||
unsigned char *data,
|
||||
size_t datalen,
|
||||
int copy)
|
||||
}
|
||||
|
||||
# ----- BASELINE -- FOR -- 8.7.0 ----- #
|
||||
|
||||
|
||||
|
||||
##############################################################################
|
||||
|
||||
# Define the platform specific public Tcl interface. These functions are only
|
||||
@@ -2344,6 +2365,9 @@ interface tclPlat
|
||||
################################
|
||||
# Unix specific functions
|
||||
# (none)
|
||||
declare 2 unix {
|
||||
int TclZipfs_AppHook(int *argc, char ***argv)
|
||||
}
|
||||
|
||||
################################
|
||||
# Windows specific functions
|
||||
@@ -2356,7 +2380,9 @@ declare 0 win {
|
||||
declare 1 win {
|
||||
char *Tcl_WinTCharToUtf(const TCHAR *str, int len, Tcl_DString *dsPtr)
|
||||
}
|
||||
|
||||
declare 2 win {
|
||||
int TclZipfs_AppHook(int *argc, TCHAR ***argv)
|
||||
}
|
||||
################################
|
||||
# Mac OS X specific functions
|
||||
|
||||
@@ -2378,6 +2404,10 @@ declare 1 macosx {
|
||||
export {
|
||||
void Tcl_Main(int argc, char **argv, Tcl_AppInitProc *appInitProc)
|
||||
}
|
||||
export {
|
||||
void Tcl_MainEx(int argc, char **argv, Tcl_AppInitProc *appInitProc,
|
||||
Tcl_Interp *interp)
|
||||
}
|
||||
export {
|
||||
const char *Tcl_InitStubs(Tcl_Interp *interp, const char *version,
|
||||
int exact)
|
||||
|
||||
+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
|
||||
}
|
||||
|
||||
@@ -2253,7 +2253,7 @@ GetListIndexOperand(
|
||||
if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &value) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Convert to an integer, advance to the next token and return. */
|
||||
/*
|
||||
* NOTE: Indexing a list with an index before it yields the
|
||||
|
||||
+54
-90
@@ -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
|
||||
@@ -999,6 +999,9 @@ Tcl_CreateInterp(void)
|
||||
if (TclZlibInit(interp) != TCL_OK) {
|
||||
Tcl_Panic("%s", TclGetString(Tcl_GetObjResult(interp)));
|
||||
}
|
||||
if (TclZipfs_Init(interp) != TCL_OK) {
|
||||
Tcl_Panic("%s", Tcl_GetString(Tcl_GetObjResult(interp)));
|
||||
}
|
||||
#endif
|
||||
|
||||
TOP_CB(iPtr) = NULL;
|
||||
@@ -2295,30 +2298,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 +2336,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 +2371,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 +2391,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 +2448,7 @@ TclCreateObjCommandInNs (
|
||||
cmdPtr->importRefPtr = oldRefPtr;
|
||||
while (oldRefPtr != NULL) {
|
||||
Command *refCmdPtr = oldRefPtr->importedCmdPtr;
|
||||
|
||||
dataPtr = refCmdPtr->objClientData;
|
||||
dataPtr->realCmdPtr = cmdPtr;
|
||||
oldRefPtr = oldRefPtr->nextPtr;
|
||||
@@ -7504,7 +7516,7 @@ ExprAbsFunc(
|
||||
}
|
||||
}
|
||||
goto unChanged;
|
||||
} else if (l == LLONG_MIN) {
|
||||
} else if (l == WIDE_MIN) {
|
||||
TclInitBignumFromWideInt(&big, l);
|
||||
goto tooLarge;
|
||||
}
|
||||
@@ -7629,7 +7641,7 @@ ExprEntierFunc(
|
||||
|
||||
if (type == TCL_NUMBER_DOUBLE) {
|
||||
d = *((const double *) ptr);
|
||||
if ((d >= (double)LONG_MAX) || (d <= (double)LONG_MIN)) {
|
||||
if ((d >= (double)WIDE_MAX) || (d <= (double)WIDE_MIN)) {
|
||||
mp_int big;
|
||||
|
||||
if (Tcl_InitBignumFromDouble(interp, d, &big) != TCL_OK) {
|
||||
@@ -7639,9 +7651,9 @@ ExprEntierFunc(
|
||||
Tcl_SetObjResult(interp, Tcl_NewBignumObj(&big));
|
||||
return TCL_OK;
|
||||
} else {
|
||||
long result = (long) d;
|
||||
Tcl_WideInt result = (Tcl_WideInt) d;
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewLongObj(result));
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(result));
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
@@ -7671,27 +7683,14 @@ ExprIntFunc(
|
||||
int objc, /* Actual parameter count. */
|
||||
Tcl_Obj *const *objv) /* Actual parameter vector. */
|
||||
{
|
||||
long iResult;
|
||||
Tcl_WideInt wResult;
|
||||
Tcl_Obj *objPtr;
|
||||
if (ExprEntierFunc(NULL, interp, objc, objv) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
objPtr = Tcl_GetObjResult(interp);
|
||||
if (TclGetLongFromObj(NULL, objPtr, &iResult) != TCL_OK) {
|
||||
/*
|
||||
* Truncate the bignum; keep only bits in long range.
|
||||
*/
|
||||
|
||||
mp_int big;
|
||||
|
||||
Tcl_GetBignumFromObj(NULL, objPtr, &big);
|
||||
mp_mod_2d(&big, (int) CHAR_BIT * sizeof(long), &big);
|
||||
objPtr = Tcl_NewBignumObj(&big);
|
||||
Tcl_IncrRefCount(objPtr);
|
||||
TclGetLongFromObj(NULL, objPtr, &iResult);
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewLongObj(iResult));
|
||||
TclGetWideBitsFromObj(NULL, objPtr, &wResult);
|
||||
Tcl_SetObjResult(interp, Tcl_NewLongObj((long)wResult));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -7704,26 +7703,11 @@ ExprWideFunc(
|
||||
Tcl_Obj *const *objv) /* Actual parameter vector. */
|
||||
{
|
||||
Tcl_WideInt wResult;
|
||||
Tcl_Obj *objPtr;
|
||||
|
||||
if (ExprEntierFunc(NULL, interp, objc, objv) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
objPtr = Tcl_GetObjResult(interp);
|
||||
if (TclGetWideIntFromObj(NULL, objPtr, &wResult) != TCL_OK) {
|
||||
/*
|
||||
* Truncate the bignum; keep only bits in wide int range.
|
||||
*/
|
||||
|
||||
mp_int big;
|
||||
|
||||
Tcl_GetBignumFromObj(NULL, objPtr, &big);
|
||||
mp_mod_2d(&big, (int) CHAR_BIT * sizeof(Tcl_WideInt), &big);
|
||||
objPtr = Tcl_NewBignumObj(&big);
|
||||
Tcl_IncrRefCount(objPtr);
|
||||
TclGetWideIntFromObj(NULL, objPtr, &wResult);
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
}
|
||||
TclGetWideBitsFromObj(NULL, Tcl_GetObjResult(interp), &wResult);
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(wResult));
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -7826,7 +7810,7 @@ ExprRandFunc(
|
||||
* Make sure 1 <= randSeed <= (2^31) - 2. See below.
|
||||
*/
|
||||
|
||||
iPtr->randSeed &= (unsigned long) 0x7fffffff;
|
||||
iPtr->randSeed &= 0x7fffffff;
|
||||
if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) {
|
||||
iPtr->randSeed ^= 123459876;
|
||||
}
|
||||
@@ -7970,7 +7954,7 @@ ExprSrandFunc(
|
||||
Tcl_Obj *const *objv) /* Parameter vector. */
|
||||
{
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
long i = 0; /* Initialized to avoid compiler warning. */
|
||||
Tcl_WideInt w = 0; /* Initialized to avoid compiler warning. */
|
||||
|
||||
/*
|
||||
* Convert argument and use it to reset the seed.
|
||||
@@ -7981,20 +7965,8 @@ ExprSrandFunc(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if (TclGetLongFromObj(NULL, objv[1], &i) != TCL_OK) {
|
||||
Tcl_Obj *objPtr;
|
||||
mp_int big;
|
||||
|
||||
if (Tcl_GetBignumFromObj(interp, objv[1], &big) != TCL_OK) {
|
||||
/* TODO: more ::errorInfo here? or in caller? */
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
mp_mod_2d(&big, (int) CHAR_BIT * sizeof(long), &big);
|
||||
objPtr = Tcl_NewBignumObj(&big);
|
||||
Tcl_IncrRefCount(objPtr);
|
||||
TclGetLongFromObj(NULL, objPtr, &i);
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
if (TclGetWideBitsFromObj(NULL, objv[1], &w) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -8003,8 +7975,7 @@ ExprSrandFunc(
|
||||
*/
|
||||
|
||||
iPtr->flags |= RAND_SEED_INITIALIZED;
|
||||
iPtr->randSeed = i;
|
||||
iPtr->randSeed &= (unsigned long) 0x7fffffff;
|
||||
iPtr->randSeed = (long) w & 0x7fffffff;
|
||||
if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) {
|
||||
iPtr->randSeed ^= 123459876;
|
||||
}
|
||||
@@ -8276,23 +8247,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 +8370,6 @@ TclPushTailcallPoint(
|
||||
TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL);
|
||||
((Interp *) interp)->numLevels++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -8432,7 +8405,6 @@ TclSetTailcall(
|
||||
}
|
||||
runPtr->data[1] = listPtr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -8490,25 +8462,18 @@ TclNRTailcallObjCmd(
|
||||
if (objc > 1) {
|
||||
Tcl_Obj *listPtr, *nsObjPtr;
|
||||
Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
|
||||
Tcl_Namespace *ns1Ptr;
|
||||
|
||||
/* The tailcall data is in a Tcl list: the first element is the
|
||||
* namespace, the rest the command to be tailcalled. */
|
||||
|
||||
listPtr = Tcl_NewListObj(objc, objv);
|
||||
|
||||
nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1);
|
||||
if ((TCL_OK != TclGetNamespaceFromObj(interp, nsObjPtr, &ns1Ptr))
|
||||
|| (nsPtr != ns1Ptr)) {
|
||||
Tcl_Panic("Tailcall failed to find the proper namespace");
|
||||
}
|
||||
listPtr = Tcl_NewListObj(objc, objv);
|
||||
TclListObjSetElement(interp, listPtr, 0, nsObjPtr);
|
||||
|
||||
iPtr->varFramePtr->tailcallPtr = listPtr;
|
||||
}
|
||||
return TCL_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -8576,7 +8541,6 @@ TclNRReleaseValues(
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Tcl_NRAddCallback(
|
||||
|
||||
+17
-18
@@ -1963,7 +1963,6 @@ FormatNumber(
|
||||
Tcl_Obj *src, /* Number to format. */
|
||||
unsigned char **cursorPtr) /* Pointer to index into destination buffer. */
|
||||
{
|
||||
long value;
|
||||
double dvalue;
|
||||
Tcl_WideInt wvalue;
|
||||
float fvalue;
|
||||
@@ -2025,7 +2024,7 @@ FormatNumber(
|
||||
case 'w':
|
||||
case 'W':
|
||||
case 'm':
|
||||
if (Tcl_GetWideIntFromObj(interp, src, &wvalue) != TCL_OK) {
|
||||
if (TclGetWideBitsFromObj(interp, src, &wvalue) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (NeedReversing(type)) {
|
||||
@@ -2055,19 +2054,19 @@ FormatNumber(
|
||||
case 'i':
|
||||
case 'I':
|
||||
case 'n':
|
||||
if (TclGetLongFromObj(interp, src, &value) != TCL_OK) {
|
||||
if (TclGetWideBitsFromObj(interp, src, &wvalue) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (NeedReversing(type)) {
|
||||
*(*cursorPtr)++ = UCHAR(value);
|
||||
*(*cursorPtr)++ = UCHAR(value >> 8);
|
||||
*(*cursorPtr)++ = UCHAR(value >> 16);
|
||||
*(*cursorPtr)++ = UCHAR(value >> 24);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue >> 8);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue >> 16);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue >> 24);
|
||||
} else {
|
||||
*(*cursorPtr)++ = UCHAR(value >> 24);
|
||||
*(*cursorPtr)++ = UCHAR(value >> 16);
|
||||
*(*cursorPtr)++ = UCHAR(value >> 8);
|
||||
*(*cursorPtr)++ = UCHAR(value);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue >> 24);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue >> 16);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue >> 8);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue);
|
||||
}
|
||||
return TCL_OK;
|
||||
|
||||
@@ -2077,15 +2076,15 @@ FormatNumber(
|
||||
case 's':
|
||||
case 'S':
|
||||
case 't':
|
||||
if (TclGetLongFromObj(interp, src, &value) != TCL_OK) {
|
||||
if (TclGetWideBitsFromObj(interp, src, &wvalue) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (NeedReversing(type)) {
|
||||
*(*cursorPtr)++ = UCHAR(value);
|
||||
*(*cursorPtr)++ = UCHAR(value >> 8);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue >> 8);
|
||||
} else {
|
||||
*(*cursorPtr)++ = UCHAR(value >> 8);
|
||||
*(*cursorPtr)++ = UCHAR(value);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue >> 8);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue);
|
||||
}
|
||||
return TCL_OK;
|
||||
|
||||
@@ -2093,10 +2092,10 @@ FormatNumber(
|
||||
* 8-bit integer values.
|
||||
*/
|
||||
case 'c':
|
||||
if (TclGetLongFromObj(interp, src, &value) != TCL_OK) {
|
||||
if (TclGetWideBitsFromObj(interp, src, &wvalue) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
*(*cursorPtr)++ = UCHAR(value);
|
||||
*(*cursorPtr)++ = UCHAR(wvalue);
|
||||
return TCL_OK;
|
||||
|
||||
default:
|
||||
|
||||
@@ -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
|
||||
|
||||
+4
-61
@@ -513,63 +513,6 @@ Tcl_ContinueObjCmd(
|
||||
return TCL_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_EncodingObjCmd --
|
||||
*
|
||||
* This command manipulates encodings.
|
||||
*
|
||||
* Results:
|
||||
* A standard Tcl result.
|
||||
*
|
||||
* Side effects:
|
||||
* See the user documentation.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
Tcl_EncodingObjCmd(
|
||||
ClientData dummy, /* Not used. */
|
||||
Tcl_Interp *interp, /* Current interpreter. */
|
||||
int objc, /* Number of arguments. */
|
||||
Tcl_Obj *const objv[]) /* Argument objects. */
|
||||
{
|
||||
int index;
|
||||
|
||||
static const char *const optionStrings[] = {
|
||||
"convertfrom", "convertto", "dirs", "names", "system",
|
||||
NULL
|
||||
};
|
||||
enum options {
|
||||
ENC_CONVERTFROM, ENC_CONVERTTO, ENC_DIRS, ENC_NAMES, ENC_SYSTEM
|
||||
};
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
|
||||
&index) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
switch ((enum options) index) {
|
||||
case ENC_CONVERTTO:
|
||||
return EncodingConverttoObjCmd(dummy, interp, objc, objv);
|
||||
case ENC_CONVERTFROM:
|
||||
return EncodingConvertfromObjCmd(dummy, interp, objc, objv);
|
||||
case ENC_DIRS:
|
||||
return EncodingDirsObjCmd(dummy, interp, objc, objv);
|
||||
case ENC_NAMES:
|
||||
return EncodingNamesObjCmd(dummy, interp, objc, objv);
|
||||
case ENC_SYSTEM:
|
||||
return EncodingSystemObjCmd(dummy, interp, objc, objv);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
@@ -1455,9 +1398,9 @@ FileAttrAccessTimeCmd(
|
||||
* platforms. [Bug 698146]
|
||||
*/
|
||||
|
||||
long newTime;
|
||||
Tcl_WideInt newTime;
|
||||
|
||||
if (TclGetLongFromObj(interp, objv[2], &newTime) != TCL_OK) {
|
||||
if (TclGetWideIntFromObj(interp, objv[2], &newTime) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -1536,9 +1479,9 @@ FileAttrModifyTimeCmd(
|
||||
* platforms. [Bug 698146]
|
||||
*/
|
||||
|
||||
long newTime;
|
||||
Tcl_WideInt newTime;
|
||||
|
||||
if (TclGetLongFromObj(interp, objv[2], &newTime) != TCL_OK) {
|
||||
if (TclGetWideIntFromObj(interp, objv[2], &newTime) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -3333,7 +3333,7 @@ Tcl_LsearchObjCmd(
|
||||
* sense in doing this when the match sense is inverted.
|
||||
*/
|
||||
|
||||
/*
|
||||
/*
|
||||
* With -stride, lower, upper and i are kept as multiples of groupSize.
|
||||
*/
|
||||
|
||||
@@ -4015,7 +4015,7 @@ Tcl_LsortObjCmd(
|
||||
/*
|
||||
* Do not shrink the actual memory block used; that doesn't
|
||||
* work with TclStackAlloc-allocated memory. [Bug 2918962]
|
||||
*
|
||||
*
|
||||
* TODO: Consider a pointer increment to replace this
|
||||
* array shift.
|
||||
*/
|
||||
|
||||
+49
-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);
|
||||
@@ -1447,6 +1447,9 @@ StringIndexCmd(
|
||||
char buf[4];
|
||||
|
||||
length = Tcl_UniCharToUtf(ch, buf);
|
||||
if (!length) {
|
||||
length = Tcl_UniCharToUtf(-1, buf);
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, length));
|
||||
}
|
||||
}
|
||||
@@ -2001,8 +2004,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 +2036,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 +2049,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 +2549,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 +2560,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 +2589,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 +2626,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 +2659,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;
|
||||
}
|
||||
|
||||
|
||||
+25
-23
@@ -27,7 +27,6 @@ static void CompileReturnInternal(CompileEnv *envPtr,
|
||||
Tcl_Obj *returnOpts);
|
||||
static int IndexTailVarIfKnown(Tcl_Interp *interp,
|
||||
Tcl_Token *varTokenPtr, CompileEnv *envPtr);
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -35,7 +34,7 @@ static int IndexTailVarIfKnown(Tcl_Interp *interp,
|
||||
* TclGetIndexFromToken --
|
||||
*
|
||||
* Parse a token to determine if an index value is known at
|
||||
* compile time.
|
||||
* compile time.
|
||||
*
|
||||
* Returns:
|
||||
* TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
|
||||
@@ -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);
|
||||
@@ -1551,7 +1553,7 @@ TclCompileLreplaceCmd(
|
||||
|
||||
emptyPrefix = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* [lreplace] raises an error when idx1 points after the list, but
|
||||
* only when the list is not empty. This is maximum stupidity.
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1002,13 +1002,13 @@ TclCompileStringReplaceCmd(
|
||||
if (parsePtr->numWords < 4 || parsePtr->numWords > 5) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Bytecode to compute/push string argument being replaced */
|
||||
valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
|
||||
CompileWord(envPtr, valueTokenPtr, interp, 1);
|
||||
|
||||
/*
|
||||
* Check for first index known and useful at compile time.
|
||||
* Check for first index known and useful at compile time.
|
||||
*/
|
||||
tokenPtr = TokenAfter(valueTokenPtr);
|
||||
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_AFTER,
|
||||
@@ -1017,7 +1017,7 @@ TclCompileStringReplaceCmd(
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for last index known and useful at compile time.
|
||||
* Check for last index known and useful at compile time.
|
||||
*/
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_AFTER,
|
||||
@@ -1025,7 +1025,7 @@ TclCompileStringReplaceCmd(
|
||||
goto genericReplace;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* [string replace] is an odd bird. For many arguments it is
|
||||
* a conventional substring replacer. However it also goes out
|
||||
* of its way to become a no-op for many cases where it would be
|
||||
@@ -1108,12 +1108,12 @@ TclCompileStringReplaceCmd(
|
||||
* Finally we need, third:
|
||||
*
|
||||
* (first <= last)
|
||||
*
|
||||
*
|
||||
* Considered in combination with the constraints we already have,
|
||||
* we see that we can proceed when (first == TCL_INDEX_BEFORE)
|
||||
* or (last == TCL_INDEX_AFTER). These also permit simplification
|
||||
* of the prefix|replace|suffix construction. The other constraints,
|
||||
* though, interfere with getting a guarantee that first <= last.
|
||||
* though, interfere with getting a guarantee that first <= last.
|
||||
*/
|
||||
|
||||
if ((first == TCL_INDEX_BEFORE) && (last >= TCL_INDEX_START)) {
|
||||
@@ -1141,7 +1141,7 @@ TclCompileStringReplaceCmd(
|
||||
/* FLOW THROUGH TO genericReplace */
|
||||
|
||||
} else {
|
||||
/*
|
||||
/*
|
||||
* When we have no replacement string to worry about, we may
|
||||
* have more luck, because the forbidden empty string replacements
|
||||
* are harmless when they are replaced by another empty string.
|
||||
|
||||
+1
-1
@@ -1348,7 +1348,7 @@ yyparse (info)
|
||||
int yychar;
|
||||
|
||||
/* The semantic value of the look-ahead symbol. */
|
||||
YYSTYPE yylval;
|
||||
YYSTYPE yylval = {0};
|
||||
|
||||
/* Number of syntax errors so far. */
|
||||
int yynerrs;
|
||||
|
||||
+100
-53
@@ -119,7 +119,8 @@ EXTERN void Tcl_DbIncrRefCount(Tcl_Obj *objPtr, const char *file,
|
||||
EXTERN int Tcl_DbIsShared(Tcl_Obj *objPtr, const char *file,
|
||||
int line);
|
||||
/* 22 */
|
||||
EXTERN Tcl_Obj * Tcl_DbNewBooleanObj(int boolValue, const char *file,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
Tcl_Obj * Tcl_DbNewBooleanObj(int boolValue, const char *file,
|
||||
int line);
|
||||
/* 23 */
|
||||
EXTERN Tcl_Obj * Tcl_DbNewByteArrayObj(const unsigned char *bytes,
|
||||
@@ -131,7 +132,8 @@ EXTERN Tcl_Obj * Tcl_DbNewDoubleObj(double doubleValue,
|
||||
EXTERN Tcl_Obj * Tcl_DbNewListObj(int objc, Tcl_Obj *const *objv,
|
||||
const char *file, int line);
|
||||
/* 26 */
|
||||
EXTERN Tcl_Obj * Tcl_DbNewLongObj(long longValue, const char *file,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
Tcl_Obj * Tcl_DbNewLongObj(long longValue, const char *file,
|
||||
int line);
|
||||
/* 27 */
|
||||
EXTERN Tcl_Obj * Tcl_DbNewObj(const char *file, int line);
|
||||
@@ -158,7 +160,8 @@ EXTERN int Tcl_GetDouble(Tcl_Interp *interp, const char *src,
|
||||
EXTERN int Tcl_GetDoubleFromObj(Tcl_Interp *interp,
|
||||
Tcl_Obj *objPtr, double *doublePtr);
|
||||
/* 36 */
|
||||
EXTERN int Tcl_GetIndexFromObj(Tcl_Interp *interp,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
int Tcl_GetIndexFromObj(Tcl_Interp *interp,
|
||||
Tcl_Obj *objPtr, const char *const *tablePtr,
|
||||
const char *msg, int flags, int *indexPtr);
|
||||
/* 37 */
|
||||
@@ -198,24 +201,28 @@ EXTERN int Tcl_ListObjReplace(Tcl_Interp *interp,
|
||||
Tcl_Obj *listPtr, int first, int count,
|
||||
int objc, Tcl_Obj *const objv[]);
|
||||
/* 49 */
|
||||
EXTERN Tcl_Obj * Tcl_NewBooleanObj(int boolValue);
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
Tcl_Obj * Tcl_NewBooleanObj(int boolValue);
|
||||
/* 50 */
|
||||
EXTERN Tcl_Obj * Tcl_NewByteArrayObj(const unsigned char *bytes,
|
||||
int length);
|
||||
/* 51 */
|
||||
EXTERN Tcl_Obj * Tcl_NewDoubleObj(double doubleValue);
|
||||
/* 52 */
|
||||
EXTERN Tcl_Obj * Tcl_NewIntObj(int intValue);
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
Tcl_Obj * Tcl_NewIntObj(int intValue);
|
||||
/* 53 */
|
||||
EXTERN Tcl_Obj * Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
|
||||
/* 54 */
|
||||
EXTERN Tcl_Obj * Tcl_NewLongObj(long longValue);
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
Tcl_Obj * Tcl_NewLongObj(long longValue);
|
||||
/* 55 */
|
||||
EXTERN Tcl_Obj * Tcl_NewObj(void);
|
||||
/* 56 */
|
||||
EXTERN Tcl_Obj * Tcl_NewStringObj(const char *bytes, int length);
|
||||
/* 57 */
|
||||
EXTERN void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue);
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue);
|
||||
/* 58 */
|
||||
EXTERN unsigned char * Tcl_SetByteArrayLength(Tcl_Obj *objPtr, int length);
|
||||
/* 59 */
|
||||
@@ -224,22 +231,26 @@ EXTERN void Tcl_SetByteArrayObj(Tcl_Obj *objPtr,
|
||||
/* 60 */
|
||||
EXTERN void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue);
|
||||
/* 61 */
|
||||
EXTERN void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue);
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue);
|
||||
/* 62 */
|
||||
EXTERN void Tcl_SetListObj(Tcl_Obj *objPtr, int objc,
|
||||
Tcl_Obj *const objv[]);
|
||||
/* 63 */
|
||||
EXTERN void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue);
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue);
|
||||
/* 64 */
|
||||
EXTERN void Tcl_SetObjLength(Tcl_Obj *objPtr, int length);
|
||||
/* 65 */
|
||||
EXTERN void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes,
|
||||
int length);
|
||||
/* 66 */
|
||||
EXTERN void Tcl_AddErrorInfo(Tcl_Interp *interp,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
void Tcl_AddErrorInfo(Tcl_Interp *interp,
|
||||
const char *message);
|
||||
/* 67 */
|
||||
EXTERN void Tcl_AddObjErrorInfo(Tcl_Interp *interp,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
void Tcl_AddObjErrorInfo(Tcl_Interp *interp,
|
||||
const char *message, int length);
|
||||
/* 68 */
|
||||
EXTERN void Tcl_AllowExceptions(Tcl_Interp *interp);
|
||||
@@ -422,7 +433,8 @@ EXTERN int Tcl_Eval(Tcl_Interp *interp, const char *script);
|
||||
EXTERN int Tcl_EvalFile(Tcl_Interp *interp,
|
||||
const char *fileName);
|
||||
/* 131 */
|
||||
EXTERN int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
|
||||
/* 132 */
|
||||
EXTERN void Tcl_EventuallyFree(ClientData clientData,
|
||||
Tcl_FreeProc *freeProc);
|
||||
@@ -549,7 +561,8 @@ EXTERN Tcl_Channel Tcl_GetStdChannel(int type);
|
||||
/* 174 */
|
||||
EXTERN const char * Tcl_GetStringResult(Tcl_Interp *interp);
|
||||
/* 175 */
|
||||
EXTERN const char * Tcl_GetVar(Tcl_Interp *interp, const char *varName,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
const char * Tcl_GetVar(Tcl_Interp *interp, const char *varName,
|
||||
int flags);
|
||||
/* 176 */
|
||||
EXTERN const char * Tcl_GetVar2(Tcl_Interp *interp, const char *part1,
|
||||
@@ -558,7 +571,8 @@ EXTERN const char * Tcl_GetVar2(Tcl_Interp *interp, const char *part1,
|
||||
EXTERN int Tcl_GlobalEval(Tcl_Interp *interp,
|
||||
const char *command);
|
||||
/* 178 */
|
||||
EXTERN int Tcl_GlobalEvalObj(Tcl_Interp *interp,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
int Tcl_GlobalEvalObj(Tcl_Interp *interp,
|
||||
Tcl_Obj *objPtr);
|
||||
/* 179 */
|
||||
EXTERN int Tcl_HideCommand(Tcl_Interp *interp,
|
||||
@@ -713,7 +727,8 @@ EXTERN void Tcl_SetObjResult(Tcl_Interp *interp,
|
||||
/* 236 */
|
||||
EXTERN void Tcl_SetStdChannel(Tcl_Channel channel, int type);
|
||||
/* 237 */
|
||||
EXTERN const char * Tcl_SetVar(Tcl_Interp *interp, const char *varName,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
const char * Tcl_SetVar(Tcl_Interp *interp, const char *varName,
|
||||
const char *newValue, int flags);
|
||||
/* 238 */
|
||||
EXTERN const char * Tcl_SetVar2(Tcl_Interp *interp, const char *part1,
|
||||
@@ -743,7 +758,8 @@ EXTERN int Tcl_StringMatch(const char *str, const char *pattern);
|
||||
TCL_DEPRECATED("")
|
||||
int Tcl_TellOld(Tcl_Channel chan);
|
||||
/* 247 */
|
||||
EXTERN int Tcl_TraceVar(Tcl_Interp *interp, const char *varName,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
int Tcl_TraceVar(Tcl_Interp *interp, const char *varName,
|
||||
int flags, Tcl_VarTraceProc *proc,
|
||||
ClientData clientData);
|
||||
/* 248 */
|
||||
@@ -764,13 +780,15 @@ EXTERN void Tcl_UnlinkVar(Tcl_Interp *interp,
|
||||
EXTERN int Tcl_UnregisterChannel(Tcl_Interp *interp,
|
||||
Tcl_Channel chan);
|
||||
/* 253 */
|
||||
EXTERN int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName,
|
||||
int flags);
|
||||
/* 254 */
|
||||
EXTERN int Tcl_UnsetVar2(Tcl_Interp *interp, const char *part1,
|
||||
const char *part2, int flags);
|
||||
/* 255 */
|
||||
EXTERN void Tcl_UntraceVar(Tcl_Interp *interp,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
void Tcl_UntraceVar(Tcl_Interp *interp,
|
||||
const char *varName, int flags,
|
||||
Tcl_VarTraceProc *proc,
|
||||
ClientData clientData);
|
||||
@@ -783,7 +801,8 @@ EXTERN void Tcl_UntraceVar2(Tcl_Interp *interp,
|
||||
EXTERN void Tcl_UpdateLinkedVar(Tcl_Interp *interp,
|
||||
const char *varName);
|
||||
/* 258 */
|
||||
EXTERN int Tcl_UpVar(Tcl_Interp *interp, const char *frameName,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
int Tcl_UpVar(Tcl_Interp *interp, const char *frameName,
|
||||
const char *varName, const char *localName,
|
||||
int flags);
|
||||
/* 259 */
|
||||
@@ -793,7 +812,8 @@ EXTERN int Tcl_UpVar2(Tcl_Interp *interp, const char *frameName,
|
||||
/* 260 */
|
||||
EXTERN int Tcl_VarEval(Tcl_Interp *interp, ...);
|
||||
/* 261 */
|
||||
EXTERN ClientData Tcl_VarTraceInfo(Tcl_Interp *interp,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
ClientData Tcl_VarTraceInfo(Tcl_Interp *interp,
|
||||
const char *varName, int flags,
|
||||
Tcl_VarTraceProc *procPtr,
|
||||
ClientData prevClientData);
|
||||
@@ -825,17 +845,20 @@ EXTERN char * Tcl_HashStats(Tcl_HashTable *tablePtr);
|
||||
EXTERN const char * Tcl_ParseVar(Tcl_Interp *interp, const char *start,
|
||||
const char **termPtr);
|
||||
/* 271 */
|
||||
EXTERN const char * Tcl_PkgPresent(Tcl_Interp *interp, const char *name,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
const char * Tcl_PkgPresent(Tcl_Interp *interp, const char *name,
|
||||
const char *version, int exact);
|
||||
/* 272 */
|
||||
EXTERN const char * Tcl_PkgPresentEx(Tcl_Interp *interp,
|
||||
const char *name, const char *version,
|
||||
int exact, void *clientDataPtr);
|
||||
/* 273 */
|
||||
EXTERN int Tcl_PkgProvide(Tcl_Interp *interp, const char *name,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
int Tcl_PkgProvide(Tcl_Interp *interp, const char *name,
|
||||
const char *version);
|
||||
/* 274 */
|
||||
EXTERN const char * Tcl_PkgRequire(Tcl_Interp *interp, const char *name,
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
const char * Tcl_PkgRequire(Tcl_Interp *interp, const char *name,
|
||||
const char *version, int exact);
|
||||
/* 275 */
|
||||
TCL_DEPRECATED("see TIP #422")
|
||||
@@ -1125,7 +1148,8 @@ EXTERN int Tcl_GetCharLength(Tcl_Obj *objPtr);
|
||||
/* 381 */
|
||||
EXTERN int Tcl_GetUniChar(Tcl_Obj *objPtr, int index);
|
||||
/* 382 */
|
||||
EXTERN Tcl_UniChar * Tcl_GetUnicode(Tcl_Obj *objPtr);
|
||||
TCL_DEPRECATED("No longer in use, changed to macro")
|
||||
Tcl_UniChar * Tcl_GetUnicode(Tcl_Obj *objPtr);
|
||||
/* 383 */
|
||||
EXTERN Tcl_Obj * Tcl_GetRange(Tcl_Obj *objPtr, int first, int last);
|
||||
/* 384 */
|
||||
@@ -1838,6 +1862,18 @@ EXTERN Tcl_Channel Tcl_OpenTcpServerEx(Tcl_Interp *interp,
|
||||
unsigned int flags,
|
||||
Tcl_TcpAcceptProc *acceptProc,
|
||||
ClientData callbackData);
|
||||
/* 632 */
|
||||
EXTERN int TclZipfs_Mount(Tcl_Interp *interp, const char *mntpt,
|
||||
const char *zipname, const char *passwd);
|
||||
/* 633 */
|
||||
EXTERN int TclZipfs_Unmount(Tcl_Interp *interp,
|
||||
const char *zipname);
|
||||
/* 634 */
|
||||
EXTERN Tcl_Obj * TclZipfs_TclLibrary(void);
|
||||
/* 635 */
|
||||
EXTERN int TclZipfs_Mount_Buffer(Tcl_Interp *interp,
|
||||
const char *mntpt, unsigned char *data,
|
||||
size_t datalen, int copy);
|
||||
|
||||
typedef struct {
|
||||
const struct TclPlatStubs *tclPlatStubs;
|
||||
@@ -1887,11 +1923,11 @@ typedef struct TclStubs {
|
||||
void (*tcl_DbDecrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 19 */
|
||||
void (*tcl_DbIncrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 20 */
|
||||
int (*tcl_DbIsShared) (Tcl_Obj *objPtr, const char *file, int line); /* 21 */
|
||||
Tcl_Obj * (*tcl_DbNewBooleanObj) (int boolValue, const char *file, int line); /* 22 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_DbNewBooleanObj) (int boolValue, const char *file, int line); /* 22 */
|
||||
Tcl_Obj * (*tcl_DbNewByteArrayObj) (const unsigned char *bytes, int length, const char *file, int line); /* 23 */
|
||||
Tcl_Obj * (*tcl_DbNewDoubleObj) (double doubleValue, const char *file, int line); /* 24 */
|
||||
Tcl_Obj * (*tcl_DbNewListObj) (int objc, Tcl_Obj *const *objv, const char *file, int line); /* 25 */
|
||||
Tcl_Obj * (*tcl_DbNewLongObj) (long longValue, const char *file, int line); /* 26 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_DbNewLongObj) (long longValue, const char *file, int line); /* 26 */
|
||||
Tcl_Obj * (*tcl_DbNewObj) (const char *file, int line); /* 27 */
|
||||
Tcl_Obj * (*tcl_DbNewStringObj) (const char *bytes, int length, const char *file, int line); /* 28 */
|
||||
Tcl_Obj * (*tcl_DuplicateObj) (Tcl_Obj *objPtr); /* 29 */
|
||||
@@ -1901,7 +1937,7 @@ typedef struct TclStubs {
|
||||
unsigned char * (*tcl_GetByteArrayFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 33 */
|
||||
int (*tcl_GetDouble) (Tcl_Interp *interp, const char *src, double *doublePtr); /* 34 */
|
||||
int (*tcl_GetDoubleFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr); /* 35 */
|
||||
int (*tcl_GetIndexFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *const *tablePtr, const char *msg, int flags, int *indexPtr); /* 36 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_GetIndexFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *const *tablePtr, const char *msg, int flags, int *indexPtr); /* 36 */
|
||||
int (*tcl_GetInt) (Tcl_Interp *interp, const char *src, int *intPtr); /* 37 */
|
||||
int (*tcl_GetIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 38 */
|
||||
int (*tcl_GetLongFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr); /* 39 */
|
||||
@@ -1914,25 +1950,25 @@ typedef struct TclStubs {
|
||||
int (*tcl_ListObjIndex) (Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj **objPtrPtr); /* 46 */
|
||||
int (*tcl_ListObjLength) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr); /* 47 */
|
||||
int (*tcl_ListObjReplace) (Tcl_Interp *interp, Tcl_Obj *listPtr, int first, int count, int objc, Tcl_Obj *const objv[]); /* 48 */
|
||||
Tcl_Obj * (*tcl_NewBooleanObj) (int boolValue); /* 49 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_NewBooleanObj) (int boolValue); /* 49 */
|
||||
Tcl_Obj * (*tcl_NewByteArrayObj) (const unsigned char *bytes, int length); /* 50 */
|
||||
Tcl_Obj * (*tcl_NewDoubleObj) (double doubleValue); /* 51 */
|
||||
Tcl_Obj * (*tcl_NewIntObj) (int intValue); /* 52 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_NewIntObj) (int intValue); /* 52 */
|
||||
Tcl_Obj * (*tcl_NewListObj) (int objc, Tcl_Obj *const objv[]); /* 53 */
|
||||
Tcl_Obj * (*tcl_NewLongObj) (long longValue); /* 54 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_NewLongObj) (long longValue); /* 54 */
|
||||
Tcl_Obj * (*tcl_NewObj) (void); /* 55 */
|
||||
Tcl_Obj * (*tcl_NewStringObj) (const char *bytes, int length); /* 56 */
|
||||
void (*tcl_SetBooleanObj) (Tcl_Obj *objPtr, int boolValue); /* 57 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_SetBooleanObj) (Tcl_Obj *objPtr, int boolValue); /* 57 */
|
||||
unsigned char * (*tcl_SetByteArrayLength) (Tcl_Obj *objPtr, int length); /* 58 */
|
||||
void (*tcl_SetByteArrayObj) (Tcl_Obj *objPtr, const unsigned char *bytes, int length); /* 59 */
|
||||
void (*tcl_SetDoubleObj) (Tcl_Obj *objPtr, double doubleValue); /* 60 */
|
||||
void (*tcl_SetIntObj) (Tcl_Obj *objPtr, int intValue); /* 61 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_SetIntObj) (Tcl_Obj *objPtr, int intValue); /* 61 */
|
||||
void (*tcl_SetListObj) (Tcl_Obj *objPtr, int objc, Tcl_Obj *const objv[]); /* 62 */
|
||||
void (*tcl_SetLongObj) (Tcl_Obj *objPtr, long longValue); /* 63 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_SetLongObj) (Tcl_Obj *objPtr, long longValue); /* 63 */
|
||||
void (*tcl_SetObjLength) (Tcl_Obj *objPtr, int length); /* 64 */
|
||||
void (*tcl_SetStringObj) (Tcl_Obj *objPtr, const char *bytes, int length); /* 65 */
|
||||
void (*tcl_AddErrorInfo) (Tcl_Interp *interp, const char *message); /* 66 */
|
||||
void (*tcl_AddObjErrorInfo) (Tcl_Interp *interp, const char *message, int length); /* 67 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_AddErrorInfo) (Tcl_Interp *interp, const char *message); /* 66 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_AddObjErrorInfo) (Tcl_Interp *interp, const char *message, int length); /* 67 */
|
||||
void (*tcl_AllowExceptions) (Tcl_Interp *interp); /* 68 */
|
||||
void (*tcl_AppendElement) (Tcl_Interp *interp, const char *element); /* 69 */
|
||||
void (*tcl_AppendResult) (Tcl_Interp *interp, ...); /* 70 */
|
||||
@@ -1996,7 +2032,7 @@ typedef struct TclStubs {
|
||||
const char * (*tcl_ErrnoMsg) (int err); /* 128 */
|
||||
int (*tcl_Eval) (Tcl_Interp *interp, const char *script); /* 129 */
|
||||
int (*tcl_EvalFile) (Tcl_Interp *interp, const char *fileName); /* 130 */
|
||||
int (*tcl_EvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 131 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_EvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 131 */
|
||||
void (*tcl_EventuallyFree) (ClientData clientData, Tcl_FreeProc *freeProc); /* 132 */
|
||||
TCL_NORETURN1 void (*tcl_Exit) (int status); /* 133 */
|
||||
int (*tcl_ExposeCommand) (Tcl_Interp *interp, const char *hiddenCmdToken, const char *cmdName); /* 134 */
|
||||
@@ -2048,10 +2084,10 @@ typedef struct TclStubs {
|
||||
Tcl_Interp * (*tcl_GetSlave) (Tcl_Interp *interp, const char *slaveName); /* 172 */
|
||||
Tcl_Channel (*tcl_GetStdChannel) (int type); /* 173 */
|
||||
const char * (*tcl_GetStringResult) (Tcl_Interp *interp); /* 174 */
|
||||
const char * (*tcl_GetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 175 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_GetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 175 */
|
||||
const char * (*tcl_GetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 176 */
|
||||
int (*tcl_GlobalEval) (Tcl_Interp *interp, const char *command); /* 177 */
|
||||
int (*tcl_GlobalEvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 178 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_GlobalEvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 178 */
|
||||
int (*tcl_HideCommand) (Tcl_Interp *interp, const char *cmdName, const char *hiddenCmdToken); /* 179 */
|
||||
int (*tcl_Init) (Tcl_Interp *interp); /* 180 */
|
||||
void (*tcl_InitHashTable) (Tcl_HashTable *tablePtr, int keyType); /* 181 */
|
||||
@@ -2110,7 +2146,7 @@ typedef struct TclStubs {
|
||||
void (*tcl_SetObjErrorCode) (Tcl_Interp *interp, Tcl_Obj *errorObjPtr); /* 234 */
|
||||
void (*tcl_SetObjResult) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr); /* 235 */
|
||||
void (*tcl_SetStdChannel) (Tcl_Channel channel, int type); /* 236 */
|
||||
const char * (*tcl_SetVar) (Tcl_Interp *interp, const char *varName, const char *newValue, int flags); /* 237 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_SetVar) (Tcl_Interp *interp, const char *varName, const char *newValue, int flags); /* 237 */
|
||||
const char * (*tcl_SetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, const char *newValue, int flags); /* 238 */
|
||||
const char * (*tcl_SignalId) (int sig); /* 239 */
|
||||
const char * (*tcl_SignalMsg) (int sig); /* 240 */
|
||||
@@ -2120,21 +2156,21 @@ typedef struct TclStubs {
|
||||
void (*tcl_StaticPackage) (Tcl_Interp *interp, const char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc); /* 244 */
|
||||
int (*tcl_StringMatch) (const char *str, const char *pattern); /* 245 */
|
||||
TCL_DEPRECATED_API("") int (*tcl_TellOld) (Tcl_Channel chan); /* 246 */
|
||||
int (*tcl_TraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 247 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_TraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 247 */
|
||||
int (*tcl_TraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 248 */
|
||||
char * (*tcl_TranslateFileName) (Tcl_Interp *interp, const char *name, Tcl_DString *bufferPtr); /* 249 */
|
||||
int (*tcl_Ungets) (Tcl_Channel chan, const char *str, int len, int atHead); /* 250 */
|
||||
void (*tcl_UnlinkVar) (Tcl_Interp *interp, const char *varName); /* 251 */
|
||||
int (*tcl_UnregisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 252 */
|
||||
int (*tcl_UnsetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 253 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_UnsetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 253 */
|
||||
int (*tcl_UnsetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 254 */
|
||||
void (*tcl_UntraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 255 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_UntraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 255 */
|
||||
void (*tcl_UntraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 256 */
|
||||
void (*tcl_UpdateLinkedVar) (Tcl_Interp *interp, const char *varName); /* 257 */
|
||||
int (*tcl_UpVar) (Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags); /* 258 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_UpVar) (Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags); /* 258 */
|
||||
int (*tcl_UpVar2) (Tcl_Interp *interp, const char *frameName, const char *part1, const char *part2, const char *localName, int flags); /* 259 */
|
||||
int (*tcl_VarEval) (Tcl_Interp *interp, ...); /* 260 */
|
||||
ClientData (*tcl_VarTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 261 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") ClientData (*tcl_VarTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 261 */
|
||||
ClientData (*tcl_VarTraceInfo2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 262 */
|
||||
int (*tcl_Write) (Tcl_Channel chan, const char *s, int slen); /* 263 */
|
||||
void (*tcl_WrongNumArgs) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *message); /* 264 */
|
||||
@@ -2144,10 +2180,10 @@ typedef struct TclStubs {
|
||||
TCL_DEPRECATED_API("see TIP #422") void (*tcl_AppendStringsToObjVA) (Tcl_Obj *objPtr, va_list argList); /* 268 */
|
||||
char * (*tcl_HashStats) (Tcl_HashTable *tablePtr); /* 269 */
|
||||
const char * (*tcl_ParseVar) (Tcl_Interp *interp, const char *start, const char **termPtr); /* 270 */
|
||||
const char * (*tcl_PkgPresent) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 271 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_PkgPresent) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 271 */
|
||||
const char * (*tcl_PkgPresentEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 272 */
|
||||
int (*tcl_PkgProvide) (Tcl_Interp *interp, const char *name, const char *version); /* 273 */
|
||||
const char * (*tcl_PkgRequire) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 274 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_PkgProvide) (Tcl_Interp *interp, const char *name, const char *version); /* 273 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_PkgRequire) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 274 */
|
||||
TCL_DEPRECATED_API("see TIP #422") void (*tcl_SetErrorCodeVA) (Tcl_Interp *interp, va_list argList); /* 275 */
|
||||
TCL_DEPRECATED_API("see TIP #422") int (*tcl_VarEvalVA) (Tcl_Interp *interp, va_list argList); /* 276 */
|
||||
Tcl_Pid (*tcl_WaitPid) (Tcl_Pid pid, int *statPtr, int options); /* 277 */
|
||||
@@ -2255,7 +2291,7 @@ typedef struct TclStubs {
|
||||
void (*tcl_SetUnicodeObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int numChars); /* 379 */
|
||||
int (*tcl_GetCharLength) (Tcl_Obj *objPtr); /* 380 */
|
||||
int (*tcl_GetUniChar) (Tcl_Obj *objPtr, int index); /* 381 */
|
||||
Tcl_UniChar * (*tcl_GetUnicode) (Tcl_Obj *objPtr); /* 382 */
|
||||
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_UniChar * (*tcl_GetUnicode) (Tcl_Obj *objPtr); /* 382 */
|
||||
Tcl_Obj * (*tcl_GetRange) (Tcl_Obj *objPtr, int first, int last); /* 383 */
|
||||
void (*tcl_AppendUnicodeToObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int length); /* 384 */
|
||||
int (*tcl_RegExpMatchObj) (Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj); /* 385 */
|
||||
@@ -2505,6 +2541,10 @@ typedef struct TclStubs {
|
||||
int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */
|
||||
void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */
|
||||
Tcl_Channel (*tcl_OpenTcpServerEx) (Tcl_Interp *interp, const char *service, const char *host, unsigned int flags, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData); /* 631 */
|
||||
int (*tclZipfs_Mount) (Tcl_Interp *interp, const char *mntpt, const char *zipname, const char *passwd); /* 632 */
|
||||
int (*tclZipfs_Unmount) (Tcl_Interp *interp, const char *zipname); /* 633 */
|
||||
Tcl_Obj * (*tclZipfs_TclLibrary) (void); /* 634 */
|
||||
int (*tclZipfs_Mount_Buffer) (Tcl_Interp *interp, const char *mntpt, unsigned char *data, size_t datalen, int copy); /* 635 */
|
||||
} TclStubs;
|
||||
|
||||
extern const TclStubs *tclStubsPtr;
|
||||
@@ -3799,6 +3839,14 @@ extern const TclStubs *tclStubsPtr;
|
||||
(tclStubsPtr->tcl_ZlibStreamSetCompressionDictionary) /* 630 */
|
||||
#define Tcl_OpenTcpServerEx \
|
||||
(tclStubsPtr->tcl_OpenTcpServerEx) /* 631 */
|
||||
#define TclZipfs_Mount \
|
||||
(tclStubsPtr->tclZipfs_Mount) /* 632 */
|
||||
#define TclZipfs_Unmount \
|
||||
(tclStubsPtr->tclZipfs_Unmount) /* 633 */
|
||||
#define TclZipfs_TclLibrary \
|
||||
(tclStubsPtr->tclZipfs_TclLibrary) /* 634 */
|
||||
#define TclZipfs_Mount_Buffer \
|
||||
(tclStubsPtr->tclZipfs_Mount_Buffer) /* 635 */
|
||||
|
||||
#endif /* defined(USE_TCL_STUBS) */
|
||||
|
||||
@@ -3810,15 +3858,12 @@ extern const TclStubs *tclStubsPtr;
|
||||
# undef Tcl_GetStringResult
|
||||
# undef Tcl_Init
|
||||
# undef Tcl_SetPanicProc
|
||||
# undef Tcl_SetVar
|
||||
# undef Tcl_ObjSetVar2
|
||||
# undef Tcl_StaticPackage
|
||||
# define Tcl_CreateInterp() (tclStubsPtr->tcl_CreateInterp())
|
||||
# define Tcl_GetStringResult(interp) (tclStubsPtr->tcl_GetStringResult(interp))
|
||||
# define Tcl_Init(interp) (tclStubsPtr->tcl_Init(interp))
|
||||
# define Tcl_SetPanicProc(proc) (tclStubsPtr->tcl_SetPanicProc(proc))
|
||||
# define Tcl_SetVar(interp, varName, newValue, flags) \
|
||||
(tclStubsPtr->tcl_SetVar(interp, varName, newValue, flags))
|
||||
# define Tcl_ObjSetVar2(interp, part1, part2, newValue, flags) \
|
||||
(tclStubsPtr->tcl_ObjSetVar2(interp, part1, part2, newValue, flags))
|
||||
#endif
|
||||
@@ -3974,9 +4019,11 @@ extern const TclStubs *tclStubsPtr;
|
||||
#undef Tcl_DbNewLongObj
|
||||
#define Tcl_DbNewLongObj(value, file, line) Tcl_DbNewWideIntObj((long)(value), file, line)
|
||||
#undef Tcl_SetIntObj
|
||||
#define Tcl_SetIntObj(objPtr, value) Tcl_SetWideIntObj(objPtr, (int)(value))
|
||||
#define Tcl_SetIntObj(objPtr, value) Tcl_SetWideIntObj((objPtr), (int)(value))
|
||||
#undef Tcl_SetLongObj
|
||||
#define Tcl_SetLongObj(objPtr, value) Tcl_SetWideIntObj(objPtr, (long)(value))
|
||||
#define Tcl_SetLongObj(objPtr, value) Tcl_SetWideIntObj((objPtr), (long)(value))
|
||||
#undef Tcl_GetUnicode
|
||||
#define Tcl_GetUnicode(objPtr) Tcl_GetUnicodeFromObj((objPtr), NULL)
|
||||
|
||||
/*
|
||||
* Deprecated Tcl procedures:
|
||||
|
||||
@@ -153,7 +153,7 @@ typedef struct Dict {
|
||||
* must be assignable as well as readable.
|
||||
*/
|
||||
|
||||
#define DICT(dictObj) (*((Dict **)&(dictObj)->internalRep.twoPtrValue.ptr1))
|
||||
#define DICT(dictObj) ((dictObj)->internalRep.twoPtrValue.ptr1)
|
||||
|
||||
/*
|
||||
* The structure below defines the dictionary object type by means of
|
||||
|
||||
@@ -894,7 +894,7 @@ PrintSourceToObj(
|
||||
Tcl_AppendPrintfToObj(appendObj, "\\U%08x", ch);
|
||||
i += 10;
|
||||
} else
|
||||
#elif TCL_UTF_MAX > 3
|
||||
#else
|
||||
/* If len == 0, this means we have a char > 0xffff, resulting in
|
||||
* TclUtfToUniChar producing a surrogate pair. We want to output
|
||||
* this pair as a single Unicode character.
|
||||
|
||||
+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);
|
||||
|
||||
+12
-1
@@ -723,14 +723,25 @@ TclFinalizeEnvironment(void)
|
||||
* strings. This may leak more memory that strictly necessary, since some
|
||||
* of the strings may no longer be in the environment. However,
|
||||
* determining which ones are ok to delete is n-squared, and is pretty
|
||||
* unlikely, so we don't bother.
|
||||
* unlikely, so we don't bother. However, in the case of DPURIFY, just
|
||||
* free all strings in the cache.
|
||||
*/
|
||||
|
||||
if (env.cache) {
|
||||
#ifdef PURIFY
|
||||
int i;
|
||||
for (i = 0; i < env.cacheSize; i++) {
|
||||
ckfree(env.cache[i]);
|
||||
}
|
||||
#endif
|
||||
ckfree(env.cache);
|
||||
env.cache = NULL;
|
||||
env.cacheSize = 0;
|
||||
#ifndef USE_PUTENV
|
||||
if ((env.ourEnviron != NULL)) {
|
||||
ckfree(env.ourEnviron);
|
||||
env.ourEnviron = NULL;
|
||||
}
|
||||
env.ourEnvironSize = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
+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;
|
||||
|
||||
|
||||
+36
-100
@@ -4964,7 +4964,7 @@ TEBCresume(
|
||||
|
||||
/* Decode index value operands. */
|
||||
|
||||
/*
|
||||
/*
|
||||
assert ( toIdx != TCL_INDEX_AFTER);
|
||||
*
|
||||
* Extra safety for legacy bytecodes:
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5301,9 +5223,15 @@ TEBCresume(
|
||||
* but creating the object as a string seems to be faster in
|
||||
* practical use.
|
||||
*/
|
||||
|
||||
length = (ch != -1) ? Tcl_UniCharToUtf(ch, buf) : 0;
|
||||
objResultPtr = Tcl_NewStringObj(buf, length);
|
||||
if (ch == -1) {
|
||||
objResultPtr = Tcl_NewObj();
|
||||
} else {
|
||||
length = Tcl_UniCharToUtf(ch, buf);
|
||||
if (!length) {
|
||||
length = Tcl_UniCharToUtf(-1, buf);
|
||||
}
|
||||
objResultPtr = Tcl_NewStringObj(buf, length);
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_APPEND(("\"%s\"\n", O2S(objResultPtr)));
|
||||
@@ -5707,17 +5635,17 @@ TEBCresume(
|
||||
if (GetNumberFromObj(NULL, OBJ_AT_TOS, &ptr1, &type1) != TCL_OK) {
|
||||
type1 = 0;
|
||||
} else if (type1 == TCL_NUMBER_WIDE) {
|
||||
/* value is between LLONG_MIN and LLONG_MAX */
|
||||
/* value is between WIDE_MIN and WIDE_MAX */
|
||||
/* [string is integer] is -UINT_MAX to UINT_MAX range */
|
||||
/* [string is wideinteger] is -ULLONG_MAX to ULLONG_MAX range */
|
||||
/* [string is wideinteger] is -UWIDE_MAX to UWIDE_MAX range */
|
||||
int i;
|
||||
|
||||
if (Tcl_GetIntFromObj(NULL, OBJ_AT_TOS, &i) == TCL_OK) {
|
||||
type1 = TCL_NUMBER_LONG;
|
||||
}
|
||||
} else if (type1 == TCL_NUMBER_BIG) {
|
||||
/* value is an integer outside the LLONG_MIN to LLONG_MAX range */
|
||||
/* [string is wideinteger] is -ULLONG_MAX to ULLONG_MAX range */
|
||||
/* value is an integer outside the WIDE_MIN to WIDE_MAX range */
|
||||
/* [string is wideinteger] is -UWIDE_MAX to UWIDE_MAX range */
|
||||
Tcl_WideInt w;
|
||||
|
||||
if (Tcl_GetWideIntFromObj(NULL, OBJ_AT_TOS, &w) == TCL_OK) {
|
||||
@@ -5739,6 +5667,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) {
|
||||
/*
|
||||
@@ -6125,9 +6061,9 @@ TEBCresume(
|
||||
TRACE(("%s %s => DIVIDE BY ZERO\n",
|
||||
O2S(valuePtr), O2S(value2Ptr)));
|
||||
goto divideByZero;
|
||||
} else if ((w1 == LLONG_MIN) && (w2 == -1)) {
|
||||
} else if ((w1 == WIDE_MIN) && (w2 == -1)) {
|
||||
/*
|
||||
* Can't represent (-LLONG_MIN) as a Tcl_WideInt.
|
||||
* Can't represent (-WIDE_MIN) as a Tcl_WideInt.
|
||||
*/
|
||||
|
||||
goto overflow;
|
||||
@@ -6260,7 +6196,7 @@ TEBCresume(
|
||||
NEXT_INST_F(1, 0, 0);
|
||||
case TCL_NUMBER_WIDE:
|
||||
w1 = *((const Tcl_WideInt *) ptr1);
|
||||
if (w1 != LLONG_MIN) {
|
||||
if (w1 != WIDE_MIN) {
|
||||
if (Tcl_IsShared(valuePtr)) {
|
||||
TclNewIntObj(objResultPtr, -w1);
|
||||
TRACE_APPEND(("%s\n", O2S(objResultPtr)));
|
||||
@@ -8734,10 +8670,10 @@ ExecuteExtendedBinaryMathOp(
|
||||
}
|
||||
|
||||
/*
|
||||
* Need a bignum to represent (LLONG_MIN / -1)
|
||||
* Need a bignum to represent (WIDE_MIN / -1)
|
||||
*/
|
||||
|
||||
if ((w1 == LLONG_MIN) && (w2 == -1)) {
|
||||
if ((w1 == WIDE_MIN) && (w2 == -1)) {
|
||||
goto overflowBasic;
|
||||
}
|
||||
wResult = w1 / w2;
|
||||
@@ -8840,7 +8776,7 @@ ExecuteExtendedUnaryMathOp(
|
||||
DOUBLE_RESULT(-(*((const double *) ptr)));
|
||||
case TCL_NUMBER_WIDE:
|
||||
w = *((const Tcl_WideInt *) ptr);
|
||||
if (w != LLONG_MIN) {
|
||||
if (w != WIDE_MIN) {
|
||||
WIDE_RESULT(-w);
|
||||
}
|
||||
TclInitBignumFromWideInt(&big, w);
|
||||
@@ -8926,10 +8862,10 @@ TclCompareTwoNumbers(
|
||||
* integer comparison can tell the difference.
|
||||
*/
|
||||
|
||||
if (d2 < (double)LLONG_MIN) {
|
||||
if (d2 < (double)WIDE_MIN) {
|
||||
return MP_GT;
|
||||
}
|
||||
if (d2 > (double)LLONG_MAX) {
|
||||
if (d2 > (double)WIDE_MAX) {
|
||||
return MP_LT;
|
||||
}
|
||||
w2 = (Tcl_WideInt) d2;
|
||||
@@ -8959,10 +8895,10 @@ TclCompareTwoNumbers(
|
||||
|| w2 == (Tcl_WideInt) d2 || modf(d1, &tmp) != 0.0) {
|
||||
goto doubleCompare;
|
||||
}
|
||||
if (d1 < (double)LLONG_MIN) {
|
||||
if (d1 < (double)WIDE_MIN) {
|
||||
return MP_LT;
|
||||
}
|
||||
if (d1 > (double)LLONG_MAX) {
|
||||
if (d1 > (double)WIDE_MAX) {
|
||||
return MP_GT;
|
||||
}
|
||||
w1 = (Tcl_WideInt) d1;
|
||||
@@ -8972,7 +8908,7 @@ TclCompareTwoNumbers(
|
||||
return (d1 > 0.0) ? MP_GT : MP_LT;
|
||||
}
|
||||
Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
|
||||
if ((d1 < (double)LLONG_MAX) && (d1 > (double)LLONG_MIN)) {
|
||||
if ((d1 < (double)WIDE_MAX) && (d1 > (double)WIDE_MIN)) {
|
||||
if (mp_isneg(&big2)) {
|
||||
compare = MP_GT;
|
||||
} else {
|
||||
@@ -9005,7 +8941,7 @@ TclCompareTwoNumbers(
|
||||
mp_clear(&big1);
|
||||
return compare;
|
||||
}
|
||||
if ((d2 < (double)LLONG_MAX) && (d2 > (double)LLONG_MIN)) {
|
||||
if ((d2 < (double)WIDE_MAX) && (d2 > (double)WIDE_MIN)) {
|
||||
compare = mp_cmp_d(&big1, 0);
|
||||
mp_clear(&big1);
|
||||
return compare;
|
||||
|
||||
+20
-14
@@ -240,9 +240,13 @@ TclFileMakeDirsCmd(
|
||||
break;
|
||||
}
|
||||
for (j = 0; j < pobjc; j++) {
|
||||
int errCount = 2;
|
||||
|
||||
target = Tcl_FSJoinPath(split, j + 1);
|
||||
Tcl_IncrRefCount(target);
|
||||
|
||||
createDir:
|
||||
|
||||
/*
|
||||
* Call Tcl_FSStat() so that if target is a symlink that points to
|
||||
* a directory we will create subdirectories in that directory.
|
||||
@@ -269,23 +273,25 @@ TclFileMakeDirsCmd(
|
||||
* subdirectory.
|
||||
*/
|
||||
|
||||
if (errno != EEXIST) {
|
||||
errfile = target;
|
||||
goto done;
|
||||
} else if ((Tcl_FSStat(target, &statBuf) == 0)
|
||||
&& S_ISDIR(statBuf.st_mode)) {
|
||||
/*
|
||||
* It is a directory that wasn't there before, so keep
|
||||
* going without error.
|
||||
*/
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
} else {
|
||||
errfile = target;
|
||||
goto done;
|
||||
if (errno == EEXIST) {
|
||||
/* Be aware other workers could delete it immediately after
|
||||
* creation, so give this worker still one chance (repeat once),
|
||||
* see [270f78ca95] for description of the race-condition.
|
||||
* Don't repeat the create always (to avoid endless loop). */
|
||||
if (--errCount > 0) {
|
||||
goto createDir;
|
||||
}
|
||||
/* Already tried, with delete in-between directly after
|
||||
* creation, so just continue (assume created successful). */
|
||||
goto nextPart;
|
||||
}
|
||||
|
||||
/* return with error */
|
||||
errfile = target;
|
||||
goto done;
|
||||
}
|
||||
|
||||
nextPart:
|
||||
/*
|
||||
* Forget about this sub-path.
|
||||
*/
|
||||
|
||||
@@ -1881,7 +1881,7 @@ TclGlob(
|
||||
separators = "/\\";
|
||||
|
||||
} else if (tclPlatform == TCL_PLATFORM_UNIX) {
|
||||
if (pathPrefix == NULL && tail[0] == '/') {
|
||||
if (pathPrefix == NULL && tail[0] == '/' && tail[1] != '/') {
|
||||
pathPrefix = Tcl_NewStringObj(tail, 1);
|
||||
tail++;
|
||||
Tcl_IncrRefCount(pathPrefix);
|
||||
|
||||
+17
-17
@@ -482,13 +482,13 @@ ChanSeek(
|
||||
offset, mode, errnoPtr);
|
||||
}
|
||||
|
||||
if (offset<Tcl_LongAsWide(LONG_MIN) || offset>Tcl_LongAsWide(LONG_MAX)) {
|
||||
if (offset<LONG_MIN || offset>LONG_MAX) {
|
||||
*errnoPtr = EOVERFLOW;
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Tcl_LongAsWide(chanPtr->typePtr->seekProc(chanPtr->instanceData,
|
||||
Tcl_WideAsLong(offset), mode, errnoPtr));
|
||||
return chanPtr->typePtr->seekProc(chanPtr->instanceData,
|
||||
offset, mode, errnoPtr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -6953,7 +6953,7 @@ Tcl_Seek(
|
||||
* non-blocking mode after the seek. */
|
||||
|
||||
if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) {
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -6964,7 +6964,7 @@ Tcl_Seek(
|
||||
*/
|
||||
|
||||
if (CheckForDeadChannel(NULL, statePtr)) {
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -6980,7 +6980,7 @@ Tcl_Seek(
|
||||
|
||||
if (chanPtr->typePtr->seekProc == NULL) {
|
||||
Tcl_SetErrno(EINVAL);
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -6993,7 +6993,7 @@ Tcl_Seek(
|
||||
|
||||
if ((inputBuffered != 0) && (outputBuffered != 0)) {
|
||||
Tcl_SetErrno(EFAULT);
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7036,7 +7036,7 @@ Tcl_Seek(
|
||||
wasAsync = 1;
|
||||
result = StackSetBlockMode(chanPtr, TCL_MODE_BLOCKING);
|
||||
if (result != 0) {
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
ResetFlag(statePtr, CHANNEL_NONBLOCKING);
|
||||
if (GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
|
||||
@@ -7061,7 +7061,7 @@ Tcl_Seek(
|
||||
*/
|
||||
|
||||
curPos = ChanSeek(chanPtr, offset, mode, &result);
|
||||
if (curPos == Tcl_LongAsWide(-1)) {
|
||||
if (curPos == -1) {
|
||||
Tcl_SetErrno(result);
|
||||
}
|
||||
}
|
||||
@@ -7077,7 +7077,7 @@ Tcl_Seek(
|
||||
SetFlag(statePtr, CHANNEL_NONBLOCKING);
|
||||
result = StackSetBlockMode(chanPtr, TCL_MODE_NONBLOCKING);
|
||||
if (result != 0) {
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7117,7 +7117,7 @@ Tcl_Tell(
|
||||
Tcl_WideInt curPos; /* Position on device. */
|
||||
|
||||
if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) {
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7128,7 +7128,7 @@ Tcl_Tell(
|
||||
*/
|
||||
|
||||
if (CheckForDeadChannel(NULL, statePtr)) {
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7144,7 +7144,7 @@ Tcl_Tell(
|
||||
|
||||
if (chanPtr->typePtr->seekProc == NULL) {
|
||||
Tcl_SetErrno(EINVAL);
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7161,10 +7161,10 @@ Tcl_Tell(
|
||||
* wideSeekProc if that is available and non-NULL...
|
||||
*/
|
||||
|
||||
curPos = ChanSeek(chanPtr, Tcl_LongAsWide(0), SEEK_CUR, &result);
|
||||
if (curPos == Tcl_LongAsWide(-1)) {
|
||||
curPos = ChanSeek(chanPtr, 0, SEEK_CUR, &result);
|
||||
if (curPos == -1) {
|
||||
Tcl_SetErrno(result);
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inputBuffered != 0) {
|
||||
|
||||
+2
-2
@@ -559,7 +559,7 @@ Tcl_SeekObjCmd(
|
||||
|
||||
TclChannelPreserve(chan);
|
||||
result = Tcl_Seek(chan, offset, mode);
|
||||
if (result == Tcl_LongAsWide(-1)) {
|
||||
if (result == -1) {
|
||||
/*
|
||||
* TIP #219.
|
||||
* Capture error messages put by the driver into the bypass area and
|
||||
@@ -1913,7 +1913,7 @@ ChanTruncateObjCmd(
|
||||
*/
|
||||
|
||||
length = Tcl_Tell(chan);
|
||||
if (length == Tcl_WideAsLong(-1)) {
|
||||
if (length == -1) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"could not determine current location in \"%s\": %s",
|
||||
TclGetString(objv[1]), Tcl_PosixError(interp)));
|
||||
|
||||
+6
-7
@@ -910,7 +910,7 @@ TransformWideSeekProc(
|
||||
Tcl_ChannelWideSeekProc(parentType);
|
||||
ClientData parentData = Tcl_GetChannelInstanceData(parent);
|
||||
|
||||
if ((offset == Tcl_LongAsWide(0)) && (mode == SEEK_CUR)) {
|
||||
if ((offset == 0) && (mode == SEEK_CUR)) {
|
||||
/*
|
||||
* This is no seek but a request to tell the caller the current
|
||||
* location. Simply pass the request down.
|
||||
@@ -920,8 +920,7 @@ TransformWideSeekProc(
|
||||
return parentWideSeekProc(parentData, offset, mode, errorCodePtr);
|
||||
}
|
||||
|
||||
return Tcl_LongAsWide(parentSeekProc(parentData, 0, mode,
|
||||
errorCodePtr));
|
||||
return parentSeekProc(parentData, 0, mode, errorCodePtr);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -961,13 +960,13 @@ TransformWideSeekProc(
|
||||
* to go out of the representable range.
|
||||
*/
|
||||
|
||||
if (offset<Tcl_LongAsWide(LONG_MIN) || offset>Tcl_LongAsWide(LONG_MAX)) {
|
||||
if (offset<LONG_MIN || offset>LONG_MAX) {
|
||||
*errorCodePtr = EOVERFLOW;
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Tcl_LongAsWide(parentSeekProc(parentData, Tcl_WideAsLong(offset),
|
||||
mode, errorCodePtr));
|
||||
return parentSeekProc(parentData, offset,
|
||||
mode, errorCodePtr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+27
-27
@@ -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;
|
||||
|
||||
@@ -1544,7 +1544,7 @@ ReflectSeekWide(
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (newLoc < Tcl_LongAsWide(0)) {
|
||||
if (newLoc < 0) {
|
||||
SetChannelErrorStr(rcPtr->chan, msg_seek_beforestart);
|
||||
goto invalid;
|
||||
}
|
||||
@@ -1576,7 +1576,7 @@ ReflectSeek(
|
||||
* routine.
|
||||
*/
|
||||
|
||||
return (int) ReflectSeekWide(clientData, Tcl_LongAsWide(offset), seekMode,
|
||||
return ReflectSeekWide(clientData, offset, seekMode,
|
||||
errorCodePtr);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -3079,7 +3079,7 @@ ForwardProc(
|
||||
Tcl_WideInt newLoc;
|
||||
|
||||
if (Tcl_GetWideIntFromObj(interp, resObj, &newLoc) == TCL_OK) {
|
||||
if (newLoc < Tcl_LongAsWide(0)) {
|
||||
if (newLoc < 0) {
|
||||
ForwardSetStaticError(paramPtr, msg_seek_beforestart);
|
||||
paramPtr->seek.offset = -1;
|
||||
} else {
|
||||
|
||||
+27
-28
@@ -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) {
|
||||
@@ -1340,7 +1340,7 @@ ReflectSeekWide(
|
||||
|
||||
if (seekProc == NULL) {
|
||||
Tcl_SetErrno(EINVAL);
|
||||
return Tcl_LongAsWide(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1390,16 +1390,15 @@ ReflectSeekWide(
|
||||
parent->typePtr->wideSeekProc != NULL) {
|
||||
curPos = parent->typePtr->wideSeekProc(parent->instanceData, offset,
|
||||
seekMode, errorCodePtr);
|
||||
} else if (offset < Tcl_LongAsWide(LONG_MIN) ||
|
||||
offset > Tcl_LongAsWide(LONG_MAX)) {
|
||||
} else if (offset < LONG_MIN || offset > LONG_MAX) {
|
||||
*errorCodePtr = EOVERFLOW;
|
||||
curPos = Tcl_LongAsWide(-1);
|
||||
curPos = -1;
|
||||
} else {
|
||||
curPos = Tcl_LongAsWide(parent->typePtr->seekProc(
|
||||
parent->instanceData, Tcl_WideAsLong(offset), seekMode,
|
||||
errorCodePtr));
|
||||
curPos = parent->typePtr->seekProc(
|
||||
parent->instanceData, offset, seekMode,
|
||||
errorCodePtr);
|
||||
}
|
||||
if (curPos == Tcl_LongAsWide(-1)) {
|
||||
if (curPos == -1) {
|
||||
Tcl_SetErrno(*errorCodePtr);
|
||||
}
|
||||
|
||||
@@ -1422,7 +1421,7 @@ ReflectSeek(
|
||||
* routine.
|
||||
*/
|
||||
|
||||
return (int) ReflectSeekWide(clientData, Tcl_LongAsWide(offset), seekMode,
|
||||
return ReflectSeekWide(clientData, offset, seekMode,
|
||||
errorCodePtr);
|
||||
}
|
||||
|
||||
@@ -1767,7 +1766,7 @@ NewReflectedTransform(
|
||||
|
||||
rtPtr->chan = NULL;
|
||||
rtPtr->methods = 0;
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
rtPtr->thread = Tcl_GetCurrentThread();
|
||||
#endif
|
||||
rtPtr->parent = parentChan;
|
||||
@@ -2152,7 +2151,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 +2181,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 +2253,7 @@ DeleteReflectedTransformMap(
|
||||
#endif /* TCL_THREADS */
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -3088,7 +3087,7 @@ TransformRead(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -3144,7 +3143,7 @@ TransformWrite(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -3210,7 +3209,7 @@ TransformDrain(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -3260,7 +3259,7 @@ TransformFlush(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -3315,7 +3314,7 @@ TransformClear(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
@@ -3347,7 +3346,7 @@ TransformLimit(
|
||||
* Are we in the correct thread?
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
if (rtPtr->thread != Tcl_GetCurrentThread()) {
|
||||
ForwardParam p;
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "tclInt.h"
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
#if defined(_WIN32)
|
||||
/*
|
||||
* On Windows, we need to do proper Unicode->UTF-8 conversion.
|
||||
*/
|
||||
|
||||
+55
-45
@@ -139,7 +139,6 @@ Tcl_FSRenameFileProc TclpObjRenameFile;
|
||||
Tcl_FSCreateDirectoryProc TclpObjCreateDirectory;
|
||||
Tcl_FSCopyDirectoryProc TclpObjCopyDirectory;
|
||||
Tcl_FSRemoveDirectoryProc TclpObjRemoveDirectory;
|
||||
Tcl_FSUnloadFileProc TclpUnloadFile;
|
||||
Tcl_FSLinkProc TclpObjLink;
|
||||
Tcl_FSListVolumesProc TclpObjListVolumes;
|
||||
|
||||
@@ -276,8 +275,8 @@ Tcl_Stat(
|
||||
Tcl_WideInt tmp1, tmp2, tmp3 = 0;
|
||||
|
||||
# define OUT_OF_RANGE(x) \
|
||||
(((Tcl_WideInt)(x)) < Tcl_LongAsWide(LONG_MIN) || \
|
||||
((Tcl_WideInt)(x)) > Tcl_LongAsWide(LONG_MAX))
|
||||
(((Tcl_WideInt)(x)) < LONG_MIN || \
|
||||
((Tcl_WideInt)(x)) > LONG_MAX)
|
||||
# define OUT_OF_URANGE(x) \
|
||||
(((Tcl_WideUInt)(x)) > ((Tcl_WideUInt)ULONG_MAX))
|
||||
|
||||
@@ -1391,31 +1390,62 @@ TclFSNormalizeToUniquePath(
|
||||
{
|
||||
FilesystemRecord *fsRecPtr, *firstFsRecPtr;
|
||||
|
||||
/*
|
||||
* Call each of the "normalise path" functions in succession. This is a
|
||||
* special case, in which if we have a native filesystem handler, we call
|
||||
* it first. This is because the root of Tcl's filesystem is always a
|
||||
* native filesystem (i.e., '/' on unix is native).
|
||||
*/
|
||||
int i;
|
||||
int isVfsPath = 0;
|
||||
char *path;
|
||||
|
||||
/*
|
||||
* Paths starting with a UNC prefix whose final character is a colon
|
||||
* are reserved for VFS use. These names can not conflict with real
|
||||
* UNC paths per https://msdn.microsoft.com/en-us/library/gg465305.aspx
|
||||
* and rfc3986's definition of reg-name.
|
||||
*
|
||||
* We check these first to avoid useless calls to the native filesystem's
|
||||
* normalizePathProc.
|
||||
*/
|
||||
path = Tcl_GetStringFromObj(pathPtr, &i);
|
||||
|
||||
if ( (i >= 3) && ( (path[0] == '/' && path[1] == '/')
|
||||
|| (path[0] == '\\' && path[1] == '\\') ) ) {
|
||||
for ( i = 2; ; i++) {
|
||||
if (path[i] == '\0') break;
|
||||
if (path[i] == path[0]) break;
|
||||
}
|
||||
--i;
|
||||
if (path[i] == ':') isVfsPath = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call each of the "normalise path" functions in succession.
|
||||
*/
|
||||
firstFsRecPtr = FsGetFirstFilesystem();
|
||||
|
||||
Claim();
|
||||
for (fsRecPtr=firstFsRecPtr; fsRecPtr!=NULL; fsRecPtr=fsRecPtr->nextPtr) {
|
||||
if (fsRecPtr->fsPtr != &tclNativeFilesystem) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isVfsPath) {
|
||||
|
||||
/*
|
||||
* TODO: Assume that we always find the native file system; it should
|
||||
* always be there...
|
||||
* If we have a native filesystem handler, we call it first. This is
|
||||
* because the root of Tcl's filesystem is always a native filesystem
|
||||
* (i.e., '/' on unix is native).
|
||||
*/
|
||||
|
||||
if (fsRecPtr->fsPtr->normalizePathProc != NULL) {
|
||||
startAt = fsRecPtr->fsPtr->normalizePathProc(interp, pathPtr,
|
||||
startAt);
|
||||
for (fsRecPtr=firstFsRecPtr; fsRecPtr!=NULL; fsRecPtr=fsRecPtr->nextPtr) {
|
||||
if (fsRecPtr->fsPtr != &tclNativeFilesystem) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Assume that we always find the native file system; it should
|
||||
* always be there...
|
||||
*/
|
||||
|
||||
if (fsRecPtr->fsPtr->normalizePathProc != NULL) {
|
||||
startAt = fsRecPtr->fsPtr->normalizePathProc(interp, pathPtr,
|
||||
startAt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (fsRecPtr=firstFsRecPtr; fsRecPtr!=NULL; fsRecPtr=fsRecPtr->nextPtr) {
|
||||
@@ -3154,8 +3184,8 @@ Tcl_FSLoadFile(
|
||||
* present and set to true (any integer > 0) then the unlink is skipped.
|
||||
*/
|
||||
|
||||
int
|
||||
TclSkipUnlink(
|
||||
static int
|
||||
skipUnlink(
|
||||
Tcl_Obj *shlibFile)
|
||||
{
|
||||
/*
|
||||
@@ -3197,8 +3227,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;
|
||||
}
|
||||
}
|
||||
@@ -3413,7 +3443,7 @@ Tcl_LoadFile(
|
||||
* avoids any worries about leaving the copy laying around on exit.
|
||||
*/
|
||||
|
||||
if (!TclSkipUnlink(copyToPtr) &&
|
||||
if (!skipUnlink(copyToPtr) &&
|
||||
(Tcl_FSDeleteFile(copyToPtr) == TCL_OK)) {
|
||||
Tcl_DecrRefCount(copyToPtr);
|
||||
|
||||
@@ -3682,30 +3712,10 @@ Tcl_FSUnloadFile(
|
||||
}
|
||||
return TCL_ERROR;
|
||||
}
|
||||
TclpUnloadFile(handle);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclpUnloadFile --
|
||||
*
|
||||
* Unloads a library given its handle
|
||||
*
|
||||
* This function was once filesystem-specific, but has been made portable by
|
||||
* having TclpDlopen return a structure that includes procedure pointers.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
TclpUnloadFile(
|
||||
Tcl_LoadHandle handle)
|
||||
{
|
||||
if (handle->unloadFileProcPtr != NULL) {
|
||||
handle->unloadFileProcPtr(handle);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
+86
-39
@@ -38,6 +38,23 @@
|
||||
|
||||
#define AVOID_HACKS_FOR_ITCL 1
|
||||
|
||||
|
||||
/*
|
||||
* Used to tag functions that are only to be visible within the module being
|
||||
* built and not outside it (where this is supported by the linker).
|
||||
* Also used in the platform-specific *Port.h files.
|
||||
*/
|
||||
|
||||
#ifndef MODULE_SCOPE
|
||||
# ifdef __cplusplus
|
||||
# define MODULE_SCOPE extern "C"
|
||||
# else
|
||||
# define MODULE_SCOPE extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Common include files needed by most of the Tcl source files are included
|
||||
* here, so that system-dependent personalizations for the include files only
|
||||
@@ -94,19 +111,6 @@ typedef int ptrdiff_t;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Used to tag functions that are only to be visible within the module being
|
||||
* built and not outside it (where this is supported by the linker).
|
||||
*/
|
||||
|
||||
#ifndef MODULE_SCOPE
|
||||
# ifdef __cplusplus
|
||||
# define MODULE_SCOPE extern "C"
|
||||
# else
|
||||
# define MODULE_SCOPE extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macros used to cast between pointers and integers (e.g. when storing an int
|
||||
* in ClientData), on 64-bit architectures they avoid gcc warning about "cast
|
||||
@@ -136,6 +140,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 +1170,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 +2788,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 +2932,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 +2948,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 +2981,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 +3011,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);
|
||||
@@ -3018,6 +3041,8 @@ MODULE_SCOPE char * TclGetStringStorage(Tcl_Obj *objPtr,
|
||||
MODULE_SCOPE int TclGetLoadedPackagesEx(Tcl_Interp *interp,
|
||||
const char *targetName,
|
||||
const char *packageName);
|
||||
MODULE_SCOPE int TclGetWideBitsFromObj(Tcl_Interp *, Tcl_Obj *,
|
||||
Tcl_WideInt *);
|
||||
MODULE_SCOPE int TclGlob(Tcl_Interp *interp, char *pattern,
|
||||
Tcl_Obj *unquotedPrefix, int globFlags,
|
||||
Tcl_GlobTypeData *types);
|
||||
@@ -3173,7 +3198,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 +3211,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,
|
||||
@@ -3229,12 +3261,20 @@ MODULE_SCOPE Tcl_WideInt TclpGetWideClicks(void);
|
||||
MODULE_SCOPE double TclpWideClicksToNanoseconds(Tcl_WideInt clicks);
|
||||
#endif
|
||||
MODULE_SCOPE int TclZlibInit(Tcl_Interp *interp);
|
||||
MODULE_SCOPE int TclZipfsInit(Tcl_Interp *interp);
|
||||
MODULE_SCOPE int TclZipfsMount(Tcl_Interp *interp, const char *zipname,
|
||||
const char *mntpt, const char *passwd);
|
||||
MODULE_SCOPE int TclZipfsUnmount(Tcl_Interp *interp, const char *zipname);
|
||||
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);
|
||||
/* Tip 430 */
|
||||
MODULE_SCOPE int TclZipfs_Init(Tcl_Interp *interp);
|
||||
MODULE_SCOPE int TclZipfs_SafeInit(Tcl_Interp *interp);
|
||||
|
||||
MODULE_SCOPE void TclErrorStackResetIf(Tcl_Interp *interp, const char *msg, int length);
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------
|
||||
@@ -4087,7 +4127,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 +4238,10 @@ typedef const char *TclDTraceStr;
|
||||
} \
|
||||
}
|
||||
|
||||
#if TCL_THREADS && !defined(USE_THREAD_ALLOC)
|
||||
# define USE_THREAD_ALLOC 1
|
||||
#endif
|
||||
|
||||
#if defined(PURIFY)
|
||||
|
||||
/*
|
||||
@@ -4215,7 +4259,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 +4324,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 +4584,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 */
|
||||
|
||||
@@ -402,6 +402,7 @@ Tcl_Init(
|
||||
" set scripts {{set tcl_library}}\n"
|
||||
" } else {\n"
|
||||
" set scripts {}\n"
|
||||
" lappend scripts {zipfs tcl_library}\n"
|
||||
" if {[info exists env(TCL_LIBRARY)] && ($env(TCL_LIBRARY) ne {})} {\n"
|
||||
" lappend scripts {set env(TCL_LIBRARY)}\n"
|
||||
" lappend scripts {\n"
|
||||
|
||||
+139
-84
@@ -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},
|
||||
@@ -100,6 +102,13 @@ static int PrivateObjectCmd(ClientData clientData,
|
||||
static int PrivateNRObjectCmd(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const *objv);
|
||||
static int MyClassObjCmd(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const *objv);
|
||||
static int MyClassNRObjCmd(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const *objv);
|
||||
static void MyClassDeleted(ClientData clientData);
|
||||
|
||||
/*
|
||||
* Methods in the oo::object and oo::class classes. First, we define a helper
|
||||
@@ -150,65 +159,10 @@ static const char *initScript =
|
||||
/* " tcloo.tcl OO_LIBRARY oo::library;"; */
|
||||
|
||||
/*
|
||||
* The scripted part of the definitions of slots.
|
||||
* The scripted part of the definitions of TclOO.
|
||||
*/
|
||||
|
||||
static const char *slotScript =
|
||||
"::oo::define ::oo::Slot {\n"
|
||||
" method Get {} {error unimplemented}\n"
|
||||
" method Set list {error unimplemented}\n"
|
||||
" method -set args {\n"
|
||||
" uplevel 1 [list [namespace which my] Set $args]\n"
|
||||
" }\n"
|
||||
" method -append args {\n"
|
||||
" uplevel 1 [list [namespace which my] Set [list"
|
||||
" {*}[uplevel 1 [list [namespace which my] Get]] {*}$args]]\n"
|
||||
" }\n"
|
||||
" method -clear {} {uplevel 1 [list [namespace which my] Set {}]}\n"
|
||||
" forward --default-operation my -append\n"
|
||||
" method unknown {args} {\n"
|
||||
" set def --default-operation\n"
|
||||
" if {[llength $args] == 0} {\n"
|
||||
" return [uplevel 1 [list [namespace which my] $def]]\n"
|
||||
" } elseif {![string match -* [lindex $args 0]]} {\n"
|
||||
" return [uplevel 1 [list [namespace which my] $def {*}$args]]\n"
|
||||
" }\n"
|
||||
" next {*}$args\n"
|
||||
" }\n"
|
||||
" export -set -append -clear\n"
|
||||
" unexport unknown destroy\n"
|
||||
"}\n"
|
||||
"::oo::objdefine ::oo::define::superclass forward --default-operation my -set\n"
|
||||
"::oo::objdefine ::oo::define::mixin forward --default-operation my -set\n"
|
||||
"::oo::objdefine ::oo::objdefine::mixin forward --default-operation my -set\n";
|
||||
|
||||
/*
|
||||
* The body of the <cloned> method of oo::object.
|
||||
*/
|
||||
|
||||
static const char *clonedBody =
|
||||
"foreach p [info procs [info object namespace $originObject]::*] {"
|
||||
" set args [info args $p];"
|
||||
" set idx -1;"
|
||||
" foreach a $args {"
|
||||
" lset args [incr idx] "
|
||||
" [if {[info default $p $a d]} {list $a $d} {list $a}]"
|
||||
" };"
|
||||
" set b [info body $p];"
|
||||
" set p [namespace tail $p];"
|
||||
" proc $p $args $b;"
|
||||
"};"
|
||||
"foreach v [info vars [info object namespace $originObject]::*] {"
|
||||
" upvar 0 $v vOrigin;"
|
||||
" namespace upvar [namespace current] [namespace tail $v] vNew;"
|
||||
" if {[info exists vOrigin]} {"
|
||||
" if {[array exists vOrigin]} {"
|
||||
" array set vNew [array get vOrigin];"
|
||||
" } else {"
|
||||
" set vNew $vOrigin;"
|
||||
" }"
|
||||
" }"
|
||||
"}";
|
||||
#include "tclOOScript.h"
|
||||
|
||||
/*
|
||||
* The actual definition of the variable holding the TclOO stub table.
|
||||
@@ -358,7 +312,7 @@ InitFoundation(
|
||||
ThreadLocalData *tsdPtr =
|
||||
Tcl_GetThreadData(&tsdKey, sizeof(ThreadLocalData));
|
||||
Foundation *fPtr = ckalloc(sizeof(Foundation));
|
||||
Tcl_Obj *namePtr, *argsPtr, *bodyPtr;
|
||||
Tcl_Obj *namePtr;
|
||||
Tcl_DString buffer;
|
||||
Command *cmdPtr;
|
||||
int i;
|
||||
@@ -437,18 +391,6 @@ InitFoundation(
|
||||
TclOONewBasicMethod(interp, fPtr->classCls, &clsMethods[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the default <cloned> method implementation, used when 'oo::copy'
|
||||
* is called to finish the copying of one object to another.
|
||||
*/
|
||||
|
||||
TclNewLiteralStringObj(argsPtr, "originObject");
|
||||
Tcl_IncrRefCount(argsPtr);
|
||||
bodyPtr = Tcl_NewStringObj(clonedBody, -1);
|
||||
TclOONewProcMethod(interp, fPtr->objectCls, 0, fPtr->clonedName, argsPtr,
|
||||
bodyPtr, NULL);
|
||||
TclDecrRefCount(argsPtr);
|
||||
|
||||
/*
|
||||
* Finish setting up the class of classes by marking the 'new' method as
|
||||
* private; classes, unlike general objects, must have explicit names. We
|
||||
@@ -489,7 +431,12 @@ InitFoundation(
|
||||
if (TclOODefineSlots(fPtr) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return Tcl_EvalEx(interp, slotScript, -1, 0);
|
||||
|
||||
/*
|
||||
* Evaluate the remaining definitions, which are a compiled-in Tcl script.
|
||||
*/
|
||||
|
||||
return Tcl_EvalEx(interp, tclOOSetupScript, -1, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -795,6 +742,9 @@ AllocObject(
|
||||
|
||||
oPtr->myCommand = TclNRCreateCommandInNs(interp, "my", oPtr->namespacePtr,
|
||||
PrivateObjectCmd, PrivateNRObjectCmd, oPtr, MyDeleted);
|
||||
oPtr->myclassCommand = TclNRCreateCommandInNs(interp, "myclass",
|
||||
oPtr->namespacePtr, MyClassObjCmd, MyClassNRObjCmd, oPtr,
|
||||
MyClassDeleted);
|
||||
return oPtr;
|
||||
}
|
||||
|
||||
@@ -822,12 +772,12 @@ SquelchCachedName(
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* MyDeleted --
|
||||
* MyDeleted, MyClassDeleted --
|
||||
*
|
||||
* This callback is triggered when the object's [my] command is deleted
|
||||
* by any mechanism. It just marks the object as not having a [my]
|
||||
* command, and so prevents cleanup of that when the object itself is
|
||||
* deleted.
|
||||
* These callbacks are triggered when the object's [my] or [myclass]
|
||||
* commands are deleted by any mechanism. They just mark the object as
|
||||
* not having a [my] command or [myclass] command, and so prevent cleanup
|
||||
* of those commands when the object itself is deleted.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -841,6 +791,14 @@ MyDeleted(
|
||||
|
||||
oPtr->myCommand = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
MyClassDeleted(
|
||||
ClientData clientData)
|
||||
{
|
||||
Object *oPtr = clientData;
|
||||
oPtr->myclassCommand = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
@@ -993,6 +951,7 @@ ReleaseClassContents(
|
||||
Method *mPtr;
|
||||
Foundation *fPtr = oPtr->fPtr;
|
||||
Tcl_Obj *variableObj;
|
||||
PrivateVariableMapping *privateVariable;
|
||||
|
||||
/*
|
||||
* Sanity check!
|
||||
@@ -1099,6 +1058,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 +1095,7 @@ ObjectNamespaceDeleted(
|
||||
Class *mixinPtr;
|
||||
Method *mPtr;
|
||||
Tcl_Obj *filterObj, *variableObj;
|
||||
PrivateVariableMapping *privateVariable;
|
||||
Tcl_Interp *interp = oPtr->fPtr->interp;
|
||||
int i;
|
||||
|
||||
@@ -1162,7 +1130,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;
|
||||
@@ -1203,6 +1171,9 @@ ObjectNamespaceDeleted(
|
||||
Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->command);
|
||||
}
|
||||
|
||||
if (oPtr->myclassCommand) {
|
||||
Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->myclassCommand);
|
||||
}
|
||||
if (oPtr->myCommand) {
|
||||
Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->myCommand);
|
||||
}
|
||||
@@ -1248,6 +1219,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 +1610,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 +1683,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 +1863,7 @@ Tcl_CopyObjectInstance(
|
||||
Class *mixinPtr;
|
||||
CallContext *contextPtr;
|
||||
Tcl_Obj *keyPtr, *filterObj, *variableObj, *args[3];
|
||||
PrivateVariableMapping *privateVariable;
|
||||
int i, result;
|
||||
|
||||
/*
|
||||
@@ -1953,7 +1933,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 +1941,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 +2036,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 +2044,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 +2123,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;
|
||||
@@ -2499,6 +2494,43 @@ TclOOInvokeObject(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* MyClassObjCmd, MyClassNRObjCmd --
|
||||
*
|
||||
* Special trap door to allow an object to delegate simply to its class.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int
|
||||
MyClassObjCmd(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
return Tcl_NRCallObjProc(interp, MyClassNRObjCmd, clientData, objc, objv);
|
||||
}
|
||||
|
||||
static int
|
||||
MyClassNRObjCmd(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
Object *oPtr = clientData;
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "methodName ?arg ...?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TclOOObjectCmdCore(oPtr->selfCls->thisPtr, interp, objc, objv, 0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
@@ -2526,6 +2558,9 @@ TclOOObjectCmdCore(
|
||||
{
|
||||
CallContext *contextPtr;
|
||||
Tcl_Obj *methodNamePtr;
|
||||
CallFrame *framePtr = ((Interp *) interp)->varFramePtr;
|
||||
Object *callerObjPtr = NULL;
|
||||
Class *callerClsPtr = NULL;
|
||||
int result;
|
||||
|
||||
/*
|
||||
@@ -2539,6 +2574,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 +2619,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 +2637,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
|
||||
|
||||
+113
-19
@@ -83,7 +83,7 @@ TclOO_Class_Constructor(
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
|
||||
Tcl_Obj **invoke;
|
||||
Tcl_Obj **invoke, *nameObj;
|
||||
|
||||
if (objc-1 > Tcl_ObjectContextSkippedArgs(context)) {
|
||||
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
|
||||
@@ -93,6 +93,17 @@ TclOO_Class_Constructor(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the class definition delegate. This is special; it doesn't reenter
|
||||
* here (and the class definition delegate doesn't run any constructors).
|
||||
*/
|
||||
|
||||
nameObj = Tcl_NewStringObj(oPtr->namespacePtr->fullName, -1);
|
||||
Tcl_AppendToObj(nameObj, ":: oo ::delegate", -1);
|
||||
Tcl_NewObjectInstance(interp, (Tcl_Class) oPtr->fPtr->classCls,
|
||||
TclGetString(nameObj), NULL, -1, NULL, -1);
|
||||
Tcl_DecrRefCount(nameObj);
|
||||
|
||||
/*
|
||||
* Delegate to [oo::define] to do the work.
|
||||
*/
|
||||
@@ -111,7 +122,7 @@ TclOO_Class_Constructor(
|
||||
Tcl_IncrRefCount(invoke[1]);
|
||||
Tcl_IncrRefCount(invoke[2]);
|
||||
TclNRAddCallback(interp, DecrRefsPostClassConstructor,
|
||||
invoke, NULL, NULL, NULL);
|
||||
invoke, oPtr, NULL, NULL);
|
||||
|
||||
/*
|
||||
* Tricky point: do not want the extra reported level in the Tcl stack
|
||||
@@ -128,12 +139,27 @@ DecrRefsPostClassConstructor(
|
||||
int result)
|
||||
{
|
||||
Tcl_Obj **invoke = data[0];
|
||||
Object *oPtr = data[1];
|
||||
Tcl_InterpState saved;
|
||||
int code;
|
||||
|
||||
TclDecrRefCount(invoke[0]);
|
||||
TclDecrRefCount(invoke[1]);
|
||||
TclDecrRefCount(invoke[2]);
|
||||
invoke[0] = Tcl_NewStringObj("::oo::MixinClassDelegates", -1);
|
||||
invoke[1] = TclOOObjectName(interp, oPtr);
|
||||
Tcl_IncrRefCount(invoke[0]);
|
||||
Tcl_IncrRefCount(invoke[1]);
|
||||
saved = Tcl_SaveInterpState(interp, result);
|
||||
code = Tcl_EvalObjv(interp, 2, invoke, 0);
|
||||
TclDecrRefCount(invoke[0]);
|
||||
TclDecrRefCount(invoke[1]);
|
||||
ckfree(invoke);
|
||||
return result;
|
||||
if (code != TCL_OK) {
|
||||
Tcl_DiscardInterpState(saved);
|
||||
return code;
|
||||
}
|
||||
return Tcl_RestoreInterpState(interp, saved);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -347,7 +373,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 +526,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 +545,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 +735,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 +761,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 +833,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
-164
@@ -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.
|
||||
@@ -1599,70 +1838,6 @@ TclOODefineMethodObjCmd(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* TclOODefineMixinObjCmd --
|
||||
*
|
||||
* Implementation of the "mixin" subcommand of the "oo::define" and
|
||||
* "oo::objdefine" commands.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
TclOODefineMixinObjCmd(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
const int objc,
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
int isInstanceMixin = (clientData != NULL);
|
||||
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
|
||||
Class **mixins;
|
||||
int i;
|
||||
|
||||
if (oPtr == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (!isInstanceMixin && !oPtr->classPtr) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
"attempt to misuse API", -1));
|
||||
Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
mixins = TclStackAlloc(interp, sizeof(Class *) * (objc-1));
|
||||
|
||||
for (i=1 ; i<objc ; i++) {
|
||||
Class *clsPtr = GetClassInOuterContext(interp, objv[i],
|
||||
"may only mix in classes");
|
||||
|
||||
if (clsPtr == NULL) {
|
||||
goto freeAndError;
|
||||
}
|
||||
if (!isInstanceMixin && TclOOIsReachable(oPtr->classPtr, clsPtr)) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
"may not mix a class into itself", -1));
|
||||
Tcl_SetErrorCode(interp, "TCL", "OO", "SELF_MIXIN", NULL);
|
||||
goto freeAndError;
|
||||
}
|
||||
mixins[i-1] = clsPtr;
|
||||
}
|
||||
|
||||
if (isInstanceMixin) {
|
||||
TclOOObjectSetMixins(oPtr, objc-1, mixins);
|
||||
} else {
|
||||
TclOOClassSetMixins(interp, oPtr->classPtr, objc-1, mixins);
|
||||
}
|
||||
|
||||
TclStackFree(interp, mixins);
|
||||
return TCL_OK;
|
||||
|
||||
freeAndError:
|
||||
TclStackFree(interp, mixins);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
@@ -1795,8 +1970,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 +2463,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 +2481,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 +2508,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 +2549,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 +2732,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 +2744,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 +2771,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 +2804,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));
|
||||
|
||||
+57
-5
@@ -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,12 @@ 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. */
|
||||
Tcl_Command myclassCommand; /* Reference to this object's class dispatcher
|
||||
* command. */
|
||||
} Object;
|
||||
|
||||
#define OBJECT_DELETED 1 /* Flag to say that an object has been
|
||||
@@ -214,6 +238,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 +296,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 +401,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 +467,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 +543,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 +553,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);
|
||||
@@ -558,13 +599,24 @@ MODULE_SCOPE void TclOOSetupVariableResolver(Tcl_Namespace *nsPtr);
|
||||
#define FOREACH(var,ary) \
|
||||
for(i=0 ; i<(ary).num; i++) if ((ary).list[i] == NULL) { \
|
||||
continue; \
|
||||
} else if (var = (ary).list[i], 1)
|
||||
} 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.
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* tclOOScript.h --
|
||||
*
|
||||
* This file contains support scripts for TclOO. They are defined here so
|
||||
* that the code can be definitely run even in safe interpreters; TclOO's
|
||||
* core setup is safe.
|
||||
*
|
||||
* Copyright (c) 2012-2018 Donal K. Fellows
|
||||
* Copyright (c) 2013 Andreas Kupries
|
||||
* Copyright (c) 2017 Gerald Lester
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution of
|
||||
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
|
||||
#ifndef TCL_OO_SCRIPT_H
|
||||
#define TCL_OO_SCRIPT_H
|
||||
|
||||
/*
|
||||
* The scripted part of the definitions of TclOO.
|
||||
*
|
||||
* Compiled from generic/tclOOScript.tcl by tools/makeHeader.tcl, which
|
||||
* contains the commented version of everything; *this* file is automatically
|
||||
* generated.
|
||||
*/
|
||||
|
||||
static const char *tclOOSetupScript =
|
||||
/* !BEGIN!: Do not edit below this line. */
|
||||
"::namespace eval ::oo {\n"
|
||||
"\t::namespace path {}\n"
|
||||
"\tnamespace eval Helpers {\n"
|
||||
"\t\t::namespace path {}\n"
|
||||
"\t\tproc callback {method args} {\n"
|
||||
"\t\t\tlist [uplevel 1 {::namespace which my}] $method {*}$args\n"
|
||||
"\t\t}\n"
|
||||
"\t\tnamespace export callback\n"
|
||||
"\t\tnamespace eval tmp {namespace import ::oo::Helpers::callback}\n"
|
||||
"\t\tnamespace export -clear\n"
|
||||
"\t\trename tmp::callback mymethod\n"
|
||||
"\t\tnamespace delete tmp\n"
|
||||
"\t\tproc classvariable {name args} {\n"
|
||||
"\t\t\tset ns [info object namespace [uplevel 1 {self class}]]\n"
|
||||
"\t\t\tforeach v [list $name {*}$args] {\n"
|
||||
"\t\t\t\tif {[string match *(*) $v]} {\n"
|
||||
"\t\t\t\t\tset reason \"can\'t create a scalar variable that looks like an array element\"\n"
|
||||
"\t\t\t\t\treturn -code error -errorcode {TCL UPVAR LOCAL_ELEMENT} \\\n"
|
||||
"\t\t\t\t\t\t[format {bad variable name \"%s\": %s} $v $reason]\n"
|
||||
"\t\t\t\t}\n"
|
||||
"\t\t\t\tif {[string match *::* $v]} {\n"
|
||||
"\t\t\t\t\tset reason \"can\'t create a local variable with a namespace separator in it\"\n"
|
||||
"\t\t\t\t\treturn -code error -errorcode {TCL UPVAR INVERTED} \\\n"
|
||||
"\t\t\t\t\t\t[format {bad variable name \"%s\": %s} $v $reason]\n"
|
||||
"\t\t\t\t}\n"
|
||||
"\t\t\t\tlappend vs $v $v\n"
|
||||
"\t\t\t}\n"
|
||||
"\t\t\ttailcall namespace upvar $ns {*}$vs\n"
|
||||
"\t\t}\n"
|
||||
"\t\tproc link {args} {\n"
|
||||
"\t\t\tset ns [uplevel 1 {::namespace current}]\n"
|
||||
"\t\t\tforeach link $args {\n"
|
||||
"\t\t\t\tif {[llength $link] == 2} {\n"
|
||||
"\t\t\t\t\tlassign $link src dst\n"
|
||||
"\t\t\t\t} elseif {[llength $link] == 1} {\n"
|
||||
"\t\t\t\t\tlassign $link src\n"
|
||||
"\t\t\t\t\tset dst $src\n"
|
||||
"\t\t\t\t} else {\n"
|
||||
"\t\t\t\t\treturn -code error -errorcode {TCLOO CMDLINK FORMAT} \\\n"
|
||||
"\t\t\t\t\t\t\"bad link description; must only have one or two elements\"\n"
|
||||
"\t\t\t\t}\n"
|
||||
"\t\t\t\tif {![string match ::* $src]} {\n"
|
||||
"\t\t\t\t\tset src [string cat $ns :: $src]\n"
|
||||
"\t\t\t\t}\n"
|
||||
"\t\t\t\tinterp alias {} $src {} ${ns}::my $dst\n"
|
||||
"\t\t\t\ttrace add command ${ns}::my delete [list \\\n"
|
||||
"\t\t\t\t\t::oo::UnlinkLinkedCommand $src]\n"
|
||||
"\t\t\t}\n"
|
||||
"\t\t\treturn\n"
|
||||
"\t\t}\n"
|
||||
"\t}\n"
|
||||
"\tproc UnlinkLinkedCommand {cmd args} {\n"
|
||||
"\t\tif {[namespace which $cmd] ne {}} {\n"
|
||||
"\t\t\trename $cmd {}\n"
|
||||
"\t\t}\n"
|
||||
"\t}\n"
|
||||
"\tproc DelegateName {class} {\n"
|
||||
"\t\tstring cat [info object namespace $class] {:: oo ::delegate}\n"
|
||||
"\t}\n"
|
||||
"\tproc MixinClassDelegates {class} {\n"
|
||||
"\t\tif {![info object isa class $class]} {\n"
|
||||
"\t\t\treturn\n"
|
||||
"\t\t}\n"
|
||||
"\t\tset delegate [DelegateName $class]\n"
|
||||
"\t\tif {![info object isa class $delegate]} {\n"
|
||||
"\t\t\treturn\n"
|
||||
"\t\t}\n"
|
||||
"\t\tforeach c [info class superclass $class] {\n"
|
||||
"\t\t\tset d [DelegateName $c]\n"
|
||||
"\t\t\tif {![info object isa class $d]} {\n"
|
||||
"\t\t\t\tcontinue\n"
|
||||
"\t\t\t}\n"
|
||||
"\t\t\tdefine $delegate superclass -append $d\n"
|
||||
"\t\t}\n"
|
||||
"\t\tobjdefine $class mixin -append $delegate\n"
|
||||
"\t}\n"
|
||||
"\tproc UpdateClassDelegatesAfterClone {originObject targetObject} {\n"
|
||||
"\t\tset originDelegate [DelegateName $originObject]\n"
|
||||
"\t\tset targetDelegate [DelegateName $targetObject]\n"
|
||||
"\t\tif {\n"
|
||||
"\t\t\t[info object isa class $originDelegate]\n"
|
||||
"\t\t\t&& ![info object isa class $targetDelegate]\n"
|
||||
"\t\t} then {\n"
|
||||
"\t\t\tcopy $originDelegate $targetDelegate\n"
|
||||
"\t\t\tobjdefine $targetObject mixin -set \\\n"
|
||||
"\t\t\t\t{*}[lmap c [info object mixin $targetObject] {\n"
|
||||
"\t\t\t\t\tif {$c eq $originDelegate} {set targetDelegate} {set c}\n"
|
||||
"\t\t\t\t}]\n"
|
||||
"\t\t}\n"
|
||||
"\t}\n"
|
||||
"\tproc define::classmethod {name {args {}} {body {}}} {\n"
|
||||
"\t\t::set argc [::llength [::info level 0]]\n"
|
||||
"\t\t::if {$argc == 3} {\n"
|
||||
"\t\t\t::return -code error -errorcode {TCL WRONGARGS} [::format \\\n"
|
||||
"\t\t\t\t{wrong # args: should be \"%s name \?args body\?\"} \\\n"
|
||||
"\t\t\t\t[::lindex [::info level 0] 0]]\n"
|
||||
"\t\t}\n"
|
||||
"\t\t::set cls [::uplevel 1 self]\n"
|
||||
"\t\t::if {$argc == 4} {\n"
|
||||
"\t\t\t::oo::define [::oo::DelegateName $cls] method $name $args $body\n"
|
||||
"\t\t}\n"
|
||||
"\t\t::tailcall forward $name myclass $name\n"
|
||||
"\t}\n"
|
||||
"\tproc define::initialise {body} {\n"
|
||||
"\t\t::set clsns [::info object namespace [::uplevel 1 self]]\n"
|
||||
"\t\t::tailcall apply [::list {} $body $clsns]\n"
|
||||
"\t}\n"
|
||||
"\tnamespace eval define {\n"
|
||||
"\t\t::namespace export initialise\n"
|
||||
"\t\t::namespace eval tmp {::namespace import ::oo::define::initialise}\n"
|
||||
"\t\t::namespace export -clear\n"
|
||||
"\t\t::rename tmp::initialise initialize\n"
|
||||
"\t\t::namespace delete tmp\n"
|
||||
"\t}\n"
|
||||
"\tdefine Slot {\n"
|
||||
"\t\tmethod Get {} {\n"
|
||||
"\t\t\treturn -code error -errorcode {TCLOO ABSTRACT_SLOT} \"unimplemented\"\n"
|
||||
"\t\t}\n"
|
||||
"\t\tmethod Set list {\n"
|
||||
"\t\t\treturn -code error -errorcode {TCLOO ABSTRACT_SLOT} \"unimplemented\"\n"
|
||||
"\t\t}\n"
|
||||
"\t\tmethod -set args {tailcall my Set $args}\n"
|
||||
"\t\tmethod -append args {\n"
|
||||
"\t\t\tset current [uplevel 1 [list [namespace which my] Get]]\n"
|
||||
"\t\t\ttailcall my Set [list {*}$current {*}$args]\n"
|
||||
"\t\t}\n"
|
||||
"\t\tmethod -clear {} {tailcall my Set {}}\n"
|
||||
"\t\tforward --default-operation my -append\n"
|
||||
"\t\tmethod unknown {args} {\n"
|
||||
"\t\t\tset def --default-operation\n"
|
||||
"\t\t\tif {[llength $args] == 0} {\n"
|
||||
"\t\t\t\ttailcall my $def\n"
|
||||
"\t\t\t} elseif {![string match -* [lindex $args 0]]} {\n"
|
||||
"\t\t\t\ttailcall my $def {*}$args\n"
|
||||
"\t\t\t}\n"
|
||||
"\t\t\tnext {*}$args\n"
|
||||
"\t\t}\n"
|
||||
"\t\texport -set -append -clear\n"
|
||||
"\t\tunexport unknown destroy\n"
|
||||
"\t}\n"
|
||||
"\tobjdefine define::superclass forward --default-operation my -set\n"
|
||||
"\tobjdefine define::mixin forward --default-operation my -set\n"
|
||||
"\tobjdefine objdefine::mixin forward --default-operation my -set\n"
|
||||
"\tdefine object method <cloned> {originObject} {\n"
|
||||
"\t\tforeach p [info procs [info object namespace $originObject]::*] {\n"
|
||||
"\t\t\tset args [info args $p]\n"
|
||||
"\t\t\tset idx -1\n"
|
||||
"\t\t\tforeach a $args {\n"
|
||||
"\t\t\t\tif {[info default $p $a d]} {\n"
|
||||
"\t\t\t\t\tlset args [incr idx] [list $a $d]\n"
|
||||
"\t\t\t\t} else {\n"
|
||||
"\t\t\t\t\tlset args [incr idx] [list $a]\n"
|
||||
"\t\t\t\t}\n"
|
||||
"\t\t\t}\n"
|
||||
"\t\t\tset b [info body $p]\n"
|
||||
"\t\t\tset p [namespace tail $p]\n"
|
||||
"\t\t\tproc $p $args $b\n"
|
||||
"\t\t}\n"
|
||||
"\t\tforeach v [info vars [info object namespace $originObject]::*] {\n"
|
||||
"\t\t\tupvar 0 $v vOrigin\n"
|
||||
"\t\t\tnamespace upvar [namespace current] [namespace tail $v] vNew\n"
|
||||
"\t\t\tif {[info exists vOrigin]} {\n"
|
||||
"\t\t\t\tif {[array exists vOrigin]} {\n"
|
||||
"\t\t\t\t\tarray set vNew [array get vOrigin]\n"
|
||||
"\t\t\t\t} else {\n"
|
||||
"\t\t\t\t\tset vNew $vOrigin\n"
|
||||
"\t\t\t\t}\n"
|
||||
"\t\t\t}\n"
|
||||
"\t\t}\n"
|
||||
"\t}\n"
|
||||
"\tdefine class method <cloned> {originObject} {\n"
|
||||
"\t\tnext $originObject\n"
|
||||
"\t\t::oo::UpdateClassDelegatesAfterClone $originObject [self]\n"
|
||||
"\t}\n"
|
||||
"\tclass create singleton {\n"
|
||||
"\t\tsuperclass class\n"
|
||||
"\t\tvariable object\n"
|
||||
"\t\tunexport create createWithNamespace\n"
|
||||
"\t\tmethod new args {\n"
|
||||
"\t\t\tif {![info exists object] || ![info object isa object $object]} {\n"
|
||||
"\t\t\t\tset object [next {*}$args]\n"
|
||||
"\t\t\t\t::oo::objdefine $object {\n"
|
||||
"\t\t\t\t\tmethod destroy {} {\n"
|
||||
"\t\t\t\t\t\t::return -code error -errorcode {TCLOO SINGLETON} \\\n"
|
||||
"\t\t\t\t\t\t\t\"may not destroy a singleton object\"\n"
|
||||
"\t\t\t\t\t}\n"
|
||||
"\t\t\t\t\tmethod <cloned> {originObject} {\n"
|
||||
"\t\t\t\t\t\t::return -code error -errorcode {TCLOO SINGLETON} \\\n"
|
||||
"\t\t\t\t\t\t\t\"may not clone a singleton object\"\n"
|
||||
"\t\t\t\t\t}\n"
|
||||
"\t\t\t\t}\n"
|
||||
"\t\t\t}\n"
|
||||
"\t\t\treturn $object\n"
|
||||
"\t\t}\n"
|
||||
"\t}\n"
|
||||
"\tclass create abstract {\n"
|
||||
"\t\tsuperclass class\n"
|
||||
"\t\tunexport create createWithNamespace new\n"
|
||||
"\t}\n"
|
||||
"}\n"
|
||||
/* !END!: Do not edit above this line. */
|
||||
;
|
||||
|
||||
#endif /* TCL_OO_SCRIPT_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: c
|
||||
* c-basic-offset: 4
|
||||
* fill-column: 78
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,422 @@
|
||||
# tclOOScript.h --
|
||||
#
|
||||
# This file contains support scripts for TclOO. They are defined here so
|
||||
# that the code can be definitely run even in safe interpreters; TclOO's
|
||||
# core setup is safe.
|
||||
#
|
||||
# Copyright (c) 2012-2018 Donal K. Fellows
|
||||
# Copyright (c) 2013 Andreas Kupries
|
||||
# Copyright (c) 2017 Gerald Lester
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution of
|
||||
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
|
||||
::namespace eval ::oo {
|
||||
::namespace path {}
|
||||
|
||||
#
|
||||
# Commands that are made available to objects by default.
|
||||
#
|
||||
namespace eval Helpers {
|
||||
::namespace path {}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# callback, mymethod --
|
||||
#
|
||||
# Create a script prefix that calls a method on the current
|
||||
# object. Same operation, two names.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
proc callback {method args} {
|
||||
list [uplevel 1 {::namespace which my}] $method {*}$args
|
||||
}
|
||||
|
||||
# Make the [callback] command appear as [mymethod] too.
|
||||
namespace export callback
|
||||
namespace eval tmp {namespace import ::oo::Helpers::callback}
|
||||
namespace export -clear
|
||||
rename tmp::callback mymethod
|
||||
namespace delete tmp
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# classvariable --
|
||||
#
|
||||
# Link to a variable in the class of the current object.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
proc classvariable {name args} {
|
||||
# Get a reference to the class's namespace
|
||||
set ns [info object namespace [uplevel 1 {self class}]]
|
||||
# Double up the list of variable names
|
||||
foreach v [list $name {*}$args] {
|
||||
if {[string match *(*) $v]} {
|
||||
set reason "can't create a scalar variable that looks like an array element"
|
||||
return -code error -errorcode {TCL UPVAR LOCAL_ELEMENT} \
|
||||
[format {bad variable name "%s": %s} $v $reason]
|
||||
}
|
||||
if {[string match *::* $v]} {
|
||||
set reason "can't create a local variable with a namespace separator in it"
|
||||
return -code error -errorcode {TCL UPVAR INVERTED} \
|
||||
[format {bad variable name "%s": %s} $v $reason]
|
||||
}
|
||||
lappend vs $v $v
|
||||
}
|
||||
# Lastly, link the caller's local variables to the class's variables
|
||||
tailcall namespace upvar $ns {*}$vs
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# link --
|
||||
#
|
||||
# Make a command that invokes a method on the current object.
|
||||
# The name of the command and the name of the method match by
|
||||
# default.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
proc link {args} {
|
||||
set ns [uplevel 1 {::namespace current}]
|
||||
foreach link $args {
|
||||
if {[llength $link] == 2} {
|
||||
lassign $link src dst
|
||||
} elseif {[llength $link] == 1} {
|
||||
lassign $link src
|
||||
set dst $src
|
||||
} else {
|
||||
return -code error -errorcode {TCLOO CMDLINK FORMAT} \
|
||||
"bad link description; must only have one or two elements"
|
||||
}
|
||||
if {![string match ::* $src]} {
|
||||
set src [string cat $ns :: $src]
|
||||
}
|
||||
interp alias {} $src {} ${ns}::my $dst
|
||||
trace add command ${ns}::my delete [list \
|
||||
::oo::UnlinkLinkedCommand $src]
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# UnlinkLinkedCommand --
|
||||
#
|
||||
# Callback used to remove linked command when the underlying mechanism
|
||||
# that supports it is deleted.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
proc UnlinkLinkedCommand {cmd args} {
|
||||
if {[namespace which $cmd] ne {}} {
|
||||
rename $cmd {}
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# DelegateName --
|
||||
#
|
||||
# Utility that gets the name of the class delegate for a class. It's
|
||||
# trivial, but makes working with them much easier as delegate names are
|
||||
# intentionally hard to create by accident.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
proc DelegateName {class} {
|
||||
string cat [info object namespace $class] {:: oo ::delegate}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# MixinClassDelegates --
|
||||
#
|
||||
# Support code called *after* [oo::define] inside the constructor of a
|
||||
# class that patches in the appropriate class delegates.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
proc MixinClassDelegates {class} {
|
||||
if {![info object isa class $class]} {
|
||||
return
|
||||
}
|
||||
set delegate [DelegateName $class]
|
||||
if {![info object isa class $delegate]} {
|
||||
return
|
||||
}
|
||||
foreach c [info class superclass $class] {
|
||||
set d [DelegateName $c]
|
||||
if {![info object isa class $d]} {
|
||||
continue
|
||||
}
|
||||
define $delegate superclass -append $d
|
||||
}
|
||||
objdefine $class mixin -append $delegate
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# UpdateClassDelegatesAfterClone --
|
||||
#
|
||||
# Support code that is like [MixinClassDelegates] except for when a
|
||||
# class is cloned.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
proc UpdateClassDelegatesAfterClone {originObject targetObject} {
|
||||
# Rebuild the class inheritance delegation class
|
||||
set originDelegate [DelegateName $originObject]
|
||||
set targetDelegate [DelegateName $targetObject]
|
||||
if {
|
||||
[info object isa class $originDelegate]
|
||||
&& ![info object isa class $targetDelegate]
|
||||
} then {
|
||||
copy $originDelegate $targetDelegate
|
||||
objdefine $targetObject mixin -set \
|
||||
{*}[lmap c [info object mixin $targetObject] {
|
||||
if {$c eq $originDelegate} {set targetDelegate} {set c}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# oo::define::classmethod --
|
||||
#
|
||||
# Defines a class method. See define(n) for details.
|
||||
#
|
||||
# Note that the ::oo::define namespace is semi-public and a bit weird
|
||||
# anyway, so we don't regard the namespace path as being under control:
|
||||
# fully qualified names are used for everything.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
proc define::classmethod {name {args {}} {body {}}} {
|
||||
# Create the method on the class if the caller gave arguments and body
|
||||
::set argc [::llength [::info level 0]]
|
||||
::if {$argc == 3} {
|
||||
::return -code error -errorcode {TCL WRONGARGS} [::format \
|
||||
{wrong # args: should be "%s name ?args body?"} \
|
||||
[::lindex [::info level 0] 0]]
|
||||
}
|
||||
::set cls [::uplevel 1 self]
|
||||
::if {$argc == 4} {
|
||||
::oo::define [::oo::DelegateName $cls] method $name $args $body
|
||||
}
|
||||
# Make the connection by forwarding
|
||||
::tailcall forward $name myclass $name
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# oo::define::initialise, oo::define::initialize --
|
||||
#
|
||||
# Do specific initialisation for a class. See define(n) for details.
|
||||
#
|
||||
# Note that the ::oo::define namespace is semi-public and a bit weird
|
||||
# anyway, so we don't regard the namespace path as being under control:
|
||||
# fully qualified names are used for everything.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
proc define::initialise {body} {
|
||||
::set clsns [::info object namespace [::uplevel 1 self]]
|
||||
::tailcall apply [::list {} $body $clsns]
|
||||
}
|
||||
|
||||
# Make the [initialise] definition appear as [initialize] too
|
||||
namespace eval define {
|
||||
::namespace export initialise
|
||||
::namespace eval tmp {::namespace import ::oo::define::initialise}
|
||||
::namespace export -clear
|
||||
::rename tmp::initialise initialize
|
||||
::namespace delete tmp
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# Slot --
|
||||
#
|
||||
# The class of slot operations, which are basically lists at the low
|
||||
# level of TclOO; this provides a more consistent interface to them.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
define Slot {
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Slot Get --
|
||||
#
|
||||
# Basic slot getter. Retrieves the contents of the slot.
|
||||
# Particular slots must provide concrete non-erroring
|
||||
# implementation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
method Get {} {
|
||||
return -code error -errorcode {TCLOO ABSTRACT_SLOT} "unimplemented"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Slot Set --
|
||||
#
|
||||
# Basic slot setter. Sets the contents of the slot. Particular
|
||||
# slots must provide concrete non-erroring implementation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
method Set list {
|
||||
return -code error -errorcode {TCLOO ABSTRACT_SLOT} "unimplemented"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Slot -set, -append, -clear, --default-operation --
|
||||
#
|
||||
# Standard public slot operations. If a slot can't figure out
|
||||
# what method to call directly, it uses --default-operation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
method -set args {tailcall my Set $args}
|
||||
method -append args {
|
||||
set current [uplevel 1 [list [namespace which my] Get]]
|
||||
tailcall my Set [list {*}$current {*}$args]
|
||||
}
|
||||
method -clear {} {tailcall my Set {}}
|
||||
|
||||
# Default handling
|
||||
forward --default-operation my -append
|
||||
method unknown {args} {
|
||||
set def --default-operation
|
||||
if {[llength $args] == 0} {
|
||||
tailcall my $def
|
||||
} elseif {![string match -* [lindex $args 0]]} {
|
||||
tailcall my $def {*}$args
|
||||
}
|
||||
next {*}$args
|
||||
}
|
||||
|
||||
# Set up what is exported and what isn't
|
||||
export -set -append -clear
|
||||
unexport unknown destroy
|
||||
}
|
||||
|
||||
# Set the default operation differently for these slots
|
||||
objdefine define::superclass forward --default-operation my -set
|
||||
objdefine define::mixin forward --default-operation my -set
|
||||
objdefine objdefine::mixin forward --default-operation my -set
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# oo::object <cloned> --
|
||||
#
|
||||
# Handler for cloning objects that clones basic bits (only!) of the
|
||||
# object's namespace. Non-procedures, traces, sub-namespaces, etc. need
|
||||
# more complex (and class-specific) handling.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
define object method <cloned> {originObject} {
|
||||
# Copy over the procedures from the original namespace
|
||||
foreach p [info procs [info object namespace $originObject]::*] {
|
||||
set args [info args $p]
|
||||
set idx -1
|
||||
foreach a $args {
|
||||
if {[info default $p $a d]} {
|
||||
lset args [incr idx] [list $a $d]
|
||||
} else {
|
||||
lset args [incr idx] [list $a]
|
||||
}
|
||||
}
|
||||
set b [info body $p]
|
||||
set p [namespace tail $p]
|
||||
proc $p $args $b
|
||||
}
|
||||
# Copy over the variables from the original namespace
|
||||
foreach v [info vars [info object namespace $originObject]::*] {
|
||||
upvar 0 $v vOrigin
|
||||
namespace upvar [namespace current] [namespace tail $v] vNew
|
||||
if {[info exists vOrigin]} {
|
||||
if {[array exists vOrigin]} {
|
||||
array set vNew [array get vOrigin]
|
||||
} else {
|
||||
set vNew $vOrigin
|
||||
}
|
||||
}
|
||||
}
|
||||
# General commands, sub-namespaces and advancd variable config (traces,
|
||||
# etc) are *not* copied over. Classes that want that should do it
|
||||
# themselves.
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# oo::class <cloned> --
|
||||
#
|
||||
# Handler for cloning classes, which fixes up the delegates.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
define class method <cloned> {originObject} {
|
||||
next $originObject
|
||||
# Rebuild the class inheritance delegation class
|
||||
::oo::UpdateClassDelegatesAfterClone $originObject [self]
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# oo::singleton --
|
||||
#
|
||||
# A metaclass that is used to make classes that only permit one instance
|
||||
# of them to exist. See singleton(n).
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
class create singleton {
|
||||
superclass class
|
||||
variable object
|
||||
unexport create createWithNamespace
|
||||
method new args {
|
||||
if {![info exists object] || ![info object isa object $object]} {
|
||||
set object [next {*}$args]
|
||||
::oo::objdefine $object {
|
||||
method destroy {} {
|
||||
::return -code error -errorcode {TCLOO SINGLETON} \
|
||||
"may not destroy a singleton object"
|
||||
}
|
||||
method <cloned> {originObject} {
|
||||
::return -code error -errorcode {TCLOO SINGLETON} \
|
||||
"may not clone a singleton object"
|
||||
}
|
||||
}
|
||||
}
|
||||
return $object
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# oo::abstract --
|
||||
#
|
||||
# A metaclass that is used to make classes that can't be directly
|
||||
# instantiated. See abstract(n).
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
class create abstract {
|
||||
superclass class
|
||||
unexport create createWithNamespace new
|
||||
}
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# mode: tcl
|
||||
# c-basic-offset: 4
|
||||
# fill-column: 78
|
||||
# End:
|
||||
@@ -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. */
|
||||
|
||||
+127
-40
@@ -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
|
||||
@@ -1632,32 +1632,30 @@ Tcl_GetString(
|
||||
register Tcl_Obj *objPtr) /* Object whose string rep byte pointer should
|
||||
* be returned. */
|
||||
{
|
||||
if (objPtr->bytes != NULL) {
|
||||
return objPtr->bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note we do not check for objPtr->typePtr == NULL. An invariant of
|
||||
* a properly maintained Tcl_Obj is that at least one of objPtr->bytes
|
||||
* and objPtr->typePtr must not be NULL. If broken extensions fail to
|
||||
* maintain that invariant, we can crash here.
|
||||
*/
|
||||
|
||||
if (objPtr->typePtr->updateStringProc == NULL) {
|
||||
if (objPtr->bytes == NULL) {
|
||||
/*
|
||||
* Those Tcl_ObjTypes which choose not to define an updateStringProc
|
||||
* must be written in such a way that (objPtr->bytes) never becomes
|
||||
* NULL. This panic was added in Tcl 8.1.
|
||||
* Note we do not check for objPtr->typePtr == NULL. An invariant
|
||||
* of a properly maintained Tcl_Obj is that at least one of
|
||||
* objPtr->bytes and objPtr->typePtr must not be NULL. If broken
|
||||
* extensions fail to maintain that invariant, we can crash here.
|
||||
*/
|
||||
|
||||
Tcl_Panic("UpdateStringProc should not be invoked for type %s",
|
||||
objPtr->typePtr->name);
|
||||
}
|
||||
objPtr->typePtr->updateStringProc(objPtr);
|
||||
if (objPtr->bytes == NULL || objPtr->length < 0
|
||||
|| objPtr->bytes[objPtr->length] != '\0') {
|
||||
Tcl_Panic("UpdateStringProc for type '%s' "
|
||||
"failed to create a valid string rep", objPtr->typePtr->name);
|
||||
if (objPtr->typePtr->updateStringProc == NULL) {
|
||||
/*
|
||||
* Those Tcl_ObjTypes which choose not to define an
|
||||
* updateStringProc must be written in such a way that
|
||||
* (objPtr->bytes) never becomes NULL.
|
||||
*/
|
||||
Tcl_Panic("UpdateStringProc should not be invoked for type %s",
|
||||
objPtr->typePtr->name);
|
||||
}
|
||||
objPtr->typePtr->updateStringProc(objPtr);
|
||||
if (objPtr->bytes == NULL || objPtr->length < 0
|
||||
|| objPtr->bytes[objPtr->length] != '\0') {
|
||||
Tcl_Panic("UpdateStringProc for type '%s' "
|
||||
"failed to create a valid string rep",
|
||||
objPtr->typePtr->name);
|
||||
}
|
||||
}
|
||||
return objPtr->bytes;
|
||||
}
|
||||
@@ -1693,8 +1691,31 @@ Tcl_GetStringFromObj(
|
||||
* rep's byte array length should * be stored.
|
||||
* If NULL, no length is stored. */
|
||||
{
|
||||
(void) TclGetString(objPtr);
|
||||
if (objPtr->bytes == NULL) {
|
||||
/*
|
||||
* Note we do not check for objPtr->typePtr == NULL. An invariant
|
||||
* of a properly maintained Tcl_Obj is that at least one of
|
||||
* objPtr->bytes and objPtr->typePtr must not be NULL. If broken
|
||||
* extensions fail to maintain that invariant, we can crash here.
|
||||
*/
|
||||
|
||||
if (objPtr->typePtr->updateStringProc == NULL) {
|
||||
/*
|
||||
* Those Tcl_ObjTypes which choose not to define an
|
||||
* updateStringProc must be written in such a way that
|
||||
* (objPtr->bytes) never becomes NULL.
|
||||
*/
|
||||
Tcl_Panic("UpdateStringProc should not be invoked for type %s",
|
||||
objPtr->typePtr->name);
|
||||
}
|
||||
objPtr->typePtr->updateStringProc(objPtr);
|
||||
if (objPtr->bytes == NULL || objPtr->length < 0
|
||||
|| objPtr->bytes[objPtr->length] != '\0') {
|
||||
Tcl_Panic("UpdateStringProc for type '%s' "
|
||||
"failed to create a valid string rep",
|
||||
objPtr->typePtr->name);
|
||||
}
|
||||
}
|
||||
if (lengthPtr != NULL) {
|
||||
*lengthPtr = objPtr->length;
|
||||
}
|
||||
@@ -2786,7 +2807,7 @@ Tcl_GetLongFromObj(
|
||||
|
||||
if (w >= -(Tcl_WideInt)(ULONG_MAX)
|
||||
&& w <= (Tcl_WideInt)(ULONG_MAX)) {
|
||||
*longPtr = Tcl_WideAsLong(w);
|
||||
*longPtr = (long) w;
|
||||
return TCL_OK;
|
||||
}
|
||||
goto tooLarge;
|
||||
@@ -2812,10 +2833,9 @@ Tcl_GetLongFromObj(
|
||||
mp_int big;
|
||||
|
||||
UNPACK_BIGNUM(objPtr, big);
|
||||
if ((size_t) big.used <= (CHAR_BIT * sizeof(long) + DIGIT_BIT - 1)
|
||||
if ((size_t) big.used <= (CHAR_BIT * sizeof(unsigned long) + DIGIT_BIT - 1)
|
||||
/ DIGIT_BIT) {
|
||||
unsigned long value = 0, numBytes = sizeof(long);
|
||||
long scratch;
|
||||
unsigned long scratch, value = 0, numBytes = sizeof(unsigned long);
|
||||
unsigned char *bytes = (unsigned char *) &scratch;
|
||||
|
||||
if (mp_to_unsigned_bin_n(&big, bytes, &numBytes) == MP_OKAY) {
|
||||
@@ -3083,6 +3103,73 @@ Tcl_GetWideIntFromObj(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclGetWideBitsFromObj --
|
||||
*
|
||||
* Attempt to return a wide integer from the Tcl object "objPtr". If the
|
||||
* object is not already a int, double or bignum, an attempt will be made
|
||||
* to convert it to one of these. Out-of-range values don't result in an
|
||||
* error, but only the least significant 64 bits will be returned.
|
||||
*
|
||||
* Results:
|
||||
* The return value is a standard Tcl object result. If an error occurs
|
||||
* during conversion, an error message is left in the interpreter's
|
||||
* result unless "interp" is NULL.
|
||||
*
|
||||
* Side effects:
|
||||
* If the object is not already an int, double or bignum object, the
|
||||
* conversion will free any old internal representation.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
TclGetWideBitsFromObj(
|
||||
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
|
||||
Tcl_Obj *objPtr, /* Object from which to get a wide int. */
|
||||
Tcl_WideInt *wideIntPtr) /* Place to store resulting wide integer. */
|
||||
{
|
||||
do {
|
||||
if (objPtr->typePtr == &tclIntType) {
|
||||
*wideIntPtr = objPtr->internalRep.wideValue;
|
||||
return TCL_OK;
|
||||
}
|
||||
if (objPtr->typePtr == &tclDoubleType) {
|
||||
if (interp != NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"expected integer but got \"%s\"",
|
||||
TclGetString(objPtr)));
|
||||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
|
||||
}
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (objPtr->typePtr == &tclBignumType) {
|
||||
mp_int big;
|
||||
|
||||
Tcl_WideUInt value = 0, scratch;
|
||||
unsigned long numBytes = sizeof(Tcl_WideInt);
|
||||
unsigned char *bytes = (unsigned char *) &scratch;
|
||||
|
||||
Tcl_GetBignumFromObj(NULL, objPtr, &big);
|
||||
mp_mod_2d(&big, (int) (CHAR_BIT * sizeof(Tcl_WideInt)), &big);
|
||||
mp_to_unsigned_bin_n(&big, bytes, &numBytes);
|
||||
while (numBytes-- > 0) {
|
||||
value = (value << CHAR_BIT) | *bytes++;
|
||||
}
|
||||
if (big.sign) {
|
||||
value = -value;
|
||||
}
|
||||
*wideIntPtr = (Tcl_WideInt) value;
|
||||
mp_clear(&big);
|
||||
return TCL_OK;
|
||||
}
|
||||
} while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
|
||||
TCL_PARSE_INTEGER_ONLY)==TCL_OK);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -3449,7 +3536,7 @@ Tcl_SetBignumObj(
|
||||
while (numBytes-- > 0) {
|
||||
value = (value << CHAR_BIT) | *bytes++;
|
||||
}
|
||||
if (value > (((~(Tcl_WideUInt)0) >> 1) + bignumValue->sign)) {
|
||||
if (value > ((Tcl_WideUInt)WIDE_MAX + bignumValue->sign)) {
|
||||
goto tooLargeForWide;
|
||||
}
|
||||
if (bignumValue->sign) {
|
||||
@@ -3598,7 +3685,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 +3748,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 +3813,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)
|
||||
|
||||
+6
-1
@@ -979,7 +979,12 @@ TclParseBackslash(
|
||||
if (readPtr != NULL) {
|
||||
*readPtr = count;
|
||||
}
|
||||
return Tcl_UniCharToUtf(result, dst);
|
||||
count = Tcl_UniCharToUtf(result, dst);
|
||||
if (!count) {
|
||||
/* Special case for handling upper surrogates. */
|
||||
count = Tcl_UniCharToUtf(-1, dst);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -577,7 +577,7 @@ SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
|
||||
PkgAvail *availPtr, *bestPtr, *bestStablePtr;
|
||||
char *availVersion, *bestVersion, *bestStableVersion;
|
||||
/* Internal rep. of versions */
|
||||
int availStable, satisfies;
|
||||
int availStable, satisfies;
|
||||
Require *reqPtr = data[0];
|
||||
int reqc = PTR2INT(data[1]);
|
||||
Tcl_Obj **const reqv = data[2];
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
* configuration information.
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
# define CFG_THREADED "1"
|
||||
#else
|
||||
# define CFG_THREADED "0"
|
||||
@@ -105,6 +105,8 @@ static Tcl_Config const cfg[] = {
|
||||
{"scriptdir,runtime", CFG_RUNTIME_SCRDIR},
|
||||
{"includedir,runtime", CFG_RUNTIME_INCDIR},
|
||||
{"docdir,runtime", CFG_RUNTIME_DOCDIR},
|
||||
{"dllfile,runtime", CFG_RUNTIME_DLLFILE},
|
||||
{"zipfile,runtime", CFG_RUNTIME_ZIPFILE},
|
||||
|
||||
/* Installation paths to various stuff */
|
||||
|
||||
|
||||
@@ -50,6 +50,12 @@ extern "C" {
|
||||
* Exported function declarations:
|
||||
*/
|
||||
|
||||
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */
|
||||
/* Slot 0 is reserved */
|
||||
/* Slot 1 is reserved */
|
||||
/* 2 */
|
||||
EXTERN int TclZipfs_AppHook(int *argc, char ***argv);
|
||||
#endif /* UNIX */
|
||||
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
|
||||
/* 0 */
|
||||
EXTERN TCHAR * Tcl_WinUtfToTChar(const char *str, int len,
|
||||
@@ -57,6 +63,8 @@ EXTERN TCHAR * Tcl_WinUtfToTChar(const char *str, int len,
|
||||
/* 1 */
|
||||
EXTERN char * Tcl_WinTCharToUtf(const TCHAR *str, int len,
|
||||
Tcl_DString *dsPtr);
|
||||
/* 2 */
|
||||
EXTERN int TclZipfs_AppHook(int *argc, TCHAR ***argv);
|
||||
#endif /* WIN */
|
||||
#ifdef MAC_OSX_TCL /* MACOSX */
|
||||
/* 0 */
|
||||
@@ -69,19 +77,28 @@ EXTERN int Tcl_MacOSXOpenVersionedBundleResources(
|
||||
const char *bundleVersion,
|
||||
int hasResourceFile, int maxPathLen,
|
||||
char *libraryPath);
|
||||
/* 2 */
|
||||
EXTERN int TclZipfs_AppHook(int *argc, char ***argv);
|
||||
#endif /* MACOSX */
|
||||
|
||||
typedef struct TclPlatStubs {
|
||||
int magic;
|
||||
void *hooks;
|
||||
|
||||
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */
|
||||
void (*reserved0)(void);
|
||||
void (*reserved1)(void);
|
||||
int (*tclZipfs_AppHook) (int *argc, char ***argv); /* 2 */
|
||||
#endif /* UNIX */
|
||||
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
|
||||
TCHAR * (*tcl_WinUtfToTChar) (const char *str, int len, Tcl_DString *dsPtr); /* 0 */
|
||||
char * (*tcl_WinTCharToUtf) (const TCHAR *str, int len, Tcl_DString *dsPtr); /* 1 */
|
||||
int (*tclZipfs_AppHook) (int *argc, TCHAR ***argv); /* 2 */
|
||||
#endif /* WIN */
|
||||
#ifdef MAC_OSX_TCL /* MACOSX */
|
||||
int (*tcl_MacOSXOpenBundleResources) (Tcl_Interp *interp, const char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath); /* 0 */
|
||||
int (*tcl_MacOSXOpenVersionedBundleResources) (Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath); /* 1 */
|
||||
int (*tclZipfs_AppHook) (int *argc, char ***argv); /* 2 */
|
||||
#endif /* MACOSX */
|
||||
} TclPlatStubs;
|
||||
|
||||
@@ -97,17 +114,27 @@ extern const TclPlatStubs *tclPlatStubsPtr;
|
||||
* Inline function declarations:
|
||||
*/
|
||||
|
||||
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */
|
||||
/* Slot 0 is reserved */
|
||||
/* Slot 1 is reserved */
|
||||
#define TclZipfs_AppHook \
|
||||
(tclPlatStubsPtr->tclZipfs_AppHook) /* 2 */
|
||||
#endif /* UNIX */
|
||||
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
|
||||
#define Tcl_WinUtfToTChar \
|
||||
(tclPlatStubsPtr->tcl_WinUtfToTChar) /* 0 */
|
||||
#define Tcl_WinTCharToUtf \
|
||||
(tclPlatStubsPtr->tcl_WinTCharToUtf) /* 1 */
|
||||
#define TclZipfs_AppHook \
|
||||
(tclPlatStubsPtr->tclZipfs_AppHook) /* 2 */
|
||||
#endif /* WIN */
|
||||
#ifdef MAC_OSX_TCL /* MACOSX */
|
||||
#define Tcl_MacOSXOpenBundleResources \
|
||||
(tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */
|
||||
#define Tcl_MacOSXOpenVersionedBundleResources \
|
||||
(tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */
|
||||
#define TclZipfs_AppHook \
|
||||
(tclPlatStubsPtr->tclZipfs_AppHook) /* 2 */
|
||||
#endif /* MACOSX */
|
||||
|
||||
#endif /* defined(USE_TCL_STUBS) */
|
||||
|
||||
+3
-15
@@ -24,20 +24,8 @@
|
||||
#endif
|
||||
#include "tcl.h"
|
||||
|
||||
#if !defined(LLONG_MIN)
|
||||
# ifdef TCL_WIDE_INT_IS_LONG
|
||||
# define LLONG_MIN LONG_MIN
|
||||
# else
|
||||
# ifdef LLONG_BIT
|
||||
# define LLONG_MIN ((Tcl_WideInt)(Tcl_LongAsWide(1)<<(LLONG_BIT-1)))
|
||||
# else
|
||||
/* Assume we're on a system with a 64-bit 'long long' type */
|
||||
# define LLONG_MIN ((Tcl_WideInt)(Tcl_LongAsWide(1)<<63))
|
||||
# endif
|
||||
# endif
|
||||
/* Assume that if LLONG_MIN is undefined, then so is LLONG_MAX */
|
||||
# define LLONG_MAX (~LLONG_MIN)
|
||||
#endif
|
||||
|
||||
#define UWIDE_MAX ((Tcl_WideUInt)-1)
|
||||
#define WIDE_MAX ((Tcl_WideInt)(UWIDE_MAX >> 1))
|
||||
#define WIDE_MIN ((Tcl_WideInt)((Tcl_WideUInt)WIDE_MAX+1))
|
||||
|
||||
#endif /* _TCLPORT */
|
||||
|
||||
+5
-5
@@ -505,10 +505,11 @@ TclCreateProc(
|
||||
goto procError;
|
||||
}
|
||||
|
||||
nameLength = Tcl_NumUtfChars(Tcl_GetString(fieldValues[0]), fieldValues[0]->length);
|
||||
argname = Tcl_GetStringFromObj(fieldValues[0], &plen);
|
||||
nameLength = Tcl_NumUtfChars(argname, plen);
|
||||
if (fieldCount == 2) {
|
||||
valueLength = Tcl_NumUtfChars(Tcl_GetString(fieldValues[1]),
|
||||
fieldValues[1]->length);
|
||||
const char * value = TclGetString(fieldValues[1]);
|
||||
valueLength = Tcl_NumUtfChars(value, fieldValues[1]->length);
|
||||
} else {
|
||||
valueLength = 0;
|
||||
}
|
||||
@@ -517,7 +518,6 @@ TclCreateProc(
|
||||
* Check that the formal parameter name is a scalar.
|
||||
*/
|
||||
|
||||
argname = Tcl_GetStringFromObj(fieldValues[0], &plen);
|
||||
argnamei = argname;
|
||||
argnamelast = argname[plen-1];
|
||||
while (plen--) {
|
||||
@@ -611,7 +611,7 @@ TclCreateProc(
|
||||
procPtr->lastLocalPtr = localPtr;
|
||||
}
|
||||
localPtr->nextPtr = NULL;
|
||||
localPtr->nameLength = Tcl_NumUtfChars(argname, fieldValues[0]->length);
|
||||
localPtr->nameLength = nameLength;
|
||||
localPtr->frameIndex = i;
|
||||
localPtr->flags = VAR_ARGUMENT;
|
||||
localPtr->resolveInfo = NULL;
|
||||
|
||||
+35
-35
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* tclProcess.c --
|
||||
*
|
||||
* This file implements the "tcl::process" ensemble for subprocess
|
||||
* This file implements the "tcl::process" ensemble for subprocess
|
||||
* management as defined by TIP #462.
|
||||
*
|
||||
* Copyright (c) 2017 Frederic Bonnet.
|
||||
@@ -13,14 +13,14 @@
|
||||
#include "tclInt.h"
|
||||
|
||||
/*
|
||||
* Autopurge flag. Process-global because of the way Tcl manages child
|
||||
* Autopurge flag. Process-global because of the way Tcl manages child
|
||||
* processes (see tclPipe.c).
|
||||
*/
|
||||
|
||||
static int autopurge = 1; /* Autopurge flag. */
|
||||
|
||||
/*
|
||||
* Hash tables that keeps track of all child process statuses. Keys are the
|
||||
* Hash tables that keeps track of all child process statuses. Keys are the
|
||||
* child process ids and resolved pids, values are (ProcessInfo *).
|
||||
*/
|
||||
|
||||
@@ -29,7 +29,7 @@ typedef struct ProcessInfo {
|
||||
int resolvedPid; /* Resolved process id. */
|
||||
int purge; /* Purge eventualy. */
|
||||
TclProcessWaitStatus status;/* Process status. */
|
||||
int code; /* Error code, exit status or signal
|
||||
int code; /* Error code, exit status or signal
|
||||
number. */
|
||||
Tcl_Obj *msg; /* Error message. */
|
||||
Tcl_Obj *error; /* Error code. */
|
||||
@@ -47,7 +47,7 @@ static void InitProcessInfo(ProcessInfo *info, Tcl_Pid pid,
|
||||
int resolvedPid);
|
||||
static void FreeProcessInfo(ProcessInfo *info);
|
||||
static int RefreshProcessInfo(ProcessInfo *info, int options);
|
||||
static TclProcessWaitStatus WaitProcessStatus(Tcl_Pid pid, int resolvedPid,
|
||||
static TclProcessWaitStatus WaitProcessStatus(Tcl_Pid pid, int resolvedPid,
|
||||
int options, int *codePtr, Tcl_Obj **msgPtr,
|
||||
Tcl_Obj **errorObjPtr);
|
||||
static Tcl_Obj * BuildProcessStatusObj(ProcessInfo *info);
|
||||
@@ -160,7 +160,7 @@ RefreshProcessInfo(
|
||||
* Refresh & store status.
|
||||
*/
|
||||
|
||||
info->status = WaitProcessStatus(info->pid, info->resolvedPid,
|
||||
info->status = WaitProcessStatus(info->pid, info->resolvedPid,
|
||||
options, &info->code, &info->msg, &info->error);
|
||||
if (info->msg) Tcl_IncrRefCount(info->msg);
|
||||
if (info->error) Tcl_IncrRefCount(info->error);
|
||||
@@ -214,7 +214,7 @@ WaitProcessStatus(
|
||||
/*
|
||||
* No change.
|
||||
*/
|
||||
|
||||
|
||||
return TCL_PROCESS_UNCHANGED;
|
||||
}
|
||||
|
||||
@@ -370,7 +370,7 @@ BuildProcessStatusObj(
|
||||
/*
|
||||
* Normal exit, return TCL_OK.
|
||||
*/
|
||||
|
||||
|
||||
return Tcl_NewIntObj(TCL_OK);
|
||||
}
|
||||
|
||||
@@ -388,7 +388,7 @@ BuildProcessStatusObj(
|
||||
*
|
||||
* ProcessListObjCmd --
|
||||
*
|
||||
* This function implements the 'tcl::process list' Tcl command.
|
||||
* This function implements the 'tcl::process list' Tcl command.
|
||||
* Refer to the user documentation for details on what it does.
|
||||
*
|
||||
* Results:
|
||||
@@ -423,10 +423,10 @@ ProcessListObjCmd(
|
||||
|
||||
list = Tcl_NewListObj(0, NULL);
|
||||
Tcl_MutexLock(&infoTablesMutex);
|
||||
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
|
||||
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
|
||||
entry != NULL; entry = Tcl_NextHashEntry(&search)) {
|
||||
info = (ProcessInfo *) Tcl_GetHashValue(entry);
|
||||
Tcl_ListObjAppendElement(interp, list,
|
||||
Tcl_ListObjAppendElement(interp, list,
|
||||
Tcl_NewIntObj(info->resolvedPid));
|
||||
}
|
||||
Tcl_MutexUnlock(&infoTablesMutex);
|
||||
@@ -438,7 +438,7 @@ ProcessListObjCmd(
|
||||
*
|
||||
* ProcessStatusObjCmd --
|
||||
*
|
||||
* This function implements the 'tcl::process status' Tcl command.
|
||||
* This function implements the 'tcl::process status' Tcl command.
|
||||
* Refer to the user documentation for details on what it does.
|
||||
*
|
||||
* Results:
|
||||
@@ -504,7 +504,7 @@ ProcessStatusObjCmd(
|
||||
|
||||
dict = Tcl_NewDictObj();
|
||||
Tcl_MutexLock(&infoTablesMutex);
|
||||
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
|
||||
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
|
||||
entry != NULL; entry = Tcl_NextHashEntry(&search)) {
|
||||
info = (ProcessInfo *) Tcl_GetHashValue(entry);
|
||||
RefreshProcessInfo(info, options);
|
||||
@@ -513,7 +513,7 @@ ProcessStatusObjCmd(
|
||||
/*
|
||||
* Purge entry.
|
||||
*/
|
||||
|
||||
|
||||
Tcl_DeleteHashEntry(entry);
|
||||
entry = Tcl_FindHashEntry(&infoTablePerPid, info->pid);
|
||||
Tcl_DeleteHashEntry(entry);
|
||||
@@ -523,7 +523,7 @@ ProcessStatusObjCmd(
|
||||
* Add to result.
|
||||
*/
|
||||
|
||||
Tcl_DictObjPut(interp, dict, Tcl_NewIntObj(info->resolvedPid),
|
||||
Tcl_DictObjPut(interp, dict, Tcl_NewIntObj(info->resolvedPid),
|
||||
BuildProcessStatusObj(info));
|
||||
}
|
||||
}
|
||||
@@ -532,7 +532,7 @@ ProcessStatusObjCmd(
|
||||
/*
|
||||
* Only return statuses of provided processes.
|
||||
*/
|
||||
|
||||
|
||||
result = Tcl_ListObjGetElements(interp, objv[1], &numPids, &pidObjs);
|
||||
if (result != TCL_OK) {
|
||||
return result;
|
||||
@@ -552,10 +552,10 @@ ProcessStatusObjCmd(
|
||||
/*
|
||||
* Skip unknown process.
|
||||
*/
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
info = (ProcessInfo *) Tcl_GetHashValue(entry);
|
||||
RefreshProcessInfo(info, options);
|
||||
|
||||
@@ -563,7 +563,7 @@ ProcessStatusObjCmd(
|
||||
/*
|
||||
* Purge entry.
|
||||
*/
|
||||
|
||||
|
||||
Tcl_DeleteHashEntry(entry);
|
||||
entry = Tcl_FindHashEntry(&infoTablePerPid, info->pid);
|
||||
Tcl_DeleteHashEntry(entry);
|
||||
@@ -573,7 +573,7 @@ ProcessStatusObjCmd(
|
||||
* Add to result.
|
||||
*/
|
||||
|
||||
Tcl_DictObjPut(interp, dict, Tcl_NewIntObj(info->resolvedPid),
|
||||
Tcl_DictObjPut(interp, dict, Tcl_NewIntObj(info->resolvedPid),
|
||||
BuildProcessStatusObj(info));
|
||||
}
|
||||
}
|
||||
@@ -587,7 +587,7 @@ ProcessStatusObjCmd(
|
||||
*
|
||||
* ProcessPurgeObjCmd --
|
||||
*
|
||||
* This function implements the 'tcl::process purge' Tcl command.
|
||||
* This function implements the 'tcl::process purge' Tcl command.
|
||||
* Refer to the user documentation for details on what it does.
|
||||
*
|
||||
* Results:
|
||||
@@ -632,7 +632,7 @@ ProcessPurgeObjCmd(
|
||||
*/
|
||||
|
||||
Tcl_MutexLock(&infoTablesMutex);
|
||||
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
|
||||
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
|
||||
entry != NULL; entry = Tcl_NextHashEntry(&search)) {
|
||||
info = (ProcessInfo *) Tcl_GetHashValue(entry);
|
||||
if (info->purge) {
|
||||
@@ -647,7 +647,7 @@ ProcessPurgeObjCmd(
|
||||
/*
|
||||
* Purge only provided processes.
|
||||
*/
|
||||
|
||||
|
||||
result = Tcl_ListObjGetElements(interp, objv[1], &numPids, &pidObjs);
|
||||
if (result != TCL_OK) {
|
||||
return result;
|
||||
@@ -665,7 +665,7 @@ ProcessPurgeObjCmd(
|
||||
/*
|
||||
* Skip unknown process.
|
||||
*/
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -687,7 +687,7 @@ ProcessPurgeObjCmd(
|
||||
*
|
||||
* ProcessAutopurgeObjCmd --
|
||||
*
|
||||
* This function implements the 'tcl::process autopurge' Tcl command.
|
||||
* This function implements the 'tcl::process autopurge' Tcl command.
|
||||
* Refer to the user documentation for details on what it does.
|
||||
*
|
||||
* Results:
|
||||
@@ -715,7 +715,7 @@ ProcessAutopurgeObjCmd(
|
||||
/*
|
||||
* Set given value.
|
||||
*/
|
||||
|
||||
|
||||
int flag;
|
||||
int result = Tcl_GetBooleanFromObj(interp, objv[1], &flag);
|
||||
if (result != TCL_OK) {
|
||||
@@ -725,8 +725,8 @@ ProcessAutopurgeObjCmd(
|
||||
autopurge = !!flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return current value.
|
||||
/*
|
||||
* Return current value.
|
||||
*/
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(autopurge));
|
||||
@@ -821,9 +821,9 @@ TclProcessCreated(
|
||||
/*
|
||||
* Pid was reused, free old info and reuse structure.
|
||||
*/
|
||||
|
||||
|
||||
info = (ProcessInfo *) Tcl_GetHashValue(entry);
|
||||
entry2 = Tcl_FindHashEntry(&infoTablePerResolvedPid,
|
||||
entry2 = Tcl_FindHashEntry(&infoTablePerResolvedPid,
|
||||
INT2PTR(resolvedPid));
|
||||
if (entry2) Tcl_DeleteHashEntry(entry2);
|
||||
FreeProcessInfo(info);
|
||||
@@ -893,8 +893,8 @@ TclProcessWait(
|
||||
/*
|
||||
* Unknown process, just call WaitProcessStatus and return.
|
||||
*/
|
||||
|
||||
result = WaitProcessStatus(pid, TclpGetPid(pid), options, codePtr,
|
||||
|
||||
result = WaitProcessStatus(pid, TclpGetPid(pid), options, codePtr,
|
||||
msgObjPtr, errorObjPtr);
|
||||
if (msgObjPtr && *msgObjPtr) Tcl_IncrRefCount(*msgObjPtr);
|
||||
if (errorObjPtr && *errorObjPtr) Tcl_IncrRefCount(*errorObjPtr);
|
||||
@@ -909,7 +909,7 @@ TclProcessWait(
|
||||
* so report no change.
|
||||
*/
|
||||
Tcl_MutexUnlock(&infoTablesMutex);
|
||||
|
||||
|
||||
return TCL_PROCESS_UNCHANGED;
|
||||
}
|
||||
|
||||
@@ -919,7 +919,7 @@ TclProcessWait(
|
||||
* No change, stop there.
|
||||
*/
|
||||
Tcl_MutexUnlock(&infoTablesMutex);
|
||||
|
||||
|
||||
return TCL_PROCESS_UNCHANGED;
|
||||
}
|
||||
|
||||
@@ -940,7 +940,7 @@ TclProcessWait(
|
||||
*/
|
||||
|
||||
Tcl_DeleteHashEntry(entry);
|
||||
entry = Tcl_FindHashEntry(&infoTablePerResolvedPid,
|
||||
entry = Tcl_FindHashEntry(&infoTablePerResolvedPid,
|
||||
INT2PTR(info->resolvedPid));
|
||||
Tcl_DeleteHashEntry(entry);
|
||||
FreeProcessInfo(info);
|
||||
|
||||
+2
-2
@@ -926,9 +926,9 @@ Tcl_ScanObjCmd(
|
||||
}
|
||||
if (flags & SCAN_LONGER) {
|
||||
if (Tcl_GetWideIntFromObj(NULL, objPtr, &wideValue) != TCL_OK) {
|
||||
wideValue = LLONG_MAX;
|
||||
wideValue = WIDE_MAX;
|
||||
if (TclGetString(objPtr)[0] == '-') {
|
||||
wideValue = LLONG_MIN;
|
||||
wideValue = WIDE_MIN;
|
||||
}
|
||||
}
|
||||
if ((flags & SCAN_UNSIGNED) && (wideValue < 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)) {
|
||||
|
||||
+377
-114
@@ -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;
|
||||
}
|
||||
@@ -562,6 +606,8 @@ Tcl_GetUniChar(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef TCL_NO_DEPRECATED
|
||||
#undef Tcl_GetUnicode
|
||||
Tcl_UniChar *
|
||||
Tcl_GetUnicode(
|
||||
Tcl_Obj *objPtr) /* The object to find the unicode string
|
||||
@@ -569,6 +615,7 @@ Tcl_GetUnicode(
|
||||
{
|
||||
return Tcl_GetUnicodeFromObj(objPtr, NULL);
|
||||
}
|
||||
#endif /* TCL_NO_DEPRECATED */
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -644,7 +691,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 +700,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 +746,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 +1322,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 +1414,7 @@ Tcl_AppendObjToObj(
|
||||
numChars = stringPtr->numChars;
|
||||
if ((numChars >= 0) && (appendObjPtr->typePtr == &tclStringType)) {
|
||||
String *appendStringPtr = GET_STRING(appendObjPtr);
|
||||
|
||||
appendNumChars = appendStringPtr->numChars;
|
||||
}
|
||||
|
||||
@@ -1847,6 +1904,11 @@ Tcl_AppendFormatToObj(
|
||||
width = 0;
|
||||
if (isdigit(UCHAR(ch))) {
|
||||
width = strtoul(format, &end, 10);
|
||||
if (width < 0) {
|
||||
msg = overflow;
|
||||
errCode = "OVERFLOW";
|
||||
goto errorMsg;
|
||||
}
|
||||
format = end;
|
||||
step = TclUtfToUniChar(format, &ch);
|
||||
} else if (ch == '*') {
|
||||
@@ -1943,7 +2005,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;
|
||||
@@ -1985,6 +2048,10 @@ Tcl_AppendFormatToObj(
|
||||
goto error;
|
||||
}
|
||||
length = Tcl_UniCharToUtf(code, buf);
|
||||
if (!length) {
|
||||
/* Special case for handling upper surrogates. */
|
||||
length = Tcl_UniCharToUtf(-1, buf);
|
||||
}
|
||||
segment = Tcl_NewStringObj(buf, length);
|
||||
Tcl_IncrRefCount(segment);
|
||||
allocSegment = 1;
|
||||
@@ -2030,35 +2097,17 @@ Tcl_AppendFormatToObj(
|
||||
}
|
||||
#ifndef TCL_WIDE_INT_IS_LONG
|
||||
} else if (useWide) {
|
||||
if (TclGetWideIntFromObj(NULL, segment, &w) != TCL_OK) {
|
||||
Tcl_Obj *objPtr;
|
||||
|
||||
if (Tcl_GetBignumFromObj(interp,segment,&big) != TCL_OK) {
|
||||
goto error;
|
||||
}
|
||||
mp_mod_2d(&big, (int) CHAR_BIT*sizeof(Tcl_WideInt), &big);
|
||||
objPtr = Tcl_NewBignumObj(&big);
|
||||
Tcl_IncrRefCount(objPtr);
|
||||
TclGetWideIntFromObj(NULL, objPtr, &w);
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
if (TclGetWideBitsFromObj(interp, segment, &w) != TCL_OK) {
|
||||
goto error;
|
||||
}
|
||||
isNegative = (w < (Tcl_WideInt) 0);
|
||||
if (w == (Tcl_WideInt) 0) gotHash = 0;
|
||||
#endif
|
||||
} else if (TclGetLongFromObj(NULL, segment, &l) != TCL_OK) {
|
||||
if (TclGetWideIntFromObj(NULL, segment, &w) != TCL_OK) {
|
||||
Tcl_Obj *objPtr;
|
||||
|
||||
if (Tcl_GetBignumFromObj(interp,segment,&big) != TCL_OK) {
|
||||
goto error;
|
||||
}
|
||||
mp_mod_2d(&big, (int) CHAR_BIT * sizeof(long), &big);
|
||||
objPtr = Tcl_NewBignumObj(&big);
|
||||
Tcl_IncrRefCount(objPtr);
|
||||
TclGetLongFromObj(NULL, objPtr, &l);
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
if (TclGetWideBitsFromObj(interp, segment, &w) != TCL_OK) {
|
||||
goto error;
|
||||
} else {
|
||||
l = Tcl_WideAsLong(w);
|
||||
l = (long) w;
|
||||
}
|
||||
if (useShort) {
|
||||
s = (short) l;
|
||||
@@ -2468,7 +2517,7 @@ Tcl_AppendFormatToObj(
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_Format--
|
||||
* Tcl_Format --
|
||||
*
|
||||
* Results:
|
||||
* A refcount zero Tcl_Obj.
|
||||
@@ -2859,7 +2908,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 +2937,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 +3024,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,15 +3048,25 @@ 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
|
||||
*/
|
||||
|
||||
int numBytes;
|
||||
ov = objv;
|
||||
oc = objc;
|
||||
do {
|
||||
Tcl_Obj *objPtr = *ov++;
|
||||
|
||||
if (objPtr->bytes == NULL) {
|
||||
int numBytes;
|
||||
/*
|
||||
* Every argument is either a bytearray with a ("pure")
|
||||
* value we know we can safely use, or it is an empty string.
|
||||
* We don't need to count bytes for the empty strings.
|
||||
*/
|
||||
|
||||
if (TclIsPureByteArray(objPtr)) {
|
||||
Tcl_GetByteArrayFromObj(objPtr, &numBytes); /* PANIC? */
|
||||
|
||||
if (numBytes) {
|
||||
last = objc - oc;
|
||||
if (length == 0) {
|
||||
@@ -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;
|
||||
|
||||
@@ -3149,7 +3218,13 @@ TclStringCat(
|
||||
while (objc--) {
|
||||
Tcl_Obj *objPtr = *objv++;
|
||||
|
||||
if (objPtr->bytes == NULL) {
|
||||
/*
|
||||
* Every argument is either a bytearray with a ("pure")
|
||||
* value we know we can safely use, or it is an empty string.
|
||||
* We don't need to copy bytes from the empty strings.
|
||||
*/
|
||||
|
||||
if (TclIsPureByteArray(objPtr)) {
|
||||
int more;
|
||||
unsigned char *src = Tcl_GetByteArrayFromObj(objPtr, &more);
|
||||
memcpy(dst, src, (size_t) more);
|
||||
@@ -3250,6 +3325,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 +3344,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;
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
@@ -3298,7 +3555,7 @@ TclStringFirst(
|
||||
start = 0;
|
||||
}
|
||||
if (ln == 0) {
|
||||
/* We don't find empty substrings. Bizarre!
|
||||
/* We don't find empty substrings. Bizarre!
|
||||
* Whenever this routine is turned into a proper substring
|
||||
* finder, change to `return start` after limits imposed. */
|
||||
return -1;
|
||||
@@ -3462,18 +3719,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 +3781,10 @@ TclStringReverse(
|
||||
*to++ = *src;
|
||||
}
|
||||
} else {
|
||||
/* Reversing in place */
|
||||
/*
|
||||
* Reversing in place.
|
||||
*/
|
||||
|
||||
while (--src > from) {
|
||||
ch = *src;
|
||||
*src = *from;
|
||||
@@ -3546,20 +3808,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 +3853,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
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -3689,7 +3952,7 @@ TclStringReplace(
|
||||
result = Tcl_NewByteArrayObj(NULL, numBytes - count + newBytes);
|
||||
/* PANIC? */
|
||||
Tcl_SetByteArrayLength(result, 0);
|
||||
TclAppendBytesToByteArray(result, bytes, first);
|
||||
TclAppendBytesToByteArray(result, bytes, first);
|
||||
TclAppendBytesToByteArray(result, iBytes, newBytes);
|
||||
TclAppendBytesToByteArray(result, bytes + first + count,
|
||||
numBytes - count - first);
|
||||
@@ -3711,7 +3974,7 @@ TclStringReplace(
|
||||
Tcl_UniChar *ustring = Tcl_GetUnicodeFromObj(objPtr, &numChars);
|
||||
|
||||
/* TODO: Is there an in-place option worth pursuing here? */
|
||||
|
||||
|
||||
result = Tcl_NewUnicodeObj(ustring, first);
|
||||
if (insertPtr) {
|
||||
Tcl_AppendObjToObj(result, insertPtr);
|
||||
|
||||
+56
-14
@@ -34,12 +34,14 @@
|
||||
#undef Tcl_DbNewLongObj
|
||||
#undef Tcl_NewObj
|
||||
#undef Tcl_NewStringObj
|
||||
#undef Tcl_GetUnicode
|
||||
#undef Tcl_DumpActiveMemory
|
||||
#undef Tcl_ValidateAllMemory
|
||||
#undef Tcl_FindHashEntry
|
||||
#undef Tcl_CreateHashEntry
|
||||
#undef Tcl_Panic
|
||||
#undef Tcl_FindExecutable
|
||||
#undef Tcl_SetPanicProc
|
||||
#undef TclpGetPid
|
||||
#undef TclSockMinimumBuffers
|
||||
#undef Tcl_SetIntObj
|
||||
@@ -223,17 +225,31 @@ Tcl_WinUtfToTChar(
|
||||
int len,
|
||||
Tcl_DString *dsPtr)
|
||||
{
|
||||
WCHAR *wp;
|
||||
WCHAR *wp, *p;
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, string, len, 0, 0);
|
||||
|
||||
Tcl_DStringInit(dsPtr);
|
||||
Tcl_DStringSetLength(dsPtr, 2*size+2);
|
||||
wp = (WCHAR *)Tcl_DStringValue(dsPtr);
|
||||
p = wp = (WCHAR *)Tcl_DStringValue(dsPtr);
|
||||
MultiByteToWideChar(CP_UTF8, 0, string, len, wp, size+1);
|
||||
if (len == -1) --size; /* account for 0-byte at string end */
|
||||
|
||||
/* It turns out that MultiByteToWideChar() cannot handle the 'modified'
|
||||
* UTF-8 as used by Tcl. Every sequence of 0xC0 followed by 0x80 will
|
||||
* be translated to two 0xfffd characters. This results in a test-failure
|
||||
* of the registry-6.20 test-case. The simplest solution is to search for
|
||||
* those two 0xfffd characters and replace them by a \u0000 character. */
|
||||
while (p < wp + size - 1) {
|
||||
if (p[0] == 0xfffd && p[1] == 0xfffd) {
|
||||
memmove(p+1, p+2, sizeof(WCHAR) * (p - wp + size - 2));
|
||||
p[0] = '\0';
|
||||
++p; --size;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
Tcl_DStringSetLength(dsPtr, 2*size);
|
||||
wp[size] = 0;
|
||||
return (char *)wp;
|
||||
return (char *) wp;
|
||||
}
|
||||
|
||||
char *
|
||||
@@ -242,7 +258,7 @@ Tcl_WinTCharToUtf(
|
||||
int len,
|
||||
Tcl_DString *dsPtr)
|
||||
{
|
||||
char *p;
|
||||
char *p, *r;
|
||||
int size;
|
||||
|
||||
if (len > 0) {
|
||||
@@ -250,10 +266,20 @@ Tcl_WinTCharToUtf(
|
||||
}
|
||||
size = WideCharToMultiByte(CP_UTF8, 0, string, len, 0, 0, NULL, NULL);
|
||||
Tcl_DStringInit(dsPtr);
|
||||
Tcl_DStringSetLength(dsPtr, size+1);
|
||||
p = (char *)Tcl_DStringValue(dsPtr);
|
||||
Tcl_DStringSetLength(dsPtr, size+8); /* Add some spare, in case of NULL-bytes */
|
||||
r = p = (char *)Tcl_DStringValue(dsPtr);
|
||||
WideCharToMultiByte(CP_UTF8, 0, string, len, p, size, NULL, NULL);
|
||||
if (len == -1) --size; /* account for 0-byte at string end */
|
||||
while (r < p+size) {
|
||||
if (!*r) {
|
||||
/* Output contains '\0'-byte, but Tcl expect two-bytes: C0 80 */
|
||||
memmove(r+2, r+1, p-r+size-1);
|
||||
memcpy(r++, "\xC0\x80", 2);
|
||||
Tcl_DStringSetLength(dsPtr, ++size + 1);
|
||||
r = p = (char *)Tcl_DStringValue(dsPtr);
|
||||
}
|
||||
++r;
|
||||
}
|
||||
Tcl_DStringSetLength(dsPtr, size);
|
||||
p[size] = 0;
|
||||
return p;
|
||||
@@ -401,6 +427,7 @@ static int uniCharNcasecmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsig
|
||||
# define TclpGmtime 0
|
||||
# define TclpLocaltime_unix 0
|
||||
# define TclpGmtime_unix 0
|
||||
# define Tcl_GetUnicode 0
|
||||
#else /* TCL_NO_DEPRECATED */
|
||||
# define Tcl_SeekOld seekOld
|
||||
# define Tcl_TellOld tellOld
|
||||
@@ -428,20 +455,14 @@ seekOld(
|
||||
int offset, /* Offset to seek to. */
|
||||
int mode) /* Relative to which location to seek? */
|
||||
{
|
||||
Tcl_WideInt wOffset, wResult;
|
||||
|
||||
wOffset = Tcl_LongAsWide((long) offset);
|
||||
wResult = Tcl_Seek(chan, wOffset, mode);
|
||||
return (int) Tcl_WideAsLong(wResult);
|
||||
return Tcl_Seek(chan, offset, mode);
|
||||
}
|
||||
|
||||
static int
|
||||
tellOld(
|
||||
Tcl_Channel chan) /* The channel to return pos for. */
|
||||
{
|
||||
Tcl_WideInt wResult = Tcl_Tell(chan);
|
||||
|
||||
return (int) Tcl_WideAsLong(wResult);
|
||||
return Tcl_Tell(chan);
|
||||
}
|
||||
#endif /* !TCL_NO_DEPRECATED */
|
||||
|
||||
@@ -454,6 +475,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 = {
|
||||
@@ -825,13 +855,20 @@ static const TclIntPlatStubs tclIntPlatStubs = {
|
||||
static const TclPlatStubs tclPlatStubs = {
|
||||
TCL_STUB_MAGIC,
|
||||
0,
|
||||
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */
|
||||
0, /* 0 */
|
||||
0, /* 1 */
|
||||
TclZipfs_AppHook, /* 2 */
|
||||
#endif /* UNIX */
|
||||
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
|
||||
Tcl_WinUtfToTChar, /* 0 */
|
||||
Tcl_WinTCharToUtf, /* 1 */
|
||||
TclZipfs_AppHook, /* 2 */
|
||||
#endif /* WIN */
|
||||
#ifdef MAC_OSX_TCL /* MACOSX */
|
||||
Tcl_MacOSXOpenBundleResources, /* 0 */
|
||||
Tcl_MacOSXOpenVersionedBundleResources, /* 1 */
|
||||
TclZipfs_AppHook, /* 2 */
|
||||
#endif /* MACOSX */
|
||||
};
|
||||
|
||||
@@ -910,6 +947,7 @@ const TclTomMathStubs tclTomMathStubs = {
|
||||
TclBN_mp_get_long_long, /* 69 */
|
||||
TclBN_mp_set_long, /* 70 */
|
||||
TclBN_mp_get_long, /* 71 */
|
||||
TclBN_mp_get_int, /* 72 */
|
||||
};
|
||||
|
||||
static const TclStubHooks tclStubHooks = {
|
||||
@@ -1577,6 +1615,10 @@ const TclStubs tclStubs = {
|
||||
Tcl_FSUnloadFile, /* 629 */
|
||||
Tcl_ZlibStreamSetCompressionDictionary, /* 630 */
|
||||
Tcl_OpenTcpServerEx, /* 631 */
|
||||
TclZipfs_Mount, /* 632 */
|
||||
TclZipfs_Unmount, /* 633 */
|
||||
TclZipfs_TclLibrary, /* 634 */
|
||||
TclZipfs_Mount_Buffer, /* 635 */
|
||||
};
|
||||
|
||||
/* !END!: Do not edit above this line. */
|
||||
|
||||
+28
-6
@@ -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(
|
||||
@@ -293,6 +293,8 @@ static int TestgetassocdataCmd(ClientData dummy,
|
||||
Tcl_Interp *interp, int argc, const char **argv);
|
||||
static int TestgetintCmd(ClientData dummy,
|
||||
Tcl_Interp *interp, int argc, const char **argv);
|
||||
static int TestlongsizeCmd(ClientData dummy,
|
||||
Tcl_Interp *interp, int argc, const char **argv);
|
||||
static int TestgetplatformCmd(ClientData dummy,
|
||||
Tcl_Interp *interp, int argc, const char **argv);
|
||||
static int TestgetvarfullnameCmd(
|
||||
@@ -645,6 +647,8 @@ Tcltest_Init(
|
||||
NULL, NULL);
|
||||
Tcl_CreateCommand(interp, "testgetint", TestgetintCmd,
|
||||
NULL, NULL);
|
||||
Tcl_CreateCommand(interp, "testlongsize", TestlongsizeCmd,
|
||||
NULL, NULL);
|
||||
Tcl_CreateCommand(interp, "testgetplatform", TestgetplatformCmd,
|
||||
NULL, NULL);
|
||||
Tcl_CreateObjCommand(interp, "testgetvarfullname",
|
||||
@@ -722,7 +726,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 +906,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 +1003,7 @@ AsyncHandlerProc(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
#if TCL_THREADS
|
||||
static Tcl_ThreadCreateType
|
||||
AsyncThreadProc(
|
||||
ClientData clientData) /* Parameter is the id of a
|
||||
@@ -2828,7 +2832,7 @@ TestlinkCmd(
|
||||
static int intVar = 43;
|
||||
static int boolVar = 4;
|
||||
static double realVar = 1.23;
|
||||
static Tcl_WideInt wideVar = Tcl_LongAsWide(79);
|
||||
static Tcl_WideInt wideVar = 79;
|
||||
static char *stringVar = NULL;
|
||||
static char charVar = '@';
|
||||
static unsigned char ucharVar = 130;
|
||||
@@ -2838,7 +2842,7 @@ TestlinkCmd(
|
||||
static long longVar = 123456789L;
|
||||
static unsigned long ulongVar = 3456789012UL;
|
||||
static float floatVar = 4.5;
|
||||
static Tcl_WideUInt uwideVar = (Tcl_WideUInt) Tcl_LongAsWide(123);
|
||||
static Tcl_WideUInt uwideVar = 123;
|
||||
static int created = 0;
|
||||
char buffer[2*TCL_DOUBLE_SPACE];
|
||||
int writable, flag;
|
||||
@@ -6936,6 +6940,24 @@ TestgetintCmd(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Used for determining sizeof(long) at script level.
|
||||
*/
|
||||
static int
|
||||
TestlongsizeCmd(
|
||||
ClientData dummy,
|
||||
Tcl_Interp *interp,
|
||||
int argc,
|
||||
const char **argv)
|
||||
{
|
||||
if (argc != 1) {
|
||||
Tcl_AppendResult(interp, "wrong # args", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)sizeof(long)));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
NREUnwind_callback(
|
||||
ClientData data[],
|
||||
|
||||
+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
|
||||
@@ -174,7 +174,6 @@ TclThread_Init(
|
||||
Tcl_CreateObjCommand(interp, "testthread", ThreadObjCmd, NULL, NULL);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -1158,6 +1157,14 @@ ThreadExitProc(
|
||||
|
||||
Tcl_MutexLock(&threadMutex);
|
||||
|
||||
if (self == errorThreadId) {
|
||||
if (errorProcString) { /* Extra safety */
|
||||
ckfree(errorProcString);
|
||||
errorProcString = NULL;
|
||||
}
|
||||
errorThreadId = 0;
|
||||
}
|
||||
|
||||
if (threadEvalScript) {
|
||||
ckfree(threadEvalScript);
|
||||
threadEvalScript = NULL;
|
||||
|
||||
@@ -250,6 +250,9 @@ declare 70 {
|
||||
declare 71 {
|
||||
unsigned long TclBN_mp_get_long(const mp_int *a)
|
||||
}
|
||||
declare 72 {
|
||||
unsigned long TclBN_mp_get_int(const mp_int *a)
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# mode: tcl
|
||||
|
||||
@@ -98,7 +98,6 @@
|
||||
#define mp_radix_size TclBN_mp_radix_size
|
||||
#define mp_read_radix TclBN_mp_read_radix
|
||||
#define mp_rshd TclBN_mp_rshd
|
||||
#define mp_s_rmap TclBNMpSRmap
|
||||
#define mp_set TclBN_mp_set
|
||||
#define mp_set_int TclBN_mp_set_int
|
||||
#define mp_set_long TclBN_mp_set_long
|
||||
@@ -324,6 +323,8 @@ EXTERN Tcl_WideUInt TclBN_mp_get_long_long(const mp_int *a);
|
||||
EXTERN int TclBN_mp_set_long(mp_int *a, unsigned long i);
|
||||
/* 71 */
|
||||
EXTERN unsigned long TclBN_mp_get_long(const mp_int *a);
|
||||
/* 72 */
|
||||
EXTERN unsigned long TclBN_mp_get_int(const mp_int *a);
|
||||
|
||||
typedef struct TclTomMathStubs {
|
||||
int magic;
|
||||
@@ -401,6 +402,7 @@ typedef struct TclTomMathStubs {
|
||||
Tcl_WideUInt (*tclBN_mp_get_long_long) (const mp_int *a); /* 69 */
|
||||
int (*tclBN_mp_set_long) (mp_int *a, unsigned long i); /* 70 */
|
||||
unsigned long (*tclBN_mp_get_long) (const mp_int *a); /* 71 */
|
||||
unsigned long (*tclBN_mp_get_int) (const mp_int *a); /* 72 */
|
||||
} TclTomMathStubs;
|
||||
|
||||
extern const TclTomMathStubs *tclTomMathStubsPtr;
|
||||
@@ -559,6 +561,8 @@ extern const TclTomMathStubs *tclTomMathStubsPtr;
|
||||
(tclTomMathStubsPtr->tclBN_mp_set_long) /* 70 */
|
||||
#define TclBN_mp_get_long \
|
||||
(tclTomMathStubsPtr->tclBN_mp_get_long) /* 71 */
|
||||
#define TclBN_mp_get_int \
|
||||
(tclTomMathStubsPtr->tclBN_mp_get_int) /* 72 */
|
||||
|
||||
#endif /* defined(USE_TCL_STUBS) */
|
||||
|
||||
|
||||
+24
-8
@@ -173,6 +173,13 @@ Tcl_UniCharToUtf(
|
||||
buf[0] = (char) ((ch >> 18) | 0xF0);
|
||||
return 4;
|
||||
}
|
||||
} else if (ch == -1) {
|
||||
if (((buf[0] & 0xF8) == 0xF0) && ((buf[1] & 0xC0) == 0x80)
|
||||
&& ((buf[2] & 0xCF) == 0)) {
|
||||
ch = 0xD7C0 + ((buf[0] & 0x07) << 8) + ((buf[1] & 0x3F) << 2)
|
||||
+ ((buf[2] & 0x30) >> 4);
|
||||
goto three;
|
||||
}
|
||||
}
|
||||
|
||||
ch = 0xFFFD;
|
||||
@@ -211,7 +218,7 @@ Tcl_UniCharToUtfDString(
|
||||
{
|
||||
const Tcl_UniChar *w, *wEnd;
|
||||
char *p, *string;
|
||||
int oldLength;
|
||||
int oldLength, len = 1;
|
||||
|
||||
/*
|
||||
* UTF-8 string length in bytes will be <= Unicode string length * 4.
|
||||
@@ -224,9 +231,18 @@ Tcl_UniCharToUtfDString(
|
||||
p = string;
|
||||
wEnd = uniStr + uniLength;
|
||||
for (w = uniStr; w < wEnd; ) {
|
||||
p += Tcl_UniCharToUtf(*w, p);
|
||||
if (!len && ((*w & 0xFC00) != 0xDC00)) {
|
||||
/* Special case for handling upper surrogates. */
|
||||
p += Tcl_UniCharToUtf(-1, p);
|
||||
}
|
||||
len = Tcl_UniCharToUtf(*w, p);
|
||||
p += len;
|
||||
w++;
|
||||
}
|
||||
if (!len) {
|
||||
/* Special case for handling upper surrogates. */
|
||||
p += Tcl_UniCharToUtf(-1, p);
|
||||
}
|
||||
Tcl_DStringSetLength(dsPtr, oldLength + (p - string));
|
||||
|
||||
return string;
|
||||
@@ -892,7 +908,7 @@ Tcl_UtfToUpper(
|
||||
* char to dst if its size is <= the original char.
|
||||
*/
|
||||
|
||||
if (bytes < TclUtfCount(upChar)) {
|
||||
if ((bytes < TclUtfCount(upChar)) || ((upChar & 0xF800) == 0xD800)) {
|
||||
memcpy(dst, src, (size_t) bytes);
|
||||
dst += bytes;
|
||||
} else {
|
||||
@@ -955,7 +971,7 @@ Tcl_UtfToLower(
|
||||
* char to dst if its size is <= the original char.
|
||||
*/
|
||||
|
||||
if (bytes < TclUtfCount(lowChar)) {
|
||||
if ((bytes < TclUtfCount(lowChar)) || ((lowChar & 0xF800) == 0xD800)) {
|
||||
memcpy(dst, src, (size_t) bytes);
|
||||
dst += bytes;
|
||||
} else {
|
||||
@@ -1015,7 +1031,7 @@ Tcl_UtfToTitle(
|
||||
#endif
|
||||
titleChar = Tcl_UniCharToTitle(titleChar);
|
||||
|
||||
if (bytes < TclUtfCount(titleChar)) {
|
||||
if ((bytes < TclUtfCount(titleChar)) || ((titleChar & 0xF800) == 0xD800)) {
|
||||
memcpy(dst, src, (size_t) bytes);
|
||||
dst += bytes;
|
||||
} else {
|
||||
@@ -1034,12 +1050,12 @@ 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);
|
||||
}
|
||||
|
||||
if (bytes < TclUtfCount(lowChar)) {
|
||||
if ((bytes < TclUtfCount(lowChar)) || ((lowChar & 0xF800) == 0xD800)) {
|
||||
memcpy(dst, src, (size_t) bytes);
|
||||
dst += bytes;
|
||||
} else {
|
||||
|
||||
+5
-5
@@ -120,7 +120,7 @@ static int FindElement(Tcl_Interp *interp, const char *string,
|
||||
/*
|
||||
* The following is the Tcl object type definition for an object that
|
||||
* represents a list index in the form, "end-offset". It is used as a
|
||||
* performance optimization in TclGetIntForIndex. The internal rep is
|
||||
* performance optimization in TclGetIntForIndex. The internal rep is
|
||||
* stored directly in the wideValue, so no memory management is required
|
||||
* for it. This is a caching intrep, keeping the result of a parse
|
||||
* around. This type is only created from a pre-existing string, so an
|
||||
@@ -1673,7 +1673,7 @@ UtfWellFormedEnd(
|
||||
if (Tcl_UtfCharComplete(p, l - p)) {
|
||||
return bytes;
|
||||
}
|
||||
/*
|
||||
/*
|
||||
* Malformed utf-8 end, be sure we've NTS to safe compare of end-character,
|
||||
* avoid segfault by access violation out of range.
|
||||
*/
|
||||
@@ -3793,7 +3793,7 @@ GetEndOffsetFromObj(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -3976,12 +3976,12 @@ TclIndexEncode(
|
||||
/* usual case, the absolute index value encodes itself */
|
||||
} else if (TCL_OK == GetEndOffsetFromObj(objPtr, 0, &idx)) {
|
||||
/*
|
||||
* We parsed an end+offset index value.
|
||||
* We parsed an end+offset index value.
|
||||
* idx holds the offset value in the range INT_MIN...INT_MAX.
|
||||
*/
|
||||
if (idx > 0) {
|
||||
/*
|
||||
* All end+postive or end-negative expressions
|
||||
* All end+postive or end-negative expressions
|
||||
* always indicate "after the end".
|
||||
*/
|
||||
idx = after;
|
||||
|
||||
+175
-144
@@ -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,14 +2986,14 @@ 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;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ArrayForObjCmd(
|
||||
ClientData dummy, /* Not used. */
|
||||
Tcl_Interp *interp, /* Current interpreter. */
|
||||
@@ -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
|
||||
|
||||
+4525
File diff suppressed because it is too large
Load Diff
@@ -74,6 +74,54 @@ proc tcl_findLibrary {basename version patch initScript enVarName varName} {
|
||||
lappend dirs $env($enVarName)
|
||||
}
|
||||
|
||||
catch {
|
||||
set found 0
|
||||
set root [zipfs root]
|
||||
set mountpoint [file join $root lib [string tolower $basename]]
|
||||
lappend dirs [file join $root app ${basename}_library]
|
||||
lappend dirs [file join $root lib $mountpoint ${basename}_library]
|
||||
lappend dirs [file join $root lib $mountpoint]
|
||||
if {![zipfs exists [file join $root app ${basename}_library]] && ![zipfs exists $mountpoint]} {
|
||||
set found 0
|
||||
foreach pkgdat [info loaded] {
|
||||
lassign $pkgdat dllfile dllpkg
|
||||
if {[string tolower $dllpkg] ne [string tolower $basename]} continue
|
||||
if {$dllfile eq {}} {
|
||||
# Loaded statically
|
||||
break
|
||||
}
|
||||
set found 1
|
||||
zipfs mount $dllfile $mountpoint
|
||||
break
|
||||
}
|
||||
if {!$found} {
|
||||
set paths {}
|
||||
lappend paths [file join $root app]
|
||||
lappend paths [::${basename}::pkgconfig get libdir,runtime]
|
||||
lappend paths [::${basename}::pkgconfig get bindir,runtime]
|
||||
if {[catch {::${basename}::pkgconfig get zipfile,runtime} zipfile]} {
|
||||
set zipfile [string tolower "lib${basename}_[join [list {*}[split $version .] {*}$patch] _].zip"]
|
||||
}
|
||||
foreach path $paths {
|
||||
set archive [file join $path $zipfile]
|
||||
if {![file exists $archive]} continue
|
||||
zipfs mount $archive $mountpoint
|
||||
if {[zipfs exists [file join $mountpoint ${basename}_library $initScript]]} {
|
||||
lappend dirs [file join $mountpoint ${basename}_library]
|
||||
set found 1
|
||||
break
|
||||
} elseif {[zipfs exists [file join $mountpoint $initScript]]} {
|
||||
lappend dirs [file join $mountpoint $initScript]
|
||||
set found 1
|
||||
break
|
||||
} else {
|
||||
catch {zipfs unmount $archive}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 2. In the package script directory registered within the
|
||||
# configuration of the package itself.
|
||||
|
||||
|
||||
+2177
-335
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user