Compare commits
885
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2021349249 | ||
|
|
e006418946 | ||
|
|
2881b5c3df | ||
|
|
e0209e39ea | ||
|
|
e1196c53f2 | ||
|
|
56b431c4c2 | ||
|
|
ac4291f473 | ||
|
|
bbdb1f12a0 | ||
|
|
f9a4d9f781 | ||
|
|
1a664df87f | ||
|
|
cc4dae5c0f | ||
|
|
8985ee2114 | ||
|
|
85aac3aef7 | ||
|
|
c3c71b5f3c | ||
|
|
9feb8b7c29 | ||
|
|
50a1375461 | ||
|
|
3d5f129cb0 | ||
|
|
6cdb3193ec | ||
|
|
bf46b6a1da | ||
|
|
d5583552c0 | ||
|
|
338b9ec9d2 | ||
|
|
6d3aeef45e | ||
|
|
63ef0e3d26 | ||
|
|
39318d91b7 | ||
|
|
d24a3eb2ba | ||
|
|
cdce5491b3 | ||
|
|
9a15a1b586 | ||
|
|
95db69f27b | ||
|
|
e80eaec4d3 | ||
|
|
b9577c0641 | ||
|
|
cb9f3f9268 | ||
|
|
6d88b01d1e | ||
|
|
77a26f5c95 | ||
|
|
9cec6bac27 | ||
|
|
2f19b0f346 | ||
|
|
265c9d416f | ||
|
|
db610f91eb | ||
|
|
afb5bf5583 | ||
|
|
9b7ce068fe | ||
|
|
820a737a2f | ||
|
|
c2d61d8dbc | ||
|
|
fb0bf9d1b9 | ||
|
|
01dd016ad8 | ||
|
|
d660b325b5 | ||
|
|
26b477b907 | ||
|
|
89ff80fbdd | ||
|
|
90afac281e | ||
|
|
aed158b518 | ||
|
|
6c78bf0adc | ||
|
|
8346cad0dd | ||
|
|
de5637f853 | ||
|
|
c1ae69114b | ||
|
|
5902889825 | ||
|
|
04c687936c | ||
|
|
2133e40e58 | ||
|
|
c7cdc550c4 | ||
|
|
7e727bed70 | ||
|
|
164a7f04c0 | ||
|
|
814c867db4 | ||
|
|
d00a212e82 | ||
|
|
7fb72851e8 | ||
|
|
4a3f32b84a | ||
|
|
a1790a1683 | ||
|
|
885a163b3c | ||
|
|
2a46a48670 | ||
|
|
51aecf205d | ||
|
|
367ce9ad48 | ||
|
|
9da2aebeae | ||
|
|
ed5ed756bc | ||
|
|
0839047d8b | ||
|
|
e2a79c2604 | ||
|
|
6cbfdcc4a3 | ||
|
|
94ec3d9431 | ||
|
|
6c1e9f2b0c | ||
|
|
563bd6e4dd | ||
|
|
b418ff1759 | ||
|
|
56ca35e8a9 | ||
|
|
107fb1eb33 | ||
|
|
c911dc937f | ||
|
|
645241afc1 | ||
|
|
03a3c09b1f | ||
|
|
3c57d80efe | ||
|
|
04004f3abc | ||
|
|
155e8a1ad5 | ||
|
|
625aca976a | ||
|
|
e9c0ec1219 | ||
|
|
8047a470ef | ||
|
|
2b739c838a | ||
|
|
983854ad7b | ||
|
|
41a6159754 | ||
|
|
df97278634 | ||
|
|
06fc5fb636 | ||
|
|
e393000b1d | ||
|
|
83d92bd747 | ||
|
|
5a05e0d782 | ||
|
|
9c8f784329 | ||
|
|
1efbaebb6a | ||
|
|
ac47e6953d | ||
|
|
400feb302b | ||
|
|
9c9b3d93f9 | ||
|
|
04d1270786 | ||
|
|
b89a3efc56 | ||
|
|
240e6b50d2 | ||
|
|
754bb107b4 | ||
|
|
a2ce3dab9b | ||
|
|
6a4d06759e | ||
|
|
6966f0a2b1 | ||
|
|
89a84af271 | ||
|
|
5e7a1545a6 | ||
|
|
f4651a5660 | ||
|
|
a0290b85c5 | ||
|
|
8145564d30 | ||
|
|
6d943ef7b5 | ||
|
|
1c13d543f4 | ||
|
|
263de53394 | ||
|
|
a410c0d8d5 | ||
|
|
ecec1703aa | ||
|
|
36a1a69178 | ||
|
|
dffe6bc7f1 | ||
|
|
423f761169 | ||
|
|
ba42e43e97 | ||
|
|
7672af7212 | ||
|
|
eae621b175 | ||
|
|
6d0cc0c589 | ||
|
|
d9bc6cbae2 | ||
|
|
ede72e80ac | ||
|
|
7bf3f83abd | ||
|
|
f7f4cbb151 | ||
|
|
f5e8751307 | ||
|
|
47e9dbdc37 | ||
|
|
8fd1568405 | ||
|
|
78ee8c697e | ||
|
|
5f0cf291f5 | ||
|
|
db133f0144 | ||
|
|
86c6a11cdb | ||
|
|
e383cd7b26 | ||
|
|
3a3fd2954f | ||
|
|
096a011c43 | ||
|
|
71938f034c | ||
|
|
0fc27b893e | ||
|
|
debcb2bf01 | ||
|
|
6ef77228ca | ||
|
|
ddfce0ed3f | ||
|
|
c876decde3 | ||
|
|
4519681dcd | ||
|
|
9acb063268 | ||
|
|
8e06fd796b | ||
|
|
227db01958 | ||
|
|
41954059c4 | ||
|
|
b169c964e6 | ||
|
|
ae76fbd559 | ||
|
|
3771e638b0 | ||
|
|
1734eed89f | ||
|
|
75bd116527 | ||
|
|
7ac6487eda | ||
|
|
df94eecf11 | ||
|
|
8d0340e39e | ||
|
|
61f580bd36 | ||
|
|
08c1a8dd34 | ||
|
|
fb91d4b68b | ||
|
|
327595170b | ||
|
|
6b8039a952 | ||
|
|
62ea5e49a1 | ||
|
|
5dff80f2fe | ||
|
|
f316d7539c | ||
|
|
05845fbe5f | ||
|
|
80e5aed49e | ||
|
|
4588d7300e | ||
|
|
d690b84738 | ||
|
|
9856afd590 | ||
|
|
a9ef86f152 | ||
|
|
24a04c0819 | ||
|
|
ff7812fe97 | ||
|
|
689f5653f9 | ||
|
|
9077b8ce60 | ||
|
|
6bc8c27b7f | ||
|
|
6a58a0cab2 | ||
|
|
1357172367 | ||
|
|
466fd1d930 | ||
|
|
441e4f6796 | ||
|
|
3117af219f | ||
|
|
a0e1b18138 | ||
|
|
70af5c2b82 | ||
|
|
d38ae8f974 | ||
|
|
0d887fa465 | ||
|
|
e9bb0992b0 | ||
|
|
f35c0dc2ed | ||
|
|
e80e214673 | ||
|
|
731f40c6d9 | ||
|
|
767cf6314a | ||
|
|
b00317d174 | ||
|
|
a8408767a4 | ||
|
|
4f8b177250 | ||
|
|
25aad1ab18 | ||
|
|
3b48db4a90 | ||
|
|
58eff8f224 | ||
|
|
97721e9675 | ||
|
|
d88d33f74d | ||
|
|
0a9706f48f | ||
|
|
45f91441a5 | ||
|
|
38781266d3 | ||
|
|
843d29b448 | ||
|
|
1a73baff09 | ||
|
|
05c789647a | ||
|
|
da169b1600 | ||
|
|
570af63547 | ||
|
|
c5e979695a | ||
|
|
99ab923ed5 | ||
|
|
72c721f3e7 | ||
|
|
6d4320b5fb | ||
|
|
73de582148 | ||
|
|
1bf60bab3c | ||
|
|
77ab9f868a | ||
|
|
6e7c474da7 | ||
|
|
b16ec6f23b | ||
|
|
0d0b8e03ed | ||
|
|
fd2d896c8f | ||
|
|
f597744c5f | ||
|
|
261fbdac7e | ||
|
|
ec5288cc2e | ||
|
|
90f38b1023 | ||
|
|
64eaafad72 | ||
|
|
a275b8a5ea | ||
|
|
debafda1e7 | ||
|
|
1af314024c | ||
|
|
23178bb208 | ||
|
|
a28f176470 | ||
|
|
de9c1aff4a | ||
|
|
e7a5b8aaa5 | ||
|
|
cd39f34fa5 | ||
|
|
a0374a6e61 | ||
|
|
3f3c89a947 | ||
|
|
d9dbcf5afb | ||
|
|
e7a86d967c | ||
|
|
6fce39545c | ||
|
|
87fd09e44a | ||
|
|
cd4e0ec5de | ||
|
|
954522812e | ||
|
|
db9b0eccf3 | ||
|
|
06c3fd0c5b | ||
|
|
c13e34da37 | ||
|
|
a9d546dfbc | ||
|
|
6798b2404f | ||
|
|
5fd318bc35 | ||
|
|
88812125b1 | ||
|
|
947fb98db5 | ||
|
|
ed53b715ac | ||
|
|
b8b87e5280 | ||
|
|
0c5bd7480e | ||
|
|
64038c5656 | ||
|
|
101ac8bca7 | ||
|
|
30e7e05895 | ||
|
|
ce6aa3ea08 | ||
|
|
d7f41b448c | ||
|
|
2c44354d13 | ||
|
|
612199cbe9 | ||
|
|
f337281f75 | ||
|
|
7fe003f8d2 | ||
|
|
f003df5624 | ||
|
|
9fb9471807 | ||
|
|
8c2cbf3211 | ||
|
|
c68d043691 | ||
|
|
720c8de452 | ||
|
|
596e89b17d | ||
|
|
847a048c18 | ||
|
|
da8fbb89c4 | ||
|
|
465d28aa75 | ||
|
|
6c0170972f | ||
|
|
683dada217 | ||
|
|
2cd8bf554e | ||
|
|
468041eef8 | ||
|
|
85233a4693 | ||
|
|
455b61dce3 | ||
|
|
dda81853f3 | ||
|
|
919808c6a5 | ||
|
|
beff988e79 | ||
|
|
e8f10bd44e | ||
|
|
fa3a1e4638 | ||
|
|
74c5043b5a | ||
|
|
dafcde1702 | ||
|
|
e16817b409 | ||
|
|
03a4436237 | ||
|
|
e52e074e4f | ||
|
|
0b5a1c79b7 | ||
|
|
0c44c5003d | ||
|
|
2b9b50b436 | ||
|
|
80fc86a116 | ||
|
|
1da12398f2 | ||
|
|
4322dab97e | ||
|
|
3243dfedd1 | ||
|
|
fa5058cbca | ||
|
|
ade95255b9 | ||
|
|
e6dd74e90e | ||
|
|
cf4de002dc | ||
|
|
b9b319fad2 | ||
|
|
5d5bd4cd55 | ||
|
|
1e854210b7 | ||
|
|
7d25e385a2 | ||
|
|
40e9ab2e65 | ||
|
|
c6eb0cc51d | ||
|
|
a7c17bc224 | ||
|
|
2606a3a7db | ||
|
|
ea6e8c9dcd | ||
|
|
396c1a637c | ||
|
|
1553090bc3 | ||
|
|
f4babdb0ac | ||
|
|
4c79bcbe64 | ||
|
|
568724e468 | ||
|
|
ad022e6d3b | ||
|
|
5765c1e392 | ||
|
|
4f65558ad0 | ||
|
|
b618278c9f | ||
|
|
adf9cf5543 | ||
|
|
a0c6bf8d92 | ||
|
|
19c0142741 | ||
|
|
189d0a83d2 | ||
|
|
aa4c401952 | ||
|
|
f08ea44564 | ||
|
|
e403ff8f45 | ||
|
|
5fea88381c | ||
|
|
45e646472d | ||
|
|
063db11523 | ||
|
|
26b5bf3eca | ||
|
|
ad43c617e3 | ||
|
|
301f6bcb83 | ||
|
|
9a7ce78e96 | ||
|
|
82cd662f00 | ||
|
|
f2f7b85f88 | ||
|
|
71df313773 | ||
|
|
28361a2bfe | ||
|
|
c1f84789ba | ||
|
|
1725b74695 | ||
|
|
e10cd2e0a5 | ||
|
|
f4cc39572c | ||
|
|
9acbab2c0e | ||
|
|
0fb81cb5dd | ||
|
|
e0360a8c34 | ||
|
|
50bb6253da | ||
|
|
48549d55b0 | ||
|
|
8c866ee6be | ||
|
|
c220b0dcfa | ||
|
|
5cddfdcda6 | ||
|
|
a2c5ea2c08 | ||
|
|
6c313a5846 | ||
|
|
bbaba520ab | ||
|
|
a0a62d119d | ||
|
|
5d11ad1e8a | ||
|
|
cd525c7bb1 | ||
|
|
0af956fe7e | ||
|
|
9ba4b4f901 | ||
|
|
cf3348e41c | ||
|
|
7b04f399b0 | ||
|
|
3aab0c568b | ||
|
|
07aa7381a9 | ||
|
|
bb1c5fe833 | ||
|
|
f3af86c67e | ||
|
|
3eef9fcea1 | ||
|
|
906cf353b2 | ||
|
|
8a44c35e8c | ||
|
|
3e34d38b2d | ||
|
|
92f8ce13df | ||
|
|
b8fbe8c1d3 | ||
|
|
4bbfdee3db | ||
|
|
d7d31d6041 | ||
|
|
e68b491806 | ||
|
|
e87d0bcdf4 | ||
|
|
4fc9a4c991 | ||
|
|
14c8dabffe | ||
|
|
9b1ecce298 | ||
|
|
75924256c1 | ||
|
|
42c80667fd | ||
|
|
3c942c50d9 | ||
|
|
335305de9c | ||
|
|
48047bb120 | ||
|
|
b44ffcf5e2 | ||
|
|
ff436137df | ||
|
|
42236b435f | ||
|
|
a27501598a | ||
|
|
28017c14e3 | ||
|
|
ac3259b669 | ||
|
|
5560b9198b | ||
|
|
51319d2cae | ||
|
|
5ff5853a6e | ||
|
|
24d7fa6401 | ||
|
|
65007a4d02 | ||
|
|
c4d4363abd | ||
|
|
0197a30845 | ||
|
|
346cce5745 | ||
|
|
e3439b6af2 | ||
|
|
59ebc49f0f | ||
|
|
ca86fd3219 | ||
|
|
9f65735813 | ||
|
|
2ea108ae28 | ||
|
|
d7b5cde35f | ||
|
|
ba9e81068e | ||
|
|
a7b6d60948 | ||
|
|
eb2a9484b8 | ||
|
|
a92e1c508f | ||
|
|
0fc6533fcb | ||
|
|
01fd6594cf | ||
|
|
752cfbe04c | ||
|
|
1ffeaf24ef | ||
|
|
78374f18a4 | ||
|
|
729fcd5f09 | ||
|
|
c59b3f3bc1 | ||
|
|
12d3a7d307 | ||
|
|
5188d1d927 | ||
|
|
b8bf04f5ec | ||
|
|
f31af075d0 | ||
|
|
a2d6ec1119 | ||
|
|
2ba5fab30e | ||
|
|
f74bde3e62 | ||
|
|
98c6b22c10 | ||
|
|
be0c5786a0 | ||
|
|
fd61a8e89e | ||
|
|
c7530621ad | ||
|
|
d0665d7a12 | ||
|
|
ac4fb39a73 | ||
|
|
45808db8dc | ||
|
|
c06751fdf8 | ||
|
|
22719c6596 | ||
|
|
ded2a79966 | ||
|
|
4030616bbf | ||
|
|
b55d5cc57e | ||
|
|
e4356f7d64 | ||
|
|
0480b5d79b | ||
|
|
10a9305777 | ||
|
|
d8596e5583 | ||
|
|
5528e1c1a2 | ||
|
|
785f1059e4 | ||
|
|
274ab123a8 | ||
|
|
d33ee7bc07 | ||
|
|
8bb421f959 | ||
|
|
2ff3ecb534 | ||
|
|
e0578530b0 | ||
|
|
a79bc3c8ce | ||
|
|
30c40c4540 | ||
|
|
c5865fcd24 | ||
|
|
c8342af338 | ||
|
|
1d0751deb7 | ||
|
|
2318b70929 | ||
|
|
bed6e18d15 | ||
|
|
c668ed46ec | ||
|
|
0a3f9ca6fc | ||
|
|
261012ce98 | ||
|
|
2f8bbbe141 | ||
|
|
4ab9cb5418 | ||
|
|
3888c4fda4 | ||
|
|
fa2e7e8949 | ||
|
|
c324bb3eff | ||
|
|
053a74e0fa | ||
|
|
ff1c348970 | ||
|
|
30c6827ee1 | ||
|
|
eb2cfa3e6f | ||
|
|
40d9b81e23 | ||
|
|
1552384787 | ||
|
|
9306fa604c | ||
|
|
d5f679a3f6 | ||
|
|
e532a0de84 | ||
|
|
745b43f627 | ||
|
|
f18d453679 | ||
|
|
2332ac45ca | ||
|
|
634213a9c8 | ||
|
|
8e537759cf | ||
|
|
fada619052 | ||
|
|
319b71965b | ||
|
|
47a0727695 | ||
|
|
45d0977a5c | ||
|
|
4407704316 | ||
|
|
fe8915122a | ||
|
|
e9b584f81b | ||
|
|
cdb25d8946 | ||
|
|
7db056b75a | ||
|
|
6f23316c4a | ||
|
|
56d6e9480f | ||
|
|
df974e71f9 | ||
|
|
7393032d5e | ||
|
|
252f75d8c8 | ||
|
|
69030a86c8 | ||
|
|
fa7141288f | ||
|
|
63a9fcf2e7 | ||
|
|
b6f90aaf1f | ||
|
|
4ef03a8950 | ||
|
|
823edbf0ab | ||
|
|
8a910c1a53 | ||
|
|
e7582d10c6 | ||
|
|
5064777d16 | ||
|
|
5b74714749 | ||
|
|
15a7950c9e | ||
|
|
c925a86988 | ||
|
|
75ecb090c6 | ||
|
|
b8e5e2909e | ||
|
|
0c646bc3d1 | ||
|
|
f4e4349cad | ||
|
|
9845cc7c9c | ||
|
|
fdc29e53d3 | ||
|
|
a0f84e1b73 | ||
|
|
21379b0cf5 | ||
|
|
65895760ea | ||
|
|
20730e0afb | ||
|
|
c0295836a8 | ||
|
|
8c50df7bbf | ||
|
|
ec0fc7f816 | ||
|
|
fd6a064ee7 | ||
|
|
f5c6b07246 | ||
|
|
35256f809e | ||
|
|
6881a1a274 | ||
|
|
01201582b7 | ||
|
|
24b65fbe41 | ||
|
|
457587f033 | ||
|
|
78cf383197 | ||
|
|
71c784c8bc | ||
|
|
e4269a7140 | ||
|
|
3734937878 | ||
|
|
07c1c221cb | ||
|
|
246e599142 | ||
|
|
f1aa04858d | ||
|
|
301208c889 | ||
|
|
b5e3779cf2 | ||
|
|
56e2bd0be4 | ||
|
|
34cb030c7b | ||
|
|
a91099b33b | ||
|
|
ad9a3b8b45 | ||
|
|
c7e43807bf | ||
|
|
d8e7cf09b1 | ||
|
|
b0fe49c36d | ||
|
|
a52f0db3e4 | ||
|
|
4bf8f43b3a | ||
|
|
d45863129f | ||
|
|
4f406d752d | ||
|
|
1b28405773 | ||
|
|
65703d1f87 | ||
|
|
6d85564696 | ||
|
|
071f38c482 | ||
|
|
b81c66b4c7 | ||
|
|
0e5d15e072 | ||
|
|
78a20a11b2 | ||
|
|
54431f3360 | ||
|
|
f75f76c9d4 | ||
|
|
f5ea63343e | ||
|
|
a708ae2da2 | ||
|
|
d4e73bcab5 | ||
|
|
8f339500a2 | ||
|
|
bf01a303da | ||
|
|
99d940211c | ||
|
|
7b8b406719 | ||
|
|
db3273f346 | ||
|
|
c659b044b1 | ||
|
|
3e55dbb18c | ||
|
|
b2446d8d41 | ||
|
|
e86e8a501d | ||
|
|
d03a4dcc88 | ||
|
|
4ce5b276eb | ||
|
|
877e9d6b11 | ||
|
|
413fe66650 | ||
|
|
ca70072a99 | ||
|
|
d9f2bf1d17 | ||
|
|
c2846c0f5c | ||
|
|
a15279ffd1 | ||
|
|
b74f59a5b4 | ||
|
|
e08c86934d | ||
|
|
a3dfc55957 | ||
|
|
e3f7bc2783 | ||
|
|
564b991088 | ||
|
|
0ff317501d | ||
|
|
f42f0060be | ||
|
|
3ec5b35deb | ||
|
|
7afc6b1c17 | ||
|
|
ce58cdff9f | ||
|
|
4b9e6d92be | ||
|
|
e28f1eece4 | ||
|
|
4ce83fdb43 | ||
|
|
ce32fdecb2 | ||
|
|
105a61c09b | ||
|
|
25b97a7df9 | ||
|
|
432e75210f | ||
|
|
595e613479 | ||
|
|
c0e413055e | ||
|
|
11719ccf59 | ||
|
|
7c7a396fc5 | ||
|
|
7aafa756ac | ||
|
|
6d8b0c705f | ||
|
|
faaf0a0fe6 | ||
|
|
07bcf919d6 | ||
|
|
f70c0ac860 | ||
|
|
97d25d7902 | ||
|
|
c3d5808cdd | ||
|
|
187a67149b | ||
|
|
2d65cb7514 | ||
|
|
92a05930af | ||
|
|
1ef0babc38 | ||
|
|
92265d56a3 | ||
|
|
4264a4f6ab | ||
|
|
a95a7dd265 | ||
|
|
2e9194366a | ||
|
|
ce72664606 | ||
|
|
5210283d10 | ||
|
|
0eb18d8f91 | ||
|
|
29be40bf89 | ||
|
|
e6336bb806 | ||
|
|
a04094e9a5 | ||
|
|
922d8a71a5 | ||
|
|
13d9910fd6 | ||
|
|
277f101d7f | ||
|
|
a50a381b04 | ||
|
|
e513ec3916 | ||
|
|
89fcfadbbf | ||
|
|
89ce4defb5 | ||
|
|
ad9bc7297d | ||
|
|
0079285837 | ||
|
|
8ccd8d10ef | ||
|
|
aedd652645 | ||
|
|
4056a4dc4b | ||
|
|
ffaeeeddaa | ||
|
|
c2982f8f62 | ||
|
|
587206a660 | ||
|
|
545f5e64be | ||
|
|
385b618c74 | ||
|
|
3a07a6d26f | ||
|
|
df9ea61fbf | ||
|
|
5f7ca471e4 | ||
|
|
ac8ddf5d4a | ||
|
|
664774bec4 | ||
|
|
3cf11a1ce9 | ||
|
|
6da97c627b | ||
|
|
735ca3d3a8 | ||
|
|
72396a1929 | ||
|
|
816674cdb7 | ||
|
|
6bcfd54d3a | ||
|
|
bb331bf1d8 | ||
|
|
b095f046e6 | ||
|
|
cee94b0658 | ||
|
|
f94f5914a8 | ||
|
|
9dd9b629b3 | ||
|
|
440dbbf620 | ||
|
|
b1243f2603 | ||
|
|
f553fe3b01 | ||
|
|
457f43e25b | ||
|
|
578eeb06bc | ||
|
|
515f0f32c0 | ||
|
|
bcb9c34521 | ||
|
|
af0816e0ca | ||
|
|
ac0fdb5bf8 | ||
|
|
2ee7180448 | ||
|
|
5541cc57f7 | ||
|
|
692ea37c40 | ||
|
|
58dd15c51d | ||
|
|
d0996f3402 | ||
|
|
39356c4079 | ||
|
|
a646f081bc | ||
|
|
89f6884455 | ||
|
|
45cf14ed03 | ||
|
|
5314bbe0ef | ||
|
|
5b2c81a0f3 | ||
|
|
f242dd36bd | ||
|
|
fb2aa596ab | ||
|
|
5621809b18 | ||
|
|
7a8a4b15c4 | ||
|
|
f4615ea166 | ||
|
|
2bd7095b87 | ||
|
|
400f9d27f5 | ||
|
|
5d68b7ef56 | ||
|
|
ba387de8cd | ||
|
|
70d12096d5 | ||
|
|
3dedad17ed | ||
|
|
a9c238476a | ||
|
|
cfafc391f2 | ||
|
|
0fbade1cf8 | ||
|
|
dd54301fb6 | ||
|
|
6352a07912 | ||
|
|
440f85800c | ||
|
|
2a11adb848 | ||
|
|
77f95f38bf | ||
|
|
2710235273 | ||
|
|
042e99227a | ||
|
|
64c9b509b0 | ||
|
|
d39c33303f | ||
|
|
6454bee19b | ||
|
|
45175dd264 | ||
|
|
9983a05a80 | ||
|
|
20b4459b9d | ||
|
|
c488b70a47 | ||
|
|
952acc3754 | ||
|
|
73f548527a | ||
|
|
3923106cf7 | ||
|
|
17711009b6 | ||
|
|
b3bda726c1 | ||
|
|
e1b4ae0798 | ||
|
|
aca86a46ff | ||
|
|
94754be1d7 | ||
|
|
9ddb31d522 | ||
|
|
6123ba004c | ||
|
|
56ea73145f | ||
|
|
bc4db4d40e | ||
|
|
0f0ca3d932 | ||
|
|
2cdd3134ab | ||
|
|
107760e1da | ||
|
|
d453cdacec | ||
|
|
e8d9fe8ebe | ||
|
|
6168d91b0e | ||
|
|
ad34457a54 | ||
|
|
2712a556fb | ||
|
|
3f2eb64de8 | ||
|
|
4b81f6ff43 | ||
|
|
cc72d116bd | ||
|
|
94b635d569 | ||
|
|
de1c1f0f47 | ||
|
|
a4f7145579 | ||
|
|
bbcbd64e3b | ||
|
|
36d9205d97 | ||
|
|
7673d614a9 | ||
|
|
c348386388 | ||
|
|
878c874975 | ||
|
|
b796f3dee7 | ||
|
|
dd96539335 | ||
|
|
23ab25afdc | ||
|
|
192d5ccf32 | ||
|
|
9ce3a23afe | ||
|
|
c2e241f3cd | ||
|
|
9562ecd7fa | ||
|
|
16f3f234e8 | ||
|
|
fbfe81cc7b | ||
|
|
73a3dfdeea | ||
|
|
4cf238f3c3 | ||
|
|
1b667ef114 | ||
|
|
0aa0da515c | ||
|
|
5667bb5f8e | ||
|
|
f8bc248cc3 | ||
|
|
b0146fbd50 | ||
|
|
615771f0b6 | ||
|
|
8d78b23f96 | ||
|
|
fab7d970af | ||
|
|
617e92d7b4 | ||
|
|
7edce7686e | ||
|
|
3d8a0152af | ||
|
|
cb68061d12 | ||
|
|
5c4bb0f4e9 | ||
|
|
f165025992 | ||
|
|
8129d3e1c3 | ||
|
|
3cdd3064b5 | ||
|
|
708ca98ace | ||
|
|
f5f03750c8 | ||
|
|
901f58f13b | ||
|
|
c688e0737c | ||
|
|
21dfa74b03 | ||
|
|
3f0e8d6265 | ||
|
|
aaca962ffe | ||
|
|
ca9d6593d1 | ||
|
|
bbb13bf577 | ||
|
|
c05da96a35 | ||
|
|
73b3bf53ad | ||
|
|
e06e0c8625 | ||
|
|
b63d3d703e | ||
|
|
a59ccae461 | ||
|
|
c922cc78a8 | ||
|
|
3be2fece8c | ||
|
|
919fc57599 | ||
|
|
5badb6535f | ||
|
|
cf0cf6ad90 | ||
|
|
f3ea991996 | ||
|
|
8a90be9a10 | ||
|
|
14949f27a3 | ||
|
|
62e71e311e | ||
|
|
df664778c8 | ||
|
|
2f9e40fef1 | ||
|
|
34189452da | ||
|
|
2a5ae4319f | ||
|
|
dea5aab977 | ||
|
|
c6484de085 | ||
|
|
5d20272000 | ||
|
|
a6c79230c3 | ||
|
|
d6de0fb46b | ||
|
|
6b33bdad03 | ||
|
|
5171d6b4ef | ||
|
|
0d218fca03 | ||
|
|
2130fd8582 | ||
|
|
1ed15145a6 | ||
|
|
f9d42ebf8c | ||
|
|
ca65694482 | ||
|
|
0177abb172 | ||
|
|
dd53d408e3 | ||
|
|
ce501f14c5 | ||
|
|
63cf0366bd | ||
|
|
52e520be10 | ||
|
|
af718696fb | ||
|
|
709366bdfe | ||
|
|
910200b637 | ||
|
|
be831d7ecb | ||
|
|
44c544160a | ||
|
|
799554b1c5 | ||
|
|
90ffbb4170 | ||
|
|
77822d9462 | ||
|
|
adfd841d9d | ||
|
|
198407b5ba | ||
|
|
83495af5ce | ||
|
|
10ab52081d | ||
|
|
0b9703a36f | ||
|
|
e3a9350e58 | ||
|
|
78a7a5b561 | ||
|
|
04086099d0 | ||
|
|
fbbc93906e | ||
|
|
7fde7fcf7b | ||
|
|
2f99ece694 | ||
|
|
c1b1e9af62 | ||
|
|
bcbbf6dacf | ||
|
|
cdccb19d1c | ||
|
|
93a924d020 | ||
|
|
a3fdca376e | ||
|
|
bfdfb7479d | ||
|
|
2c5d1036db | ||
|
|
15b0a7813d | ||
|
|
d2595ccfea | ||
|
|
6be0cf66e0 | ||
|
|
5b059dfd6b | ||
|
|
1a3c0d9be9 | ||
|
|
5ba18ec98d | ||
|
|
62b2b9bf45 | ||
|
|
e006ff39be | ||
|
|
9b4213bb3f | ||
|
|
1e22d92c69 | ||
|
|
cd48f2d313 | ||
|
|
26f98a5e56 | ||
|
|
bbfc7b1ea2 | ||
|
|
1e3fa455c9 | ||
|
|
d00198bd14 | ||
|
|
ff4b11441b | ||
|
|
904733362e | ||
|
|
44de3dd8da | ||
|
|
55edd253ff | ||
|
|
19719bf57f | ||
|
|
f3a4ae987d | ||
|
|
85397cf893 | ||
|
|
ce7746b49e | ||
|
|
5e45fd7662 | ||
|
|
354e08673b | ||
|
|
810395f913 | ||
|
|
8dfdec39fd | ||
|
|
0abecbc87d | ||
|
|
efbb62b5bd | ||
|
|
dd5e309d31 | ||
|
|
0c0b1e1498 | ||
|
|
920aa8280f | ||
|
|
8a2c820213 | ||
|
|
ab08379d1c | ||
|
|
321cd769b7 | ||
|
|
91cb892574 | ||
|
|
e58e9e1fb9 | ||
|
|
d7802b428a | ||
|
|
dc25a1a62b | ||
|
|
754b233873 | ||
|
|
b8d35358ad | ||
|
|
5617ad7c18 | ||
|
|
909f1a1a30 | ||
|
|
f6837a8ef4 | ||
|
|
488735e4a2 | ||
|
|
a3f676461c | ||
|
|
daac4e5d34 | ||
|
|
6f905e1f0f | ||
|
|
4ccedfaec4 | ||
|
|
c010901ea9 | ||
|
|
c0bedd810f | ||
|
|
57ceb807ca | ||
|
|
5d66bf5a1f | ||
|
|
91d32c4556 | ||
|
|
e9e0f57d92 | ||
|
|
f090fee89b | ||
|
|
f55296bdf0 | ||
|
|
bed000d72e | ||
|
|
b2181df698 | ||
|
|
6469ae095f | ||
|
|
636e904b09 | ||
|
|
da85dcc288 | ||
|
|
ac3cb936ee | ||
|
|
874b8643e0 | ||
|
|
d18329a21e | ||
|
|
82296abf08 | ||
|
|
5772e32729 | ||
|
|
3ef7160d41 | ||
|
|
efa3ec6939 | ||
|
|
cdb6b73776 | ||
|
|
fad7a0e23d | ||
|
|
da7cc28446 | ||
|
|
e6e391530f | ||
|
|
a0256cda63 | ||
|
|
85daeb5e16 |
@@ -3,12 +3,17 @@ compat/zlib/contrib/vstudio/readme.txt
|
||||
compat/zlib/contrib/vstudio/*/zlib.rc
|
||||
compat/zlib/win32/*.txt
|
||||
compat/zlib/win64/*.txt
|
||||
libtommath/*.dsp
|
||||
libtommath/*.sln
|
||||
libtommath/*.vcproj
|
||||
tools/tcl.hpj.in
|
||||
tools/tcl.wse.in
|
||||
win/buildall.vc.bat
|
||||
win/coffbase.txt
|
||||
win/makefile.vc
|
||||
win/rules.vc
|
||||
win/rules-ext.vc
|
||||
win/targets.vc
|
||||
win/tcl.dsp
|
||||
win/tcl.dsw
|
||||
win/tcl.hpj.in
|
||||
@@ -3,12 +3,17 @@ compat/zlib/contrib/vstudio/readme.txt
|
||||
compat/zlib/contrib/vstudio/*/zlib.rc
|
||||
compat/zlib/win32/*.txt
|
||||
compat/zlib/win64/*.txt
|
||||
libtommath/*.dsp
|
||||
libtommath/*.sln
|
||||
libtommath/*.vcproj
|
||||
tools/tcl.hpj.in
|
||||
tools/tcl.wse.in
|
||||
win/buildall.vc.bat
|
||||
win/coffbase.txt
|
||||
win/makefile.vc
|
||||
win/rules.vc
|
||||
win/rules-ext.vc
|
||||
win/targets.vc
|
||||
win/tcl.dsp
|
||||
win/tcl.dsw
|
||||
win/tcl.hpj.in
|
||||
@@ -18,6 +18,7 @@
|
||||
*/tclsh*
|
||||
*/tcltest*
|
||||
*/versions.vc
|
||||
*/version.vc
|
||||
html
|
||||
libtommath/bn.ilg
|
||||
libtommath/bn.ind
|
||||
@@ -40,7 +41,8 @@ unix/dltest.marker
|
||||
unix/tcl.pc
|
||||
unix/tclIndex
|
||||
unix/pkgs/*
|
||||
win/Debug_VC*
|
||||
win/Release_VC*
|
||||
win/Debug*
|
||||
win/Release*
|
||||
win/pkgs/*
|
||||
win/tcl.hpj
|
||||
win/tcl.hpj
|
||||
win/nmhlp-out.txt
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
README: Tcl
|
||||
This is the Tcl 8.6.6 source distribution.
|
||||
This is the Tcl 8.6.8 source distribution.
|
||||
http://sourceforge.net/projects/tcl/files/Tcl/
|
||||
You can get any source release of Tcl from the URL above.
|
||||
|
||||
|
||||
@@ -8698,3 +8698,135 @@ improvements to regexp engine from Postgres (lane,porter,fellows,seltenreich)
|
||||
2016-07-20 tzdata updated to Olson's tzdata2016f (venkat)
|
||||
|
||||
--- Released 8.6.6, July 27, 2016 --- http://core.tcl.tk/tcl/ for details
|
||||
|
||||
2016-09-07 (bug)[c09edf] Bad caching with custom resolver (neumann,nijtmans)
|
||||
|
||||
2016-09-07 (bug)[4dbdd9] Memleak in test var-8.3 (mr_calvin,porter)
|
||||
|
||||
2016-10-03 (bug)[2bf561] Allow empty command as alias target (yorick,nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-10-04 (bug)[4d5ae7] Crash in async connects host no address (gahr,fellows)
|
||||
|
||||
2016-10-08 (bug)[838e99] treat application/xml as text (gahr,fellows)
|
||||
=> http 2.8.10
|
||||
|
||||
2016-10-11 (bug)[3cc1d9] Thread finalization crash in zippy (neumann)
|
||||
|
||||
2016-10-12 (bug)[be003d] Fix [scan 0x1 %b], [scan 0x1 %o] (porter)
|
||||
|
||||
2016-10-14 (bug)[eb6b68] Fix stringComp-14.5 (porter)
|
||||
|
||||
2016-10-30 (bug)[b26e38] Fix zlib-7.8 (fellows)
|
||||
|
||||
2016-10-30 (bug)[1ae129] Fix memleak in [history] destruction (fellows)
|
||||
|
||||
2016-11-04 (feature) Provisional Tcl 9 support in msgcat and tcltest (nijtmans)
|
||||
=> msgcat 1.6.1
|
||||
=> tcltest 2.4.1
|
||||
|
||||
2016-11-04 (bug)[824752] Crash in Tcl_ListObjReplace() (gahr,porter)
|
||||
|
||||
2016-11-11 (bug)[79614f] invalidate VFS mounts on sytem encoding change (yorick)
|
||||
|
||||
2016-11-14 OSX: End panic() as legacy support macro; system conflicts (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-11-15 (bug) TclOO fix stops crash mixing Itcl and snit (fellows)
|
||||
|
||||
2016-11-17 (update) Reconcile libtommath updates; purge unused files (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2017-01-09 (bug)[b87ad7] Repair drifts in timer clock (sebres)
|
||||
|
||||
2017-01-17 (update) => zlib 1.2.11 (nijtmans)
|
||||
|
||||
2017-01-31 (bug)[39f630] Revise Tcl_LinkVar to tolerate some prefixes (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2017-02-01 (bug)[d0f7ba] Improper NAN optimization. expr-22.1[01] (aspect)
|
||||
|
||||
2017-02-26 (bug)[25842c] zlib stream finalization (aspect)
|
||||
|
||||
2017-03-07 (deprecate) Remove unmaintained makefile.bc file (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2017-03-14 (enhancement) [clock] and [encoding] are now ensembles (kenny)
|
||||
|
||||
2017-03-15 (enhancement) several [clock] subcommands bytecoded (kenny)
|
||||
|
||||
2017-03-23 tzdata updated to Olson's tzdata2017b (jima)
|
||||
|
||||
2017-03-29 (bug)[900cb0] Fix OO unexport introspection (napier)
|
||||
|
||||
2017-04-12 (bug)[42202b] Nesting imbalance in coro injection (nadkarni,sebres)
|
||||
|
||||
2017-04-18 (bug)[bc4322] http package support for safe interps (nash,nijtmans)
|
||||
|
||||
2017-04-28 (bug)[f34cf8] [file join a //b] => /b (neumann,porter)
|
||||
|
||||
2017-05-01 (bug)[8bd13f] Windows threads and pipes (sebres,nijtmans)
|
||||
|
||||
2017-05-01 (bug)[f9fe90] [file join //a b] EIAS violation (aspect,porter)
|
||||
|
||||
2017-05-04 (bug) Make test filesystem-1.52 pass on Windows (nijtmans)
|
||||
|
||||
2017-05-05 (bug)[601522] [binary] field spec overflow -> segfault (porter)
|
||||
|
||||
2017-05-08 (bug)[6ca52a] http memleak handling keep-alive (aspect,nijtmans)
|
||||
=> http 2.8.11
|
||||
|
||||
2017-05-29 (bug)[a3fb33] crash in [lsort] on long lists (sebres)
|
||||
|
||||
2017-06-05 (bug)[67aa9a] Tcl_UtfToUniChar() revised handling invalid UTF-8 (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2017-06-08 (bug)[2738427] Tcl_NumUtfChars() corner case utf-4.9 (nijtmans)
|
||||
|
||||
2017-06-22 (update) Update Unicode data to 10.0 (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2017-06-22 (TIP 473) Let [oo::copy] specify target namespace (fellows)
|
||||
|
||||
2017-06-26 (bug)[46f801] Repair autoloader fragility (porter)
|
||||
|
||||
2017-07-06 (bug)[adb198] Plug memleak in TclJoinPath (sebres,porter)
|
||||
|
||||
2017-07-17 (bug)[fb2208] Repeatable tclIndex generation (wiedemann,nijtmans)
|
||||
|
||||
--- Released 8.6.7, August 9, 2017 --- http://core.tcl.tk/tcl/ for details
|
||||
|
||||
2017-08-10 [array names -regexp] supports backrefs (goth)
|
||||
|
||||
2017-08-10 Fix gcc build failures due to #pragma placement (cassoff,fellows)
|
||||
|
||||
2017-08-29 (bug)[b50fb2] exec redir append stdout and stderr to file (coulter)
|
||||
|
||||
2017-08-31 (bug)[2a9465] http state 100 continue handling broken (oehlmann)
|
||||
=> http 2.8.12
|
||||
|
||||
2017-09-02 (bug)[0e4d88] replace command, delete trace kills namespace (porter)
|
||||
|
||||
2017-10-19 (bug)[1a5655] [info * methods] includes mixins (fellows)
|
||||
|
||||
2017-10-23 tzdata updated to Olson's tzdata2017c (jima)
|
||||
|
||||
2017-10-24 (bug)[fc1409] segfault in method cloning, oo-15.15 (coulter,fellows)
|
||||
|
||||
2017-11-03 (bug)[6f2f83] More robust [load] for ReactOS (werner)
|
||||
|
||||
2017-11-08 (bug)[3298012] Stop crash when hash tables overflow 32 bits (porter)
|
||||
|
||||
2017-11-14 (bug)[5d6de6] Close failing case of [package prefer stable] (kupries)
|
||||
|
||||
2017-11-17 (bug)[fab924] Fix misleading [load] message on Windows (oehlmann)
|
||||
|
||||
2017-12-05 (bug)[4f6a1e] Crash when ensemble map and list are same (sebres)
|
||||
|
||||
2017-12-06 (bug)[ce3a21] file normalize failure when tail is empty (porter)
|
||||
|
||||
2017-12-08 (new)[TIP 477] nmake build system reform (nadkarni)
|
||||
|
||||
2017-12-19 (bug)[586e71] EvalObjv exception handling at level #0 (sebres,porter)
|
||||
|
||||
--- Released 8.6.8, December 22, 2017 --- http://core.tcl.tk/tcl/ for details
|
||||
|
||||
@@ -260,10 +260,6 @@ Windows-only convenience
|
||||
functions for converting between UTF-8 and Windows strings
|
||||
based on the TCHAR type which is by convention
|
||||
a Unicode character on Windows NT.
|
||||
These functions are essentially wrappers around
|
||||
\fBTcl_UtfToExternalDString\fR and
|
||||
\fBTcl_ExternalToUtfDString\fR that convert to and from the
|
||||
Unicode encoding.
|
||||
.PP
|
||||
\fBTcl_GetEncodingName\fR is roughly the inverse of \fBTcl_GetEncoding\fR.
|
||||
Given an \fIencoding\fR, the return value is the \fIname\fR argument that
|
||||
|
||||
+4
-4
@@ -176,10 +176,10 @@ it is faster to execute the script directly.
|
||||
.TP 23
|
||||
\fBTCL_EVAL_GLOBAL\fR
|
||||
.
|
||||
If this flag is set, the script is processed at global level. This
|
||||
means that it is evaluated in the global namespace and its variable
|
||||
context consists of global variables only (it ignores any Tcl
|
||||
procedures that are active).
|
||||
If this flag is set, the script is evaluated in the global namespace instead of
|
||||
the current namespace and its variable context consists of global variables
|
||||
only (it ignores any Tcl procedures that are active).
|
||||
.\" TODO: document TCL_EVAL_INVOKE and TCL_EVAL_NOERR.
|
||||
|
||||
.SH "MISCELLANEOUS DETAILS"
|
||||
.PP
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
'\"
|
||||
.TH Tcl_GetInt 3 "" Tcl "Tcl Library Procedures"
|
||||
.so man.macros
|
||||
.BS
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2008 by Kevin B. Kenny.
|
||||
.\" 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.
|
||||
@@ -38,43 +39,39 @@ void
|
||||
.SH ARGUMENTS
|
||||
.AS Tcl_CmdDeleteProc *interp in
|
||||
.AP Tcl_Interp *interp in
|
||||
Interpreter in which to create or evaluate a command.
|
||||
The relevant Interpreter.
|
||||
.AP char *cmdName in
|
||||
Name of a new command to create.
|
||||
Name of the command to create.
|
||||
.AP Tcl_ObjCmdProc *proc in
|
||||
Implementation of a command that will be called whenever \fIcmdName\fR
|
||||
is invoked as a command in the unoptimized way.
|
||||
Called in order to evaluate a command. Is often just a small wrapper that uses
|
||||
\fBTcl_NRCallObjProc\fR to call \fInreProc\fR using a new trampoline. Behaves
|
||||
in the same way as the \fIproc\fR argument to \fBTcl_CreateObjCommand\fR(3)
|
||||
(\fIq.v.\fR).
|
||||
.AP Tcl_ObjCmdProc *nreProc in
|
||||
Implementation of a command that will be called whenever \fIcmdName\fR
|
||||
is invoked and requested to conserve the C stack.
|
||||
Called instead of \fIproc\fR when a trampoline is already in use.
|
||||
.AP ClientData clientData in
|
||||
Arbitrary one-word value that will be passed to \fIproc\fR, \fInreProc\fR,
|
||||
\fIdeleteProc\fR and \fIobjProc\fR.
|
||||
Arbitrary one-word value passed to \fIproc\fR, \fInreProc\fR, \fIdeleteProc\fR
|
||||
and \fIobjProc\fR.
|
||||
.AP Tcl_CmdDeleteProc *deleteProc in/out
|
||||
Procedure to call before \fIcmdName\fR is deleted from the interpreter.
|
||||
This procedure allows for command-specific cleanup. If \fIdeleteProc\fR
|
||||
is \fBNULL\fR, then no procedure is called before the command is deleted.
|
||||
Called before \fIcmdName\fR is deleted from the interpreter, allowing for
|
||||
command-specific cleanup. May be NULL.
|
||||
.AP int objc in
|
||||
Count of parameters provided to the implementation of a command.
|
||||
Number of items in \fIobjv\fR.
|
||||
.AP Tcl_Obj **objv in
|
||||
Pointer to an array of Tcl values. Each value holds the value of a
|
||||
single word in the command to execute.
|
||||
Words in the command.
|
||||
.AP Tcl_Obj *objPtr in
|
||||
Pointer to a Tcl_Obj whose value is a script or expression to execute.
|
||||
A script or expression to evaluate.
|
||||
.AP int flags in
|
||||
ORed combination of flag bits that specify additional options.
|
||||
\fBTCL_EVAL_GLOBAL\fR is the only flag that is currently supported.
|
||||
.\" TODO: This is a lie. But kbk didn't grasp TCL_EVAL_INVOKE and
|
||||
.\" TCL_EVAL_NOERR well enough to document them.
|
||||
As described for \fITcl_EvalObjv\fR.
|
||||
.PP
|
||||
.AP Tcl_Command cmd in
|
||||
Token for a command that is to be used instead of the currently
|
||||
executing command.
|
||||
Token to use instead of one derived from the first word of \fIobjv\fR in order
|
||||
to evaluate a command.
|
||||
.AP Tcl_Obj *resultPtr out
|
||||
Pointer to an unshared Tcl_Obj where the result of expression
|
||||
evaluation is written.
|
||||
Pointer to an unshared Tcl_Obj where the result of the evaluation is stored if
|
||||
the return code is TCL_OK.
|
||||
.AP Tcl_NRPostProc *postProcPtr in
|
||||
Pointer to a function that will be invoked when the command currently
|
||||
executing in the interpreter designated by \fIinterp\fR completes.
|
||||
A function to push.
|
||||
.AP ClientData data0 in
|
||||
.AP ClientData data1 in
|
||||
.AP ClientData data2 in
|
||||
@@ -84,98 +81,51 @@ to the function designated by \fIpostProcPtr\fR when it is invoked.
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
This series of C functions provides an interface whereby commands that
|
||||
are implemented in C can be evaluated, and invoke Tcl commands scripts
|
||||
and scripts, without consuming space on the C stack. The non-recursive
|
||||
evaluation is done by installing a \fItrampoline\fR, a small piece of
|
||||
code that invokes a command or script, and then executes a series of
|
||||
callbacks when the command or script returns.
|
||||
These functions provide an interface to the function stack that an interpreter
|
||||
iterates through to evaluate commands. The routine behind a command is
|
||||
implemented by an initial function and any additional functions that the
|
||||
routine pushes onto the stack as it progresses. The interpreter itself pushes
|
||||
functions onto the stack to react to the end of a routine and to exercise other
|
||||
forms of control such as switching between in-progress stacks and the
|
||||
evaluation of other scripts at additional levels without adding frames to the C
|
||||
stack. To execute a routine, the initial function for the routine is called
|
||||
and then a small bit of code called a \fItrampoline\fR iteratively takes
|
||||
functions off the stack and calls them, using the value of the last call as the
|
||||
value of the routine.
|
||||
.PP
|
||||
The \fBTcl_NRCreateCommand\fR function creates a Tcl command in the
|
||||
interpreter designated by \fIinterp\fR that is prepared to handle
|
||||
nonrecursive evaluation with a trampoline. The \fIcmdName\fR argument
|
||||
gives the name of the new command. If \fIcmdName\fR contains any
|
||||
namespace qualifiers, then the new command is added to the specified
|
||||
namespace; otherwise, it is added to the global namespace. \fIproc\fR
|
||||
gives the procedure that will be called when the interpreter wishes to
|
||||
evaluate the command in an unoptimized manner, and \fInreProc\fR is
|
||||
the procedure that will be called when the interpreter wishes to
|
||||
evaluate the command using a trampoline. \fIdeleteProc\fR is a
|
||||
function that will be called before the command is deleted from the
|
||||
interpreter. When any of the three functions is invoked, it is passed
|
||||
the \fIclientData\fR parameter.
|
||||
\fBTcl_NRCallObjProc\fR calls \fInreProc\fR using a new trampoline.
|
||||
.PP
|
||||
\fBTcl_NRCreateCommand\fR deletes any existing command
|
||||
\fIname\fR already associated with the interpreter
|
||||
(however see below for an exception where the existing command
|
||||
is not deleted).
|
||||
It returns a token that may be used to refer
|
||||
to the command in subsequent calls to \fBTcl_GetCommandName\fR.
|
||||
If \fBTcl_NRCreateCommand\fR is called for an interpreter that is in
|
||||
the process of being deleted, then it does not create a new command,
|
||||
does not delete any existing command of the same name, and returns NULL.
|
||||
\fBTcl_NRCreateCommand\fR, an alternative to \fBTcl_CreateObjCommand\fR,
|
||||
resolves \fIcmdName\fR, which may contain namespace qualifiers, relative to the
|
||||
current namespace, creates a command by that name, and returns a token for the
|
||||
command which may be used in subsequent calls to \fBTcl_GetCommandName\fR.
|
||||
Except for a few cases noted below any existing command by the same name is
|
||||
first deleted. If \fIinterp\fR is in the process of being deleted
|
||||
\fBTcl_NRCreateCommand\fR does not create any command, does not delete any
|
||||
command, and returns NULL.
|
||||
.PP
|
||||
The \fIproc\fR and \fInreProc\fR function are expected to conform to
|
||||
all the rules set forth for the \fIproc\fR argument to
|
||||
\fBTcl_CreateObjCommand\fR(3) (\fIq.v.\fR).
|
||||
\fBTcl_NREvalObj\fR pushes a function that is like \fBTcl_EvalObjEx\fR but
|
||||
consumes no space on the C stack.
|
||||
.PP
|
||||
When a command that is written to cope with evaluation via trampoline
|
||||
is invoked without a trampoline on the stack, it will usually respond
|
||||
to the invocation by creating a trampoline and calling the
|
||||
trampoline-enabled implementation of the same command. This call is done by
|
||||
means of \fBTcl_NRCallObjProc\fR. In the call to
|
||||
\fBTcl_NRCallObjProc\fR, the \fIinterp\fR, \fIclientData\fR,
|
||||
\fIobjc\fR and \fIobjv\fR parameters should be the same ones that were
|
||||
passed to \fIproc\fR. The \fInreProc\fR parameter should designate the
|
||||
trampoline-enabled implementation of the command.
|
||||
\fBTcl_NREvalObjv\fR pushes a function that is like \fBTcl_EvalObjv\fR but
|
||||
consumes no space on the C stack.
|
||||
.PP
|
||||
\fBTcl_NREvalObj\fR arranges for the script contained in \fIobjPtr\fR
|
||||
to be evaluated in the interpreter designated by \fIinterp\fR after
|
||||
the current command (which must be trampoline-enabled) returns. It is
|
||||
the method by which a command may invoke a script without consuming
|
||||
space on the C stack. Similarly, \fBTcl_NREvalObjv\fR arranges to
|
||||
invoke a single Tcl command whose words have already been separated
|
||||
and substituted. The \fIobjc\fR and \fIobjv\fR parameters give the
|
||||
words of the command to be evaluated when execution reaches the
|
||||
trampoline.
|
||||
\fBTcl_NRCmdSwap\fR is like \fBTcl_NREvalObjv\fR, but uses \fIcmd\fR, a token
|
||||
previously returned by \fBTcl_CreateObjCommand\fR or
|
||||
\fBTcl_GetCommandFromObj\fR, instead of resolving the first word of \fIobjv\fR.
|
||||
. The name of this command must be the same as \fIobjv[0]\fR.
|
||||
.PP
|
||||
\fBTcl_NRCmdSwap\fR allows for trampoline evaluation of a command whose
|
||||
resolution is already known. The \fIcmd\fR parameter gives a
|
||||
\fBTcl_Command\fR token (returned from \fBTcl_CreateObjCommand\fR or
|
||||
\fBTcl_GetCommandFromObj\fR) identifying the command to be invoked in
|
||||
the trampoline; this command must match the word in \fIobjv[0]\fR.
|
||||
The remaining arguments are as for \fBTcl_NREvalObjv\fR.
|
||||
\fBTcl_NRExprObj\fR pushes a function that evaluates \fIobjPtr\fR as an
|
||||
expression in the same manner as \fBTcl_ExprObj\fR but without consuming space
|
||||
on the C stack.
|
||||
.PP
|
||||
\fBTcl_NREvalObj\fR, \fBTcl_NREvalObjv\fR and \fBTcl_NRCmdSwap\fR
|
||||
all accept a \fIflags\fR parameter, which is an OR-ed-together set of
|
||||
bits to control evaluation. At the present time, the only supported flag
|
||||
available to callers is \fBTCL_EVAL_GLOBAL\fR.
|
||||
.\" TODO: Again, this is a lie. Do we want to explain TCL_EVAL_INVOKE
|
||||
.\" and TCL_EVAL_NOERR?
|
||||
If the \fBTCL_EVAL_GLOBAL\fR flag is set, the script or command is
|
||||
evaluated in the global namespace. If it is not set, it is evaluated
|
||||
in the current namespace.
|
||||
All of the functions return \fBTCL_OK\fR if the evaluation of the script,
|
||||
command, or expression has been scheduled successfully. Otherwise (for example
|
||||
if the command name cannot be resolved), they return \fBTCL_ERROR\fR and store
|
||||
a message as the interpreter's result.
|
||||
.PP
|
||||
\fBTcl_NRExprObj\fR arranges for the expression contained in \fIobjPtr\fR
|
||||
to be evaluated in the interpreter designated by \fIinterp\fR after
|
||||
the current command (which must be trampoline-enabled) returns. It is
|
||||
the method by which a command may evaluate a Tcl expression without consuming
|
||||
space on the C stack. The argument \fIresultPtr\fR is a pointer to an
|
||||
unshared Tcl_Obj where the result of expression evaluation is to be written.
|
||||
If expression evaluation returns any code other than TCL_OK, the
|
||||
\fIresultPtr\fR value is left untouched.
|
||||
.PP
|
||||
All of the routines return \fBTCL_OK\fR if command or expression invocation
|
||||
has been scheduled successfully. If for any reason the scheduling cannot
|
||||
be completed (for example, if the interpreter is unable to find
|
||||
the requested command), they return \fBTCL_ERROR\fR with an
|
||||
appropriate message left in the interpreter's result.
|
||||
.PP
|
||||
\fBTcl_NRAddCallback\fR arranges to have a C function called when the
|
||||
current trampoline-enabled command in the Tcl interpreter designated
|
||||
by \fIinterp\fR returns. The \fIpostProcPtr\fR argument is a pointer
|
||||
to the callback function, which must have arguments and return value
|
||||
consistent with the \fBTcl_NRPostProc\fR data type:
|
||||
\fBTcl_NRAddCallback\fR pushes \fIpostProcPtr\fR. The signature for
|
||||
\fBTcl_NRPostProc\fR is:
|
||||
.PP
|
||||
.CS
|
||||
typedef int
|
||||
@@ -185,25 +135,13 @@ typedef int
|
||||
int \fIresult\fR);
|
||||
.CE
|
||||
.PP
|
||||
When the trampoline invokes the callback function, the \fIdata\fR
|
||||
parameter will point to an array containing the four one-word
|
||||
quantities that were passed to \fBTcl_NRAddCallback\fR in the
|
||||
\fIdata0\fR through \fIdata3\fR parameters. The Tcl interpreter will
|
||||
be designated by the \fIinterp\fR parameter, and the \fIresult\fR
|
||||
parameter will contain the result (\fBTCL_OK\fR, \fBTCL_ERROR\fR,
|
||||
\fBTCL_RETURN\fR, \fBTCL_BREAK\fR or \fBTCL_CONTINUE\fR) that was
|
||||
returned by the command evaluation. The callback function is expected,
|
||||
in turn, either to return a \fIresult\fR to control further evaluation.
|
||||
.PP
|
||||
Multiple \fBTcl_NRAddCallback\fR invocations may request multiple
|
||||
callbacks, which may be to the same or different callback
|
||||
functions. If multiple callbacks are requested, they are executed in
|
||||
last-in, first-out order, that is, the most recently requested
|
||||
callback is executed first.
|
||||
\fIdata\fR is a pointer to an array containing \fIdata0\fR through \fIdata3\fR.
|
||||
\fIresult\fR is the value returned by the previous function implementing part
|
||||
the routine.
|
||||
.SH EXAMPLE
|
||||
.PP
|
||||
The usual pattern for Tcl commands that invoke other Tcl commands
|
||||
is something like:
|
||||
The following command uses \fBTcl_EvalObjEx\fR, which consumes space on the C
|
||||
stack, to evalute a script:
|
||||
.PP
|
||||
.CS
|
||||
int
|
||||
@@ -228,28 +166,17 @@ int
|
||||
\fITheCmdOldObjProc\fR, clientData, TheCmdDeleteProc);
|
||||
.CE
|
||||
.PP
|
||||
To enable a command like this one for trampoline-based evaluation,
|
||||
it must be split into three pieces:
|
||||
.IP \(bu
|
||||
A non-trampoline implementation, \fITheCmdNewObjProc\fR,
|
||||
which will simply create a trampoline
|
||||
and invoke the trampoline-based implementation.
|
||||
.IP \(bu
|
||||
A trampoline-enabled implementation, \fITheCmdNRObjProc\fR. This
|
||||
function will perform the initialization, request that the trampoline
|
||||
call the postprocessing routine after command evaluation, and finally,
|
||||
request that the trampoline call the inner command.
|
||||
.IP \(bu
|
||||
A postprocessing routine, \fITheCmdPostProc\fR. This function will
|
||||
perform the postprocessing formerly done after the return from the
|
||||
inner command in \fITheCmdObjProc\fR.
|
||||
.PP
|
||||
The non-trampoline implementation is simple and stylized, containing
|
||||
a single statement:
|
||||
To avoid consuming space on the C stack, \fITheCmdOldObjProc\fR is renamed to
|
||||
\fITheCmdNRObjProc\fR and the postprocessing step is split into a separate
|
||||
function, \fITheCmdPostProc\fR, which is pushed onto the function stack.
|
||||
\fITcl_EvalObjEx\fR is replaced with \fITcl_NREvalObj\fR, which uses a
|
||||
trampoline instead of consuming space on the C stack. A new version of
|
||||
\fITheCmdOldObjProc\fR is just a a wrapper that uses \fBTcl_NRCallObjProc\fR to
|
||||
call \fITheCmdNRObjProc\fR:
|
||||
.PP
|
||||
.CS
|
||||
int
|
||||
\fITheCmdNewObjProc\fR(
|
||||
\fITheCmdOldObjProc\fR(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
@@ -260,9 +187,6 @@ int
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
The trampoline-enabled implementation requests postprocessing,
|
||||
and returns to the trampoline requesting command evaluation.
|
||||
.PP
|
||||
.CS
|
||||
int
|
||||
\fITheCmdNRObjProc\fR
|
||||
@@ -284,9 +208,6 @@ int
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
The postprocessing procedure does whatever the original command did
|
||||
upon return from the inner evaluation.
|
||||
.PP
|
||||
.CS
|
||||
int
|
||||
\fITheCmdNRPostProc\fR(
|
||||
@@ -303,26 +224,13 @@ int
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
If \fItheCommand\fR is a command that results in multiple commands or
|
||||
scripts being evaluated, its postprocessing routine may schedule
|
||||
additional postprocessing and then request another command evaluation
|
||||
by means of \fBTcl_NREvalObj\fR or one of the other evaluation
|
||||
routines. Looping and sequencing constructs may be implemented in this way.
|
||||
Any function comprising a routine can push other functions, making it possible
|
||||
implement looping and sequencing constructs using the function stack.
|
||||
.PP
|
||||
Finally, to install a trampoline-enabled command in the interpreter,
|
||||
\fBTcl_NRCreateCommand\fR is used in place of
|
||||
\fBTcl_CreateObjCommand\fR. It accepts two command procedures instead
|
||||
of one. The first is for use when no trampoline is yet on the stack,
|
||||
and the second is for use when there is already a trampoline in place.
|
||||
.PP
|
||||
.CS
|
||||
\fBTcl_NRCreateCommand\fR(interp, "theCommand",
|
||||
\fITheCmdNewObjProc\fR, \fITheCmdNRObjProc\fR, clientData,
|
||||
TheCmdDeleteProc);
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
Tcl_CreateCommand(3), Tcl_CreateObjCommand(3), Tcl_EvalObjEx(3), Tcl_GetCommandFromObj(3), Tcl_ExprObj(3)
|
||||
.SH KEYWORDS
|
||||
stackless, nonrecursive, execute, command, global, value, result, script
|
||||
.SH COPYRIGHT
|
||||
Copyright (c) 2008 by Kevin B. Kenny
|
||||
Copyright (c) 2008 by Kevin B. Kenny.
|
||||
Copyright (c) 2018 by Nathan Coulter.
|
||||
|
||||
+1
-1
@@ -257,7 +257,7 @@ The \fBincr\fR command first gets an integer from \fIx\fR's value
|
||||
by calling \fBTcl_GetIntFromObj\fR.
|
||||
This procedure checks whether the value is already an integer value.
|
||||
Since it is not, it converts the value
|
||||
by setting the value's \fIinternalRep.longValue\fR member
|
||||
by setting the value's internal representation
|
||||
to the integer \fB123\fR
|
||||
and setting the value's \fItypePtr\fR
|
||||
to point to the integer Tcl_ObjType structure.
|
||||
|
||||
+2
-2
@@ -54,9 +54,9 @@ is called, Tcl will take care of memory management.
|
||||
.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 a \fBTcl_SavedResult\fR structure
|
||||
These routines are passed a pointer to \fBTcl_SavedResult\fR
|
||||
that is used to store enough information to restore the interpreter result.
|
||||
This structure can be allocated on the stack of the calling
|
||||
\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).
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ int
|
||||
.SH ARGUMENTS
|
||||
.AS char *str in/out
|
||||
.AP int ch in
|
||||
The Tcl_UniChar to be converted.
|
||||
The Unicode character to be converted.
|
||||
.AP char *str in/out
|
||||
Pointer to UTF-8 string to be converted in place.
|
||||
.BE
|
||||
|
||||
@@ -53,14 +53,11 @@ The Tcl_UniChar to be examined.
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
All of the routines described examine Tcl_UniChars and return a
|
||||
All of the routines described examine Unicode characters and return a
|
||||
boolean value. A non-zero return value means that the character does
|
||||
belong to the character class associated with the called routine. The
|
||||
rest of this document just describes the character classes associated
|
||||
with the various routines.
|
||||
.PP
|
||||
Note: A Tcl_UniChar is a Unicode character represented as an unsigned,
|
||||
fixed-size quantity.
|
||||
|
||||
.SH "CHARACTER CLASSES"
|
||||
.PP
|
||||
|
||||
@@ -77,7 +77,7 @@ int
|
||||
Buffer in which the UTF-8 representation of the Tcl_UniChar is stored. At most
|
||||
\fBTCL_UTF_MAX\fR bytes are stored in the buffer.
|
||||
.AP int ch in
|
||||
The Tcl_UniChar to be converted or examined.
|
||||
The Unicode character to be converted or examined.
|
||||
.AP Tcl_UniChar *chPtr out
|
||||
Filled with the Tcl_UniChar represented by the head of the UTF-8 string.
|
||||
.AP "const char" *src in
|
||||
|
||||
+15
-37
@@ -87,15 +87,6 @@ slowing its clock by a tiny fraction for some minutes until it is
|
||||
back in sync with UTC; its data model does not represent minutes that
|
||||
have 59 or 61 seconds.
|
||||
.TP
|
||||
\fI\-now\fR
|
||||
Instead of \fItimeVal\fR a non-integer option \fI\-now\fR can be used as
|
||||
replacement for today, which is simply interpolated to the runt-time as value
|
||||
of \fBclock seconds\fR. For example:
|
||||
.sp
|
||||
\fBclock format -now -f %a; # current day of the week\fR
|
||||
.sp
|
||||
\fBclock add -now 1 month; # next month\fR
|
||||
.TP
|
||||
\fIunit\fR
|
||||
One of the words, \fBseconds\fR, \fBminutes\fR, \fBhours\fR,
|
||||
\fBdays\fR, \fBweeks\fR, \fBmonths\fR, or \fByears\fR, or
|
||||
@@ -462,6 +453,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
|
||||
@@ -537,12 +541,6 @@ abbreviation appropriate to the current locale, and uses it to fix
|
||||
whether \fB%Y\fR refers to years before or after Year 1 of the
|
||||
Common Era.
|
||||
.TP
|
||||
\fB%Es\fR
|
||||
This affects similar to \fB%s\fR, but in opposition to \fB%s\fR it parses
|
||||
or formats local seconds (not the posix seconds).
|
||||
Because \fB%s\fR has the same precedence as \fB%s\fR (uniquely determines
|
||||
a point in time), it overrides all other input formats.
|
||||
.TP
|
||||
\fB%Ex\fR
|
||||
On output, produces a locale-dependent representation of the date
|
||||
in the locale's alternative calendar. On input, matches
|
||||
@@ -737,15 +735,13 @@ week number \fB%V\fR; programs should use \fB%G\fR for that purpose.
|
||||
On output, produces the current time zone, expressed in hours and
|
||||
minutes east (+hhmm) or west (\-hhmm) of Greenwich. On input, accepts a
|
||||
time zone specifier (see \fBTIME ZONES\fR below) that will be used to
|
||||
determine the time zone (this token is optionally applicable on input,
|
||||
so the value is not mandatory and can be missing in input).
|
||||
determine the time zone.
|
||||
.TP
|
||||
\fB%Z\fR
|
||||
On output, produces the current time zone's name, possibly
|
||||
translated to the given locale. On input, accepts a time zone
|
||||
specifier (see \fBTIME ZONES\fR below) that will be used to determine the
|
||||
time zone (token is also like \fB%z\fR optionally applicable on input).
|
||||
This option should, in general, be used on input only when
|
||||
time zone. This option should, in general, be used on input only when
|
||||
parsing RFC822 dates. Other uses are fraught with ambiguity; for
|
||||
instance, the string \fBBST\fR may represent British Summer Time or
|
||||
Brazilian Standard Time. It is recommended that date/time strings for
|
||||
@@ -944,24 +940,6 @@ used. Finally, a correction is applied so that the correct hour of
|
||||
the day is produced after allowing for daylight savings time
|
||||
differences and the correct date is given when going from the end
|
||||
of a long month to a short month.
|
||||
.PP
|
||||
The precedence of the applying of single tokens resp. which sequence will be
|
||||
used by calculating of the time is complex, e. g. heavily dependent on the
|
||||
precision of type of the token.
|
||||
.sp
|
||||
In example below the second date-string contains "next January", therefore
|
||||
it results in next year but in January. And third date-string besides "January"
|
||||
contains also additionally "Fri", so it results in the nearest Friday.
|
||||
Thus both win before "385 days" resp. make it more precise, because of higher
|
||||
precision of this token types.
|
||||
.CS
|
||||
% clock format [clock scan "5 years 18 months 385 days" -base 0 -gmt 1] -gmt 1
|
||||
Thu Jul 21 00:00:00 GMT 1977
|
||||
% clock format [clock scan "5 years 18 months 385 days next January" -base 0 -gmt 1] -gmt 1
|
||||
Sat Jan 21 00:00:00 GMT 1978
|
||||
% clock format [clock scan "5 years 18 months 385 days next January Fri" -base 0 -gmt 1] -gmt 1
|
||||
Fri Jan 27 00:00:00 GMT 1978
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
msgcat(n)
|
||||
.SH KEYWORDS
|
||||
|
||||
+16
-6
@@ -14,7 +14,7 @@ oo::copy \- create copies of objects and classes
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBoo::copy\fI sourceObject \fR?\fItargetObject\fR?
|
||||
\fBoo::copy\fI sourceObject \fR?\fItargetObject\fR? ?\fItargetNamespace\fR?
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
@@ -22,11 +22,21 @@ package require TclOO
|
||||
The \fBoo::copy\fR command creates a copy of an object or class. It takes the
|
||||
name of the object or class to be copied, \fIsourceObject\fR, and optionally
|
||||
the name of the object or class to create, \fItargetObject\fR, which will be
|
||||
resolved relative to the current namespace if not an absolute qualified name.
|
||||
If \fItargetObject\fR is omitted, a new name is chosen. The copied object will
|
||||
be of the same class as the source object, and will have all its per-object
|
||||
methods copied. If it is a class, it will also have all the class methods in
|
||||
the class copied, but it will not have any of its instances copied.
|
||||
resolved relative to the current namespace if not an absolute qualified name
|
||||
and
|
||||
.VS TIP473
|
||||
\fItargetNamespace\fR which is the name of the namespace that will hold the
|
||||
internal state of the object (\fBmy\fR command, etc.); it \fImust not\fR
|
||||
refer to an existing namespace.
|
||||
If either \fItargetObject\fR or \fItargetNamespace\fR is omitted or is given
|
||||
as the empty string, a new name is chosen. Names, unless specified, are
|
||||
chosen with the same algorithm used by the \fBnew\fR method of
|
||||
\fBoo::class\fR.
|
||||
.VE TIP473
|
||||
The copied object will be of the same class as the source object, and will have
|
||||
all its per-object methods copied. If it is a class, it will also have all the
|
||||
class methods in the class copied, but it will not have any of its instances
|
||||
copied.
|
||||
.PP
|
||||
.VS
|
||||
After the \fItargetObject\fR has been created and all definitions of its
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ being constructed. Within the constructor, the \fBnext\fR command should be
|
||||
used to call the superclasses' constructors. If \fIbodyScript\fR is the empty
|
||||
string, the constructor will be deleted.
|
||||
.TP
|
||||
\fBdeletemethod\fI name\fR ?\fIname ...\fR
|
||||
\fBdeletemethod\fI name\fR ?\fIname ...\fR?
|
||||
.
|
||||
This deletes each of the methods called \fIname\fR from a class. The methods
|
||||
must have previously existed in that class. Does not affect the superclasses
|
||||
|
||||
+1
-1
@@ -437,7 +437,7 @@ puts $foo
|
||||
# prints: \fIa b foo {a b} bar 2 baz 3\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
append(n), array(n), foreach(n), mapeach(n), incr(n), list(n), lappend(n), set(n)
|
||||
append(n), array(n), foreach(n), incr(n), list(n), lappend(n), lmap(n), set(n)
|
||||
.SH KEYWORDS
|
||||
dictionary, create, update, lookup, iterate, filter, map
|
||||
'\" Local Variables:
|
||||
|
||||
+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"
|
||||
|
||||
+2
-2
@@ -83,7 +83,7 @@ Specifies that the number should be padded on the left with
|
||||
zeroes instead of spaces.
|
||||
.TP 10
|
||||
\fB#\fR
|
||||
Requests an alternate output form. For \fBo\fR and \fBO\fR
|
||||
Requests an alternate output form. For \fBo\fR
|
||||
conversions it guarantees that the first digit is always \fB0\fR.
|
||||
For \fBx\fR or \fBX\fR conversions, \fB0x\fR or \fB0X\fR (respectively)
|
||||
will be added to the beginning of the result unless it is zero.
|
||||
@@ -169,7 +169,7 @@ for \fBx\fR and
|
||||
for \fBX\fR).
|
||||
.TP 10
|
||||
\fBb\fR
|
||||
Convert integer to binary string, using digits 0 and 1.
|
||||
Convert integer to unsigned binary string, using digits 0 and 1.
|
||||
.TP 10
|
||||
\fBc\fR
|
||||
Convert integer to the Unicode character it represents.
|
||||
|
||||
+177
-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,8 @@ 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::reset\fR \fItoken\fR ?\fIwhy\fR?
|
||||
.sp
|
||||
\fB::http::wait \fItoken\fR
|
||||
@@ -44,12 +46,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 +99,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 +133,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 +271,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 +378,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 +464,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 +564,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 +670,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
|
||||
|
||||
+30
-10
@@ -17,7 +17,7 @@ lreplace \- Replace elements in a list with new elements
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fBlreplace\fR returns a new list formed by replacing one or more elements of
|
||||
\fBlreplace\fR returns a new list formed by replacing zero or more elements of
|
||||
\fIlist\fR with the \fIelement\fR arguments.
|
||||
\fIfirst\fR and \fIlast\fR are index values specifying the first and
|
||||
last elements of the range to replace.
|
||||
@@ -27,23 +27,26 @@ supporting simple index arithmetic and indices relative to the
|
||||
end of the list.
|
||||
0 refers to the first element of the
|
||||
list, and \fBend\fR refers to the last element of the list.
|
||||
If \fIlist\fR is empty, then \fIfirst\fR and \fIlast\fR are ignored.
|
||||
.PP
|
||||
If \fIfirst\fR is less than zero, it is considered to refer to before the
|
||||
first element of the list. For non-empty lists, the element indicated
|
||||
by \fIfirst\fR must exist or \fIfirst\fR must indicate before the
|
||||
start of the list.
|
||||
If either \fIfirst\fR or \fIlast\fR is less than zero, it is considered
|
||||
to refer to before the first element of the list. This allows \fBlreplace\fR
|
||||
to prepend elements to \fIlist\fR.
|
||||
.VS TIP505
|
||||
If either \fIfirst\fR or \fIlast\fR indicates a position greater than the
|
||||
index of the last element of the list, it is treated as if it is an
|
||||
index one greater than the last element. This allows \fBlreplace\fR to
|
||||
append elements to \fIlist\fR.
|
||||
.VE TIP505
|
||||
.PP
|
||||
If \fIlast\fR is less than \fIfirst\fR, then any specified elements
|
||||
will be inserted into the list before the point specified by \fIfirst\fR
|
||||
will be inserted into the list before the element specified by \fIfirst\fR
|
||||
with no elements being deleted.
|
||||
.PP
|
||||
The \fIelement\fR arguments specify zero or more new arguments to
|
||||
The \fIelement\fR arguments specify zero or more new elements to
|
||||
be added to the list in place of those that were deleted.
|
||||
Each \fIelement\fR argument will become a separate element of
|
||||
the list. If no \fIelement\fR arguments are specified, then the elements
|
||||
between \fIfirst\fR and \fIlast\fR are simply deleted. If \fIlist\fR
|
||||
is empty, any \fIelement\fR arguments are added to the end of the list.
|
||||
between \fIfirst\fR and \fIlast\fR are simply deleted.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
Replacing an element of a list with another:
|
||||
@@ -78,9 +81,26 @@ proc lremove {listVariable value} {
|
||||
set var [\fBlreplace\fR $var $idx $idx]
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
.VS TIP505
|
||||
Appending elements to the list; note that \fBend+2\fR will initially
|
||||
be treated as if it is \fB6\fR here, but both that and \fB12345\fR are greater
|
||||
than the index of the final item so they behave identically:
|
||||
.PP
|
||||
.CS
|
||||
% set var {a b c d e}
|
||||
a b c d e
|
||||
% set var [\fBlreplace\fR $var 12345 end+2 f g h i]
|
||||
a b c d e f g h i
|
||||
.CE
|
||||
.VE TIP505
|
||||
.SH "SEE ALSO"
|
||||
list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n),
|
||||
lset(n), lrange(n), lsort(n),
|
||||
string(n)
|
||||
.SH KEYWORDS
|
||||
element, list, replace
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
|
||||
+3
-5
@@ -115,9 +115,7 @@ Any Unicode control character.
|
||||
Any Unicode digit character. Note that this includes characters
|
||||
outside of the [0\-9] range.
|
||||
.IP \fBdouble\fR 12
|
||||
Any of the valid forms for a double in Tcl, with optional surrounding
|
||||
whitespace. In case of under/overflow in the value, 0 is returned and
|
||||
the \fIvarname\fR will contain \-1.
|
||||
Any of the forms allowed to \fBTcl_GetDoubleFromObj\fR.
|
||||
.IP \fBentier\fR 12
|
||||
.VS 8.6
|
||||
Any of the valid string formats for an integer value of arbitrary size
|
||||
@@ -131,7 +129,7 @@ false.
|
||||
Any Unicode printing character, except space.
|
||||
.IP \fBinteger\fR 12
|
||||
Any of the valid string formats for a 32-bit integer value in Tcl,
|
||||
with optional surrounding whitespace. In case of under/overflow in
|
||||
with optional surrounding whitespace. In case of overflow in
|
||||
the value, 0 is returned and the \fIvarname\fR will contain \-1.
|
||||
.IP \fBlist\fR 12
|
||||
Any proper list structure, with optional surrounding whitespace. In
|
||||
@@ -156,7 +154,7 @@ true.
|
||||
Any upper case alphabet character in the Unicode character set.
|
||||
.IP \fBwideinteger\fR 12
|
||||
Any of the valid forms for a wide integer in Tcl, with optional
|
||||
surrounding whitespace. In case of under/overflow in the value, 0 is
|
||||
surrounding whitespace. In case of overflow in the value, 0 is
|
||||
returned and the \fIvarname\fR will contain \-1.
|
||||
.IP \fBwordchar\fR 12
|
||||
Any Unicode word character. That is any alphanumeric character, and
|
||||
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2005 Sergey Brester aka sebres.
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH timerate n "" Tcl "Tcl Built-In Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
timerate \- Time-related execution resp. performance measurement of a script
|
||||
.SH SYNOPSIS
|
||||
\fBtimerate \fIscript\fR \fI?time?\fR
|
||||
.sp
|
||||
\fBtimerate \fI?-direct?\fR \fI?-overhead double?\fR \fIscript\fR \fI?time?\fR
|
||||
.sp
|
||||
\fBtimerate \fI?-calibrate?\fR \fI?-direct?\fR \fIscript\fR \fI?time?\fR
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The first and second form will evaluate \fIscript\fR until the interval
|
||||
\fItime\fR given in milliseconds elapses, or for 1000 milliseconds (1 second)
|
||||
if \fItime\fR is not specified.
|
||||
.sp
|
||||
It will then return a canonical tcl-list of the form
|
||||
.PP
|
||||
.CS
|
||||
\f0.095977 µs/# 52095836 # 10419167 #/sec 5000.000 nett-ms\fR
|
||||
.CE
|
||||
.PP
|
||||
which indicates:
|
||||
.IP \(bu
|
||||
the average amount of time required per iteration, in microseconds (lindex $result 0)
|
||||
.IP \(bu
|
||||
the count how many times it was executed (lindex $result 2)
|
||||
.IP \(bu
|
||||
the estimated rate per second (lindex $result 4)
|
||||
.IP \(bu
|
||||
the estimated real execution time without measurement overhead (lindex $result 6)
|
||||
.PP
|
||||
Time is measured in elapsed time using heighest timer resolution as possible, not CPU time.
|
||||
This command may be used to provide information as to how well the script or a tcl-command
|
||||
is performing and can help determine bottlenecks and fine-tune application performance.
|
||||
.PP
|
||||
\fI-calibrate\fR
|
||||
.
|
||||
To measure very fast scripts as exact as posible the calibration process
|
||||
may be required.
|
||||
|
||||
This parameter used to calibrate \fBtimerate\fR calculating the estimated overhead
|
||||
of given \fIscript\fR as default overhead for further execution of \fBtimerate\fR.
|
||||
It can take up to 10 seconds if parameter \fItime\fR is not specified.
|
||||
.PP
|
||||
\fI-overhead double\fR
|
||||
.
|
||||
This parameter used to supply the measurement overhead of single iteration
|
||||
(in microseconds) that should be ignored during whole evaluation process.
|
||||
.PP
|
||||
\fI-direct\fR
|
||||
.
|
||||
Causes direct execution per iteration (not compiled variant of evaluation used).
|
||||
.PP
|
||||
In opposition to \fBtime\fR the execution limited here by fixed time instead of
|
||||
repetition count.
|
||||
Additionally the compiled variant of the script will be used during whole evaluation
|
||||
(as if it were part of a compiled \fBproc\fR), if parameter \fI-direct\fR is not specified.
|
||||
Therefore it provides more precise results and prevents very long execution time
|
||||
by slow scripts resp. scripts with unknown speed.
|
||||
|
||||
.SH EXAMPLE
|
||||
Estimate how fast it takes for a simple Tcl \fBfor\fR loop (including
|
||||
operations on variable \fIi\fR) to count to a ten:
|
||||
.PP
|
||||
.CS
|
||||
# calibrate:
|
||||
timerate -calibrate {}
|
||||
# measure:
|
||||
timerate { for {set i 0} {$i<10} {incr i} {} } 5000
|
||||
.CE
|
||||
.PP
|
||||
Estimate how fast it takes for a simple Tcl \fBfor\fR loop only (ignoring the
|
||||
overhead for operations on variable \fIi\fR) to count to a ten:
|
||||
.PP
|
||||
.CS
|
||||
# calibrate for overhead of variable operations:
|
||||
set i 0; timerate -calibrate {expr {$i<10}; incr i} 1000
|
||||
# measure:
|
||||
timerate { for {set i 0} {$i<10} {incr i} {} } 5000
|
||||
.CE
|
||||
.PP
|
||||
Estimate the rate of calculating the hour using \fBclock format\fR only, ignoring
|
||||
overhead of the rest, without measurement how fast it takes for a whole script:
|
||||
.PP
|
||||
.CS
|
||||
# calibrate:
|
||||
timerate -calibrate {}
|
||||
# estimate overhead:
|
||||
set tm 0
|
||||
set ovh [lindex [timerate { incr tm [expr {24*60*60}] }] 0]
|
||||
# measure using esimated overhead:
|
||||
set tm 0
|
||||
timerate -overhead $ovh {
|
||||
clock format $tm -format %H
|
||||
incr tm [expr {24*60*60}]; # overhead for this is ignored
|
||||
} 5000
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
time(n)
|
||||
.SH KEYWORDS
|
||||
script, timerate, time
|
||||
.\" Local Variables:
|
||||
.\" mode: nroff
|
||||
.\" End:
|
||||
+306
-293
@@ -137,109 +137,110 @@ static const crange alphaRangeTable[] = {
|
||||
{0x41, 0x5a}, {0x61, 0x7a}, {0xc0, 0xd6}, {0xd8, 0xf6},
|
||||
{0xf8, 0x2c1}, {0x2c6, 0x2d1}, {0x2e0, 0x2e4}, {0x370, 0x374},
|
||||
{0x37a, 0x37d}, {0x388, 0x38a}, {0x38e, 0x3a1}, {0x3a3, 0x3f5},
|
||||
{0x3f7, 0x481}, {0x48a, 0x52f}, {0x531, 0x556}, {0x561, 0x587},
|
||||
{0x5d0, 0x5ea}, {0x5f0, 0x5f2}, {0x620, 0x64a}, {0x671, 0x6d3},
|
||||
{0x3f7, 0x481}, {0x48a, 0x52f}, {0x531, 0x556}, {0x560, 0x588},
|
||||
{0x5d0, 0x5ea}, {0x5ef, 0x5f2}, {0x620, 0x64a}, {0x671, 0x6d3},
|
||||
{0x6fa, 0x6fc}, {0x712, 0x72f}, {0x74d, 0x7a5}, {0x7ca, 0x7ea},
|
||||
{0x800, 0x815}, {0x840, 0x858}, {0x8a0, 0x8b4}, {0x8b6, 0x8bd},
|
||||
{0x904, 0x939}, {0x958, 0x961}, {0x971, 0x980}, {0x985, 0x98c},
|
||||
{0x993, 0x9a8}, {0x9aa, 0x9b0}, {0x9b6, 0x9b9}, {0x9df, 0x9e1},
|
||||
{0xa05, 0xa0a}, {0xa13, 0xa28}, {0xa2a, 0xa30}, {0xa59, 0xa5c},
|
||||
{0xa72, 0xa74}, {0xa85, 0xa8d}, {0xa8f, 0xa91}, {0xa93, 0xaa8},
|
||||
{0xaaa, 0xab0}, {0xab5, 0xab9}, {0xb05, 0xb0c}, {0xb13, 0xb28},
|
||||
{0xb2a, 0xb30}, {0xb35, 0xb39}, {0xb5f, 0xb61}, {0xb85, 0xb8a},
|
||||
{0xb8e, 0xb90}, {0xb92, 0xb95}, {0xba8, 0xbaa}, {0xbae, 0xbb9},
|
||||
{0xc05, 0xc0c}, {0xc0e, 0xc10}, {0xc12, 0xc28}, {0xc2a, 0xc39},
|
||||
{0xc58, 0xc5a}, {0xc85, 0xc8c}, {0xc8e, 0xc90}, {0xc92, 0xca8},
|
||||
{0xcaa, 0xcb3}, {0xcb5, 0xcb9}, {0xd05, 0xd0c}, {0xd0e, 0xd10},
|
||||
{0xd12, 0xd3a}, {0xd54, 0xd56}, {0xd5f, 0xd61}, {0xd7a, 0xd7f},
|
||||
{0xd85, 0xd96}, {0xd9a, 0xdb1}, {0xdb3, 0xdbb}, {0xdc0, 0xdc6},
|
||||
{0xe01, 0xe30}, {0xe40, 0xe46}, {0xe94, 0xe97}, {0xe99, 0xe9f},
|
||||
{0xea1, 0xea3}, {0xead, 0xeb0}, {0xec0, 0xec4}, {0xedc, 0xedf},
|
||||
{0xf40, 0xf47}, {0xf49, 0xf6c}, {0xf88, 0xf8c}, {0x1000, 0x102a},
|
||||
{0x1050, 0x1055}, {0x105a, 0x105d}, {0x106e, 0x1070}, {0x1075, 0x1081},
|
||||
{0x10a0, 0x10c5}, {0x10d0, 0x10fa}, {0x10fc, 0x1248}, {0x124a, 0x124d},
|
||||
{0x1250, 0x1256}, {0x125a, 0x125d}, {0x1260, 0x1288}, {0x128a, 0x128d},
|
||||
{0x1290, 0x12b0}, {0x12b2, 0x12b5}, {0x12b8, 0x12be}, {0x12c2, 0x12c5},
|
||||
{0x12c8, 0x12d6}, {0x12d8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135a},
|
||||
{0x1380, 0x138f}, {0x13a0, 0x13f5}, {0x13f8, 0x13fd}, {0x1401, 0x166c},
|
||||
{0x166f, 0x167f}, {0x1681, 0x169a}, {0x16a0, 0x16ea}, {0x16f1, 0x16f8},
|
||||
{0x1700, 0x170c}, {0x170e, 0x1711}, {0x1720, 0x1731}, {0x1740, 0x1751},
|
||||
{0x1760, 0x176c}, {0x176e, 0x1770}, {0x1780, 0x17b3}, {0x1820, 0x1877},
|
||||
{0x1880, 0x1884}, {0x1887, 0x18a8}, {0x18b0, 0x18f5}, {0x1900, 0x191e},
|
||||
{0x1950, 0x196d}, {0x1970, 0x1974}, {0x1980, 0x19ab}, {0x19b0, 0x19c9},
|
||||
{0x1a00, 0x1a16}, {0x1a20, 0x1a54}, {0x1b05, 0x1b33}, {0x1b45, 0x1b4b},
|
||||
{0x1b83, 0x1ba0}, {0x1bba, 0x1be5}, {0x1c00, 0x1c23}, {0x1c4d, 0x1c4f},
|
||||
{0x1c5a, 0x1c7d}, {0x1c80, 0x1c88}, {0x1ce9, 0x1cec}, {0x1cee, 0x1cf1},
|
||||
{0x1d00, 0x1dbf}, {0x1e00, 0x1f15}, {0x1f18, 0x1f1d}, {0x1f20, 0x1f45},
|
||||
{0x1f48, 0x1f4d}, {0x1f50, 0x1f57}, {0x1f5f, 0x1f7d}, {0x1f80, 0x1fb4},
|
||||
{0x1fb6, 0x1fbc}, {0x1fc2, 0x1fc4}, {0x1fc6, 0x1fcc}, {0x1fd0, 0x1fd3},
|
||||
{0x1fd6, 0x1fdb}, {0x1fe0, 0x1fec}, {0x1ff2, 0x1ff4}, {0x1ff6, 0x1ffc},
|
||||
{0x2090, 0x209c}, {0x210a, 0x2113}, {0x2119, 0x211d}, {0x212a, 0x212d},
|
||||
{0x212f, 0x2139}, {0x213c, 0x213f}, {0x2145, 0x2149}, {0x2c00, 0x2c2e},
|
||||
{0x2c30, 0x2c5e}, {0x2c60, 0x2ce4}, {0x2ceb, 0x2cee}, {0x2d00, 0x2d25},
|
||||
{0x2d30, 0x2d67}, {0x2d80, 0x2d96}, {0x2da0, 0x2da6}, {0x2da8, 0x2dae},
|
||||
{0x2db0, 0x2db6}, {0x2db8, 0x2dbe}, {0x2dc0, 0x2dc6}, {0x2dc8, 0x2dce},
|
||||
{0x2dd0, 0x2dd6}, {0x2dd8, 0x2dde}, {0x3031, 0x3035}, {0x3041, 0x3096},
|
||||
{0x309d, 0x309f}, {0x30a1, 0x30fa}, {0x30fc, 0x30ff}, {0x3105, 0x312d},
|
||||
{0x3131, 0x318e}, {0x31a0, 0x31ba}, {0x31f0, 0x31ff}, {0x3400, 0x4db5},
|
||||
{0x4e00, 0x9fd5}, {0xa000, 0xa48c}, {0xa4d0, 0xa4fd}, {0xa500, 0xa60c},
|
||||
{0xa610, 0xa61f}, {0xa640, 0xa66e}, {0xa67f, 0xa69d}, {0xa6a0, 0xa6e5},
|
||||
{0xa717, 0xa71f}, {0xa722, 0xa788}, {0xa78b, 0xa7ae}, {0xa7b0, 0xa7b7},
|
||||
{0xa7f7, 0xa801}, {0xa803, 0xa805}, {0xa807, 0xa80a}, {0xa80c, 0xa822},
|
||||
{0xa840, 0xa873}, {0xa882, 0xa8b3}, {0xa8f2, 0xa8f7}, {0xa90a, 0xa925},
|
||||
{0xa930, 0xa946}, {0xa960, 0xa97c}, {0xa984, 0xa9b2}, {0xa9e0, 0xa9e4},
|
||||
{0xa9e6, 0xa9ef}, {0xa9fa, 0xa9fe}, {0xaa00, 0xaa28}, {0xaa40, 0xaa42},
|
||||
{0xaa44, 0xaa4b}, {0xaa60, 0xaa76}, {0xaa7e, 0xaaaf}, {0xaab9, 0xaabd},
|
||||
{0xaadb, 0xaadd}, {0xaae0, 0xaaea}, {0xaaf2, 0xaaf4}, {0xab01, 0xab06},
|
||||
{0xab09, 0xab0e}, {0xab11, 0xab16}, {0xab20, 0xab26}, {0xab28, 0xab2e},
|
||||
{0xab30, 0xab5a}, {0xab5c, 0xab65}, {0xab70, 0xabe2}, {0xac00, 0xd7a3},
|
||||
{0xd7b0, 0xd7c6}, {0xd7cb, 0xd7fb}, {0xdc00, 0xdc3e}, {0xdc40, 0xdc7e},
|
||||
{0xdc80, 0xdcbe}, {0xdcc0, 0xdcfe}, {0xdd00, 0xdd3e}, {0xdd40, 0xdd7e},
|
||||
{0xdd80, 0xddbe}, {0xddc0, 0xddfe}, {0xde00, 0xde3e}, {0xde40, 0xde7e},
|
||||
{0xde80, 0xdebe}, {0xdec0, 0xdefe}, {0xdf00, 0xdf3e}, {0xdf40, 0xdf7e},
|
||||
{0xdf80, 0xdfbe}, {0xdfc0, 0xdffe}, {0xf900, 0xfa6d}, {0xfa70, 0xfad9},
|
||||
{0xfb00, 0xfb06}, {0xfb13, 0xfb17}, {0xfb1f, 0xfb28}, {0xfb2a, 0xfb36},
|
||||
{0xfb38, 0xfb3c}, {0xfb46, 0xfbb1}, {0xfbd3, 0xfd3d}, {0xfd50, 0xfd8f},
|
||||
{0xfd92, 0xfdc7}, {0xfdf0, 0xfdfb}, {0xfe70, 0xfe74}, {0xfe76, 0xfefc},
|
||||
{0xff21, 0xff3a}, {0xff41, 0xff5a}, {0xff66, 0xffbe}, {0xffc2, 0xffc7},
|
||||
{0xffca, 0xffcf}, {0xffd2, 0xffd7}, {0xffda, 0xffdc}
|
||||
#if TCL_UTF_MAX > 4
|
||||
{0x800, 0x815}, {0x840, 0x858}, {0x860, 0x86a}, {0x8a0, 0x8b4},
|
||||
{0x8b6, 0x8bd}, {0x904, 0x939}, {0x958, 0x961}, {0x971, 0x980},
|
||||
{0x985, 0x98c}, {0x993, 0x9a8}, {0x9aa, 0x9b0}, {0x9b6, 0x9b9},
|
||||
{0x9df, 0x9e1}, {0xa05, 0xa0a}, {0xa13, 0xa28}, {0xa2a, 0xa30},
|
||||
{0xa59, 0xa5c}, {0xa72, 0xa74}, {0xa85, 0xa8d}, {0xa8f, 0xa91},
|
||||
{0xa93, 0xaa8}, {0xaaa, 0xab0}, {0xab5, 0xab9}, {0xb05, 0xb0c},
|
||||
{0xb13, 0xb28}, {0xb2a, 0xb30}, {0xb35, 0xb39}, {0xb5f, 0xb61},
|
||||
{0xb85, 0xb8a}, {0xb8e, 0xb90}, {0xb92, 0xb95}, {0xba8, 0xbaa},
|
||||
{0xbae, 0xbb9}, {0xc05, 0xc0c}, {0xc0e, 0xc10}, {0xc12, 0xc28},
|
||||
{0xc2a, 0xc39}, {0xc58, 0xc5a}, {0xc85, 0xc8c}, {0xc8e, 0xc90},
|
||||
{0xc92, 0xca8}, {0xcaa, 0xcb3}, {0xcb5, 0xcb9}, {0xd05, 0xd0c},
|
||||
{0xd0e, 0xd10}, {0xd12, 0xd3a}, {0xd54, 0xd56}, {0xd5f, 0xd61},
|
||||
{0xd7a, 0xd7f}, {0xd85, 0xd96}, {0xd9a, 0xdb1}, {0xdb3, 0xdbb},
|
||||
{0xdc0, 0xdc6}, {0xe01, 0xe30}, {0xe40, 0xe46}, {0xe94, 0xe97},
|
||||
{0xe99, 0xe9f}, {0xea1, 0xea3}, {0xead, 0xeb0}, {0xec0, 0xec4},
|
||||
{0xedc, 0xedf}, {0xf40, 0xf47}, {0xf49, 0xf6c}, {0xf88, 0xf8c},
|
||||
{0x1000, 0x102a}, {0x1050, 0x1055}, {0x105a, 0x105d}, {0x106e, 0x1070},
|
||||
{0x1075, 0x1081}, {0x10a0, 0x10c5}, {0x10d0, 0x10fa}, {0x10fc, 0x1248},
|
||||
{0x124a, 0x124d}, {0x1250, 0x1256}, {0x125a, 0x125d}, {0x1260, 0x1288},
|
||||
{0x128a, 0x128d}, {0x1290, 0x12b0}, {0x12b2, 0x12b5}, {0x12b8, 0x12be},
|
||||
{0x12c2, 0x12c5}, {0x12c8, 0x12d6}, {0x12d8, 0x1310}, {0x1312, 0x1315},
|
||||
{0x1318, 0x135a}, {0x1380, 0x138f}, {0x13a0, 0x13f5}, {0x13f8, 0x13fd},
|
||||
{0x1401, 0x166c}, {0x166f, 0x167f}, {0x1681, 0x169a}, {0x16a0, 0x16ea},
|
||||
{0x16f1, 0x16f8}, {0x1700, 0x170c}, {0x170e, 0x1711}, {0x1720, 0x1731},
|
||||
{0x1740, 0x1751}, {0x1760, 0x176c}, {0x176e, 0x1770}, {0x1780, 0x17b3},
|
||||
{0x1820, 0x1878}, {0x1880, 0x1884}, {0x1887, 0x18a8}, {0x18b0, 0x18f5},
|
||||
{0x1900, 0x191e}, {0x1950, 0x196d}, {0x1970, 0x1974}, {0x1980, 0x19ab},
|
||||
{0x19b0, 0x19c9}, {0x1a00, 0x1a16}, {0x1a20, 0x1a54}, {0x1b05, 0x1b33},
|
||||
{0x1b45, 0x1b4b}, {0x1b83, 0x1ba0}, {0x1bba, 0x1be5}, {0x1c00, 0x1c23},
|
||||
{0x1c4d, 0x1c4f}, {0x1c5a, 0x1c7d}, {0x1c80, 0x1c88}, {0x1c90, 0x1cba},
|
||||
{0x1cbd, 0x1cbf}, {0x1ce9, 0x1cec}, {0x1cee, 0x1cf1}, {0x1d00, 0x1dbf},
|
||||
{0x1e00, 0x1f15}, {0x1f18, 0x1f1d}, {0x1f20, 0x1f45}, {0x1f48, 0x1f4d},
|
||||
{0x1f50, 0x1f57}, {0x1f5f, 0x1f7d}, {0x1f80, 0x1fb4}, {0x1fb6, 0x1fbc},
|
||||
{0x1fc2, 0x1fc4}, {0x1fc6, 0x1fcc}, {0x1fd0, 0x1fd3}, {0x1fd6, 0x1fdb},
|
||||
{0x1fe0, 0x1fec}, {0x1ff2, 0x1ff4}, {0x1ff6, 0x1ffc}, {0x2090, 0x209c},
|
||||
{0x210a, 0x2113}, {0x2119, 0x211d}, {0x212a, 0x212d}, {0x212f, 0x2139},
|
||||
{0x213c, 0x213f}, {0x2145, 0x2149}, {0x2c00, 0x2c2e}, {0x2c30, 0x2c5e},
|
||||
{0x2c60, 0x2ce4}, {0x2ceb, 0x2cee}, {0x2d00, 0x2d25}, {0x2d30, 0x2d67},
|
||||
{0x2d80, 0x2d96}, {0x2da0, 0x2da6}, {0x2da8, 0x2dae}, {0x2db0, 0x2db6},
|
||||
{0x2db8, 0x2dbe}, {0x2dc0, 0x2dc6}, {0x2dc8, 0x2dce}, {0x2dd0, 0x2dd6},
|
||||
{0x2dd8, 0x2dde}, {0x3031, 0x3035}, {0x3041, 0x3096}, {0x309d, 0x309f},
|
||||
{0x30a1, 0x30fa}, {0x30fc, 0x30ff}, {0x3105, 0x312f}, {0x3131, 0x318e},
|
||||
{0x31a0, 0x31ba}, {0x31f0, 0x31ff}, {0x3400, 0x4db5}, {0x4e00, 0x9fef},
|
||||
{0xa000, 0xa48c}, {0xa4d0, 0xa4fd}, {0xa500, 0xa60c}, {0xa610, 0xa61f},
|
||||
{0xa640, 0xa66e}, {0xa67f, 0xa69d}, {0xa6a0, 0xa6e5}, {0xa717, 0xa71f},
|
||||
{0xa722, 0xa788}, {0xa78b, 0xa7b9}, {0xa7f7, 0xa801}, {0xa803, 0xa805},
|
||||
{0xa807, 0xa80a}, {0xa80c, 0xa822}, {0xa840, 0xa873}, {0xa882, 0xa8b3},
|
||||
{0xa8f2, 0xa8f7}, {0xa90a, 0xa925}, {0xa930, 0xa946}, {0xa960, 0xa97c},
|
||||
{0xa984, 0xa9b2}, {0xa9e0, 0xa9e4}, {0xa9e6, 0xa9ef}, {0xa9fa, 0xa9fe},
|
||||
{0xaa00, 0xaa28}, {0xaa40, 0xaa42}, {0xaa44, 0xaa4b}, {0xaa60, 0xaa76},
|
||||
{0xaa7e, 0xaaaf}, {0xaab9, 0xaabd}, {0xaadb, 0xaadd}, {0xaae0, 0xaaea},
|
||||
{0xaaf2, 0xaaf4}, {0xab01, 0xab06}, {0xab09, 0xab0e}, {0xab11, 0xab16},
|
||||
{0xab20, 0xab26}, {0xab28, 0xab2e}, {0xab30, 0xab5a}, {0xab5c, 0xab65},
|
||||
{0xab70, 0xabe2}, {0xac00, 0xd7a3}, {0xd7b0, 0xd7c6}, {0xd7cb, 0xd7fb},
|
||||
{0xf900, 0xfa6d}, {0xfa70, 0xfad9}, {0xfb00, 0xfb06}, {0xfb13, 0xfb17},
|
||||
{0xfb1f, 0xfb28}, {0xfb2a, 0xfb36}, {0xfb38, 0xfb3c}, {0xfb46, 0xfbb1},
|
||||
{0xfbd3, 0xfd3d}, {0xfd50, 0xfd8f}, {0xfd92, 0xfdc7}, {0xfdf0, 0xfdfb},
|
||||
{0xfe70, 0xfe74}, {0xfe76, 0xfefc}, {0xff21, 0xff3a}, {0xff41, 0xff5a},
|
||||
{0xff66, 0xffbe}, {0xffc2, 0xffc7}, {0xffca, 0xffcf}, {0xffd2, 0xffd7},
|
||||
{0xffda, 0xffdc}
|
||||
#if CHRBITS > 16
|
||||
,{0x10000, 0x1000b}, {0x1000d, 0x10026}, {0x10028, 0x1003a}, {0x1003f, 0x1004d},
|
||||
{0x10050, 0x1005d}, {0x10080, 0x100fa}, {0x10280, 0x1029c}, {0x102a0, 0x102d0},
|
||||
{0x10300, 0x1031f}, {0x10330, 0x10340}, {0x10342, 0x10349}, {0x10350, 0x10375},
|
||||
{0x10300, 0x1031f}, {0x1032d, 0x10340}, {0x10342, 0x10349}, {0x10350, 0x10375},
|
||||
{0x10380, 0x1039d}, {0x103a0, 0x103c3}, {0x103c8, 0x103cf}, {0x10400, 0x1049d},
|
||||
{0x104b0, 0x104d3}, {0x104d8, 0x104fb}, {0x10500, 0x10527}, {0x10530, 0x10563},
|
||||
{0x10600, 0x10736}, {0x10740, 0x10755}, {0x10760, 0x10767}, {0x10800, 0x10805},
|
||||
{0x1080a, 0x10835}, {0x1083f, 0x10855}, {0x10860, 0x10876}, {0x10880, 0x1089e},
|
||||
{0x108e0, 0x108f2}, {0x10900, 0x10915}, {0x10920, 0x10939}, {0x10980, 0x109b7},
|
||||
{0x10a10, 0x10a13}, {0x10a15, 0x10a17}, {0x10a19, 0x10a33}, {0x10a60, 0x10a7c},
|
||||
{0x10a10, 0x10a13}, {0x10a15, 0x10a17}, {0x10a19, 0x10a35}, {0x10a60, 0x10a7c},
|
||||
{0x10a80, 0x10a9c}, {0x10ac0, 0x10ac7}, {0x10ac9, 0x10ae4}, {0x10b00, 0x10b35},
|
||||
{0x10b40, 0x10b55}, {0x10b60, 0x10b72}, {0x10b80, 0x10b91}, {0x10c00, 0x10c48},
|
||||
{0x10c80, 0x10cb2}, {0x10cc0, 0x10cf2}, {0x11003, 0x11037}, {0x11083, 0x110af},
|
||||
{0x110d0, 0x110e8}, {0x11103, 0x11126}, {0x11150, 0x11172}, {0x11183, 0x111b2},
|
||||
{0x111c1, 0x111c4}, {0x11200, 0x11211}, {0x11213, 0x1122b}, {0x11280, 0x11286},
|
||||
{0x1128a, 0x1128d}, {0x1128f, 0x1129d}, {0x1129f, 0x112a8}, {0x112b0, 0x112de},
|
||||
{0x11305, 0x1130c}, {0x11313, 0x11328}, {0x1132a, 0x11330}, {0x11335, 0x11339},
|
||||
{0x1135d, 0x11361}, {0x11400, 0x11434}, {0x11447, 0x1144a}, {0x11480, 0x114af},
|
||||
{0x11580, 0x115ae}, {0x115d8, 0x115db}, {0x11600, 0x1162f}, {0x11680, 0x116aa},
|
||||
{0x11700, 0x11719}, {0x118a0, 0x118df}, {0x11ac0, 0x11af8}, {0x11c00, 0x11c08},
|
||||
{0x11c0a, 0x11c2e}, {0x11c72, 0x11c8f}, {0x12000, 0x12399}, {0x12480, 0x12543},
|
||||
{0x10c80, 0x10cb2}, {0x10cc0, 0x10cf2}, {0x10d00, 0x10d23}, {0x10f00, 0x10f1c},
|
||||
{0x10f30, 0x10f45}, {0x11003, 0x11037}, {0x11083, 0x110af}, {0x110d0, 0x110e8},
|
||||
{0x11103, 0x11126}, {0x11150, 0x11172}, {0x11183, 0x111b2}, {0x111c1, 0x111c4},
|
||||
{0x11200, 0x11211}, {0x11213, 0x1122b}, {0x11280, 0x11286}, {0x1128a, 0x1128d},
|
||||
{0x1128f, 0x1129d}, {0x1129f, 0x112a8}, {0x112b0, 0x112de}, {0x11305, 0x1130c},
|
||||
{0x11313, 0x11328}, {0x1132a, 0x11330}, {0x11335, 0x11339}, {0x1135d, 0x11361},
|
||||
{0x11400, 0x11434}, {0x11447, 0x1144a}, {0x11480, 0x114af}, {0x11580, 0x115ae},
|
||||
{0x115d8, 0x115db}, {0x11600, 0x1162f}, {0x11680, 0x116aa}, {0x11700, 0x1171a},
|
||||
{0x11800, 0x1182b}, {0x118a0, 0x118df}, {0x11a0b, 0x11a32}, {0x11a5c, 0x11a83},
|
||||
{0x11a86, 0x11a89}, {0x11ac0, 0x11af8}, {0x11c00, 0x11c08}, {0x11c0a, 0x11c2e},
|
||||
{0x11c72, 0x11c8f}, {0x11d00, 0x11d06}, {0x11d0b, 0x11d30}, {0x11d60, 0x11d65},
|
||||
{0x11d6a, 0x11d89}, {0x11ee0, 0x11ef2}, {0x12000, 0x12399}, {0x12480, 0x12543},
|
||||
{0x13000, 0x1342e}, {0x14400, 0x14646}, {0x16800, 0x16a38}, {0x16a40, 0x16a5e},
|
||||
{0x16ad0, 0x16aed}, {0x16b00, 0x16b2f}, {0x16b40, 0x16b43}, {0x16b63, 0x16b77},
|
||||
{0x16b7d, 0x16b8f}, {0x16f00, 0x16f44}, {0x16f93, 0x16f9f}, {0x17000, 0x187ec},
|
||||
{0x18800, 0x18af2}, {0x1bc00, 0x1bc6a}, {0x1bc70, 0x1bc7c}, {0x1bc80, 0x1bc88},
|
||||
{0x1bc90, 0x1bc99}, {0x1d400, 0x1d454}, {0x1d456, 0x1d49c}, {0x1d4a9, 0x1d4ac},
|
||||
{0x1d4ae, 0x1d4b9}, {0x1d4bd, 0x1d4c3}, {0x1d4c5, 0x1d505}, {0x1d507, 0x1d50a},
|
||||
{0x1d50d, 0x1d514}, {0x1d516, 0x1d51c}, {0x1d51e, 0x1d539}, {0x1d53b, 0x1d53e},
|
||||
{0x1d540, 0x1d544}, {0x1d54a, 0x1d550}, {0x1d552, 0x1d6a5}, {0x1d6a8, 0x1d6c0},
|
||||
{0x1d6c2, 0x1d6da}, {0x1d6dc, 0x1d6fa}, {0x1d6fc, 0x1d714}, {0x1d716, 0x1d734},
|
||||
{0x1d736, 0x1d74e}, {0x1d750, 0x1d76e}, {0x1d770, 0x1d788}, {0x1d78a, 0x1d7a8},
|
||||
{0x1d7aa, 0x1d7c2}, {0x1d7c4, 0x1d7cb}, {0x1e800, 0x1e8c4}, {0x1e900, 0x1e943},
|
||||
{0x1ee00, 0x1ee03}, {0x1ee05, 0x1ee1f}, {0x1ee29, 0x1ee32}, {0x1ee34, 0x1ee37},
|
||||
{0x1ee4d, 0x1ee4f}, {0x1ee67, 0x1ee6a}, {0x1ee6c, 0x1ee72}, {0x1ee74, 0x1ee77},
|
||||
{0x1ee79, 0x1ee7c}, {0x1ee80, 0x1ee89}, {0x1ee8b, 0x1ee9b}, {0x1eea1, 0x1eea3},
|
||||
{0x1eea5, 0x1eea9}, {0x1eeab, 0x1eebb}, {0x20000, 0x2a6d6}, {0x2a700, 0x2b734},
|
||||
{0x2b740, 0x2b81d}, {0x2b820, 0x2cea1}, {0x2f800, 0x2fa1d}
|
||||
{0x16b7d, 0x16b8f}, {0x16e40, 0x16e7f}, {0x16f00, 0x16f44}, {0x16f93, 0x16f9f},
|
||||
{0x17000, 0x187f1}, {0x18800, 0x18af2}, {0x1b000, 0x1b11e}, {0x1b170, 0x1b2fb},
|
||||
{0x1bc00, 0x1bc6a}, {0x1bc70, 0x1bc7c}, {0x1bc80, 0x1bc88}, {0x1bc90, 0x1bc99},
|
||||
{0x1d400, 0x1d454}, {0x1d456, 0x1d49c}, {0x1d4a9, 0x1d4ac}, {0x1d4ae, 0x1d4b9},
|
||||
{0x1d4bd, 0x1d4c3}, {0x1d4c5, 0x1d505}, {0x1d507, 0x1d50a}, {0x1d50d, 0x1d514},
|
||||
{0x1d516, 0x1d51c}, {0x1d51e, 0x1d539}, {0x1d53b, 0x1d53e}, {0x1d540, 0x1d544},
|
||||
{0x1d54a, 0x1d550}, {0x1d552, 0x1d6a5}, {0x1d6a8, 0x1d6c0}, {0x1d6c2, 0x1d6da},
|
||||
{0x1d6dc, 0x1d6fa}, {0x1d6fc, 0x1d714}, {0x1d716, 0x1d734}, {0x1d736, 0x1d74e},
|
||||
{0x1d750, 0x1d76e}, {0x1d770, 0x1d788}, {0x1d78a, 0x1d7a8}, {0x1d7aa, 0x1d7c2},
|
||||
{0x1d7c4, 0x1d7cb}, {0x1e800, 0x1e8c4}, {0x1e900, 0x1e943}, {0x1ee00, 0x1ee03},
|
||||
{0x1ee05, 0x1ee1f}, {0x1ee29, 0x1ee32}, {0x1ee34, 0x1ee37}, {0x1ee4d, 0x1ee4f},
|
||||
{0x1ee67, 0x1ee6a}, {0x1ee6c, 0x1ee72}, {0x1ee74, 0x1ee77}, {0x1ee79, 0x1ee7c},
|
||||
{0x1ee80, 0x1ee89}, {0x1ee8b, 0x1ee9b}, {0x1eea1, 0x1eea3}, {0x1eea5, 0x1eea9},
|
||||
{0x1eeab, 0x1eebb}, {0x20000, 0x2a6d6}, {0x2a700, 0x2b734}, {0x2b740, 0x2b81d},
|
||||
{0x2b820, 0x2cea1}, {0x2ceb0, 0x2ebe0}, {0x2f800, 0x2fa1d}
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -250,28 +251,30 @@ static const chr alphaCharTable[] = {
|
||||
0x38c, 0x559, 0x66e, 0x66f, 0x6d5, 0x6e5, 0x6e6, 0x6ee, 0x6ef,
|
||||
0x6ff, 0x710, 0x7b1, 0x7f4, 0x7f5, 0x7fa, 0x81a, 0x824, 0x828,
|
||||
0x93d, 0x950, 0x98f, 0x990, 0x9b2, 0x9bd, 0x9ce, 0x9dc, 0x9dd,
|
||||
0x9f0, 0x9f1, 0xa0f, 0xa10, 0xa32, 0xa33, 0xa35, 0xa36, 0xa38,
|
||||
0xa39, 0xa5e, 0xab2, 0xab3, 0xabd, 0xad0, 0xae0, 0xae1, 0xaf9,
|
||||
0xb0f, 0xb10, 0xb32, 0xb33, 0xb3d, 0xb5c, 0xb5d, 0xb71, 0xb83,
|
||||
0xb99, 0xb9a, 0xb9c, 0xb9e, 0xb9f, 0xba3, 0xba4, 0xbd0, 0xc3d,
|
||||
0xc60, 0xc61, 0xc80, 0xcbd, 0xcde, 0xce0, 0xce1, 0xcf1, 0xcf2,
|
||||
0xd3d, 0xd4e, 0xdbd, 0xe32, 0xe33, 0xe81, 0xe82, 0xe84, 0xe87,
|
||||
0xe88, 0xe8a, 0xe8d, 0xea5, 0xea7, 0xeaa, 0xeab, 0xeb2, 0xeb3,
|
||||
0xebd, 0xec6, 0xf00, 0x103f, 0x1061, 0x1065, 0x1066, 0x108e, 0x10c7,
|
||||
0x10cd, 0x1258, 0x12c0, 0x17d7, 0x17dc, 0x18aa, 0x1aa7, 0x1bae, 0x1baf,
|
||||
0x1cf5, 0x1cf6, 0x1f59, 0x1f5b, 0x1f5d, 0x1fbe, 0x2071, 0x207f, 0x2102,
|
||||
0x2107, 0x2115, 0x2124, 0x2126, 0x2128, 0x214e, 0x2183, 0x2184, 0x2cf2,
|
||||
0x2cf3, 0x2d27, 0x2d2d, 0x2d6f, 0x2e2f, 0x3005, 0x3006, 0x303b, 0x303c,
|
||||
0xa62a, 0xa62b, 0xa8fb, 0xa8fd, 0xa9cf, 0xaa7a, 0xaab1, 0xaab5, 0xaab6,
|
||||
0xaac0, 0xaac2, 0xfb1d, 0xfb3e, 0xfb40, 0xfb41, 0xfb43, 0xfb44
|
||||
#if TCL_UTF_MAX > 4
|
||||
0x9f0, 0x9f1, 0x9fc, 0xa0f, 0xa10, 0xa32, 0xa33, 0xa35, 0xa36,
|
||||
0xa38, 0xa39, 0xa5e, 0xab2, 0xab3, 0xabd, 0xad0, 0xae0, 0xae1,
|
||||
0xaf9, 0xb0f, 0xb10, 0xb32, 0xb33, 0xb3d, 0xb5c, 0xb5d, 0xb71,
|
||||
0xb83, 0xb99, 0xb9a, 0xb9c, 0xb9e, 0xb9f, 0xba3, 0xba4, 0xbd0,
|
||||
0xc3d, 0xc60, 0xc61, 0xc80, 0xcbd, 0xcde, 0xce0, 0xce1, 0xcf1,
|
||||
0xcf2, 0xd3d, 0xd4e, 0xdbd, 0xe32, 0xe33, 0xe81, 0xe82, 0xe84,
|
||||
0xe87, 0xe88, 0xe8a, 0xe8d, 0xea5, 0xea7, 0xeaa, 0xeab, 0xeb2,
|
||||
0xeb3, 0xebd, 0xec6, 0xf00, 0x103f, 0x1061, 0x1065, 0x1066, 0x108e,
|
||||
0x10c7, 0x10cd, 0x1258, 0x12c0, 0x17d7, 0x17dc, 0x18aa, 0x1aa7, 0x1bae,
|
||||
0x1baf, 0x1cf5, 0x1cf6, 0x1f59, 0x1f5b, 0x1f5d, 0x1fbe, 0x2071, 0x207f,
|
||||
0x2102, 0x2107, 0x2115, 0x2124, 0x2126, 0x2128, 0x214e, 0x2183, 0x2184,
|
||||
0x2cf2, 0x2cf3, 0x2d27, 0x2d2d, 0x2d6f, 0x2e2f, 0x3005, 0x3006, 0x303b,
|
||||
0x303c, 0xa62a, 0xa62b, 0xa8fb, 0xa8fd, 0xa8fe, 0xa9cf, 0xaa7a, 0xaab1,
|
||||
0xaab5, 0xaab6, 0xaac0, 0xaac2, 0xfb1d, 0xfb3e, 0xfb40, 0xfb41, 0xfb43,
|
||||
0xfb44
|
||||
#if CHRBITS > 16
|
||||
,0x1003c, 0x1003d, 0x10808, 0x10837, 0x10838, 0x1083c, 0x108f4, 0x108f5, 0x109be,
|
||||
0x109bf, 0x10a00, 0x11176, 0x111da, 0x111dc, 0x11288, 0x1130f, 0x11310, 0x11332,
|
||||
0x11333, 0x1133d, 0x11350, 0x114c4, 0x114c5, 0x114c7, 0x11644, 0x118ff, 0x11c40,
|
||||
0x16f50, 0x16fe0, 0x1b000, 0x1b001, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a5, 0x1d4a6,
|
||||
0x1d4bb, 0x1d546, 0x1ee21, 0x1ee22, 0x1ee24, 0x1ee27, 0x1ee39, 0x1ee3b, 0x1ee42,
|
||||
0x1ee47, 0x1ee49, 0x1ee4b, 0x1ee51, 0x1ee52, 0x1ee54, 0x1ee57, 0x1ee59, 0x1ee5b,
|
||||
0x1ee5d, 0x1ee5f, 0x1ee61, 0x1ee62, 0x1ee64, 0x1ee7e
|
||||
0x109bf, 0x10a00, 0x10f27, 0x11144, 0x11176, 0x111da, 0x111dc, 0x11288, 0x1130f,
|
||||
0x11310, 0x11332, 0x11333, 0x1133d, 0x11350, 0x114c4, 0x114c5, 0x114c7, 0x11644,
|
||||
0x118ff, 0x11a00, 0x11a3a, 0x11a50, 0x11a9d, 0x11c40, 0x11d08, 0x11d09, 0x11d46,
|
||||
0x11d67, 0x11d68, 0x11d98, 0x16f50, 0x16fe0, 0x16fe1, 0x1d49e, 0x1d49f, 0x1d4a2,
|
||||
0x1d4a5, 0x1d4a6, 0x1d4bb, 0x1d546, 0x1ee21, 0x1ee22, 0x1ee24, 0x1ee27, 0x1ee39,
|
||||
0x1ee3b, 0x1ee42, 0x1ee47, 0x1ee49, 0x1ee4b, 0x1ee51, 0x1ee52, 0x1ee54, 0x1ee57,
|
||||
0x1ee59, 0x1ee5b, 0x1ee5d, 0x1ee5f, 0x1ee61, 0x1ee62, 0x1ee64, 0x1ee7e
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -285,7 +288,7 @@ static const crange controlRangeTable[] = {
|
||||
{0x0, 0x1f}, {0x7f, 0x9f}, {0x600, 0x605}, {0x200b, 0x200f},
|
||||
{0x202a, 0x202e}, {0x2060, 0x2064}, {0x2066, 0x206f}, {0xe000, 0xf8ff},
|
||||
{0xfff9, 0xfffb}
|
||||
#if TCL_UTF_MAX > 4
|
||||
#if CHRBITS > 16
|
||||
,{0x1bca0, 0x1bca3}, {0x1d173, 0x1d17a}, {0xe0020, 0xe007f}, {0xf0000, 0xffffd},
|
||||
{0x100000, 0x10fffd}
|
||||
#endif
|
||||
@@ -295,8 +298,8 @@ static const crange controlRangeTable[] = {
|
||||
|
||||
static const chr controlCharTable[] = {
|
||||
0xad, 0x61c, 0x6dd, 0x70f, 0x8e2, 0x180e, 0xfeff
|
||||
#if TCL_UTF_MAX > 4
|
||||
,0x110bd, 0xe0001
|
||||
#if CHRBITS > 16
|
||||
,0x110bd, 0x110cd, 0xe0001
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -317,12 +320,12 @@ static const crange digitRangeTable[] = {
|
||||
{0x1c50, 0x1c59}, {0xa620, 0xa629}, {0xa8d0, 0xa8d9}, {0xa900, 0xa909},
|
||||
{0xa9d0, 0xa9d9}, {0xa9f0, 0xa9f9}, {0xaa50, 0xaa59}, {0xabf0, 0xabf9},
|
||||
{0xff10, 0xff19}
|
||||
#if TCL_UTF_MAX > 4
|
||||
,{0x104a0, 0x104a9}, {0x11066, 0x1106f}, {0x110f0, 0x110f9}, {0x11136, 0x1113f},
|
||||
{0x111d0, 0x111d9}, {0x112f0, 0x112f9}, {0x11450, 0x11459}, {0x114d0, 0x114d9},
|
||||
{0x11650, 0x11659}, {0x116c0, 0x116c9}, {0x11730, 0x11739}, {0x118e0, 0x118e9},
|
||||
{0x11c50, 0x11c59}, {0x16a60, 0x16a69}, {0x16b50, 0x16b59}, {0x1d7ce, 0x1d7ff},
|
||||
{0x1e950, 0x1e959}
|
||||
#if CHRBITS > 16
|
||||
,{0x104a0, 0x104a9}, {0x10d30, 0x10d39}, {0x11066, 0x1106f}, {0x110f0, 0x110f9},
|
||||
{0x11136, 0x1113f}, {0x111d0, 0x111d9}, {0x112f0, 0x112f9}, {0x11450, 0x11459},
|
||||
{0x114d0, 0x114d9}, {0x11650, 0x11659}, {0x116c0, 0x116c9}, {0x11730, 0x11739},
|
||||
{0x118e0, 0x118e9}, {0x11c50, 0x11c59}, {0x11d50, 0x11d59}, {0x11da0, 0x11da9},
|
||||
{0x16a60, 0x16a69}, {0x16b50, 0x16b59}, {0x1d7ce, 0x1d7ff}, {0x1e950, 0x1e959}
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -345,18 +348,20 @@ static const crange punctRangeTable[] = {
|
||||
{0x1b5a, 0x1b60}, {0x1bfc, 0x1bff}, {0x1c3b, 0x1c3f}, {0x1cc0, 0x1cc7},
|
||||
{0x2010, 0x2027}, {0x2030, 0x2043}, {0x2045, 0x2051}, {0x2053, 0x205e},
|
||||
{0x2308, 0x230b}, {0x2768, 0x2775}, {0x27e6, 0x27ef}, {0x2983, 0x2998},
|
||||
{0x29d8, 0x29db}, {0x2cf9, 0x2cfc}, {0x2e00, 0x2e2e}, {0x2e30, 0x2e44},
|
||||
{0x29d8, 0x29db}, {0x2cf9, 0x2cfc}, {0x2e00, 0x2e2e}, {0x2e30, 0x2e4e},
|
||||
{0x3001, 0x3003}, {0x3008, 0x3011}, {0x3014, 0x301f}, {0xa60d, 0xa60f},
|
||||
{0xa6f2, 0xa6f7}, {0xa874, 0xa877}, {0xa8f8, 0xa8fa}, {0xa9c1, 0xa9cd},
|
||||
{0xaa5c, 0xaa5f}, {0xfe10, 0xfe19}, {0xfe30, 0xfe52}, {0xfe54, 0xfe61},
|
||||
{0xff01, 0xff03}, {0xff05, 0xff0a}, {0xff0c, 0xff0f}, {0xff3b, 0xff3d},
|
||||
{0xff5f, 0xff65}
|
||||
#if TCL_UTF_MAX > 4
|
||||
#if CHRBITS > 16
|
||||
,{0x10100, 0x10102}, {0x10a50, 0x10a58}, {0x10af0, 0x10af6}, {0x10b39, 0x10b3f},
|
||||
{0x10b99, 0x10b9c}, {0x11047, 0x1104d}, {0x110be, 0x110c1}, {0x11140, 0x11143},
|
||||
{0x111c5, 0x111c9}, {0x111dd, 0x111df}, {0x11238, 0x1123d}, {0x1144b, 0x1144f},
|
||||
{0x115c1, 0x115d7}, {0x11641, 0x11643}, {0x11660, 0x1166c}, {0x1173c, 0x1173e},
|
||||
{0x11c41, 0x11c45}, {0x12470, 0x12474}, {0x16b37, 0x16b3b}, {0x1da87, 0x1da8b}
|
||||
{0x10b99, 0x10b9c}, {0x10f55, 0x10f59}, {0x11047, 0x1104d}, {0x110be, 0x110c1},
|
||||
{0x11140, 0x11143}, {0x111c5, 0x111c8}, {0x111dd, 0x111df}, {0x11238, 0x1123d},
|
||||
{0x1144b, 0x1144f}, {0x115c1, 0x115d7}, {0x11641, 0x11643}, {0x11660, 0x1166c},
|
||||
{0x1173c, 0x1173e}, {0x11a3f, 0x11a46}, {0x11a9a, 0x11a9c}, {0x11a9e, 0x11aa2},
|
||||
{0x11c41, 0x11c45}, {0x12470, 0x12474}, {0x16b37, 0x16b3b}, {0x16e97, 0x16e9a},
|
||||
{0x1da87, 0x1da8b}
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -367,18 +372,20 @@ static const chr punctCharTable[] = {
|
||||
0xab, 0xb6, 0xb7, 0xbb, 0xbf, 0x37e, 0x387, 0x589, 0x58a,
|
||||
0x5be, 0x5c0, 0x5c3, 0x5c6, 0x5f3, 0x5f4, 0x609, 0x60a, 0x60c,
|
||||
0x60d, 0x61b, 0x61e, 0x61f, 0x6d4, 0x85e, 0x964, 0x965, 0x970,
|
||||
0xaf0, 0xdf4, 0xe4f, 0xe5a, 0xe5b, 0xf14, 0xf85, 0xfd9, 0xfda,
|
||||
0x10fb, 0x1400, 0x166d, 0x166e, 0x169b, 0x169c, 0x1735, 0x1736, 0x1944,
|
||||
0x1945, 0x1a1e, 0x1a1f, 0x1c7e, 0x1c7f, 0x1cd3, 0x207d, 0x207e, 0x208d,
|
||||
0x208e, 0x2329, 0x232a, 0x27c5, 0x27c6, 0x29fc, 0x29fd, 0x2cfe, 0x2cff,
|
||||
0x2d70, 0x3030, 0x303d, 0x30a0, 0x30fb, 0xa4fe, 0xa4ff, 0xa673, 0xa67e,
|
||||
0xa8ce, 0xa8cf, 0xa8fc, 0xa92e, 0xa92f, 0xa95f, 0xa9de, 0xa9df, 0xaade,
|
||||
0xaadf, 0xaaf0, 0xaaf1, 0xabeb, 0xfd3e, 0xfd3f, 0xfe63, 0xfe68, 0xfe6a,
|
||||
0xfe6b, 0xff1a, 0xff1b, 0xff1f, 0xff20, 0xff3f, 0xff5b, 0xff5d
|
||||
#if TCL_UTF_MAX > 4
|
||||
0x9fd, 0xa76, 0xaf0, 0xc84, 0xdf4, 0xe4f, 0xe5a, 0xe5b, 0xf14,
|
||||
0xf85, 0xfd9, 0xfda, 0x10fb, 0x1400, 0x166d, 0x166e, 0x169b, 0x169c,
|
||||
0x1735, 0x1736, 0x1944, 0x1945, 0x1a1e, 0x1a1f, 0x1c7e, 0x1c7f, 0x1cd3,
|
||||
0x207d, 0x207e, 0x208d, 0x208e, 0x2329, 0x232a, 0x27c5, 0x27c6, 0x29fc,
|
||||
0x29fd, 0x2cfe, 0x2cff, 0x2d70, 0x3030, 0x303d, 0x30a0, 0x30fb, 0xa4fe,
|
||||
0xa4ff, 0xa673, 0xa67e, 0xa8ce, 0xa8cf, 0xa8fc, 0xa92e, 0xa92f, 0xa95f,
|
||||
0xa9de, 0xa9df, 0xaade, 0xaadf, 0xaaf0, 0xaaf1, 0xabeb, 0xfd3e, 0xfd3f,
|
||||
0xfe63, 0xfe68, 0xfe6a, 0xfe6b, 0xff1a, 0xff1b, 0xff1f, 0xff20, 0xff3f,
|
||||
0xff5b, 0xff5d
|
||||
#if CHRBITS > 16
|
||||
,0x1039f, 0x103d0, 0x1056f, 0x10857, 0x1091f, 0x1093f, 0x10a7f, 0x110bb, 0x110bc,
|
||||
0x11174, 0x11175, 0x111cd, 0x111db, 0x112a9, 0x1145b, 0x1145d, 0x114c6, 0x11c70,
|
||||
0x11c71, 0x16a6e, 0x16a6f, 0x16af5, 0x16b44, 0x1bc9f, 0x1e95e, 0x1e95f
|
||||
0x11174, 0x11175, 0x111cd, 0x111db, 0x112a9, 0x1145b, 0x1145d, 0x114c6, 0x1183b,
|
||||
0x11c70, 0x11c71, 0x11ef7, 0x11ef8, 0x16a6e, 0x16a6f, 0x16af5, 0x16b44, 0x1bc9f,
|
||||
0x1e95e, 0x1e95f
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -409,25 +416,25 @@ static const crange lowerRangeTable[] = {
|
||||
{0x61, 0x7a}, {0xdf, 0xf6}, {0xf8, 0xff}, {0x17e, 0x180},
|
||||
{0x199, 0x19b}, {0x1bd, 0x1bf}, {0x233, 0x239}, {0x24f, 0x293},
|
||||
{0x295, 0x2af}, {0x37b, 0x37d}, {0x3ac, 0x3ce}, {0x3d5, 0x3d7},
|
||||
{0x3ef, 0x3f3}, {0x430, 0x45f}, {0x561, 0x587}, {0x13f8, 0x13fd},
|
||||
{0x1c80, 0x1c88}, {0x1d00, 0x1d2b}, {0x1d6b, 0x1d77}, {0x1d79, 0x1d9a},
|
||||
{0x1e95, 0x1e9d}, {0x1eff, 0x1f07}, {0x1f10, 0x1f15}, {0x1f20, 0x1f27},
|
||||
{0x1f30, 0x1f37}, {0x1f40, 0x1f45}, {0x1f50, 0x1f57}, {0x1f60, 0x1f67},
|
||||
{0x1f70, 0x1f7d}, {0x1f80, 0x1f87}, {0x1f90, 0x1f97}, {0x1fa0, 0x1fa7},
|
||||
{0x1fb0, 0x1fb4}, {0x1fc2, 0x1fc4}, {0x1fd0, 0x1fd3}, {0x1fe0, 0x1fe7},
|
||||
{0x1ff2, 0x1ff4}, {0x2146, 0x2149}, {0x2c30, 0x2c5e}, {0x2c76, 0x2c7b},
|
||||
{0x2d00, 0x2d25}, {0xa72f, 0xa731}, {0xa771, 0xa778}, {0xa793, 0xa795},
|
||||
{0xab30, 0xab5a}, {0xab60, 0xab65}, {0xab70, 0xabbf}, {0xfb00, 0xfb06},
|
||||
{0xfb13, 0xfb17}, {0xff41, 0xff5a}
|
||||
#if TCL_UTF_MAX > 4
|
||||
{0x3ef, 0x3f3}, {0x430, 0x45f}, {0x560, 0x588}, {0x10d0, 0x10fa},
|
||||
{0x10fd, 0x10ff}, {0x13f8, 0x13fd}, {0x1c80, 0x1c88}, {0x1d00, 0x1d2b},
|
||||
{0x1d6b, 0x1d77}, {0x1d79, 0x1d9a}, {0x1e95, 0x1e9d}, {0x1eff, 0x1f07},
|
||||
{0x1f10, 0x1f15}, {0x1f20, 0x1f27}, {0x1f30, 0x1f37}, {0x1f40, 0x1f45},
|
||||
{0x1f50, 0x1f57}, {0x1f60, 0x1f67}, {0x1f70, 0x1f7d}, {0x1f80, 0x1f87},
|
||||
{0x1f90, 0x1f97}, {0x1fa0, 0x1fa7}, {0x1fb0, 0x1fb4}, {0x1fc2, 0x1fc4},
|
||||
{0x1fd0, 0x1fd3}, {0x1fe0, 0x1fe7}, {0x1ff2, 0x1ff4}, {0x2146, 0x2149},
|
||||
{0x2c30, 0x2c5e}, {0x2c76, 0x2c7b}, {0x2d00, 0x2d25}, {0xa72f, 0xa731},
|
||||
{0xa771, 0xa778}, {0xa793, 0xa795}, {0xab30, 0xab5a}, {0xab60, 0xab65},
|
||||
{0xab70, 0xabbf}, {0xfb00, 0xfb06}, {0xfb13, 0xfb17}, {0xff41, 0xff5a}
|
||||
#if CHRBITS > 16
|
||||
,{0x10428, 0x1044f}, {0x104d8, 0x104fb}, {0x10cc0, 0x10cf2}, {0x118c0, 0x118df},
|
||||
{0x1d41a, 0x1d433}, {0x1d44e, 0x1d454}, {0x1d456, 0x1d467}, {0x1d482, 0x1d49b},
|
||||
{0x1d4b6, 0x1d4b9}, {0x1d4bd, 0x1d4c3}, {0x1d4c5, 0x1d4cf}, {0x1d4ea, 0x1d503},
|
||||
{0x1d51e, 0x1d537}, {0x1d552, 0x1d56b}, {0x1d586, 0x1d59f}, {0x1d5ba, 0x1d5d3},
|
||||
{0x1d5ee, 0x1d607}, {0x1d622, 0x1d63b}, {0x1d656, 0x1d66f}, {0x1d68a, 0x1d6a5},
|
||||
{0x1d6c2, 0x1d6da}, {0x1d6dc, 0x1d6e1}, {0x1d6fc, 0x1d714}, {0x1d716, 0x1d71b},
|
||||
{0x1d736, 0x1d74e}, {0x1d750, 0x1d755}, {0x1d770, 0x1d788}, {0x1d78a, 0x1d78f},
|
||||
{0x1d7aa, 0x1d7c2}, {0x1d7c4, 0x1d7c9}, {0x1e922, 0x1e943}
|
||||
{0x16e60, 0x16e7f}, {0x1d41a, 0x1d433}, {0x1d44e, 0x1d454}, {0x1d456, 0x1d467},
|
||||
{0x1d482, 0x1d49b}, {0x1d4b6, 0x1d4b9}, {0x1d4bd, 0x1d4c3}, {0x1d4c5, 0x1d4cf},
|
||||
{0x1d4ea, 0x1d503}, {0x1d51e, 0x1d537}, {0x1d552, 0x1d56b}, {0x1d586, 0x1d59f},
|
||||
{0x1d5ba, 0x1d5d3}, {0x1d5ee, 0x1d607}, {0x1d622, 0x1d63b}, {0x1d656, 0x1d66f},
|
||||
{0x1d68a, 0x1d6a5}, {0x1d6c2, 0x1d6da}, {0x1d6dc, 0x1d6e1}, {0x1d6fc, 0x1d714},
|
||||
{0x1d716, 0x1d71b}, {0x1d736, 0x1d74e}, {0x1d750, 0x1d755}, {0x1d770, 0x1d788},
|
||||
{0x1d78a, 0x1d78f}, {0x1d7aa, 0x1d7c2}, {0x1d7c4, 0x1d7c9}, {0x1e922, 0x1e943}
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -497,8 +504,8 @@ static const chr lowerCharTable[] = {
|
||||
0xa763, 0xa765, 0xa767, 0xa769, 0xa76b, 0xa76d, 0xa76f, 0xa77a, 0xa77c,
|
||||
0xa77f, 0xa781, 0xa783, 0xa785, 0xa787, 0xa78c, 0xa78e, 0xa791, 0xa797,
|
||||
0xa799, 0xa79b, 0xa79d, 0xa79f, 0xa7a1, 0xa7a3, 0xa7a5, 0xa7a7, 0xa7a9,
|
||||
0xa7b5, 0xa7b7, 0xa7fa
|
||||
#if TCL_UTF_MAX > 4
|
||||
0xa7af, 0xa7b5, 0xa7b7, 0xa7b9, 0xa7fa
|
||||
#if CHRBITS > 16
|
||||
,0x1d4bb, 0x1d7cb
|
||||
#endif
|
||||
};
|
||||
@@ -514,20 +521,22 @@ static const crange upperRangeTable[] = {
|
||||
{0x18e, 0x191}, {0x196, 0x198}, {0x1b1, 0x1b3}, {0x1f6, 0x1f8},
|
||||
{0x243, 0x246}, {0x388, 0x38a}, {0x391, 0x3a1}, {0x3a3, 0x3ab},
|
||||
{0x3d2, 0x3d4}, {0x3fd, 0x42f}, {0x531, 0x556}, {0x10a0, 0x10c5},
|
||||
{0x13a0, 0x13f5}, {0x1f08, 0x1f0f}, {0x1f18, 0x1f1d}, {0x1f28, 0x1f2f},
|
||||
{0x1f38, 0x1f3f}, {0x1f48, 0x1f4d}, {0x1f68, 0x1f6f}, {0x1fb8, 0x1fbb},
|
||||
{0x1fc8, 0x1fcb}, {0x1fd8, 0x1fdb}, {0x1fe8, 0x1fec}, {0x1ff8, 0x1ffb},
|
||||
{0x210b, 0x210d}, {0x2110, 0x2112}, {0x2119, 0x211d}, {0x212a, 0x212d},
|
||||
{0x2130, 0x2133}, {0x2c00, 0x2c2e}, {0x2c62, 0x2c64}, {0x2c6d, 0x2c70},
|
||||
{0x2c7e, 0x2c80}, {0xa7aa, 0xa7ae}, {0xa7b0, 0xa7b4}, {0xff21, 0xff3a}
|
||||
#if TCL_UTF_MAX > 4
|
||||
{0x13a0, 0x13f5}, {0x1c90, 0x1cba}, {0x1cbd, 0x1cbf}, {0x1f08, 0x1f0f},
|
||||
{0x1f18, 0x1f1d}, {0x1f28, 0x1f2f}, {0x1f38, 0x1f3f}, {0x1f48, 0x1f4d},
|
||||
{0x1f68, 0x1f6f}, {0x1fb8, 0x1fbb}, {0x1fc8, 0x1fcb}, {0x1fd8, 0x1fdb},
|
||||
{0x1fe8, 0x1fec}, {0x1ff8, 0x1ffb}, {0x210b, 0x210d}, {0x2110, 0x2112},
|
||||
{0x2119, 0x211d}, {0x212a, 0x212d}, {0x2130, 0x2133}, {0x2c00, 0x2c2e},
|
||||
{0x2c62, 0x2c64}, {0x2c6d, 0x2c70}, {0x2c7e, 0x2c80}, {0xa7aa, 0xa7ae},
|
||||
{0xa7b0, 0xa7b4}, {0xff21, 0xff3a}
|
||||
#if CHRBITS > 16
|
||||
,{0x10400, 0x10427}, {0x104b0, 0x104d3}, {0x10c80, 0x10cb2}, {0x118a0, 0x118bf},
|
||||
{0x1d400, 0x1d419}, {0x1d434, 0x1d44d}, {0x1d468, 0x1d481}, {0x1d4a9, 0x1d4ac},
|
||||
{0x1d4ae, 0x1d4b5}, {0x1d4d0, 0x1d4e9}, {0x1d507, 0x1d50a}, {0x1d50d, 0x1d514},
|
||||
{0x1d516, 0x1d51c}, {0x1d53b, 0x1d53e}, {0x1d540, 0x1d544}, {0x1d54a, 0x1d550},
|
||||
{0x1d56c, 0x1d585}, {0x1d5a0, 0x1d5b9}, {0x1d5d4, 0x1d5ed}, {0x1d608, 0x1d621},
|
||||
{0x1d63c, 0x1d655}, {0x1d670, 0x1d689}, {0x1d6a8, 0x1d6c0}, {0x1d6e2, 0x1d6fa},
|
||||
{0x1d71c, 0x1d734}, {0x1d756, 0x1d76e}, {0x1d790, 0x1d7a8}, {0x1e900, 0x1e921}
|
||||
{0x16e40, 0x16e5f}, {0x1d400, 0x1d419}, {0x1d434, 0x1d44d}, {0x1d468, 0x1d481},
|
||||
{0x1d4a9, 0x1d4ac}, {0x1d4ae, 0x1d4b5}, {0x1d4d0, 0x1d4e9}, {0x1d507, 0x1d50a},
|
||||
{0x1d50d, 0x1d514}, {0x1d516, 0x1d51c}, {0x1d53b, 0x1d53e}, {0x1d540, 0x1d544},
|
||||
{0x1d54a, 0x1d550}, {0x1d56c, 0x1d585}, {0x1d5a0, 0x1d5b9}, {0x1d5d4, 0x1d5ed},
|
||||
{0x1d608, 0x1d621}, {0x1d63c, 0x1d655}, {0x1d670, 0x1d689}, {0x1d6a8, 0x1d6c0},
|
||||
{0x1d6e2, 0x1d6fa}, {0x1d71c, 0x1d734}, {0x1d756, 0x1d76e}, {0x1d790, 0x1d7a8},
|
||||
{0x1e900, 0x1e921}
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -596,8 +605,9 @@ static const chr upperCharTable[] = {
|
||||
0xa756, 0xa758, 0xa75a, 0xa75c, 0xa75e, 0xa760, 0xa762, 0xa764, 0xa766,
|
||||
0xa768, 0xa76a, 0xa76c, 0xa76e, 0xa779, 0xa77b, 0xa77d, 0xa77e, 0xa780,
|
||||
0xa782, 0xa784, 0xa786, 0xa78b, 0xa78d, 0xa790, 0xa792, 0xa796, 0xa798,
|
||||
0xa79a, 0xa79c, 0xa79e, 0xa7a0, 0xa7a2, 0xa7a4, 0xa7a6, 0xa7a8, 0xa7b6
|
||||
#if TCL_UTF_MAX > 4
|
||||
0xa79a, 0xa79c, 0xa79e, 0xa7a0, 0xa7a2, 0xa7a4, 0xa7a6, 0xa7a8, 0xa7b6,
|
||||
0xa7b8
|
||||
#if CHRBITS > 16
|
||||
,0x1d49c, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d504, 0x1d505, 0x1d538,
|
||||
0x1d539, 0x1d546, 0x1d7ca
|
||||
#endif
|
||||
@@ -612,166 +622,169 @@ static const chr upperCharTable[] = {
|
||||
static const crange graphRangeTable[] = {
|
||||
{0x21, 0x7e}, {0xa1, 0xac}, {0xae, 0x377}, {0x37a, 0x37f},
|
||||
{0x384, 0x38a}, {0x38e, 0x3a1}, {0x3a3, 0x52f}, {0x531, 0x556},
|
||||
{0x559, 0x55f}, {0x561, 0x587}, {0x58d, 0x58f}, {0x591, 0x5c7},
|
||||
{0x5d0, 0x5ea}, {0x5f0, 0x5f4}, {0x606, 0x61b}, {0x61e, 0x6dc},
|
||||
{0x6de, 0x70d}, {0x710, 0x74a}, {0x74d, 0x7b1}, {0x7c0, 0x7fa},
|
||||
{0x800, 0x82d}, {0x830, 0x83e}, {0x840, 0x85b}, {0x8a0, 0x8b4},
|
||||
{0x8b6, 0x8bd}, {0x8d4, 0x8e1}, {0x8e3, 0x983}, {0x985, 0x98c},
|
||||
{0x559, 0x58a}, {0x58d, 0x58f}, {0x591, 0x5c7}, {0x5d0, 0x5ea},
|
||||
{0x5ef, 0x5f4}, {0x606, 0x61b}, {0x61e, 0x6dc}, {0x6de, 0x70d},
|
||||
{0x710, 0x74a}, {0x74d, 0x7b1}, {0x7c0, 0x7fa}, {0x7fd, 0x82d},
|
||||
{0x830, 0x83e}, {0x840, 0x85b}, {0x860, 0x86a}, {0x8a0, 0x8b4},
|
||||
{0x8b6, 0x8bd}, {0x8d3, 0x8e1}, {0x8e3, 0x983}, {0x985, 0x98c},
|
||||
{0x993, 0x9a8}, {0x9aa, 0x9b0}, {0x9b6, 0x9b9}, {0x9bc, 0x9c4},
|
||||
{0x9cb, 0x9ce}, {0x9df, 0x9e3}, {0x9e6, 0x9fb}, {0xa01, 0xa03},
|
||||
{0x9cb, 0x9ce}, {0x9df, 0x9e3}, {0x9e6, 0x9fe}, {0xa01, 0xa03},
|
||||
{0xa05, 0xa0a}, {0xa13, 0xa28}, {0xa2a, 0xa30}, {0xa3e, 0xa42},
|
||||
{0xa4b, 0xa4d}, {0xa59, 0xa5c}, {0xa66, 0xa75}, {0xa81, 0xa83},
|
||||
{0xa4b, 0xa4d}, {0xa59, 0xa5c}, {0xa66, 0xa76}, {0xa81, 0xa83},
|
||||
{0xa85, 0xa8d}, {0xa8f, 0xa91}, {0xa93, 0xaa8}, {0xaaa, 0xab0},
|
||||
{0xab5, 0xab9}, {0xabc, 0xac5}, {0xac7, 0xac9}, {0xacb, 0xacd},
|
||||
{0xae0, 0xae3}, {0xae6, 0xaf1}, {0xb01, 0xb03}, {0xb05, 0xb0c},
|
||||
{0xb13, 0xb28}, {0xb2a, 0xb30}, {0xb35, 0xb39}, {0xb3c, 0xb44},
|
||||
{0xb4b, 0xb4d}, {0xb5f, 0xb63}, {0xb66, 0xb77}, {0xb85, 0xb8a},
|
||||
{0xb8e, 0xb90}, {0xb92, 0xb95}, {0xba8, 0xbaa}, {0xbae, 0xbb9},
|
||||
{0xbbe, 0xbc2}, {0xbc6, 0xbc8}, {0xbca, 0xbcd}, {0xbe6, 0xbfa},
|
||||
{0xc00, 0xc03}, {0xc05, 0xc0c}, {0xc0e, 0xc10}, {0xc12, 0xc28},
|
||||
{0xae0, 0xae3}, {0xae6, 0xaf1}, {0xaf9, 0xaff}, {0xb01, 0xb03},
|
||||
{0xb05, 0xb0c}, {0xb13, 0xb28}, {0xb2a, 0xb30}, {0xb35, 0xb39},
|
||||
{0xb3c, 0xb44}, {0xb4b, 0xb4d}, {0xb5f, 0xb63}, {0xb66, 0xb77},
|
||||
{0xb85, 0xb8a}, {0xb8e, 0xb90}, {0xb92, 0xb95}, {0xba8, 0xbaa},
|
||||
{0xbae, 0xbb9}, {0xbbe, 0xbc2}, {0xbc6, 0xbc8}, {0xbca, 0xbcd},
|
||||
{0xbe6, 0xbfa}, {0xc00, 0xc0c}, {0xc0e, 0xc10}, {0xc12, 0xc28},
|
||||
{0xc2a, 0xc39}, {0xc3d, 0xc44}, {0xc46, 0xc48}, {0xc4a, 0xc4d},
|
||||
{0xc58, 0xc5a}, {0xc60, 0xc63}, {0xc66, 0xc6f}, {0xc78, 0xc83},
|
||||
{0xc85, 0xc8c}, {0xc8e, 0xc90}, {0xc92, 0xca8}, {0xcaa, 0xcb3},
|
||||
{0xcb5, 0xcb9}, {0xcbc, 0xcc4}, {0xcc6, 0xcc8}, {0xcca, 0xccd},
|
||||
{0xce0, 0xce3}, {0xce6, 0xcef}, {0xd01, 0xd03}, {0xd05, 0xd0c},
|
||||
{0xd0e, 0xd10}, {0xd12, 0xd3a}, {0xd3d, 0xd44}, {0xd46, 0xd48},
|
||||
{0xd4a, 0xd4f}, {0xd54, 0xd63}, {0xd66, 0xd7f}, {0xd85, 0xd96},
|
||||
{0xd9a, 0xdb1}, {0xdb3, 0xdbb}, {0xdc0, 0xdc6}, {0xdcf, 0xdd4},
|
||||
{0xdd8, 0xddf}, {0xde6, 0xdef}, {0xdf2, 0xdf4}, {0xe01, 0xe3a},
|
||||
{0xe3f, 0xe5b}, {0xe94, 0xe97}, {0xe99, 0xe9f}, {0xea1, 0xea3},
|
||||
{0xead, 0xeb9}, {0xebb, 0xebd}, {0xec0, 0xec4}, {0xec8, 0xecd},
|
||||
{0xed0, 0xed9}, {0xedc, 0xedf}, {0xf00, 0xf47}, {0xf49, 0xf6c},
|
||||
{0xf71, 0xf97}, {0xf99, 0xfbc}, {0xfbe, 0xfcc}, {0xfce, 0xfda},
|
||||
{0x1000, 0x10c5}, {0x10d0, 0x1248}, {0x124a, 0x124d}, {0x1250, 0x1256},
|
||||
{0x125a, 0x125d}, {0x1260, 0x1288}, {0x128a, 0x128d}, {0x1290, 0x12b0},
|
||||
{0x12b2, 0x12b5}, {0x12b8, 0x12be}, {0x12c2, 0x12c5}, {0x12c8, 0x12d6},
|
||||
{0x12d8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135a}, {0x135d, 0x137c},
|
||||
{0x1380, 0x1399}, {0x13a0, 0x13f5}, {0x13f8, 0x13fd}, {0x1400, 0x167f},
|
||||
{0x1681, 0x169c}, {0x16a0, 0x16f8}, {0x1700, 0x170c}, {0x170e, 0x1714},
|
||||
{0x1720, 0x1736}, {0x1740, 0x1753}, {0x1760, 0x176c}, {0x176e, 0x1770},
|
||||
{0x1780, 0x17dd}, {0x17e0, 0x17e9}, {0x17f0, 0x17f9}, {0x1800, 0x180d},
|
||||
{0x1810, 0x1819}, {0x1820, 0x1877}, {0x1880, 0x18aa}, {0x18b0, 0x18f5},
|
||||
{0x1900, 0x191e}, {0x1920, 0x192b}, {0x1930, 0x193b}, {0x1944, 0x196d},
|
||||
{0x1970, 0x1974}, {0x1980, 0x19ab}, {0x19b0, 0x19c9}, {0x19d0, 0x19da},
|
||||
{0x19de, 0x1a1b}, {0x1a1e, 0x1a5e}, {0x1a60, 0x1a7c}, {0x1a7f, 0x1a89},
|
||||
{0x1a90, 0x1a99}, {0x1aa0, 0x1aad}, {0x1ab0, 0x1abe}, {0x1b00, 0x1b4b},
|
||||
{0x1b50, 0x1b7c}, {0x1b80, 0x1bf3}, {0x1bfc, 0x1c37}, {0x1c3b, 0x1c49},
|
||||
{0x1c4d, 0x1c88}, {0x1cc0, 0x1cc7}, {0x1cd0, 0x1cf6}, {0x1d00, 0x1df5},
|
||||
{0x1dfb, 0x1f15}, {0x1f18, 0x1f1d}, {0x1f20, 0x1f45}, {0x1f48, 0x1f4d},
|
||||
{0x1f50, 0x1f57}, {0x1f5f, 0x1f7d}, {0x1f80, 0x1fb4}, {0x1fb6, 0x1fc4},
|
||||
{0x1fc6, 0x1fd3}, {0x1fd6, 0x1fdb}, {0x1fdd, 0x1fef}, {0x1ff2, 0x1ff4},
|
||||
{0x1ff6, 0x1ffe}, {0x2010, 0x2027}, {0x2030, 0x205e}, {0x2074, 0x208e},
|
||||
{0x2090, 0x209c}, {0x20a0, 0x20be}, {0x20d0, 0x20f0}, {0x2100, 0x218b},
|
||||
{0x2190, 0x23fe}, {0x2400, 0x2426}, {0x2440, 0x244a}, {0x2460, 0x2b73},
|
||||
{0x2b76, 0x2b95}, {0x2b98, 0x2bb9}, {0x2bbd, 0x2bc8}, {0x2bca, 0x2bd1},
|
||||
{0x2bec, 0x2bef}, {0x2c00, 0x2c2e}, {0x2c30, 0x2c5e}, {0x2c60, 0x2cf3},
|
||||
{0xc58, 0xc5a}, {0xc60, 0xc63}, {0xc66, 0xc6f}, {0xc78, 0xc8c},
|
||||
{0xc8e, 0xc90}, {0xc92, 0xca8}, {0xcaa, 0xcb3}, {0xcb5, 0xcb9},
|
||||
{0xcbc, 0xcc4}, {0xcc6, 0xcc8}, {0xcca, 0xccd}, {0xce0, 0xce3},
|
||||
{0xce6, 0xcef}, {0xd00, 0xd03}, {0xd05, 0xd0c}, {0xd0e, 0xd10},
|
||||
{0xd12, 0xd44}, {0xd46, 0xd48}, {0xd4a, 0xd4f}, {0xd54, 0xd63},
|
||||
{0xd66, 0xd7f}, {0xd85, 0xd96}, {0xd9a, 0xdb1}, {0xdb3, 0xdbb},
|
||||
{0xdc0, 0xdc6}, {0xdcf, 0xdd4}, {0xdd8, 0xddf}, {0xde6, 0xdef},
|
||||
{0xdf2, 0xdf4}, {0xe01, 0xe3a}, {0xe3f, 0xe5b}, {0xe94, 0xe97},
|
||||
{0xe99, 0xe9f}, {0xea1, 0xea3}, {0xead, 0xeb9}, {0xebb, 0xebd},
|
||||
{0xec0, 0xec4}, {0xec8, 0xecd}, {0xed0, 0xed9}, {0xedc, 0xedf},
|
||||
{0xf00, 0xf47}, {0xf49, 0xf6c}, {0xf71, 0xf97}, {0xf99, 0xfbc},
|
||||
{0xfbe, 0xfcc}, {0xfce, 0xfda}, {0x1000, 0x10c5}, {0x10d0, 0x1248},
|
||||
{0x124a, 0x124d}, {0x1250, 0x1256}, {0x125a, 0x125d}, {0x1260, 0x1288},
|
||||
{0x128a, 0x128d}, {0x1290, 0x12b0}, {0x12b2, 0x12b5}, {0x12b8, 0x12be},
|
||||
{0x12c2, 0x12c5}, {0x12c8, 0x12d6}, {0x12d8, 0x1310}, {0x1312, 0x1315},
|
||||
{0x1318, 0x135a}, {0x135d, 0x137c}, {0x1380, 0x1399}, {0x13a0, 0x13f5},
|
||||
{0x13f8, 0x13fd}, {0x1400, 0x167f}, {0x1681, 0x169c}, {0x16a0, 0x16f8},
|
||||
{0x1700, 0x170c}, {0x170e, 0x1714}, {0x1720, 0x1736}, {0x1740, 0x1753},
|
||||
{0x1760, 0x176c}, {0x176e, 0x1770}, {0x1780, 0x17dd}, {0x17e0, 0x17e9},
|
||||
{0x17f0, 0x17f9}, {0x1800, 0x180d}, {0x1810, 0x1819}, {0x1820, 0x1878},
|
||||
{0x1880, 0x18aa}, {0x18b0, 0x18f5}, {0x1900, 0x191e}, {0x1920, 0x192b},
|
||||
{0x1930, 0x193b}, {0x1944, 0x196d}, {0x1970, 0x1974}, {0x1980, 0x19ab},
|
||||
{0x19b0, 0x19c9}, {0x19d0, 0x19da}, {0x19de, 0x1a1b}, {0x1a1e, 0x1a5e},
|
||||
{0x1a60, 0x1a7c}, {0x1a7f, 0x1a89}, {0x1a90, 0x1a99}, {0x1aa0, 0x1aad},
|
||||
{0x1ab0, 0x1abe}, {0x1b00, 0x1b4b}, {0x1b50, 0x1b7c}, {0x1b80, 0x1bf3},
|
||||
{0x1bfc, 0x1c37}, {0x1c3b, 0x1c49}, {0x1c4d, 0x1c88}, {0x1c90, 0x1cba},
|
||||
{0x1cbd, 0x1cc7}, {0x1cd0, 0x1cf9}, {0x1d00, 0x1df9}, {0x1dfb, 0x1f15},
|
||||
{0x1f18, 0x1f1d}, {0x1f20, 0x1f45}, {0x1f48, 0x1f4d}, {0x1f50, 0x1f57},
|
||||
{0x1f5f, 0x1f7d}, {0x1f80, 0x1fb4}, {0x1fb6, 0x1fc4}, {0x1fc6, 0x1fd3},
|
||||
{0x1fd6, 0x1fdb}, {0x1fdd, 0x1fef}, {0x1ff2, 0x1ff4}, {0x1ff6, 0x1ffe},
|
||||
{0x2010, 0x2027}, {0x2030, 0x205e}, {0x2074, 0x208e}, {0x2090, 0x209c},
|
||||
{0x20a0, 0x20bf}, {0x20d0, 0x20f0}, {0x2100, 0x218b}, {0x2190, 0x2426},
|
||||
{0x2440, 0x244a}, {0x2460, 0x2b73}, {0x2b76, 0x2b95}, {0x2b98, 0x2bc8},
|
||||
{0x2bca, 0x2bfe}, {0x2c00, 0x2c2e}, {0x2c30, 0x2c5e}, {0x2c60, 0x2cf3},
|
||||
{0x2cf9, 0x2d25}, {0x2d30, 0x2d67}, {0x2d7f, 0x2d96}, {0x2da0, 0x2da6},
|
||||
{0x2da8, 0x2dae}, {0x2db0, 0x2db6}, {0x2db8, 0x2dbe}, {0x2dc0, 0x2dc6},
|
||||
{0x2dc8, 0x2dce}, {0x2dd0, 0x2dd6}, {0x2dd8, 0x2dde}, {0x2de0, 0x2e44},
|
||||
{0x2dc8, 0x2dce}, {0x2dd0, 0x2dd6}, {0x2dd8, 0x2dde}, {0x2de0, 0x2e4e},
|
||||
{0x2e80, 0x2e99}, {0x2e9b, 0x2ef3}, {0x2f00, 0x2fd5}, {0x2ff0, 0x2ffb},
|
||||
{0x3001, 0x303f}, {0x3041, 0x3096}, {0x3099, 0x30ff}, {0x3105, 0x312d},
|
||||
{0x3001, 0x303f}, {0x3041, 0x3096}, {0x3099, 0x30ff}, {0x3105, 0x312f},
|
||||
{0x3131, 0x318e}, {0x3190, 0x31ba}, {0x31c0, 0x31e3}, {0x31f0, 0x321e},
|
||||
{0x3220, 0x32fe}, {0x3300, 0x4db5}, {0x4dc0, 0x9fd5}, {0xa000, 0xa48c},
|
||||
{0xa490, 0xa4c6}, {0xa4d0, 0xa62b}, {0xa640, 0xa6f7}, {0xa700, 0xa7ae},
|
||||
{0xa7b0, 0xa7b7}, {0xa7f7, 0xa82b}, {0xa830, 0xa839}, {0xa840, 0xa877},
|
||||
{0xa880, 0xa8c5}, {0xa8ce, 0xa8d9}, {0xa8e0, 0xa8fd}, {0xa900, 0xa953},
|
||||
{0xa95f, 0xa97c}, {0xa980, 0xa9cd}, {0xa9cf, 0xa9d9}, {0xa9de, 0xa9fe},
|
||||
{0xaa00, 0xaa36}, {0xaa40, 0xaa4d}, {0xaa50, 0xaa59}, {0xaa5c, 0xaac2},
|
||||
{0xaadb, 0xaaf6}, {0xab01, 0xab06}, {0xab09, 0xab0e}, {0xab11, 0xab16},
|
||||
{0xab20, 0xab26}, {0xab28, 0xab2e}, {0xab30, 0xab65}, {0xab70, 0xabed},
|
||||
{0xabf0, 0xabf9}, {0xac00, 0xd7a3}, {0xd7b0, 0xd7c6}, {0xd7cb, 0xd7fb},
|
||||
{0xdc00, 0xdc3e}, {0xdc40, 0xdc7e}, {0xdc80, 0xdcbe}, {0xdcc0, 0xdcfe},
|
||||
{0xdd00, 0xdd3e}, {0xdd40, 0xdd7e}, {0xdd80, 0xddbe}, {0xddc0, 0xddfe},
|
||||
{0xde00, 0xde3e}, {0xde40, 0xde7e}, {0xde80, 0xdebe}, {0xdec0, 0xdefe},
|
||||
{0xdf00, 0xdf3e}, {0xdf40, 0xdf7e}, {0xdf80, 0xdfbe}, {0xdfc0, 0xdffe},
|
||||
{0xf900, 0xfa6d}, {0xfa70, 0xfad9}, {0xfb00, 0xfb06}, {0xfb13, 0xfb17},
|
||||
{0xfb1d, 0xfb36}, {0xfb38, 0xfb3c}, {0xfb46, 0xfbc1}, {0xfbd3, 0xfd3f},
|
||||
{0xfd50, 0xfd8f}, {0xfd92, 0xfdc7}, {0xfdf0, 0xfdfd}, {0xfe00, 0xfe19},
|
||||
{0xfe20, 0xfe52}, {0xfe54, 0xfe66}, {0xfe68, 0xfe6b}, {0xfe70, 0xfe74},
|
||||
{0xfe76, 0xfefc}, {0xff01, 0xffbe}, {0xffc2, 0xffc7}, {0xffca, 0xffcf},
|
||||
{0xffd2, 0xffd7}, {0xffda, 0xffdc}, {0xffe0, 0xffe6}, {0xffe8, 0xffee}
|
||||
#if TCL_UTF_MAX > 4
|
||||
{0x3220, 0x32fe}, {0x3300, 0x4db5}, {0x4dc0, 0x9fef}, {0xa000, 0xa48c},
|
||||
{0xa490, 0xa4c6}, {0xa4d0, 0xa62b}, {0xa640, 0xa6f7}, {0xa700, 0xa7b9},
|
||||
{0xa7f7, 0xa82b}, {0xa830, 0xa839}, {0xa840, 0xa877}, {0xa880, 0xa8c5},
|
||||
{0xa8ce, 0xa8d9}, {0xa8e0, 0xa953}, {0xa95f, 0xa97c}, {0xa980, 0xa9cd},
|
||||
{0xa9cf, 0xa9d9}, {0xa9de, 0xa9fe}, {0xaa00, 0xaa36}, {0xaa40, 0xaa4d},
|
||||
{0xaa50, 0xaa59}, {0xaa5c, 0xaac2}, {0xaadb, 0xaaf6}, {0xab01, 0xab06},
|
||||
{0xab09, 0xab0e}, {0xab11, 0xab16}, {0xab20, 0xab26}, {0xab28, 0xab2e},
|
||||
{0xab30, 0xab65}, {0xab70, 0xabed}, {0xabf0, 0xabf9}, {0xac00, 0xd7a3},
|
||||
{0xd7b0, 0xd7c6}, {0xd7cb, 0xd7fb}, {0xf900, 0xfa6d}, {0xfa70, 0xfad9},
|
||||
{0xfb00, 0xfb06}, {0xfb13, 0xfb17}, {0xfb1d, 0xfb36}, {0xfb38, 0xfb3c},
|
||||
{0xfb46, 0xfbc1}, {0xfbd3, 0xfd3f}, {0xfd50, 0xfd8f}, {0xfd92, 0xfdc7},
|
||||
{0xfdf0, 0xfdfd}, {0xfe00, 0xfe19}, {0xfe20, 0xfe52}, {0xfe54, 0xfe66},
|
||||
{0xfe68, 0xfe6b}, {0xfe70, 0xfe74}, {0xfe76, 0xfefc}, {0xff01, 0xffbe},
|
||||
{0xffc2, 0xffc7}, {0xffca, 0xffcf}, {0xffd2, 0xffd7}, {0xffda, 0xffdc},
|
||||
{0xffe0, 0xffe6}, {0xffe8, 0xffee}
|
||||
#if CHRBITS > 16
|
||||
,{0x10000, 0x1000b}, {0x1000d, 0x10026}, {0x10028, 0x1003a}, {0x1003f, 0x1004d},
|
||||
{0x10050, 0x1005d}, {0x10080, 0x100fa}, {0x10100, 0x10102}, {0x10107, 0x10133},
|
||||
{0x10137, 0x1018e}, {0x10190, 0x1019b}, {0x101d0, 0x101fd}, {0x10280, 0x1029c},
|
||||
{0x102a0, 0x102d0}, {0x102e0, 0x102fb}, {0x10300, 0x10323}, {0x10330, 0x1034a},
|
||||
{0x102a0, 0x102d0}, {0x102e0, 0x102fb}, {0x10300, 0x10323}, {0x1032d, 0x1034a},
|
||||
{0x10350, 0x1037a}, {0x10380, 0x1039d}, {0x1039f, 0x103c3}, {0x103c8, 0x103d5},
|
||||
{0x10400, 0x1049d}, {0x104a0, 0x104a9}, {0x104b0, 0x104d3}, {0x104d8, 0x104fb},
|
||||
{0x10500, 0x10527}, {0x10530, 0x10563}, {0x10600, 0x10736}, {0x10740, 0x10755},
|
||||
{0x10760, 0x10767}, {0x10800, 0x10805}, {0x1080a, 0x10835}, {0x1083f, 0x10855},
|
||||
{0x10857, 0x1089e}, {0x108a7, 0x108af}, {0x108e0, 0x108f2}, {0x108fb, 0x1091b},
|
||||
{0x1091f, 0x10939}, {0x10980, 0x109b7}, {0x109bc, 0x109cf}, {0x109d2, 0x10a03},
|
||||
{0x10a0c, 0x10a13}, {0x10a15, 0x10a17}, {0x10a19, 0x10a33}, {0x10a38, 0x10a3a},
|
||||
{0x10a3f, 0x10a47}, {0x10a50, 0x10a58}, {0x10a60, 0x10a9f}, {0x10ac0, 0x10ae6},
|
||||
{0x10a0c, 0x10a13}, {0x10a15, 0x10a17}, {0x10a19, 0x10a35}, {0x10a38, 0x10a3a},
|
||||
{0x10a3f, 0x10a48}, {0x10a50, 0x10a58}, {0x10a60, 0x10a9f}, {0x10ac0, 0x10ae6},
|
||||
{0x10aeb, 0x10af6}, {0x10b00, 0x10b35}, {0x10b39, 0x10b55}, {0x10b58, 0x10b72},
|
||||
{0x10b78, 0x10b91}, {0x10b99, 0x10b9c}, {0x10ba9, 0x10baf}, {0x10c00, 0x10c48},
|
||||
{0x10c80, 0x10cb2}, {0x10cc0, 0x10cf2}, {0x10cfa, 0x10cff}, {0x10e60, 0x10e7e},
|
||||
{0x11000, 0x1104d}, {0x11052, 0x1106f}, {0x1107f, 0x110bc}, {0x110be, 0x110c1},
|
||||
{0x110d0, 0x110e8}, {0x110f0, 0x110f9}, {0x11100, 0x11134}, {0x11136, 0x11143},
|
||||
{0x11150, 0x11176}, {0x11180, 0x111cd}, {0x111d0, 0x111df}, {0x111e1, 0x111f4},
|
||||
{0x11200, 0x11211}, {0x11213, 0x1123e}, {0x11280, 0x11286}, {0x1128a, 0x1128d},
|
||||
{0x1128f, 0x1129d}, {0x1129f, 0x112a9}, {0x112b0, 0x112ea}, {0x112f0, 0x112f9},
|
||||
{0x11300, 0x11303}, {0x11305, 0x1130c}, {0x11313, 0x11328}, {0x1132a, 0x11330},
|
||||
{0x11335, 0x11339}, {0x1133c, 0x11344}, {0x1134b, 0x1134d}, {0x1135d, 0x11363},
|
||||
{0x11366, 0x1136c}, {0x11370, 0x11374}, {0x11400, 0x11459}, {0x11480, 0x114c7},
|
||||
{0x114d0, 0x114d9}, {0x11580, 0x115b5}, {0x115b8, 0x115dd}, {0x11600, 0x11644},
|
||||
{0x11650, 0x11659}, {0x11660, 0x1166c}, {0x11680, 0x116b7}, {0x116c0, 0x116c9},
|
||||
{0x11700, 0x11719}, {0x1171d, 0x1172b}, {0x11730, 0x1173f}, {0x118a0, 0x118f2},
|
||||
{0x11ac0, 0x11af8}, {0x11c00, 0x11c08}, {0x11c0a, 0x11c36}, {0x11c38, 0x11c45},
|
||||
{0x11c50, 0x11c6c}, {0x11c70, 0x11c8f}, {0x11c92, 0x11ca7}, {0x11ca9, 0x11cb6},
|
||||
{0x10c80, 0x10cb2}, {0x10cc0, 0x10cf2}, {0x10cfa, 0x10d27}, {0x10d30, 0x10d39},
|
||||
{0x10e60, 0x10e7e}, {0x10f00, 0x10f27}, {0x10f30, 0x10f59}, {0x11000, 0x1104d},
|
||||
{0x11052, 0x1106f}, {0x1107f, 0x110bc}, {0x110be, 0x110c1}, {0x110d0, 0x110e8},
|
||||
{0x110f0, 0x110f9}, {0x11100, 0x11134}, {0x11136, 0x11146}, {0x11150, 0x11176},
|
||||
{0x11180, 0x111cd}, {0x111d0, 0x111df}, {0x111e1, 0x111f4}, {0x11200, 0x11211},
|
||||
{0x11213, 0x1123e}, {0x11280, 0x11286}, {0x1128a, 0x1128d}, {0x1128f, 0x1129d},
|
||||
{0x1129f, 0x112a9}, {0x112b0, 0x112ea}, {0x112f0, 0x112f9}, {0x11300, 0x11303},
|
||||
{0x11305, 0x1130c}, {0x11313, 0x11328}, {0x1132a, 0x11330}, {0x11335, 0x11339},
|
||||
{0x1133b, 0x11344}, {0x1134b, 0x1134d}, {0x1135d, 0x11363}, {0x11366, 0x1136c},
|
||||
{0x11370, 0x11374}, {0x11400, 0x11459}, {0x11480, 0x114c7}, {0x114d0, 0x114d9},
|
||||
{0x11580, 0x115b5}, {0x115b8, 0x115dd}, {0x11600, 0x11644}, {0x11650, 0x11659},
|
||||
{0x11660, 0x1166c}, {0x11680, 0x116b7}, {0x116c0, 0x116c9}, {0x11700, 0x1171a},
|
||||
{0x1171d, 0x1172b}, {0x11730, 0x1173f}, {0x11800, 0x1183b}, {0x118a0, 0x118f2},
|
||||
{0x11a00, 0x11a47}, {0x11a50, 0x11a83}, {0x11a86, 0x11aa2}, {0x11ac0, 0x11af8},
|
||||
{0x11c00, 0x11c08}, {0x11c0a, 0x11c36}, {0x11c38, 0x11c45}, {0x11c50, 0x11c6c},
|
||||
{0x11c70, 0x11c8f}, {0x11c92, 0x11ca7}, {0x11ca9, 0x11cb6}, {0x11d00, 0x11d06},
|
||||
{0x11d0b, 0x11d36}, {0x11d3f, 0x11d47}, {0x11d50, 0x11d59}, {0x11d60, 0x11d65},
|
||||
{0x11d6a, 0x11d8e}, {0x11d93, 0x11d98}, {0x11da0, 0x11da9}, {0x11ee0, 0x11ef8},
|
||||
{0x12000, 0x12399}, {0x12400, 0x1246e}, {0x12470, 0x12474}, {0x12480, 0x12543},
|
||||
{0x13000, 0x1342e}, {0x14400, 0x14646}, {0x16800, 0x16a38}, {0x16a40, 0x16a5e},
|
||||
{0x16a60, 0x16a69}, {0x16ad0, 0x16aed}, {0x16af0, 0x16af5}, {0x16b00, 0x16b45},
|
||||
{0x16b50, 0x16b59}, {0x16b5b, 0x16b61}, {0x16b63, 0x16b77}, {0x16b7d, 0x16b8f},
|
||||
{0x16f00, 0x16f44}, {0x16f50, 0x16f7e}, {0x16f8f, 0x16f9f}, {0x17000, 0x187ec},
|
||||
{0x18800, 0x18af2}, {0x1bc00, 0x1bc6a}, {0x1bc70, 0x1bc7c}, {0x1bc80, 0x1bc88},
|
||||
{0x1bc90, 0x1bc99}, {0x1bc9c, 0x1bc9f}, {0x1d000, 0x1d0f5}, {0x1d100, 0x1d126},
|
||||
{0x1d129, 0x1d172}, {0x1d17b, 0x1d1e8}, {0x1d200, 0x1d245}, {0x1d300, 0x1d356},
|
||||
{0x1d360, 0x1d371}, {0x1d400, 0x1d454}, {0x1d456, 0x1d49c}, {0x1d4a9, 0x1d4ac},
|
||||
{0x16e40, 0x16e9a}, {0x16f00, 0x16f44}, {0x16f50, 0x16f7e}, {0x16f8f, 0x16f9f},
|
||||
{0x17000, 0x187f1}, {0x18800, 0x18af2}, {0x1b000, 0x1b11e}, {0x1b170, 0x1b2fb},
|
||||
{0x1bc00, 0x1bc6a}, {0x1bc70, 0x1bc7c}, {0x1bc80, 0x1bc88}, {0x1bc90, 0x1bc99},
|
||||
{0x1bc9c, 0x1bc9f}, {0x1d000, 0x1d0f5}, {0x1d100, 0x1d126}, {0x1d129, 0x1d172},
|
||||
{0x1d17b, 0x1d1e8}, {0x1d200, 0x1d245}, {0x1d2e0, 0x1d2f3}, {0x1d300, 0x1d356},
|
||||
{0x1d360, 0x1d378}, {0x1d400, 0x1d454}, {0x1d456, 0x1d49c}, {0x1d4a9, 0x1d4ac},
|
||||
{0x1d4ae, 0x1d4b9}, {0x1d4bd, 0x1d4c3}, {0x1d4c5, 0x1d505}, {0x1d507, 0x1d50a},
|
||||
{0x1d50d, 0x1d514}, {0x1d516, 0x1d51c}, {0x1d51e, 0x1d539}, {0x1d53b, 0x1d53e},
|
||||
{0x1d540, 0x1d544}, {0x1d54a, 0x1d550}, {0x1d552, 0x1d6a5}, {0x1d6a8, 0x1d7cb},
|
||||
{0x1d7ce, 0x1da8b}, {0x1da9b, 0x1da9f}, {0x1daa1, 0x1daaf}, {0x1e000, 0x1e006},
|
||||
{0x1e008, 0x1e018}, {0x1e01b, 0x1e021}, {0x1e026, 0x1e02a}, {0x1e800, 0x1e8c4},
|
||||
{0x1e8c7, 0x1e8d6}, {0x1e900, 0x1e94a}, {0x1e950, 0x1e959}, {0x1ee00, 0x1ee03},
|
||||
{0x1ee05, 0x1ee1f}, {0x1ee29, 0x1ee32}, {0x1ee34, 0x1ee37}, {0x1ee4d, 0x1ee4f},
|
||||
{0x1ee67, 0x1ee6a}, {0x1ee6c, 0x1ee72}, {0x1ee74, 0x1ee77}, {0x1ee79, 0x1ee7c},
|
||||
{0x1ee80, 0x1ee89}, {0x1ee8b, 0x1ee9b}, {0x1eea1, 0x1eea3}, {0x1eea5, 0x1eea9},
|
||||
{0x1eeab, 0x1eebb}, {0x1f000, 0x1f02b}, {0x1f030, 0x1f093}, {0x1f0a0, 0x1f0ae},
|
||||
{0x1f0b1, 0x1f0bf}, {0x1f0c1, 0x1f0cf}, {0x1f0d1, 0x1f0f5}, {0x1f100, 0x1f10c},
|
||||
{0x1f110, 0x1f12e}, {0x1f130, 0x1f16b}, {0x1f170, 0x1f1ac}, {0x1f1e6, 0x1f202},
|
||||
{0x1f210, 0x1f23b}, {0x1f240, 0x1f248}, {0x1f300, 0x1f6d2}, {0x1f6e0, 0x1f6ec},
|
||||
{0x1f6f0, 0x1f6f6}, {0x1f700, 0x1f773}, {0x1f780, 0x1f7d4}, {0x1f800, 0x1f80b},
|
||||
{0x1f810, 0x1f847}, {0x1f850, 0x1f859}, {0x1f860, 0x1f887}, {0x1f890, 0x1f8ad},
|
||||
{0x1f910, 0x1f91e}, {0x1f920, 0x1f927}, {0x1f933, 0x1f93e}, {0x1f940, 0x1f94b},
|
||||
{0x1f950, 0x1f95e}, {0x1f980, 0x1f991}, {0x20000, 0x2a6d6}, {0x2a700, 0x2b734},
|
||||
{0x2b740, 0x2b81d}, {0x2b820, 0x2cea1}, {0x2f800, 0x2fa1d}, {0xe0100, 0xe01ef}
|
||||
{0x1e8c7, 0x1e8d6}, {0x1e900, 0x1e94a}, {0x1e950, 0x1e959}, {0x1ec71, 0x1ecb4},
|
||||
{0x1ee00, 0x1ee03}, {0x1ee05, 0x1ee1f}, {0x1ee29, 0x1ee32}, {0x1ee34, 0x1ee37},
|
||||
{0x1ee4d, 0x1ee4f}, {0x1ee67, 0x1ee6a}, {0x1ee6c, 0x1ee72}, {0x1ee74, 0x1ee77},
|
||||
{0x1ee79, 0x1ee7c}, {0x1ee80, 0x1ee89}, {0x1ee8b, 0x1ee9b}, {0x1eea1, 0x1eea3},
|
||||
{0x1eea5, 0x1eea9}, {0x1eeab, 0x1eebb}, {0x1f000, 0x1f02b}, {0x1f030, 0x1f093},
|
||||
{0x1f0a0, 0x1f0ae}, {0x1f0b1, 0x1f0bf}, {0x1f0c1, 0x1f0cf}, {0x1f0d1, 0x1f0f5},
|
||||
{0x1f100, 0x1f10c}, {0x1f110, 0x1f16b}, {0x1f170, 0x1f1ac}, {0x1f1e6, 0x1f202},
|
||||
{0x1f210, 0x1f23b}, {0x1f240, 0x1f248}, {0x1f260, 0x1f265}, {0x1f300, 0x1f6d4},
|
||||
{0x1f6e0, 0x1f6ec}, {0x1f6f0, 0x1f6f9}, {0x1f700, 0x1f773}, {0x1f780, 0x1f7d8},
|
||||
{0x1f800, 0x1f80b}, {0x1f810, 0x1f847}, {0x1f850, 0x1f859}, {0x1f860, 0x1f887},
|
||||
{0x1f890, 0x1f8ad}, {0x1f900, 0x1f90b}, {0x1f910, 0x1f93e}, {0x1f940, 0x1f970},
|
||||
{0x1f973, 0x1f976}, {0x1f97c, 0x1f9a2}, {0x1f9b0, 0x1f9b9}, {0x1f9c0, 0x1f9c2},
|
||||
{0x1f9d0, 0x1f9ff}, {0x1fa60, 0x1fa6d}, {0x20000, 0x2a6d6}, {0x2a700, 0x2b734},
|
||||
{0x2b740, 0x2b81d}, {0x2b820, 0x2cea1}, {0x2ceb0, 0x2ebe0}, {0x2f800, 0x2fa1d},
|
||||
{0xe0100, 0xe01ef}
|
||||
#endif
|
||||
};
|
||||
|
||||
#define NUM_GRAPH_RANGE (sizeof(graphRangeTable)/sizeof(crange))
|
||||
|
||||
static const chr graphCharTable[] = {
|
||||
0x38c, 0x589, 0x58a, 0x85e, 0x98f, 0x990, 0x9b2, 0x9c7, 0x9c8,
|
||||
0x9d7, 0x9dc, 0x9dd, 0xa0f, 0xa10, 0xa32, 0xa33, 0xa35, 0xa36,
|
||||
0xa38, 0xa39, 0xa3c, 0xa47, 0xa48, 0xa51, 0xa5e, 0xab2, 0xab3,
|
||||
0xad0, 0xaf9, 0xb0f, 0xb10, 0xb32, 0xb33, 0xb47, 0xb48, 0xb56,
|
||||
0xb57, 0xb5c, 0xb5d, 0xb82, 0xb83, 0xb99, 0xb9a, 0xb9c, 0xb9e,
|
||||
0xb9f, 0xba3, 0xba4, 0xbd0, 0xbd7, 0xc55, 0xc56, 0xcd5, 0xcd6,
|
||||
0xcde, 0xcf1, 0xcf2, 0xd82, 0xd83, 0xdbd, 0xdca, 0xdd6, 0xe81,
|
||||
0xe82, 0xe84, 0xe87, 0xe88, 0xe8a, 0xe8d, 0xea5, 0xea7, 0xeaa,
|
||||
0xeab, 0xec6, 0x10c7, 0x10cd, 0x1258, 0x12c0, 0x1772, 0x1773, 0x1940,
|
||||
0x1cf8, 0x1cf9, 0x1f59, 0x1f5b, 0x1f5d, 0x2070, 0x2071, 0x2d27, 0x2d2d,
|
||||
0x2d6f, 0x2d70, 0xfb3e, 0xfb40, 0xfb41, 0xfb43, 0xfb44, 0xfffc, 0xfffd
|
||||
#if TCL_UTF_MAX > 4
|
||||
0x38c, 0x85e, 0x98f, 0x990, 0x9b2, 0x9c7, 0x9c8, 0x9d7, 0x9dc,
|
||||
0x9dd, 0xa0f, 0xa10, 0xa32, 0xa33, 0xa35, 0xa36, 0xa38, 0xa39,
|
||||
0xa3c, 0xa47, 0xa48, 0xa51, 0xa5e, 0xab2, 0xab3, 0xad0, 0xb0f,
|
||||
0xb10, 0xb32, 0xb33, 0xb47, 0xb48, 0xb56, 0xb57, 0xb5c, 0xb5d,
|
||||
0xb82, 0xb83, 0xb99, 0xb9a, 0xb9c, 0xb9e, 0xb9f, 0xba3, 0xba4,
|
||||
0xbd0, 0xbd7, 0xc55, 0xc56, 0xcd5, 0xcd6, 0xcde, 0xcf1, 0xcf2,
|
||||
0xd82, 0xd83, 0xdbd, 0xdca, 0xdd6, 0xe81, 0xe82, 0xe84, 0xe87,
|
||||
0xe88, 0xe8a, 0xe8d, 0xea5, 0xea7, 0xeaa, 0xeab, 0xec6, 0x10c7,
|
||||
0x10cd, 0x1258, 0x12c0, 0x1772, 0x1773, 0x1940, 0x1f59, 0x1f5b, 0x1f5d,
|
||||
0x2070, 0x2071, 0x2d27, 0x2d2d, 0x2d6f, 0x2d70, 0xfb3e, 0xfb40, 0xfb41,
|
||||
0xfb43, 0xfb44, 0xfffc, 0xfffd
|
||||
#if CHRBITS > 16
|
||||
,0x1003c, 0x1003d, 0x101a0, 0x1056f, 0x10808, 0x10837, 0x10838, 0x1083c, 0x108f4,
|
||||
0x108f5, 0x1093f, 0x10a05, 0x10a06, 0x11288, 0x1130f, 0x11310, 0x11332, 0x11333,
|
||||
0x11347, 0x11348, 0x11350, 0x11357, 0x1145b, 0x1145d, 0x118ff, 0x16a6e, 0x16a6f,
|
||||
0x16fe0, 0x1b000, 0x1b001, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d4bb,
|
||||
0x11347, 0x11348, 0x11350, 0x11357, 0x1145b, 0x1145d, 0x1145e, 0x118ff, 0x11d08,
|
||||
0x11d09, 0x11d3a, 0x11d3c, 0x11d3d, 0x11d67, 0x11d68, 0x11d90, 0x11d91, 0x16a6e,
|
||||
0x16a6f, 0x16fe0, 0x16fe1, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d4bb,
|
||||
0x1d546, 0x1e023, 0x1e024, 0x1e95e, 0x1e95f, 0x1ee21, 0x1ee22, 0x1ee24, 0x1ee27,
|
||||
0x1ee39, 0x1ee3b, 0x1ee42, 0x1ee47, 0x1ee49, 0x1ee4b, 0x1ee51, 0x1ee52, 0x1ee54,
|
||||
0x1ee57, 0x1ee59, 0x1ee5b, 0x1ee5d, 0x1ee5f, 0x1ee61, 0x1ee62, 0x1ee64, 0x1ee7e,
|
||||
0x1eef0, 0x1eef1, 0x1f250, 0x1f251, 0x1f930, 0x1f9c0
|
||||
0x1eef0, 0x1eef1, 0x1f250, 0x1f251, 0x1f97a
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
+4
-1
@@ -469,7 +469,6 @@ declare 128 {
|
||||
declare 129 {
|
||||
int Tcl_Eval(Tcl_Interp *interp, const char *script)
|
||||
}
|
||||
# This is obsolete, use Tcl_FSEvalFile
|
||||
declare 130 {
|
||||
int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName)
|
||||
}
|
||||
@@ -2370,6 +2369,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)
|
||||
|
||||
+4
-4
@@ -55,10 +55,10 @@ extern "C" {
|
||||
#define TCL_MAJOR_VERSION 8
|
||||
#define TCL_MINOR_VERSION 6
|
||||
#define TCL_RELEASE_LEVEL TCL_FINAL_RELEASE
|
||||
#define TCL_RELEASE_SERIAL 6
|
||||
#define TCL_RELEASE_SERIAL 8
|
||||
|
||||
#define TCL_VERSION "8.6"
|
||||
#define TCL_PATCH_LEVEL "8.6.6"
|
||||
#define TCL_PATCH_LEVEL "8.6.8"
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------------
|
||||
@@ -1986,7 +1986,7 @@ typedef struct Tcl_Token {
|
||||
* TCL_TOKEN_OPERATOR - The token describes one expression operator.
|
||||
* An operator might be the name of a math
|
||||
* function such as "abs". A TCL_TOKEN_OPERATOR
|
||||
* token is always preceeded by one
|
||||
* token is always preceded by one
|
||||
* TCL_TOKEN_SUB_EXPR token for the operator's
|
||||
* subexpression, and is followed by zero or more
|
||||
* TCL_TOKEN_SUB_EXPR tokens for the operator's
|
||||
@@ -2622,7 +2622,7 @@ EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr);
|
||||
#ifndef TCL_NO_DEPRECATED
|
||||
/*
|
||||
* These function have been renamed. The old names are deprecated, but we
|
||||
* define these macros for backwards compatibilty.
|
||||
* define these macros for backwards compatibility.
|
||||
*/
|
||||
|
||||
# define Tcl_Ckalloc Tcl_Alloc
|
||||
|
||||
+12
-11
@@ -2248,23 +2248,24 @@ GetListIndexOperand(
|
||||
Tcl_Token* tokenPtr = *tokenPtrPtr;
|
||||
/* INOUT: Pointer to the next token in the
|
||||
* source code */
|
||||
Tcl_Obj* intObj; /* Integer from the source code */
|
||||
int status; /* Tcl status return */
|
||||
Tcl_Obj *value;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Extract the next token as a string.
|
||||
*/
|
||||
|
||||
if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &intObj) != TCL_OK) {
|
||||
/* General operand validity check */
|
||||
if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &value) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Convert to an integer, advance to the next token and return. */
|
||||
/*
|
||||
* Convert to an integer, advance to the next token and return.
|
||||
* NOTE: Indexing a list with an index before it yields the
|
||||
* same result as indexing after it, and might be more easily portable
|
||||
* when list size limits grow.
|
||||
*/
|
||||
status = TclIndexEncode(interp, value,
|
||||
TCL_INDEX_BEFORE,TCL_INDEX_BEFORE, result);
|
||||
|
||||
status = TclGetIntForIndex(interp, intObj, -2, result);
|
||||
Tcl_DecrRefCount(intObj);
|
||||
Tcl_DecrRefCount(value);
|
||||
*tokenPtrPtr = TokenAfter(tokenPtr);
|
||||
return status;
|
||||
}
|
||||
|
||||
+187
-120
@@ -234,7 +234,7 @@ static const CmdInfo builtInCmds[] = {
|
||||
{"lsearch", Tcl_LsearchObjCmd, NULL, NULL, CMD_IS_SAFE},
|
||||
{"lset", Tcl_LsetObjCmd, TclCompileLsetCmd, NULL, CMD_IS_SAFE},
|
||||
{"lsort", Tcl_LsortObjCmd, NULL, NULL, CMD_IS_SAFE},
|
||||
{"package", Tcl_PackageObjCmd, NULL, NULL, CMD_IS_SAFE},
|
||||
{"package", Tcl_PackageObjCmd, NULL, TclNRPackageObjCmd, CMD_IS_SAFE},
|
||||
{"proc", Tcl_ProcObjCmd, NULL, NULL, CMD_IS_SAFE},
|
||||
{"regexp", Tcl_RegexpObjCmd, TclCompileRegexpCmd, NULL, CMD_IS_SAFE},
|
||||
{"regsub", Tcl_RegsubObjCmd, TclCompileRegsubCmd, NULL, CMD_IS_SAFE},
|
||||
@@ -2042,11 +2042,11 @@ Tcl_CreateCommand(
|
||||
{
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
ImportRef *oldRefPtr = NULL;
|
||||
Namespace *nsPtr, *dummy1, *dummy2;
|
||||
Command *cmdPtr, *refCmdPtr;
|
||||
Namespace *nsPtr;
|
||||
Command *cmdPtr;
|
||||
Tcl_HashEntry *hPtr;
|
||||
const char *tail;
|
||||
int isNew;
|
||||
int isNew = 0, deleted = 0;
|
||||
ImportedCmdData *dataPtr;
|
||||
|
||||
if (iPtr->flags & DELETED) {
|
||||
@@ -2059,32 +2059,52 @@ Tcl_CreateCommand(
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine where the command should reside. If its name contains
|
||||
* namespace qualifiers, we put it in the specified namespace; otherwise,
|
||||
* we always put it in the global 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 (strstr(cmdName, "::") != NULL) {
|
||||
TclGetNamespaceForQualName(interp, cmdName, NULL,
|
||||
TCL_CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);
|
||||
if ((nsPtr == NULL) || (tail == NULL)) {
|
||||
return (Tcl_Command) NULL;
|
||||
while (1) {
|
||||
/*
|
||||
* Determine where the command should reside. If its name contains
|
||||
* namespace qualifiers, we put it in the specified namespace;
|
||||
* otherwise, we always put it in the global namespace.
|
||||
*/
|
||||
|
||||
if (strstr(cmdName, "::") != NULL) {
|
||||
Namespace *dummy1, *dummy2;
|
||||
|
||||
TclGetNamespaceForQualName(interp, cmdName, NULL,
|
||||
TCL_CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);
|
||||
if ((nsPtr == NULL) || (tail == NULL)) {
|
||||
return (Tcl_Command) NULL;
|
||||
}
|
||||
} else {
|
||||
nsPtr = iPtr->globalNsPtr;
|
||||
tail = cmdName;
|
||||
}
|
||||
|
||||
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &isNew);
|
||||
|
||||
if (isNew || deleted) {
|
||||
/*
|
||||
* isNew - No conflict with existing command.
|
||||
* deleted - We've already deleted a conflicting command
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
nsPtr = iPtr->globalNsPtr;
|
||||
tail = cmdName;
|
||||
}
|
||||
|
||||
/* An existing command conflicts. Try to delete it.. */
|
||||
cmdPtr = Tcl_GetHashValue(hPtr);
|
||||
|
||||
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &isNew);
|
||||
if (!isNew) {
|
||||
/*
|
||||
* Command already exists. Delete the old one. Be careful to preserve
|
||||
* Be careful to preserve
|
||||
* any existing import links so we can restore them down below. That
|
||||
* way, you can redefine a command and its import status will remain
|
||||
* intact.
|
||||
*/
|
||||
|
||||
cmdPtr = Tcl_GetHashValue(hPtr);
|
||||
cmdPtr->refCount++;
|
||||
if (cmdPtr->importRefPtr) {
|
||||
cmdPtr->flags |= CMD_REDEF_IN_PROGRESS;
|
||||
@@ -2097,18 +2117,21 @@ Tcl_CreateCommand(
|
||||
cmdPtr->importRefPtr = NULL;
|
||||
}
|
||||
TclCleanupCommandMacro(cmdPtr);
|
||||
deleted = 1;
|
||||
}
|
||||
|
||||
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &isNew);
|
||||
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 (!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).
|
||||
*/
|
||||
|
||||
ckfree(Tcl_GetHashValue(hPtr));
|
||||
}
|
||||
|
||||
if (!deleted) {
|
||||
|
||||
ckfree(Tcl_GetHashValue(hPtr));
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Command resolvers (per-interp, per-namespace) might have resolved
|
||||
* to a command for the given namespace scope with this command not
|
||||
@@ -2156,7 +2179,7 @@ Tcl_CreateCommand(
|
||||
if (oldRefPtr != NULL) {
|
||||
cmdPtr->importRefPtr = oldRefPtr;
|
||||
while (oldRefPtr != NULL) {
|
||||
refCmdPtr = oldRefPtr->importedCmdPtr;
|
||||
Command *refCmdPtr = oldRefPtr->importedCmdPtr;
|
||||
dataPtr = refCmdPtr->objClientData;
|
||||
dataPtr->realCmdPtr = cmdPtr;
|
||||
oldRefPtr = oldRefPtr->nextPtr;
|
||||
@@ -2211,37 +2234,34 @@ Tcl_CreateObjCommand(
|
||||
* 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. */
|
||||
)
|
||||
{
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
ImportRef *oldRefPtr = NULL;
|
||||
Namespace *nsPtr, *dummy1, *dummy2;
|
||||
Command *cmdPtr, *refCmdPtr;
|
||||
Tcl_HashEntry *hPtr;
|
||||
Namespace *nsPtr;
|
||||
const char *tail;
|
||||
int isNew;
|
||||
ImportedCmdData *dataPtr;
|
||||
|
||||
if (iPtr->flags & DELETED) {
|
||||
/*
|
||||
* The interpreter is being deleted. Don't create any new commands;
|
||||
* it's not safe to muck with the interpreter anymore.
|
||||
*/
|
||||
|
||||
return (Tcl_Command) NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine where the command should reside. If its name contains
|
||||
* namespace qualifiers, we put it in the specified namespace; otherwise,
|
||||
* we always put it in the global namespace.
|
||||
* namespace qualifiers, we put it in the specified namespace;
|
||||
* otherwise, we always put it in the global namespace.
|
||||
*/
|
||||
|
||||
if (strstr(cmdName, "::") != NULL) {
|
||||
Namespace *dummy1, *dummy2;
|
||||
|
||||
TclGetNamespaceForQualName(interp, cmdName, NULL,
|
||||
TCL_CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);
|
||||
TCL_CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);
|
||||
if ((nsPtr == NULL) || (tail == NULL)) {
|
||||
return (Tcl_Command) NULL;
|
||||
}
|
||||
@@ -2250,12 +2270,49 @@ Tcl_CreateObjCommand(
|
||||
tail = cmdName;
|
||||
}
|
||||
|
||||
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &isNew);
|
||||
TclInvalidateNsPath(nsPtr);
|
||||
if (!isNew) {
|
||||
cmdPtr = Tcl_GetHashValue(hPtr);
|
||||
return TclCreateObjCommandInNs(interp, tail, (Tcl_Namespace *) nsPtr,
|
||||
proc, clientData, deleteProc);
|
||||
}
|
||||
|
||||
/* Command already exists. */
|
||||
Tcl_Command
|
||||
TclCreateObjCommandInNs (
|
||||
Tcl_Interp *interp,
|
||||
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
|
||||
/* 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.
|
||||
*/
|
||||
while (1) {
|
||||
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, cmdName, &isNew);
|
||||
|
||||
if (isNew || deleted) {
|
||||
/*
|
||||
* isNew - No conflict with existing command.
|
||||
* deleted - We've already deleted a conflicting command
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* An existing command conflicts. Try to delete it.. */
|
||||
cmdPtr = Tcl_GetHashValue(hPtr);
|
||||
|
||||
/*
|
||||
* [***] This is wrong. See Tcl Bug a16752c252.
|
||||
@@ -2286,25 +2343,32 @@ Tcl_CreateObjCommand(
|
||||
cmdPtr->flags |= CMD_REDEF_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* Make sure namespace doesn't get deallocated. */
|
||||
cmdPtr->nsPtr->refCount++;
|
||||
|
||||
Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
|
||||
nsPtr = (Namespace *) TclEnsureNamespace(interp,
|
||||
(Tcl_Namespace *)cmdPtr->nsPtr);
|
||||
TclNsDecrRefCount(cmdPtr->nsPtr);
|
||||
|
||||
if (cmdPtr->flags & CMD_REDEF_IN_PROGRESS) {
|
||||
oldRefPtr = cmdPtr->importRefPtr;
|
||||
cmdPtr->importRefPtr = NULL;
|
||||
}
|
||||
TclCleanupCommandMacro(cmdPtr);
|
||||
deleted = 1;
|
||||
}
|
||||
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).
|
||||
*/
|
||||
|
||||
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &isNew);
|
||||
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).
|
||||
*/
|
||||
ckfree(Tcl_GetHashValue(hPtr));
|
||||
}
|
||||
|
||||
ckfree(Tcl_GetHashValue(hPtr));
|
||||
}
|
||||
} else {
|
||||
if (!deleted) {
|
||||
/*
|
||||
* Command resolvers (per-interp, per-namespace) might have resolved
|
||||
* to a command for the given namespace scope with this command not
|
||||
@@ -2315,7 +2379,7 @@ Tcl_CreateObjCommand(
|
||||
* commands.
|
||||
*/
|
||||
|
||||
TclInvalidateCmdLiteral(interp, tail, nsPtr);
|
||||
TclInvalidateCmdLiteral(interp, cmdName, nsPtr);
|
||||
|
||||
/*
|
||||
* The list of command exported from the namespace might have changed.
|
||||
@@ -2324,6 +2388,7 @@ Tcl_CreateObjCommand(
|
||||
*/
|
||||
|
||||
TclInvalidateNsCmdLookup(nsPtr);
|
||||
TclInvalidateNsPath(nsPtr);
|
||||
}
|
||||
cmdPtr = ckalloc(sizeof(Command));
|
||||
Tcl_SetHashValue(hPtr, cmdPtr);
|
||||
@@ -2351,7 +2416,7 @@ Tcl_CreateObjCommand(
|
||||
if (oldRefPtr != NULL) {
|
||||
cmdPtr->importRefPtr = oldRefPtr;
|
||||
while (oldRefPtr != NULL) {
|
||||
refCmdPtr = oldRefPtr->importedCmdPtr;
|
||||
Command *refCmdPtr = oldRefPtr->importedCmdPtr;
|
||||
dataPtr = refCmdPtr->objClientData;
|
||||
dataPtr->realCmdPtr = cmdPtr;
|
||||
oldRefPtr = oldRefPtr->nextPtr;
|
||||
@@ -2544,10 +2609,6 @@ TclRenameCommand(
|
||||
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", oldName, NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
cmdNsPtr = cmdPtr->nsPtr;
|
||||
oldFullName = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(oldFullName);
|
||||
Tcl_GetCommandFullName(interp, cmd, oldFullName);
|
||||
|
||||
/*
|
||||
* If the new command name is NULL or empty, delete the command. Do this
|
||||
@@ -2556,10 +2617,14 @@ TclRenameCommand(
|
||||
|
||||
if ((newName == NULL) || (*newName == '\0')) {
|
||||
Tcl_DeleteCommandFromToken(interp, cmd);
|
||||
result = TCL_OK;
|
||||
goto done;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
cmdNsPtr = cmdPtr->nsPtr;
|
||||
oldFullName = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(oldFullName);
|
||||
Tcl_GetCommandFullName(interp, cmd, oldFullName);
|
||||
|
||||
/*
|
||||
* Make sure that the destination command does not already exist. The
|
||||
* rename operation is like creating a command, so we should automatically
|
||||
@@ -3058,7 +3123,7 @@ Tcl_DeleteCommandFromToken(
|
||||
/*
|
||||
* We must delete this command, even though both traces and delete procs
|
||||
* may try to avoid this (renaming the command etc). Also traces and
|
||||
* delete procs may try to delete the command themsevles. This flag
|
||||
* delete procs may try to delete the command themselves. This flag
|
||||
* declares that a delete is in progress and that recursive deletes should
|
||||
* be ignored.
|
||||
*/
|
||||
@@ -3070,6 +3135,8 @@ Tcl_DeleteCommandFromToken(
|
||||
* traces.
|
||||
*/
|
||||
|
||||
cmdPtr->nsPtr->refCount++;
|
||||
|
||||
if (cmdPtr->tracePtr != NULL) {
|
||||
CommandTrace *tracePtr;
|
||||
CallCommandTraces(iPtr,cmdPtr,NULL,NULL,TCL_TRACE_DELETE);
|
||||
@@ -3097,6 +3164,7 @@ Tcl_DeleteCommandFromToken(
|
||||
*/
|
||||
|
||||
TclInvalidateNsCmdLookup(cmdPtr->nsPtr);
|
||||
TclNsDecrRefCount(cmdPtr->nsPtr);
|
||||
|
||||
/*
|
||||
* If the command being deleted has a compile function, increment the
|
||||
@@ -3543,7 +3611,7 @@ OldMathFuncProc(
|
||||
args[k].type = TCL_INT;
|
||||
break;
|
||||
}
|
||||
if (Tcl_GetWideIntFromObj(interp, valuePtr, &args[k].wideValue)
|
||||
if (TclGetWideIntFromObj(interp, valuePtr, &args[k].wideValue)
|
||||
== TCL_OK) {
|
||||
args[k].type = TCL_WIDE_INT;
|
||||
break;
|
||||
@@ -3569,7 +3637,7 @@ OldMathFuncProc(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
valuePtr = Tcl_GetObjResult(interp);
|
||||
Tcl_GetWideIntFromObj(NULL, valuePtr, &args[k].wideValue);
|
||||
TclGetWideIntFromObj(NULL, valuePtr, &args[k].wideValue);
|
||||
Tcl_ResetResult(interp);
|
||||
break;
|
||||
}
|
||||
@@ -4384,6 +4452,8 @@ TclNRRunCallbacks(
|
||||
(void) Tcl_GetObjResult(interp);
|
||||
}
|
||||
|
||||
/* This is the trampoline. */
|
||||
|
||||
while (TOP_CB(interp) != rootPtr) {
|
||||
callbackPtr = TOP_CB(interp);
|
||||
procPtr = callbackPtr->procPtr;
|
||||
@@ -4517,7 +4587,7 @@ TEOV_Exception(
|
||||
if (result == TCL_RETURN) {
|
||||
result = TclUpdateReturnInfo(iPtr);
|
||||
}
|
||||
if ((result != TCL_ERROR) && !allowExceptions) {
|
||||
if ((result != TCL_OK) && (result != TCL_ERROR) && !allowExceptions) {
|
||||
ProcessUnexpectedResult(interp, result);
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
@@ -7174,7 +7244,7 @@ ExprIsqrtFunc(
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (Tcl_GetWideIntFromObj(interp, objv[1], &w) != TCL_OK) {
|
||||
if (TclGetWideIntFromObj(interp, objv[1], &w) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (w < 0) {
|
||||
@@ -7536,7 +7606,19 @@ ExprEntierFunc(
|
||||
|
||||
if (type == TCL_NUMBER_DOUBLE) {
|
||||
d = *((const double *) ptr);
|
||||
if ((d >= (double)LONG_MAX) || (d <= (double)LONG_MIN)) {
|
||||
if ((d < (double)LONG_MAX) && (d > (double)LONG_MIN)) {
|
||||
long result = (long) d;
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewLongObj(result));
|
||||
return TCL_OK;
|
||||
#ifndef TCL_WIDE_INT_IS_LONG
|
||||
} else if ((d < (double)LLONG_MAX) && (d > (double)LLONG_MIN)) {
|
||||
Tcl_WideInt result = (Tcl_WideInt) d;
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(result));
|
||||
return TCL_OK;
|
||||
#endif
|
||||
} else {
|
||||
mp_int big;
|
||||
|
||||
if (Tcl_InitBignumFromDouble(interp, d, &big) != TCL_OK) {
|
||||
@@ -7545,11 +7627,6 @@ ExprEntierFunc(
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewBignumObj(&big));
|
||||
return TCL_OK;
|
||||
} else {
|
||||
long result = (long) d;
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewLongObj(result));
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7617,7 +7694,7 @@ ExprWideFunc(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
objPtr = Tcl_GetObjResult(interp);
|
||||
if (Tcl_GetWideIntFromObj(NULL, objPtr, &wResult) != TCL_OK) {
|
||||
if (TclGetWideIntFromObj(NULL, objPtr, &wResult) != TCL_OK) {
|
||||
/*
|
||||
* Truncate the bignum; keep only bits in wide int range.
|
||||
*/
|
||||
@@ -7628,7 +7705,7 @@ ExprWideFunc(
|
||||
mp_mod_2d(&big, (int) CHAR_BIT * sizeof(Tcl_WideInt), &big);
|
||||
objPtr = Tcl_NewBignumObj(&big);
|
||||
Tcl_IncrRefCount(objPtr);
|
||||
Tcl_GetWideIntFromObj(NULL, objPtr, &wResult);
|
||||
TclGetWideIntFromObj(NULL, objPtr, &wResult);
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(wResult));
|
||||
@@ -7658,8 +7735,8 @@ ExprRandFunc(
|
||||
iPtr->flags |= RAND_SEED_INITIALIZED;
|
||||
|
||||
/*
|
||||
* Take into consideration the thread this interp is running in order
|
||||
* to insure different seeds in different threads (bug #416643)
|
||||
* To ensure different seeds in different threads (bug #416643),
|
||||
* take into consideration the thread this interp is running in.
|
||||
*/
|
||||
|
||||
iPtr->randSeed = TclpGetClicks() + (PTR2INT(Tcl_GetCurrentThread())<<12);
|
||||
@@ -8123,6 +8200,22 @@ Tcl_NRCreateCommand(
|
||||
cmdPtr->nreProc = nreProc;
|
||||
return (Tcl_Command) cmdPtr;
|
||||
}
|
||||
|
||||
Tcl_Command
|
||||
TclNRCreateCommandInNs (
|
||||
Tcl_Interp *interp,
|
||||
const char *cmdName,
|
||||
Tcl_Namespace *nsPtr,
|
||||
Tcl_ObjCmdProc *proc,
|
||||
Tcl_ObjCmdProc *nreProc,
|
||||
ClientData clientData,
|
||||
Tcl_CmdDeleteProc *deleteProc) {
|
||||
Command *cmdPtr = (Command *)
|
||||
TclCreateObjCommandInNs(interp,cmdName,nsPtr,proc,clientData,deleteProc);
|
||||
|
||||
cmdPtr->nreProc = nreProc;
|
||||
return (Tcl_Command) cmdPtr;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Stuff for the public api
|
||||
@@ -8316,18 +8409,12 @@ 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;
|
||||
@@ -8908,9 +8995,9 @@ TclNRCoroutineObjCmd(
|
||||
{
|
||||
Command *cmdPtr;
|
||||
CoroutineData *corPtr;
|
||||
const char *fullName, *procName;
|
||||
Namespace *nsPtr, *altNsPtr, *cxtNsPtr;
|
||||
Tcl_DString ds;
|
||||
const char *procName, *simpleName;
|
||||
Namespace *nsPtr, *altNsPtr, *cxtNsPtr,
|
||||
*inNsPtr = (Namespace *)TclGetCurrentNamespace(interp);
|
||||
Namespace *lookupNsPtr = iPtr->varFramePtr->nsPtr;
|
||||
|
||||
if (objc < 3) {
|
||||
@@ -8918,34 +9005,21 @@ TclNRCoroutineObjCmd(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: this is copy/pasted from Tcl_ProcObjCommand. Should have
|
||||
* something in tclUtil.c to find the FQ name.
|
||||
*/
|
||||
|
||||
fullName = TclGetString(objv[1]);
|
||||
TclGetNamespaceForQualName(interp, fullName, NULL, 0,
|
||||
&nsPtr, &altNsPtr, &cxtNsPtr, &procName);
|
||||
procName = TclGetString(objv[1]);
|
||||
TclGetNamespaceForQualName(interp, procName, inNsPtr, 0,
|
||||
&nsPtr, &altNsPtr, &cxtNsPtr, &simpleName);
|
||||
|
||||
if (nsPtr == NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"can't create procedure \"%s\": unknown namespace",
|
||||
fullName));
|
||||
procName));
|
||||
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (procName == NULL) {
|
||||
if (simpleName == NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"can't create procedure \"%s\": bad procedure name",
|
||||
fullName));
|
||||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", fullName, NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if ((nsPtr != iPtr->globalNsPtr)
|
||||
&& (procName != NULL) && (procName[0] == ':')) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"can't create procedure \"%s\" in non-global namespace with"
|
||||
" name starting with \":\"", procName));
|
||||
procName));
|
||||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", procName, NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -8957,16 +9031,9 @@ TclNRCoroutineObjCmd(
|
||||
|
||||
corPtr = ckalloc(sizeof(CoroutineData));
|
||||
|
||||
Tcl_DStringInit(&ds);
|
||||
if (nsPtr != iPtr->globalNsPtr) {
|
||||
Tcl_DStringAppend(&ds, nsPtr->fullName, -1);
|
||||
TclDStringAppendLiteral(&ds, "::");
|
||||
}
|
||||
Tcl_DStringAppend(&ds, procName, -1);
|
||||
|
||||
cmdPtr = (Command *) Tcl_NRCreateCommand(interp, Tcl_DStringValue(&ds),
|
||||
/*objProc*/ NULL, TclNRInterpCoroutine, corPtr, DeleteCoroutine);
|
||||
Tcl_DStringFree(&ds);
|
||||
cmdPtr = (Command *) TclNRCreateCommandInNs(interp, simpleName,
|
||||
(Tcl_Namespace *)nsPtr, /*objProc*/ NULL, TclNRInterpCoroutine,
|
||||
corPtr, DeleteCoroutine);
|
||||
|
||||
corPtr->cmdPtr = cmdPtr;
|
||||
cmdPtr->refCount++;
|
||||
@@ -9027,7 +9094,7 @@ TclNRCoroutineObjCmd(
|
||||
TclNRAddCallback(interp, NRCoroutineExitCallback, corPtr,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
/* insure that the command is looked up in the correct namespace */
|
||||
/* ensure that the command is looked up in the correct namespace */
|
||||
iPtr->lookupNsPtr = lookupNsPtr;
|
||||
Tcl_NREvalObj(interp, Tcl_NewListObj(objc-2, objv+2), 0);
|
||||
iPtr->numLevels--;
|
||||
|
||||
+3
-3
@@ -454,7 +454,7 @@ SetByteArrayFromAny(
|
||||
const char *src, *srcEnd;
|
||||
unsigned char *dst;
|
||||
ByteArray *byteArrayPtr;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
|
||||
if (objPtr->typePtr != &tclByteArrayType) {
|
||||
src = TclGetStringFromObj(objPtr, &length);
|
||||
@@ -1210,7 +1210,7 @@ BinaryFormatCmd(
|
||||
|
||||
badField:
|
||||
{
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
char buf[TCL_UTF_MAX + 1];
|
||||
|
||||
TclUtfToUniChar(errorString, &ch);
|
||||
@@ -1580,7 +1580,7 @@ BinaryScanCmd(
|
||||
|
||||
badField:
|
||||
{
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
char buf[TCL_UTF_MAX + 1];
|
||||
|
||||
TclUtfToUniChar(errorString, &ch);
|
||||
|
||||
+282
-2301
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -512,63 +512,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;
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
|
||||
+50
-50
@@ -64,8 +64,9 @@ typedef struct SortInfo {
|
||||
* SORTMODE_COMMAND. Pre-initialized to hold
|
||||
* base of command. */
|
||||
int *indexv; /* If the -index option was specified, this
|
||||
* holds the indexes contained in the list
|
||||
* supplied as an argument to that option.
|
||||
* holds an encoding of the indexes contained
|
||||
* in the list supplied as an argument to
|
||||
* that option.
|
||||
* NULL if no indexes supplied, and points to
|
||||
* singleIndex field when only one
|
||||
* supplied. */
|
||||
@@ -92,14 +93,6 @@ typedef struct SortInfo {
|
||||
#define SORTMODE_DICTIONARY 4
|
||||
#define SORTMODE_ASCII_NC 8
|
||||
|
||||
/*
|
||||
* Magic values for the index field of the SortInfo structure. Note that the
|
||||
* index "end-1" will be translated to SORTIDX_END-1, etc.
|
||||
*/
|
||||
|
||||
#define SORTIDX_NONE -1 /* Not indexed; use whole value. */
|
||||
#define SORTIDX_END -2 /* Indexed from end. */
|
||||
|
||||
/*
|
||||
* Forward declarations for procedures defined in this file:
|
||||
*/
|
||||
@@ -2754,21 +2747,10 @@ Tcl_LreplaceObjCmd(
|
||||
if (first < 0) {
|
||||
first = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Complain if the user asked for a start element that is greater than the
|
||||
* list length. This won't ever trigger for the "end-*" case as that will
|
||||
* be properly constrained by TclGetIntForIndex because we use listLen-1
|
||||
* (to allow for replacing the last elem).
|
||||
*/
|
||||
|
||||
if ((first > listLen) && (listLen > 0)) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"list doesn't contain element %s", TclGetString(objv[2])));
|
||||
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LREPLACE", "BADIDX",
|
||||
NULL);
|
||||
return TCL_ERROR;
|
||||
if (first > listLen) {
|
||||
first = listLen;
|
||||
}
|
||||
|
||||
if (last >= listLen) {
|
||||
last = listLen - 1;
|
||||
}
|
||||
@@ -2913,7 +2895,7 @@ Tcl_LsearchObjCmd(
|
||||
Tcl_Obj *const objv[]) /* Argument values. */
|
||||
{
|
||||
const char *bytes, *patternBytes;
|
||||
int i, match, index, result, listc, length, elemLen, bisect;
|
||||
int i, match, index, result=TCL_OK, listc, length, elemLen, bisect;
|
||||
int dataType, isIncreasing, lower, upper, offset;
|
||||
Tcl_WideInt patWide, objWide;
|
||||
int allMatches, inlineReturn, negatedMatch, returnSubindices, noCase;
|
||||
@@ -3113,13 +3095,26 @@ Tcl_LsearchObjCmd(
|
||||
*/
|
||||
|
||||
for (j=0 ; j<sortInfo.indexc ; j++) {
|
||||
if (TclGetIntForIndexM(interp, indices[j], SORTIDX_END,
|
||||
&sortInfo.indexv[j]) != TCL_OK) {
|
||||
int encoded = 0;
|
||||
if (TclIndexEncode(interp, indices[j], TCL_INDEX_BEFORE,
|
||||
TCL_INDEX_AFTER, &encoded) != TCL_OK) {
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
if ((encoded == TCL_INDEX_BEFORE)
|
||||
|| (encoded == TCL_INDEX_AFTER)) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"index \"%s\" cannot select an element "
|
||||
"from any list", Tcl_GetString(indices[j])));
|
||||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX"
|
||||
"OUTOFRANGE", NULL);
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
if (result == TCL_ERROR) {
|
||||
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
|
||||
"\n (-index option item number %d)", j));
|
||||
result = TCL_ERROR;
|
||||
goto done;
|
||||
}
|
||||
sortInfo.indexv[j] = encoded;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3492,8 +3487,8 @@ Tcl_LsearchObjCmd(
|
||||
|
||||
itemPtr = Tcl_NewIntObj(i);
|
||||
for (j=0 ; j<sortInfo.indexc ; j++) {
|
||||
Tcl_ListObjAppendElement(interp, itemPtr,
|
||||
Tcl_NewIntObj(sortInfo.indexv[j]));
|
||||
Tcl_ListObjAppendElement(interp, itemPtr, Tcl_NewIntObj(
|
||||
TclIndexDecode(sortInfo.indexv[j], listc)));
|
||||
}
|
||||
Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
|
||||
} else {
|
||||
@@ -3514,8 +3509,8 @@ Tcl_LsearchObjCmd(
|
||||
|
||||
itemPtr = Tcl_NewIntObj(index);
|
||||
for (j=0 ; j<sortInfo.indexc ; j++) {
|
||||
Tcl_ListObjAppendElement(interp, itemPtr,
|
||||
Tcl_NewIntObj(sortInfo.indexv[j]));
|
||||
Tcl_ListObjAppendElement(interp, itemPtr, Tcl_NewIntObj(
|
||||
TclIndexDecode(sortInfo.indexv[j], listc)));
|
||||
}
|
||||
Tcl_SetObjResult(interp, itemPtr);
|
||||
} else {
|
||||
@@ -3732,7 +3727,7 @@ Tcl_LsortObjCmd(
|
||||
sortInfo.isIncreasing = 1;
|
||||
break;
|
||||
case LSORT_INDEX: {
|
||||
int indexc, dummy;
|
||||
int indexc;
|
||||
Tcl_Obj **indexv;
|
||||
|
||||
if (i == objc-2) {
|
||||
@@ -3758,8 +3753,20 @@ Tcl_LsortObjCmd(
|
||||
*/
|
||||
|
||||
for (j=0 ; j<indexc ; j++) {
|
||||
if (TclGetIntForIndexM(interp, indexv[j], SORTIDX_END,
|
||||
&dummy) != TCL_OK) {
|
||||
int encoded = 0;
|
||||
int result = TclIndexEncode(interp, indexv[j],
|
||||
TCL_INDEX_BEFORE, TCL_INDEX_AFTER, &encoded);
|
||||
|
||||
if ((result == TCL_OK) && ((encoded == TCL_INDEX_BEFORE)
|
||||
|| (encoded == TCL_INDEX_AFTER))) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"index \"%s\" cannot select an element "
|
||||
"from any list", Tcl_GetString(indexv[j])));
|
||||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX"
|
||||
"OUTOFRANGE", NULL);
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
if (result == TCL_ERROR) {
|
||||
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
|
||||
"\n (-index option item number %d)", j));
|
||||
sortInfo.resultCode = TCL_ERROR;
|
||||
@@ -3839,8 +3846,8 @@ Tcl_LsortObjCmd(
|
||||
* might be decreased by 1 later. */
|
||||
}
|
||||
for (j=0 ; j<sortInfo.indexc ; j++) {
|
||||
TclGetIntForIndexM(interp, indexv[j], SORTIDX_END,
|
||||
&sortInfo.indexv[j]);
|
||||
/* Prescreened values, no errors or out of range possible */
|
||||
TclIndexEncode(NULL, indexv[j], 0, 0, &sortInfo.indexv[j]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3911,10 +3918,7 @@ Tcl_LsortObjCmd(
|
||||
* offset of the element within each group by which to sort.
|
||||
*/
|
||||
|
||||
groupOffset = sortInfo.indexv[0];
|
||||
if (groupOffset <= SORTIDX_END) {
|
||||
groupOffset = (groupOffset - SORTIDX_END) + groupSize - 1;
|
||||
}
|
||||
groupOffset = TclIndexDecode(sortInfo.indexv[0], groupSize - 1);
|
||||
if (groupOffset < 0 || groupOffset >= groupSize) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
"when used with \"-stride\", the leading \"-index\""
|
||||
@@ -3933,6 +3937,9 @@ 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.
|
||||
*/
|
||||
|
||||
for (i = 0; i < sortInfo.indexc; i++) {
|
||||
@@ -4345,7 +4352,7 @@ static int
|
||||
DictionaryCompare(
|
||||
const char *left, const char *right) /* The strings to compare. */
|
||||
{
|
||||
Tcl_UniChar uniLeft, uniRight, uniLeftLower, uniRightLower;
|
||||
Tcl_UniChar uniLeft = 0, uniRight = 0, uniLeftLower, uniRightLower;
|
||||
int diff, zeros;
|
||||
int secondaryDiff = 0;
|
||||
|
||||
@@ -4501,15 +4508,8 @@ SelectObjFromSublist(
|
||||
infoPtr->resultCode = TCL_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
index = infoPtr->indexv[i];
|
||||
|
||||
/*
|
||||
* Adjust for end-based indexing.
|
||||
*/
|
||||
|
||||
if (index < SORTIDX_NONE) {
|
||||
index += listLen + 1;
|
||||
}
|
||||
index = TclIndexDecode(infoPtr->indexv[i], listLen - 1);
|
||||
|
||||
if (Tcl_ListObjIndex(infoPtr->interp, objPtr, index,
|
||||
¤tObj) != TCL_OK) {
|
||||
|
||||
+251
-187
@@ -309,7 +309,7 @@ Tcl_RegexpObjCmd(
|
||||
eflags = 0;
|
||||
} else if (offset > stringLength) {
|
||||
eflags = TCL_REG_NOTBOL;
|
||||
} else if (Tcl_GetUniChar(objPtr, offset-1) == (Tcl_UniChar)'\n') {
|
||||
} else if (Tcl_GetUniChar(objPtr, offset-1) == '\n') {
|
||||
eflags = 0;
|
||||
} else {
|
||||
eflags = TCL_REG_NOTBOL;
|
||||
@@ -1037,7 +1037,7 @@ Tcl_SplitObjCmd(
|
||||
int objc, /* Number of arguments. */
|
||||
Tcl_Obj *const objv[]) /* Argument objects. */
|
||||
{
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
int len;
|
||||
const char *splitChars;
|
||||
const char *stringPtr;
|
||||
@@ -1080,13 +1080,22 @@ Tcl_SplitObjCmd(
|
||||
Tcl_InitHashTable(&charReuseTable, TCL_ONE_WORD_KEYS);
|
||||
|
||||
for ( ; stringPtr < end; stringPtr += len) {
|
||||
int fullchar;
|
||||
len = TclUtfToUniChar(stringPtr, &ch);
|
||||
fullchar = ch;
|
||||
|
||||
#if TCL_UTF_MAX == 4
|
||||
if (!len) {
|
||||
len += TclUtfToUniChar(stringPtr, &ch);
|
||||
fullchar = (((fullchar & 0x3ff) << 10) | (ch & 0x3ff)) + 0x10000;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Assume Tcl_UniChar is an integral type...
|
||||
*/
|
||||
|
||||
hPtr = Tcl_CreateHashEntry(&charReuseTable, INT2PTR((int) ch),
|
||||
hPtr = Tcl_CreateHashEntry(&charReuseTable, INT2PTR(fullchar),
|
||||
&isNew);
|
||||
if (isNew) {
|
||||
TclNewStringObj(objPtr, stringPtr, len);
|
||||
@@ -1122,7 +1131,7 @@ Tcl_SplitObjCmd(
|
||||
} else {
|
||||
const char *element, *p, *splitEnd;
|
||||
int splitLen;
|
||||
Tcl_UniChar splitChar;
|
||||
Tcl_UniChar splitChar = 0;
|
||||
|
||||
/*
|
||||
* Normal case: split on any of a given set of characters. Discard
|
||||
@@ -1451,7 +1460,7 @@ StringIsCmd(
|
||||
Tcl_Obj *const objv[]) /* Argument objects. */
|
||||
{
|
||||
const char *string1, *end, *stop;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
int (*chcomp)(int) = NULL; /* The UniChar comparison function. */
|
||||
int i, failat = 0, result = 1, strict = 0, index, length1, length2;
|
||||
Tcl_Obj *objPtr, *failVarObj = NULL;
|
||||
@@ -1562,7 +1571,6 @@ StringIsCmd(
|
||||
chcomp = Tcl_UniCharIsDigit;
|
||||
break;
|
||||
case STR_IS_DOUBLE: {
|
||||
/* TODO */
|
||||
if ((objPtr->typePtr == &tclDoubleType) ||
|
||||
(objPtr->typePtr == &tclIntType) ||
|
||||
#ifndef TCL_WIDE_INT_IS_LONG
|
||||
@@ -1646,7 +1654,7 @@ StringIsCmd(
|
||||
}
|
||||
break;
|
||||
case STR_IS_WIDE:
|
||||
if (TCL_OK == Tcl_GetWideIntFromObj(NULL, objPtr, &w)) {
|
||||
if (TCL_OK == TclGetWideIntFromObj(NULL, objPtr, &w)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1783,8 +1791,16 @@ StringIsCmd(
|
||||
}
|
||||
end = string1 + length1;
|
||||
for (; string1 < end; string1 += length2, failat++) {
|
||||
int fullchar;
|
||||
length2 = TclUtfToUniChar(string1, &ch);
|
||||
if (!chcomp(ch)) {
|
||||
fullchar = ch;
|
||||
#if TCL_UTF_MAX == 4
|
||||
if (!length2) {
|
||||
length2 = TclUtfToUniChar(string1, &ch);
|
||||
fullchar = (((fullchar & 0x3ff) << 10) | (ch & 0x3ff)) + 0x10000;
|
||||
}
|
||||
#endif
|
||||
if (!chcomp(fullchar)) {
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
@@ -2336,7 +2352,7 @@ StringRplcCmd(
|
||||
Tcl_Obj *const objv[]) /* Argument objects. */
|
||||
{
|
||||
Tcl_UniChar *ustring;
|
||||
int first, last, length;
|
||||
int first, last, length, end;
|
||||
|
||||
if (objc < 4 || objc > 5) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "string first last ?string?");
|
||||
@@ -2344,20 +2360,38 @@ StringRplcCmd(
|
||||
}
|
||||
|
||||
ustring = Tcl_GetUnicodeFromObj(objv[1], &length);
|
||||
length--;
|
||||
end = length - 1;
|
||||
|
||||
if (TclGetIntForIndexM(interp, objv[2], length, &first) != TCL_OK ||
|
||||
TclGetIntForIndexM(interp, objv[3], length, &last) != TCL_OK){
|
||||
if (TclGetIntForIndexM(interp, objv[2], end, &first) != TCL_OK ||
|
||||
TclGetIntForIndexM(interp, objv[3], end, &last) != TCL_OK){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if ((last < first) || (last < 0) || (first > length)) {
|
||||
/*
|
||||
* The following test screens out most empty substrings as
|
||||
* candidates for replacement. When they are detected, no
|
||||
* replacement is done, and the result is the original string,
|
||||
*/
|
||||
if ((last < 0) || /* Range ends before start of string */
|
||||
(first > end) || /* Range begins after end of string */
|
||||
(last < first)) { /* Range begins after it starts */
|
||||
|
||||
/*
|
||||
* BUT!!! when (end < 0) -- an empty original string -- we can
|
||||
* have (first <= end < 0 <= last) and an empty string is permitted
|
||||
* to be replaced.
|
||||
*/
|
||||
Tcl_SetObjResult(interp, objv[1]);
|
||||
} else {
|
||||
Tcl_Obj *resultPtr;
|
||||
|
||||
/*
|
||||
* We are re-fetching in case the string argument is same value as
|
||||
* an index argument, and shimmering cost us our ustring.
|
||||
*/
|
||||
|
||||
ustring = Tcl_GetUnicodeFromObj(objv[1], &length);
|
||||
length--;
|
||||
end = length-1;
|
||||
|
||||
if (first < 0) {
|
||||
first = 0;
|
||||
@@ -2367,9 +2401,9 @@ StringRplcCmd(
|
||||
if (objc == 5) {
|
||||
Tcl_AppendObjToObj(resultPtr, objv[4]);
|
||||
}
|
||||
if (last < length) {
|
||||
if (last < end) {
|
||||
Tcl_AppendUnicodeToObj(resultPtr, ustring + last + 1,
|
||||
length - last);
|
||||
end - last);
|
||||
}
|
||||
Tcl_SetObjResult(interp, resultPtr);
|
||||
}
|
||||
@@ -2436,7 +2470,7 @@ StringStartCmd(
|
||||
int objc, /* Number of arguments. */
|
||||
Tcl_Obj *const objv[]) /* Argument objects. */
|
||||
{
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
const char *p, *string;
|
||||
int cur, index, length, numChars;
|
||||
|
||||
@@ -2497,7 +2531,7 @@ StringEndCmd(
|
||||
int objc, /* Number of arguments. */
|
||||
Tcl_Obj *const objv[]) /* Argument objects. */
|
||||
{
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
const char *p, *end, *string;
|
||||
int cur, index, length, numChars;
|
||||
|
||||
@@ -2565,10 +2599,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 length2, i, match, nocase = 0, reqlength = -1;
|
||||
|
||||
if (objc < 3 || objc > 6) {
|
||||
str_cmp_args:
|
||||
@@ -2607,78 +2639,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;
|
||||
@@ -2715,11 +2676,194 @@ 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;
|
||||
|
||||
if ((status = TclStringCmpOpts(interp, objc, objv, &nocase, &reqlength))
|
||||
!= 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 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 = "";
|
||||
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 = "";
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -2728,106 +2872,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;
|
||||
}
|
||||
|
||||
@@ -3250,8 +3315,7 @@ StringTrimCmd(
|
||||
}
|
||||
string1 = TclGetStringFromObj(objv[1], &length1);
|
||||
|
||||
triml = TclTrimLeft(string1, length1, string2, length2);
|
||||
trimr = TclTrimRight(string1 + triml, length1 - triml, string2, length2);
|
||||
triml = TclTrim(string1, length1, string2, length2, &trimr);
|
||||
|
||||
Tcl_SetObjResult(interp,
|
||||
Tcl_NewStringObj(string1 + triml, length1 - triml - trimr));
|
||||
|
||||
+15
-3
@@ -322,11 +322,22 @@ TclCompileArraySetCmd(
|
||||
*/
|
||||
|
||||
if (isDataValid && !isDataEven) {
|
||||
/* Abandon custom compile and let invocation raise the error */
|
||||
code = TclCompileBasic2ArgCmd(interp, parsePtr, cmdPtr, envPtr);
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* We used to compile to the bytecode that would throw the error,
|
||||
* but that was wrong because it would not invoke the array trace
|
||||
* on the variable.
|
||||
*
|
||||
PushStringLiteral(envPtr, "list must have an even number of elements");
|
||||
PushStringLiteral(envPtr, "-errorcode {TCL ARGUMENT FORMAT}");
|
||||
TclEmitInstInt4(INST_RETURN_IMM, TCL_ERROR, envPtr);
|
||||
TclEmitInt4( 0, envPtr);
|
||||
goto done;
|
||||
*
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -404,6 +415,10 @@ TclCompileArraySetCmd(
|
||||
* Start issuing instructions to write to the array.
|
||||
*/
|
||||
|
||||
TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
|
||||
TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr);
|
||||
TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex, envPtr);
|
||||
|
||||
CompileWord(envPtr, dataTokenPtr, interp, 2);
|
||||
if (!isDataLiteral || !isDataValid) {
|
||||
/*
|
||||
@@ -428,9 +443,6 @@ TclCompileArraySetCmd(
|
||||
TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1);
|
||||
}
|
||||
|
||||
TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
|
||||
TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr);
|
||||
TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex, envPtr);
|
||||
TclEmitInstInt4(INST_FOREACH_START, infoIndex, envPtr);
|
||||
offsetBack = CurrentOffset(envPtr);
|
||||
Emit14Inst( INST_LOAD_SCALAR, keyVar, envPtr);
|
||||
|
||||
+145
-271
@@ -28,56 +28,39 @@ static void CompileReturnInternal(CompileEnv *envPtr,
|
||||
static int IndexTailVarIfKnown(Tcl_Interp *interp,
|
||||
Tcl_Token *varTokenPtr, CompileEnv *envPtr);
|
||||
|
||||
#define INDEX_END (-2)
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* GetIndexFromToken --
|
||||
* TclGetIndexFromToken --
|
||||
*
|
||||
* Parse a token and get the encoded version of the index (as understood
|
||||
* by TEBC), assuming it is at all knowable at compile time. Only handles
|
||||
* indices that are integers or 'end' or 'end-integer'.
|
||||
* Parse a token to determine if an index value is known at
|
||||
* compile time.
|
||||
*
|
||||
* Returns:
|
||||
* TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
|
||||
*
|
||||
* Side effects:
|
||||
* Sets *index to the index value if successful.
|
||||
* When TCL_OK is returned, the encoded index value is written
|
||||
* to *index.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static inline int
|
||||
GetIndexFromToken(
|
||||
int
|
||||
TclGetIndexFromToken(
|
||||
Tcl_Token *tokenPtr,
|
||||
int *index)
|
||||
int before,
|
||||
int after,
|
||||
int *indexPtr)
|
||||
{
|
||||
Tcl_Obj *tmpObj = Tcl_NewObj();
|
||||
int result, idx;
|
||||
int result = TCL_ERROR;
|
||||
|
||||
if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
|
||||
Tcl_DecrRefCount(tmpObj);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
result = TclGetIntFromObj(NULL, tmpObj, &idx);
|
||||
if (result == TCL_OK) {
|
||||
if (idx < 0) {
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
} else {
|
||||
result = TclGetIntForIndexM(NULL, tmpObj, INDEX_END, &idx);
|
||||
if (result == TCL_OK && idx > INDEX_END) {
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
if (TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
|
||||
result = TclIndexEncode(NULL, tmpObj, before, after, indexPtr);
|
||||
}
|
||||
Tcl_DecrRefCount(tmpObj);
|
||||
|
||||
if (result == TCL_OK) {
|
||||
*index = idx;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -144,7 +127,7 @@ TclCompileGlobalCmd(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* TODO: Consider what value can pass throug the
|
||||
/* 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);
|
||||
@@ -1053,7 +1036,7 @@ TclCompileLassignCmd(
|
||||
*/
|
||||
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
|
||||
TclEmitInt4( INDEX_END, envPtr);
|
||||
TclEmitInt4( TCL_INDEX_END, envPtr);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -1104,14 +1087,14 @@ TclCompileLindexCmd(
|
||||
}
|
||||
|
||||
idxTokenPtr = TokenAfter(valTokenPtr);
|
||||
if (GetIndexFromToken(idxTokenPtr, &idx) == TCL_OK) {
|
||||
if (TclGetIndexFromToken(idxTokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_BEFORE,
|
||||
&idx) == TCL_OK) {
|
||||
/*
|
||||
* All checks have been completed, and we have exactly one of these
|
||||
* constructs:
|
||||
* lindex <arbitraryValue> <posInt>
|
||||
* lindex <arbitraryValue> end-<posInt>
|
||||
* This is best compiled as a push of the arbitrary value followed by
|
||||
* an "immediate lindex" which is the most efficient variety.
|
||||
* The idxTokenPtr parsed as a valid index value and was
|
||||
* encoded as expected by INST_LIST_INDEX_IMM.
|
||||
*
|
||||
* NOTE: that we rely on indexing before a list producing the
|
||||
* same result as indexing after a list.
|
||||
*/
|
||||
|
||||
CompileWord(envPtr, valTokenPtr, interp, 1);
|
||||
@@ -1258,7 +1241,7 @@ TclCompileListCmd(
|
||||
|
||||
if (concat && numWords == 2) {
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
|
||||
TclEmitInt4( INDEX_END, envPtr);
|
||||
TclEmitInt4( TCL_INDEX_END, envPtr);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -1332,21 +1315,25 @@ TclCompileLrangeCmd(
|
||||
}
|
||||
listTokenPtr = TokenAfter(parsePtr->tokenPtr);
|
||||
|
||||
tokenPtr = TokenAfter(listTokenPtr);
|
||||
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
|
||||
&idx1) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
/*
|
||||
* Parse the indices. Will only compile if both are constants and not an
|
||||
* _integer_ less than zero (since we reserve negative indices here for
|
||||
* end-relative indexing) or an end-based index greater than 'end' itself.
|
||||
* Token was an index value, and we treat all "first" indices
|
||||
* before the list same as the start of the list.
|
||||
*/
|
||||
|
||||
tokenPtr = TokenAfter(listTokenPtr);
|
||||
if (GetIndexFromToken(tokenPtr, &idx1) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
if (GetIndexFromToken(tokenPtr, &idx2) != TCL_OK) {
|
||||
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
|
||||
&idx2) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
/*
|
||||
* Token was an index value, and we treat all "last" indices
|
||||
* after the list same as the end of the list.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Issue instructions. It's not safe to skip doing the LIST_RANGE, as
|
||||
@@ -1396,21 +1383,30 @@ TclCompileLinsertCmd(
|
||||
*/
|
||||
|
||||
tokenPtr = TokenAfter(listTokenPtr);
|
||||
if (GetIndexFromToken(tokenPtr, &idx) != TCL_OK) {
|
||||
|
||||
/*
|
||||
* NOTE: This command treats all inserts at indices before the list
|
||||
* the same as inserts at the start of the list, and all inserts
|
||||
* after the list the same as inserts at the end of the list. We
|
||||
* make that transformation here so we can use the optimized bytecode
|
||||
* as much as possible.
|
||||
*/
|
||||
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_END,
|
||||
&idx) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are four main cases. If there are no values to insert, this is
|
||||
* just a confirm-listiness check. If the index is '0', this is a prepend.
|
||||
* If the index is 'end' (== INDEX_END), this is an append. Otherwise,
|
||||
* If the index is 'end' (== TCL_INDEX_END), this is an append. Otherwise,
|
||||
* this is a splice (== split, insert values as list, concat-3).
|
||||
*/
|
||||
|
||||
CompileWord(envPtr, listTokenPtr, interp, 1);
|
||||
if (parsePtr->numWords == 3) {
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
|
||||
TclEmitInt4( INDEX_END, envPtr);
|
||||
TclEmitInt4( TCL_INDEX_END, envPtr);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -1420,13 +1416,25 @@ TclCompileLinsertCmd(
|
||||
}
|
||||
TclEmitInstInt4( INST_LIST, i-3, envPtr);
|
||||
|
||||
if (idx == 0 /*start*/) {
|
||||
if (idx == TCL_INDEX_START) {
|
||||
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
} else if (idx == INDEX_END /*end*/) {
|
||||
} else if (idx == TCL_INDEX_END) {
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
} else {
|
||||
if (idx < 0) {
|
||||
/*
|
||||
* Here we handle two ranges for idx. First when idx > 0, we
|
||||
* want the first half of the split to end at index idx-1 and
|
||||
* the second half to start at index idx.
|
||||
* Second when idx < TCL_INDEX_END, indicating "end-N" indexing,
|
||||
* we want the first half of the split to end at index end-N and
|
||||
* the second half to start at index end-N+1. We accomplish this
|
||||
* with a pre-adjustment of the end-N value.
|
||||
* The root of this is that the commands [lrange] and [linsert]
|
||||
* differ in their interpretation of the "end" index.
|
||||
*/
|
||||
|
||||
if (idx < TCL_INDEX_END) {
|
||||
idx++;
|
||||
}
|
||||
TclEmitInstInt4( INST_OVER, 1, envPtr);
|
||||
@@ -1434,7 +1442,7 @@ TclCompileLinsertCmd(
|
||||
TclEmitInt4( idx-1, envPtr);
|
||||
TclEmitInstInt4( INST_REVERSE, 3, envPtr);
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
|
||||
TclEmitInt4( INDEX_END, envPtr);
|
||||
TclEmitInt4( TCL_INDEX_END, envPtr);
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
}
|
||||
@@ -1464,250 +1472,116 @@ TclCompileLreplaceCmd(
|
||||
{
|
||||
Tcl_Token *tokenPtr, *listTokenPtr;
|
||||
DefineLineInformation; /* TIP #280 */
|
||||
Tcl_Obj *tmpObj;
|
||||
int idx1, idx2, i, offset, offset2;
|
||||
int idx1, idx2, i;
|
||||
int emptyPrefix=1, suffixStart = 0;
|
||||
|
||||
if (parsePtr->numWords < 4) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
listTokenPtr = TokenAfter(parsePtr->tokenPtr);
|
||||
|
||||
/*
|
||||
* Parse the indices. Will only compile if both are constants and not an
|
||||
* _integer_ less than zero (since we reserve negative indices here for
|
||||
* end-relative indexing) or an end-based index greater than 'end' itself.
|
||||
*/
|
||||
|
||||
tokenPtr = TokenAfter(listTokenPtr);
|
||||
if (GetIndexFromToken(tokenPtr, &idx1) != TCL_OK) {
|
||||
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
|
||||
&idx1) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
if (GetIndexFromToken(tokenPtr, &idx2) != TCL_OK) {
|
||||
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
|
||||
&idx2) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* idx1, idx2 are now in canonical form:
|
||||
* General structure of the [lreplace] result is
|
||||
* prefix replacement suffix
|
||||
* In a few cases we can predict various parts will be empty and
|
||||
* take advantage.
|
||||
*
|
||||
* - integer: [0,len+1]
|
||||
* - end index: INDEX_END
|
||||
* - -ive offset: INDEX_END-[len-1,0]
|
||||
* - +ive offset: INDEX_END+1
|
||||
* The proper suffix begins with the greater of indices idx1 or
|
||||
* idx2 + 1. If we cannot tell at compile time which is greater,
|
||||
* we must defer to direct evaluation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Compilation fails when one index is end-based but the other isn't.
|
||||
* Fixing this will require more bytecodes, but this is a workaround for
|
||||
* now. [Bug 47ac84309b]
|
||||
*/
|
||||
|
||||
if ((idx1 <= INDEX_END) != (idx2 <= INDEX_END)) {
|
||||
if (idx1 == TCL_INDEX_AFTER) {
|
||||
suffixStart = idx1;
|
||||
} else if (idx2 == TCL_INDEX_BEFORE) {
|
||||
suffixStart = idx1;
|
||||
} else if (idx2 == TCL_INDEX_END) {
|
||||
suffixStart = TCL_INDEX_AFTER;
|
||||
} else if (((idx2 < TCL_INDEX_END) && (idx1 <= TCL_INDEX_END))
|
||||
|| ((idx2 >= TCL_INDEX_START) && (idx1 >= TCL_INDEX_START))) {
|
||||
suffixStart = (idx1 > idx2 + 1) ? idx1 : idx2 + 1;
|
||||
} else {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if (idx2 != INDEX_END && idx2 >= 0 && idx2 < idx1) {
|
||||
idx2 = idx1 - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Work out what this [lreplace] is actually doing.
|
||||
*/
|
||||
|
||||
tmpObj = NULL;
|
||||
/* All paths start with computing/pushing the original value. */
|
||||
CompileWord(envPtr, listTokenPtr, interp, 1);
|
||||
if (parsePtr->numWords == 4) {
|
||||
if (idx1 == 0) {
|
||||
if (idx2 == INDEX_END) {
|
||||
goto dropAll;
|
||||
}
|
||||
idx1 = idx2 + 1;
|
||||
idx2 = INDEX_END;
|
||||
goto dropEnd;
|
||||
} else if (idx2 == INDEX_END) {
|
||||
idx2 = idx1 - 1;
|
||||
idx1 = 0;
|
||||
goto dropEnd;
|
||||
} else {
|
||||
if (idx2 < idx1) {
|
||||
idx2 = idx1 - 1;
|
||||
}
|
||||
if (idx1 > 0) {
|
||||
tmpObj = Tcl_NewIntObj(idx1);
|
||||
Tcl_IncrRefCount(tmpObj);
|
||||
}
|
||||
goto dropRange;
|
||||
}
|
||||
}
|
||||
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
for (i=4 ; i<parsePtr->numWords ; i++) {
|
||||
CompileWord(envPtr, tokenPtr, interp, i);
|
||||
/*
|
||||
* Push all the replacement values next so any errors raised in
|
||||
* creating them get raised first.
|
||||
*/
|
||||
if (parsePtr->numWords > 4) {
|
||||
/* Push the replacement arguments */
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
for (i=4 ; i<parsePtr->numWords ; i++) {
|
||||
CompileWord(envPtr, tokenPtr, interp, i);
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
}
|
||||
|
||||
/* Make a list of them... */
|
||||
TclEmitInstInt4( INST_LIST, i - 4, envPtr);
|
||||
|
||||
emptyPrefix = 0;
|
||||
}
|
||||
TclEmitInstInt4( INST_LIST, i - 4, envPtr);
|
||||
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
|
||||
if (idx1 == 0) {
|
||||
if (idx2 == INDEX_END) {
|
||||
goto replaceAll;
|
||||
|
||||
if ((idx1 == suffixStart) && (parsePtr->numWords == 4)) {
|
||||
/*
|
||||
* This is a "no-op". Example: [lreplace {a b c} 2 0]
|
||||
* We still do a list operation to get list-verification
|
||||
* and canonicalization side effects.
|
||||
*/
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
|
||||
TclEmitInt4( TCL_INDEX_END, envPtr);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
if (idx1 != TCL_INDEX_START) {
|
||||
/* Prefix may not be empty; generate bytecode to push it */
|
||||
if (emptyPrefix) {
|
||||
TclEmitOpcode( INST_DUP, envPtr);
|
||||
} else {
|
||||
TclEmitInstInt4( INST_OVER, 1, envPtr);
|
||||
}
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
|
||||
TclEmitInt4( idx1 - 1, envPtr);
|
||||
if (!emptyPrefix) {
|
||||
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
}
|
||||
emptyPrefix = 0;
|
||||
}
|
||||
|
||||
if (!emptyPrefix) {
|
||||
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
|
||||
}
|
||||
|
||||
if (suffixStart == TCL_INDEX_AFTER) {
|
||||
TclEmitOpcode( INST_POP, envPtr);
|
||||
if (emptyPrefix) {
|
||||
PushStringLiteral(envPtr, "");
|
||||
}
|
||||
idx1 = idx2 + 1;
|
||||
idx2 = INDEX_END;
|
||||
goto replaceHead;
|
||||
} else if (idx2 == INDEX_END) {
|
||||
idx2 = idx1 - 1;
|
||||
idx1 = 0;
|
||||
goto replaceTail;
|
||||
} else {
|
||||
if (idx2 < idx1) {
|
||||
idx2 = idx1 - 1;
|
||||
/* Suffix may not be empty; generate bytecode to push it */
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, suffixStart, envPtr);
|
||||
TclEmitInt4( TCL_INDEX_END, envPtr);
|
||||
if (!emptyPrefix) {
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
}
|
||||
if (idx1 > 0) {
|
||||
tmpObj = Tcl_NewIntObj(idx1);
|
||||
Tcl_IncrRefCount(tmpObj);
|
||||
}
|
||||
goto replaceRange;
|
||||
}
|
||||
|
||||
/*
|
||||
* Issue instructions to perform the operations relating to configurations
|
||||
* that just drop. The only argument pushed on the stack is the list to
|
||||
* operate on.
|
||||
*/
|
||||
|
||||
dropAll: /* This just ensures the arg is a list. */
|
||||
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
|
||||
TclEmitOpcode( INST_POP, envPtr);
|
||||
PushStringLiteral(envPtr, "");
|
||||
goto done;
|
||||
|
||||
dropEnd:
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
|
||||
TclEmitInt4( idx2, envPtr);
|
||||
goto done;
|
||||
|
||||
dropRange:
|
||||
if (tmpObj != NULL) {
|
||||
/*
|
||||
* Emit bytecode to check the list length.
|
||||
*/
|
||||
|
||||
TclEmitOpcode( INST_DUP, envPtr);
|
||||
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
|
||||
TclEmitPush(TclAddLiteralObj(envPtr, tmpObj, NULL), envPtr);
|
||||
TclEmitOpcode( INST_GE, envPtr);
|
||||
offset = CurrentOffset(envPtr);
|
||||
TclEmitInstInt1( INST_JUMP_TRUE1, 0, envPtr);
|
||||
|
||||
/*
|
||||
* Emit an error if we've been given an empty list.
|
||||
*/
|
||||
|
||||
TclEmitOpcode( INST_DUP, envPtr);
|
||||
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
|
||||
offset2 = CurrentOffset(envPtr);
|
||||
TclEmitInstInt1( INST_JUMP_FALSE1, 0, envPtr);
|
||||
TclEmitPush(TclAddLiteralObj(envPtr, Tcl_ObjPrintf(
|
||||
"list doesn't contain element %d", idx1), NULL), envPtr);
|
||||
CompileReturnInternal(envPtr, INST_RETURN_IMM, TCL_ERROR, 0,
|
||||
Tcl_ObjPrintf("-errorcode {TCL OPERATION LREPLACE BADIDX}"));
|
||||
TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset,
|
||||
envPtr->codeStart + offset + 1);
|
||||
TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset2,
|
||||
envPtr->codeStart + offset2 + 1);
|
||||
TclAdjustStackDepth(-1, envPtr);
|
||||
}
|
||||
TclEmitOpcode( INST_DUP, envPtr);
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
|
||||
TclEmitInt4( idx1 - 1, envPtr);
|
||||
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx2 + 1, envPtr);
|
||||
TclEmitInt4( INDEX_END, envPtr);
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Issue instructions to perform the operations relating to configurations
|
||||
* that do real replacement. All arguments are pushed and assembled into a
|
||||
* pair: the list of values to replace with, and the list to do the
|
||||
* surgery on.
|
||||
*/
|
||||
|
||||
replaceAll:
|
||||
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
|
||||
TclEmitOpcode( INST_POP, envPtr);
|
||||
goto done;
|
||||
|
||||
replaceHead:
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
|
||||
TclEmitInt4( idx2, envPtr);
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
goto done;
|
||||
|
||||
replaceTail:
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
|
||||
TclEmitInt4( idx2, envPtr);
|
||||
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
goto done;
|
||||
|
||||
replaceRange:
|
||||
if (tmpObj != NULL) {
|
||||
/*
|
||||
* Emit bytecode to check the list length.
|
||||
*/
|
||||
|
||||
TclEmitOpcode( INST_DUP, envPtr);
|
||||
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
|
||||
|
||||
/*
|
||||
* Check the list length vs idx1.
|
||||
*/
|
||||
|
||||
TclEmitPush(TclAddLiteralObj(envPtr, tmpObj, NULL), envPtr);
|
||||
TclEmitOpcode( INST_GE, envPtr);
|
||||
offset = CurrentOffset(envPtr);
|
||||
TclEmitInstInt1( INST_JUMP_TRUE1, 0, envPtr);
|
||||
|
||||
/*
|
||||
* Emit an error if we've been given an empty list.
|
||||
*/
|
||||
|
||||
TclEmitOpcode( INST_DUP, envPtr);
|
||||
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
|
||||
offset2 = CurrentOffset(envPtr);
|
||||
TclEmitInstInt1( INST_JUMP_FALSE1, 0, envPtr);
|
||||
TclEmitPush(TclAddLiteralObj(envPtr, Tcl_ObjPrintf(
|
||||
"list doesn't contain element %d", idx1), NULL), envPtr);
|
||||
CompileReturnInternal(envPtr, INST_RETURN_IMM, TCL_ERROR, 0,
|
||||
Tcl_ObjPrintf("-errorcode {TCL OPERATION LREPLACE BADIDX}"));
|
||||
TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset,
|
||||
envPtr->codeStart + offset + 1);
|
||||
TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset2,
|
||||
envPtr->codeStart + offset2 + 1);
|
||||
TclAdjustStackDepth(-1, envPtr);
|
||||
}
|
||||
TclEmitOpcode( INST_DUP, envPtr);
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
|
||||
TclEmitInt4( idx1 - 1, envPtr);
|
||||
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
|
||||
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx2 + 1, envPtr);
|
||||
TclEmitInt4( INDEX_END, envPtr);
|
||||
TclEmitInstInt4( INST_REVERSE, 3, envPtr);
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
|
||||
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Clean up the allocated memory.
|
||||
*/
|
||||
|
||||
done:
|
||||
if (tmpObj != NULL) {
|
||||
Tcl_DecrRefCount(tmpObj);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -2933,7 +2807,7 @@ TclCompileVariableCmd(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* TODO: Consider what value can pass throug the
|
||||
/* 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);
|
||||
|
||||
+183
-137
@@ -107,58 +107,6 @@ const AuxDataType tclJumptableInfoType = {
|
||||
#define INVOKE(name) \
|
||||
TclEmitInvoke(envPtr,INST_##name)
|
||||
|
||||
#define INDEX_END (-2)
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* GetIndexFromToken --
|
||||
*
|
||||
* Parse a token and get the encoded version of the index (as understood
|
||||
* by TEBC), assuming it is at all knowable at compile time. Only handles
|
||||
* indices that are integers or 'end' or 'end-integer'.
|
||||
*
|
||||
* Returns:
|
||||
* TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
|
||||
*
|
||||
* Side effects:
|
||||
* Sets *index to the index value if successful.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static inline int
|
||||
GetIndexFromToken(
|
||||
Tcl_Token *tokenPtr,
|
||||
int *index)
|
||||
{
|
||||
Tcl_Obj *tmpObj = Tcl_NewObj();
|
||||
int result, idx;
|
||||
|
||||
if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
|
||||
Tcl_DecrRefCount(tmpObj);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
result = TclGetIntFromObj(NULL, tmpObj, &idx);
|
||||
if (result == TCL_OK) {
|
||||
if (idx < 0) {
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
} else {
|
||||
result = TclGetIntForIndexM(NULL, tmpObj, INDEX_END, &idx);
|
||||
if (result == TCL_OK && idx > INDEX_END) {
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
}
|
||||
Tcl_DecrRefCount(tmpObj);
|
||||
|
||||
if (result == TCL_OK) {
|
||||
*index = idx;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -982,22 +930,48 @@ TclCompileStringRangeCmd(
|
||||
fromTokenPtr = TokenAfter(stringTokenPtr);
|
||||
toTokenPtr = TokenAfter(fromTokenPtr);
|
||||
|
||||
/* Every path must push the string argument */
|
||||
CompileWord(envPtr, stringTokenPtr, interp, 1);
|
||||
|
||||
/*
|
||||
* Parse the two indices.
|
||||
*/
|
||||
|
||||
if (GetIndexFromToken(fromTokenPtr, &idx1) != TCL_OK) {
|
||||
if (TclGetIndexFromToken(fromTokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
|
||||
&idx1) != TCL_OK) {
|
||||
goto nonConstantIndices;
|
||||
}
|
||||
if (GetIndexFromToken(toTokenPtr, &idx2) != TCL_OK) {
|
||||
/*
|
||||
* Token parsed as an index expression. We treat all indices before
|
||||
* the string the same as the start of the string.
|
||||
*/
|
||||
|
||||
if (idx1 == TCL_INDEX_AFTER) {
|
||||
/* [string range $s end+1 $last] must be empty string */
|
||||
OP( POP);
|
||||
PUSH( "");
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
if (TclGetIndexFromToken(toTokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
|
||||
&idx2) != TCL_OK) {
|
||||
goto nonConstantIndices;
|
||||
}
|
||||
/*
|
||||
* Token parsed as an index expression. We treat all indices after
|
||||
* the string the same as the end of the string.
|
||||
*/
|
||||
if (idx2 == TCL_INDEX_BEFORE) {
|
||||
/* [string range $s $first -1] must be empty string */
|
||||
OP( POP);
|
||||
PUSH( "");
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Push the operand onto the stack and then the substring operation.
|
||||
*/
|
||||
|
||||
CompileWord(envPtr, stringTokenPtr, interp, 1);
|
||||
OP44( STR_RANGE_IMM, idx1, idx2);
|
||||
return TCL_OK;
|
||||
|
||||
@@ -1006,7 +980,6 @@ TclCompileStringRangeCmd(
|
||||
*/
|
||||
|
||||
nonConstantIndices:
|
||||
CompileWord(envPtr, stringTokenPtr, interp, 1);
|
||||
CompileWord(envPtr, fromTokenPtr, interp, 2);
|
||||
CompileWord(envPtr, toTokenPtr, interp, 3);
|
||||
OP( STR_RANGE);
|
||||
@@ -1022,124 +995,197 @@ TclCompileStringReplaceCmd(
|
||||
* compiled. */
|
||||
CompileEnv *envPtr) /* Holds the resulting instructions. */
|
||||
{
|
||||
Tcl_Token *tokenPtr, *valueTokenPtr, *replacementTokenPtr = NULL;
|
||||
Tcl_Token *tokenPtr, *valueTokenPtr;
|
||||
DefineLineInformation; /* TIP #280 */
|
||||
int idx1, idx2;
|
||||
int first, last;
|
||||
|
||||
if (parsePtr->numWords < 4 || parsePtr->numWords > 5) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* Bytecode to compute/push string argument being replaced */
|
||||
valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
|
||||
if (parsePtr->numWords == 5) {
|
||||
tokenPtr = TokenAfter(valueTokenPtr);
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
replacementTokenPtr = TokenAfter(tokenPtr);
|
||||
}
|
||||
CompileWord(envPtr, valueTokenPtr, interp, 1);
|
||||
|
||||
/*
|
||||
* Parse the indices. Will only compile special cases if both are
|
||||
* constants and not an _integer_ less than zero (since we reserve
|
||||
* negative indices here for end-relative indexing) or an end-based index
|
||||
* greater than 'end' itself.
|
||||
* Check for first index known and useful at compile time.
|
||||
*/
|
||||
|
||||
tokenPtr = TokenAfter(valueTokenPtr);
|
||||
if (GetIndexFromToken(tokenPtr, &idx1) != TCL_OK) {
|
||||
goto genericReplace;
|
||||
}
|
||||
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
if (GetIndexFromToken(tokenPtr, &idx2) != TCL_OK) {
|
||||
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_AFTER,
|
||||
&first) != TCL_OK) {
|
||||
goto genericReplace;
|
||||
}
|
||||
|
||||
/*
|
||||
* We handle these replacements specially: first character (where
|
||||
* idx1=idx2=0) and last character (where idx1=idx2=INDEX_END). Anything
|
||||
* else and the semantics get rather screwy.
|
||||
* Check for last index known and useful at compile time.
|
||||
*/
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_AFTER,
|
||||
&last) != TCL_OK) {
|
||||
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
|
||||
* replacing an empty substring. Precisely, it is a no-op when
|
||||
*
|
||||
* (last < first) OR
|
||||
* (last < 0) OR
|
||||
* (end < first)
|
||||
*
|
||||
* For some compile-time values we can detect these cases, and
|
||||
* compile direct to bytecode implementing the no-op.
|
||||
*/
|
||||
|
||||
if (idx1 == 0 && idx2 == 0) {
|
||||
int notEq, end;
|
||||
if ((last == TCL_INDEX_BEFORE) /* Know (last < 0) */
|
||||
|| (first == TCL_INDEX_AFTER) /* Know (first > end) */
|
||||
|
||||
/*
|
||||
* Just working with the first character.
|
||||
* Tricky to determine when runtime (last < first) can be
|
||||
* certainly known based on the encoded values. Consider the
|
||||
* cases...
|
||||
*
|
||||
* (first <= TCL_INDEX_END) &&
|
||||
* (last == TCL_INDEX_AFTER) => cannot tell REJECT
|
||||
* (last <= TCL_INDEX END) && (last < first) => ACCEPT
|
||||
* else => cannot tell REJECT
|
||||
*/
|
||||
|
||||
CompileWord(envPtr, valueTokenPtr, interp, 1);
|
||||
if (replacementTokenPtr == NULL) {
|
||||
/* Drop first */
|
||||
OP44( STR_RANGE_IMM, 1, INDEX_END);
|
||||
return TCL_OK;
|
||||
}
|
||||
/* Replace first */
|
||||
CompileWord(envPtr, replacementTokenPtr, interp, 4);
|
||||
OP4( OVER, 1);
|
||||
PUSH( "");
|
||||
OP( STR_EQ);
|
||||
JUMP1( JUMP_FALSE, notEq);
|
||||
OP( POP);
|
||||
JUMP1( JUMP, end);
|
||||
FIXJUMP1(notEq);
|
||||
TclAdjustStackDepth(1, envPtr);
|
||||
OP4( REVERSE, 2);
|
||||
OP44( STR_RANGE_IMM, 1, INDEX_END);
|
||||
OP1( STR_CONCAT1, 2);
|
||||
FIXJUMP1(end);
|
||||
return TCL_OK;
|
||||
|
||||
} else if (idx1 == INDEX_END && idx2 == INDEX_END) {
|
||||
int notEq, end;
|
||||
|
||||
|| ((first <= TCL_INDEX_END) && (last <= TCL_INDEX_END)
|
||||
&& (last < first)) /* Know (last < first) */
|
||||
/*
|
||||
* Just working with the last character.
|
||||
* (first == TCL_INDEX_BEFORE) &&
|
||||
* (last == TCL_INDEX_AFTER) => (first < last) REJECT
|
||||
* (last <= TCL_INDEX_END) => cannot tell REJECT
|
||||
* else => (first < last) REJECT
|
||||
*
|
||||
* else [[first >= TCL_INDEX_START]] &&
|
||||
* (last == TCL_INDEX_AFTER) => cannot tell REJECT
|
||||
* (last <= TCL_INDEX_END) => cannot tell REJECT
|
||||
* else [[last >= TCL_INDEX START]] && (last < first) => ACCEPT
|
||||
*/
|
||||
|
||||
CompileWord(envPtr, valueTokenPtr, interp, 1);
|
||||
if (replacementTokenPtr == NULL) {
|
||||
/* Drop last */
|
||||
OP44( STR_RANGE_IMM, 0, INDEX_END-1);
|
||||
return TCL_OK;
|
||||
|| ((first >= TCL_INDEX_START) && (last >= TCL_INDEX_START)
|
||||
&& (last < first))) { /* Know (last < first) */
|
||||
if (parsePtr->numWords == 5) {
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
CompileWord(envPtr, tokenPtr, interp, 4);
|
||||
OP( POP); /* Pop newString */
|
||||
}
|
||||
/* Replace last */
|
||||
CompileWord(envPtr, replacementTokenPtr, interp, 4);
|
||||
OP4( OVER, 1);
|
||||
PUSH( "");
|
||||
OP( STR_EQ);
|
||||
JUMP1( JUMP_FALSE, notEq);
|
||||
OP( POP);
|
||||
JUMP1( JUMP, end);
|
||||
FIXJUMP1(notEq);
|
||||
TclAdjustStackDepth(1, envPtr);
|
||||
OP4( REVERSE, 2);
|
||||
OP44( STR_RANGE_IMM, 0, INDEX_END-1);
|
||||
OP4( REVERSE, 2);
|
||||
OP1( STR_CONCAT1, 2);
|
||||
FIXJUMP1(end);
|
||||
/* Original string argument now on TOS as result */
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
if (parsePtr->numWords == 5) {
|
||||
/*
|
||||
* When we have a string replacement, we have to take care about
|
||||
* not replacing empty substrings that [string replace] promises
|
||||
* not to replace
|
||||
*
|
||||
* The remaining index values might be suitable for conventional
|
||||
* string replacement, but only if they cannot possibly meet the
|
||||
* conditions described above at runtime. If there's a chance they
|
||||
* might, we would have to emit bytecode to check and at that point
|
||||
* we're paying more in bytecode execution time than would make
|
||||
* things worthwhile. Trouble is we are very limited in
|
||||
* how much we can detect that at compile time. After decoding,
|
||||
* we need, first:
|
||||
*
|
||||
* (first <= end)
|
||||
*
|
||||
* The encoded indices (first <= TCL_INDEX END) and
|
||||
* (first == TCL_INDEX_BEFORE) always meets this condition, but
|
||||
* any other encoded first index has some list for which it fails.
|
||||
*
|
||||
* We also need, second:
|
||||
*
|
||||
* (last >= 0)
|
||||
*
|
||||
* The encoded indices (last >= TCL_INDEX_START) and
|
||||
* (last == TCL_INDEX_AFTER) always meet this condition but any
|
||||
* other encoded last index has some list for which it fails.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if ((first == TCL_INDEX_BEFORE) && (last >= TCL_INDEX_START)) {
|
||||
/* empty prefix */
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
CompileWord(envPtr, tokenPtr, interp, 4);
|
||||
OP4( REVERSE, 2);
|
||||
if (last == TCL_INDEX_AFTER) {
|
||||
OP( POP); /* Pop original */
|
||||
} else {
|
||||
OP44( STR_RANGE_IMM, last + 1, TCL_INDEX_END);
|
||||
OP1( STR_CONCAT1, 2);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
if ((last == TCL_INDEX_AFTER) && (first <= TCL_INDEX_END)) {
|
||||
OP44( STR_RANGE_IMM, 0, first-1);
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
CompileWord(envPtr, tokenPtr, interp, 4);
|
||||
OP1( STR_CONCAT1, 2);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/* FLOW THROUGH TO genericReplace */
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Need to process indices at runtime. This could be because the
|
||||
* indices are not constants, or because we need to resolve them to
|
||||
* absolute indices to work out if a replacement is going to happen.
|
||||
* In any case, to runtime it is.
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if ((first == TCL_INDEX_BEFORE) || (first == TCL_INDEX_START)) {
|
||||
/* empty prefix - build suffix only */
|
||||
|
||||
if ((last == TCL_INDEX_END) || (last == TCL_INDEX_AFTER)) {
|
||||
/* empty suffix too => empty result */
|
||||
OP( POP); /* Pop original */
|
||||
PUSH ( "");
|
||||
return TCL_OK;
|
||||
}
|
||||
OP44( STR_RANGE_IMM, last + 1, TCL_INDEX_END);
|
||||
return TCL_OK;
|
||||
} else {
|
||||
if ((last == TCL_INDEX_END) || (last == TCL_INDEX_AFTER)) {
|
||||
/* empty suffix - build prefix only */
|
||||
OP44( STR_RANGE_IMM, 0, first-1);
|
||||
return TCL_OK;
|
||||
}
|
||||
OP( DUP);
|
||||
OP44( STR_RANGE_IMM, 0, first-1);
|
||||
OP4( REVERSE, 2);
|
||||
OP44( STR_RANGE_IMM, last + 1, TCL_INDEX_END);
|
||||
OP1( STR_CONCAT1, 2);
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
genericReplace:
|
||||
CompileWord(envPtr, valueTokenPtr, interp, 1);
|
||||
tokenPtr = TokenAfter(valueTokenPtr);
|
||||
CompileWord(envPtr, tokenPtr, interp, 2);
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
CompileWord(envPtr, tokenPtr, interp, 3);
|
||||
if (replacementTokenPtr != NULL) {
|
||||
CompileWord(envPtr, replacementTokenPtr, interp, 4);
|
||||
if (parsePtr->numWords == 5) {
|
||||
tokenPtr = TokenAfter(tokenPtr);
|
||||
CompileWord(envPtr, tokenPtr, interp, 4);
|
||||
} else {
|
||||
PUSH( "");
|
||||
}
|
||||
OP( STR_REPLACE);
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -1885,7 +1885,7 @@ ParseLexeme(
|
||||
{
|
||||
const char *end;
|
||||
int scanned;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
Tcl_Obj *literal = NULL;
|
||||
unsigned char byte;
|
||||
|
||||
|
||||
+3
-20
@@ -1121,6 +1121,8 @@ MODULE_SCOPE int TclFixupForwardJump(CompileEnv *envPtr,
|
||||
int distThreshold);
|
||||
MODULE_SCOPE void TclFreeCompileEnv(CompileEnv *envPtr);
|
||||
MODULE_SCOPE void TclFreeJumpFixupArray(JumpFixupArray *fixupArrayPtr);
|
||||
MODULE_SCOPE int TclGetIndexFromToken(Tcl_Token *tokenPtr,
|
||||
int before, int after, int *indexPtr);
|
||||
MODULE_SCOPE void TclInitByteCodeObj(Tcl_Obj *objPtr,
|
||||
CompileEnv *envPtr);
|
||||
MODULE_SCOPE void TclInitCompileEnv(Tcl_Interp *interp,
|
||||
@@ -1159,25 +1161,6 @@ MODULE_SCOPE void TclPushVarName(Tcl_Interp *interp,
|
||||
Tcl_Token *varTokenPtr, CompileEnv *envPtr,
|
||||
int flags, int *localIndexPtr,
|
||||
int *isScalarPtr);
|
||||
|
||||
static inline void
|
||||
TclPreserveByteCode(
|
||||
register ByteCode *codePtr)
|
||||
{
|
||||
codePtr->refCount++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
TclReleaseByteCode(
|
||||
register ByteCode *codePtr)
|
||||
{
|
||||
if (codePtr->refCount-- > 1) {
|
||||
return;
|
||||
}
|
||||
/* Just dropped to refcount==0. Clean up. */
|
||||
TclCleanupByteCode(codePtr);
|
||||
}
|
||||
|
||||
MODULE_SCOPE void TclReleaseLiteral(Tcl_Interp *interp, Tcl_Obj *objPtr);
|
||||
MODULE_SCOPE void TclInvalidateCmdLiteral(Tcl_Interp *interp,
|
||||
const char *name, Namespace *nsPtr);
|
||||
@@ -1511,7 +1494,7 @@ MODULE_SCOPE int TclPushProcCallFrame(ClientData clientData,
|
||||
#endif
|
||||
|
||||
#define TclGetInt4AtPtr(p) \
|
||||
(((int) TclGetInt1AtPtr(p) << 24) | \
|
||||
(((int) (TclGetUInt1AtPtr(p) << 24)) | \
|
||||
(*((p)+1) << 16) | \
|
||||
(*((p)+2) << 8) | \
|
||||
(*((p)+3)))
|
||||
|
||||
+307
-247
@@ -1,14 +1,14 @@
|
||||
/* A Bison parser, made by GNU Bison 2.4.2. */
|
||||
/* A Bison parser, made by GNU Bison 2.3. */
|
||||
|
||||
/* Skeleton implementation for Bison's Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2006, 2009-2010 Free Software
|
||||
Foundation, Inc.
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@@ -16,7 +16,9 @@
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
@@ -45,7 +47,7 @@
|
||||
#define YYBISON 1
|
||||
|
||||
/* Bison version. */
|
||||
#define YYBISON_VERSION "2.4.2"
|
||||
#define YYBISON_VERSION "2.3"
|
||||
|
||||
/* Skeleton name. */
|
||||
#define YYSKELETON_NAME "yacc.c"
|
||||
@@ -53,24 +55,65 @@
|
||||
/* Pure parsers. */
|
||||
#define YYPURE 1
|
||||
|
||||
/* Push parsers. */
|
||||
#define YYPUSH 0
|
||||
|
||||
/* Pull parsers. */
|
||||
#define YYPULL 1
|
||||
|
||||
/* Using locations. */
|
||||
#define YYLSP_NEEDED 1
|
||||
|
||||
/* Substitute the variable and function names. */
|
||||
#define yyparse TclDateparse
|
||||
#define yylex TclDatelex
|
||||
#define yyerror TclDateerror
|
||||
#define yylval TclDatelval
|
||||
#define yychar TclDatechar
|
||||
#define yydebug TclDatedebug
|
||||
#define yynerrs TclDatenerrs
|
||||
#define yylloc TclDatelloc
|
||||
#define yyparse TclDateparse
|
||||
#define yylex TclDatelex
|
||||
#define yyerror TclDateerror
|
||||
#define yylval TclDatelval
|
||||
#define yychar TclDatechar
|
||||
#define yydebug TclDatedebug
|
||||
#define yynerrs TclDatenerrs
|
||||
#define yylloc TclDatelloc
|
||||
|
||||
/* Tokens. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||
know about them. */
|
||||
enum yytokentype {
|
||||
tAGO = 258,
|
||||
tDAY = 259,
|
||||
tDAYZONE = 260,
|
||||
tID = 261,
|
||||
tMERIDIAN = 262,
|
||||
tMONTH = 263,
|
||||
tMONTH_UNIT = 264,
|
||||
tSTARDATE = 265,
|
||||
tSEC_UNIT = 266,
|
||||
tSNUMBER = 267,
|
||||
tUNUMBER = 268,
|
||||
tZONE = 269,
|
||||
tEPOCH = 270,
|
||||
tDST = 271,
|
||||
tISOBASE = 272,
|
||||
tDAY_UNIT = 273,
|
||||
tNEXT = 274
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
#define tAGO 258
|
||||
#define tDAY 259
|
||||
#define tDAYZONE 260
|
||||
#define tID 261
|
||||
#define tMERIDIAN 262
|
||||
#define tMONTH 263
|
||||
#define tMONTH_UNIT 264
|
||||
#define tSTARDATE 265
|
||||
#define tSEC_UNIT 266
|
||||
#define tSNUMBER 267
|
||||
#define tUNUMBER 268
|
||||
#define tZONE 269
|
||||
#define tEPOCH 270
|
||||
#define tDST 271
|
||||
#define tISOBASE 272
|
||||
#define tDAY_UNIT 273
|
||||
#define tNEXT 274
|
||||
|
||||
|
||||
|
||||
|
||||
/* Copy the first part of user declarations. */
|
||||
|
||||
@@ -86,7 +129,6 @@
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution of
|
||||
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*
|
||||
*/
|
||||
#include "tclInt.h"
|
||||
|
||||
@@ -104,11 +146,73 @@
|
||||
* parsed fields will be returned.
|
||||
*/
|
||||
|
||||
#include "tclDate.h"
|
||||
typedef struct DateInfo {
|
||||
|
||||
Tcl_Obj* messages; /* Error messages */
|
||||
const char* separatrix; /* String separating messages */
|
||||
|
||||
time_t dateYear;
|
||||
time_t dateMonth;
|
||||
time_t dateDay;
|
||||
int dateHaveDate;
|
||||
|
||||
time_t dateHour;
|
||||
time_t dateMinutes;
|
||||
time_t dateSeconds;
|
||||
int dateMeridian;
|
||||
int dateHaveTime;
|
||||
|
||||
time_t dateTimezone;
|
||||
int dateDSTmode;
|
||||
int dateHaveZone;
|
||||
|
||||
time_t dateRelMonth;
|
||||
time_t dateRelDay;
|
||||
time_t dateRelSeconds;
|
||||
int dateHaveRel;
|
||||
|
||||
time_t dateMonthOrdinal;
|
||||
int dateHaveOrdinalMonth;
|
||||
|
||||
time_t dateDayOrdinal;
|
||||
time_t dateDayNumber;
|
||||
int dateHaveDay;
|
||||
|
||||
const char *dateStart;
|
||||
const char *dateInput;
|
||||
time_t *dateRelPointer;
|
||||
|
||||
int dateDigitCount;
|
||||
} DateInfo;
|
||||
|
||||
#define YYMALLOC ckalloc
|
||||
#define YYFREE(x) (ckfree((void*) (x)))
|
||||
|
||||
#define yyDSTmode (info->dateDSTmode)
|
||||
#define yyDayOrdinal (info->dateDayOrdinal)
|
||||
#define yyDayNumber (info->dateDayNumber)
|
||||
#define yyMonthOrdinal (info->dateMonthOrdinal)
|
||||
#define yyHaveDate (info->dateHaveDate)
|
||||
#define yyHaveDay (info->dateHaveDay)
|
||||
#define yyHaveOrdinalMonth (info->dateHaveOrdinalMonth)
|
||||
#define yyHaveRel (info->dateHaveRel)
|
||||
#define yyHaveTime (info->dateHaveTime)
|
||||
#define yyHaveZone (info->dateHaveZone)
|
||||
#define yyTimezone (info->dateTimezone)
|
||||
#define yyDay (info->dateDay)
|
||||
#define yyMonth (info->dateMonth)
|
||||
#define yyYear (info->dateYear)
|
||||
#define yyHour (info->dateHour)
|
||||
#define yyMinutes (info->dateMinutes)
|
||||
#define yySeconds (info->dateSeconds)
|
||||
#define yyMeridian (info->dateMeridian)
|
||||
#define yyRelMonth (info->dateRelMonth)
|
||||
#define yyRelDay (info->dateRelDay)
|
||||
#define yyRelSeconds (info->dateRelSeconds)
|
||||
#define yyRelPointer (info->dateRelPointer)
|
||||
#define yyInput (info->dateInput)
|
||||
#define yyDigitCount (info->dateDigitCount)
|
||||
|
||||
#define EPOCH 1970
|
||||
#define START_OF_TIME 1902
|
||||
#define END_OF_TIME 2037
|
||||
@@ -142,6 +246,13 @@ typedef enum _DSTMODE {
|
||||
DSTon, DSToff, DSTmaybe
|
||||
} DSTMODE;
|
||||
|
||||
/*
|
||||
* Meridian: am, pm, or 24-hour style.
|
||||
*/
|
||||
|
||||
typedef enum _MERIDIAN {
|
||||
MERam, MERpm, MER24
|
||||
} MERIDIAN;
|
||||
|
||||
|
||||
|
||||
@@ -163,49 +274,19 @@ typedef enum _DSTMODE {
|
||||
# define YYTOKEN_TABLE 0
|
||||
#endif
|
||||
|
||||
|
||||
/* Tokens. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||
know about them. */
|
||||
enum yytokentype {
|
||||
tAGO = 258,
|
||||
tDAY = 259,
|
||||
tDAYZONE = 260,
|
||||
tID = 261,
|
||||
tMERIDIAN = 262,
|
||||
tMONTH = 263,
|
||||
tMONTH_UNIT = 264,
|
||||
tSTARDATE = 265,
|
||||
tSEC_UNIT = 266,
|
||||
tSNUMBER = 267,
|
||||
tUNUMBER = 268,
|
||||
tZONE = 269,
|
||||
tEPOCH = 270,
|
||||
tDST = 271,
|
||||
tISOBASE = 272,
|
||||
tDAY_UNIT = 273,
|
||||
tNEXT = 274
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
typedef union YYSTYPE
|
||||
|
||||
{
|
||||
|
||||
|
||||
time_t Number;
|
||||
enum _MERIDIAN Meridian;
|
||||
}
|
||||
/* Line 187 of yacc.c. */
|
||||
|
||||
|
||||
|
||||
} YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
YYSTYPE;
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
#endif
|
||||
|
||||
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
|
||||
@@ -235,10 +316,14 @@ static int LookupWord(YYSTYPE* yylvalPtr, char *buff);
|
||||
DateInfo* info, const char *s);
|
||||
static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location,
|
||||
DateInfo* info);
|
||||
static time_t ToSeconds(time_t Hours, time_t Minutes,
|
||||
time_t Seconds, MERIDIAN Meridian);
|
||||
MODULE_SCOPE int yyparse(DateInfo*);
|
||||
|
||||
|
||||
|
||||
/* Line 216 of yacc.c. */
|
||||
|
||||
|
||||
#ifdef short
|
||||
# undef short
|
||||
@@ -274,21 +359,15 @@ typedef short int yytype_int16;
|
||||
#ifndef YYSIZE_T
|
||||
# ifdef __SIZE_TYPE__
|
||||
# define YYSIZE_T __SIZE_TYPE__
|
||||
# elif defined size_t
|
||||
# define YYSIZE_T size_t
|
||||
# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
|
||||
|| defined __cplusplus || defined _MSC_VER)
|
||||
# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
|
||||
# define YYSIZE_T size_t
|
||||
# else
|
||||
# define YYSIZE_T unsigned int
|
||||
# define YYSIZE_T size_t
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
|
||||
|
||||
#ifndef YY_
|
||||
# if defined YYENABLE_NLS && YYENABLE_NLS
|
||||
# if YYENABLE_NLS
|
||||
# if ENABLE_NLS
|
||||
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
|
||||
# define YY_(msgid) dgettext ("bison-runtime", msgid)
|
||||
@@ -313,14 +392,14 @@ typedef short int yytype_int16;
|
||||
#if (defined __STDC__ || defined __C99__FUNC__ \
|
||||
|| defined __cplusplus || defined _MSC_VER)
|
||||
static int
|
||||
YYID (int yyi)
|
||||
YYID (int i)
|
||||
#else
|
||||
static int
|
||||
YYID (yyi)
|
||||
int yyi;
|
||||
YYID (i)
|
||||
int i;
|
||||
#endif
|
||||
{
|
||||
return yyi;
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -402,9 +481,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
|
||||
/* A type that is properly aligned for any stack member. */
|
||||
union yyalloc
|
||||
{
|
||||
yytype_int16 yyss_alloc;
|
||||
YYSTYPE yyvs_alloc;
|
||||
YYLTYPE yyls_alloc;
|
||||
yytype_int16 yyss;
|
||||
YYSTYPE yyvs;
|
||||
YYLTYPE yyls;
|
||||
};
|
||||
|
||||
/* The size of the maximum gap between one aligned stack and the next. */
|
||||
@@ -439,12 +518,12 @@ union yyalloc
|
||||
elements in the stack, and YYPTR gives the new location of the
|
||||
stack. Advance YYPTR to a properly aligned location for the next
|
||||
stack. */
|
||||
# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
|
||||
# define YYSTACK_RELOCATE(Stack) \
|
||||
do \
|
||||
{ \
|
||||
YYSIZE_T yynewbytes; \
|
||||
YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
|
||||
Stack = &yyptr->Stack_alloc; \
|
||||
YYCOPY (&yyptr->Stack, Stack, yysize); \
|
||||
Stack = &yyptr->Stack; \
|
||||
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
|
||||
yyptr += yynewbytes / sizeof (*yyptr); \
|
||||
} \
|
||||
@@ -545,12 +624,12 @@ static const yytype_int8 yyrhs[] =
|
||||
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
|
||||
static const yytype_uint16 yyrline[] =
|
||||
{
|
||||
0, 152, 152, 153, 156, 159, 162, 165, 168, 171,
|
||||
174, 178, 183, 186, 192, 198, 206, 212, 223, 227,
|
||||
231, 237, 241, 245, 249, 253, 259, 263, 268, 273,
|
||||
278, 283, 287, 292, 296, 301, 308, 312, 318, 327,
|
||||
336, 346, 360, 365, 368, 371, 374, 377, 380, 385,
|
||||
388, 393, 397, 401, 407, 425, 428
|
||||
0, 225, 225, 226, 229, 232, 235, 238, 241, 244,
|
||||
247, 251, 256, 259, 265, 271, 279, 285, 296, 300,
|
||||
304, 310, 314, 318, 322, 326, 332, 336, 341, 346,
|
||||
351, 356, 360, 365, 369, 374, 381, 385, 391, 400,
|
||||
409, 419, 433, 438, 441, 444, 447, 450, 453, 458,
|
||||
461, 466, 470, 474, 480, 498, 501
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -704,18 +783,9 @@ static const yytype_uint8 yystos[] =
|
||||
|
||||
/* Like YYERROR except do call yyerror. This remains here temporarily
|
||||
to ease the transition to the new meaning of YYERROR, for GCC.
|
||||
Once GCC version 2 has supplanted version 1, this can go. However,
|
||||
YYFAIL appears to be in use. Nevertheless, it is formally deprecated
|
||||
in Bison 2.4.2's NEWS entry, where a plan to phase it out is
|
||||
discussed. */
|
||||
Once GCC version 2 has supplanted version 1, this can go. */
|
||||
|
||||
#define YYFAIL goto yyerrlab
|
||||
#if defined YYFAIL
|
||||
/* This is here to suppress warnings from the GCC cpp's
|
||||
-Wunused-macros. Normally we don't worry about that warning, but
|
||||
some users do, and we want to make it easy for users to remove
|
||||
YYFAIL uses, which will produce warnings from Bison 2.5. */
|
||||
#endif
|
||||
|
||||
#define YYRECOVERING() (!!yyerrstatus)
|
||||
|
||||
@@ -772,7 +842,7 @@ while (YYID (0))
|
||||
we won't break user code: when these are the locations we know. */
|
||||
|
||||
#ifndef YY_LOCATION_PRINT
|
||||
# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
|
||||
# if YYLTYPE_IS_TRIVIAL
|
||||
# define YY_LOCATION_PRINT(File, Loc) \
|
||||
fprintf (File, "%d.%d-%d.%d", \
|
||||
(Loc).first_line, (Loc).first_column, \
|
||||
@@ -891,20 +961,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, info)
|
||||
#if (defined __STDC__ || defined __C99__FUNC__ \
|
||||
|| defined __cplusplus || defined _MSC_VER)
|
||||
static void
|
||||
yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
|
||||
yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
|
||||
#else
|
||||
static void
|
||||
yy_stack_print (yybottom, yytop)
|
||||
yytype_int16 *yybottom;
|
||||
yytype_int16 *yytop;
|
||||
yy_stack_print (bottom, top)
|
||||
yytype_int16 *bottom;
|
||||
yytype_int16 *top;
|
||||
#endif
|
||||
{
|
||||
YYFPRINTF (stderr, "Stack now");
|
||||
for (; yybottom <= yytop; yybottom++)
|
||||
{
|
||||
int yybot = *yybottom;
|
||||
YYFPRINTF (stderr, " %d", yybot);
|
||||
}
|
||||
for (; bottom <= top; ++bottom)
|
||||
YYFPRINTF (stderr, " %d", *bottom);
|
||||
YYFPRINTF (stderr, "\n");
|
||||
}
|
||||
|
||||
@@ -940,11 +1007,11 @@ yy_reduce_print (yyvsp, yylsp, yyrule, info)
|
||||
/* The symbols being reduced. */
|
||||
for (yyi = 0; yyi < yynrhs; yyi++)
|
||||
{
|
||||
YYFPRINTF (stderr, " $%d = ", yyi + 1);
|
||||
fprintf (stderr, " $%d = ", yyi + 1);
|
||||
yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
|
||||
&(yyvsp[(yyi + 1) - (yynrhs)])
|
||||
, &(yylsp[(yyi + 1) - (yynrhs)]) , info);
|
||||
YYFPRINTF (stderr, "\n");
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1228,8 +1295,10 @@ yydestruct (yymsg, yytype, yyvaluep, yylocationp, info)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Prevent warnings from -Wmissing-prototypes. */
|
||||
|
||||
#ifdef YYPARSE_PARAM
|
||||
#if defined __STDC__ || defined __cplusplus
|
||||
int yyparse (void *YYPARSE_PARAM);
|
||||
@@ -1248,9 +1317,10 @@ int yyparse ();
|
||||
|
||||
|
||||
|
||||
/*-------------------------.
|
||||
| yyparse or yypush_parse. |
|
||||
`-------------------------*/
|
||||
|
||||
/*----------.
|
||||
| yyparse. |
|
||||
`----------*/
|
||||
|
||||
#ifdef YYPARSE_PARAM
|
||||
#if (defined __STDC__ || defined __C99__FUNC__ \
|
||||
@@ -1274,59 +1344,24 @@ yyparse (info)
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
/* The lookahead symbol. */
|
||||
/* The look-ahead symbol. */
|
||||
int yychar;
|
||||
|
||||
/* The semantic value of the lookahead symbol. */
|
||||
YYSTYPE yylval;
|
||||
/* The semantic value of the look-ahead symbol. */
|
||||
YYSTYPE yylval = {0};
|
||||
|
||||
/* Location data for the lookahead symbol. */
|
||||
/* Number of syntax errors so far. */
|
||||
int yynerrs;
|
||||
/* Location data for the look-ahead symbol. */
|
||||
YYLTYPE yylloc;
|
||||
|
||||
/* Number of syntax errors so far. */
|
||||
int yynerrs;
|
||||
|
||||
int yystate;
|
||||
/* Number of tokens to shift before error messages enabled. */
|
||||
int yyerrstatus;
|
||||
|
||||
/* The stacks and their tools:
|
||||
`yyss': related to states.
|
||||
`yyvs': related to semantic values.
|
||||
`yyls': related to locations.
|
||||
|
||||
Refer to the stacks thru separate pointers, to allow yyoverflow
|
||||
to reallocate them elsewhere. */
|
||||
|
||||
/* The state stack. */
|
||||
yytype_int16 yyssa[YYINITDEPTH];
|
||||
yytype_int16 *yyss;
|
||||
yytype_int16 *yyssp;
|
||||
|
||||
/* The semantic value stack. */
|
||||
YYSTYPE yyvsa[YYINITDEPTH];
|
||||
YYSTYPE *yyvs;
|
||||
YYSTYPE *yyvsp;
|
||||
|
||||
/* The location stack. */
|
||||
YYLTYPE yylsa[YYINITDEPTH];
|
||||
YYLTYPE *yyls;
|
||||
YYLTYPE *yylsp;
|
||||
|
||||
/* The locations where the error started and ended. */
|
||||
YYLTYPE yyerror_range[2];
|
||||
|
||||
YYSIZE_T yystacksize;
|
||||
|
||||
int yystate;
|
||||
int yyn;
|
||||
int yyresult;
|
||||
/* Lookahead token as an internal (translated) token number. */
|
||||
int yytoken;
|
||||
/* The variables used to return semantic value and location from the
|
||||
action routines. */
|
||||
YYSTYPE yyval;
|
||||
YYLTYPE yyloc;
|
||||
|
||||
/* Number of tokens to shift before error messages enabled. */
|
||||
int yyerrstatus;
|
||||
/* Look-ahead token as an internal (translated) token number. */
|
||||
int yytoken = 0;
|
||||
#if YYERROR_VERBOSE
|
||||
/* Buffer for error messages, and its allocated size. */
|
||||
char yymsgbuf[128];
|
||||
@@ -1334,37 +1369,63 @@ YYLTYPE yylloc;
|
||||
YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
|
||||
#endif
|
||||
|
||||
/* Three stacks and their tools:
|
||||
`yyss': related to states,
|
||||
`yyvs': related to semantic values,
|
||||
`yyls': related to locations.
|
||||
|
||||
Refer to the stacks thru separate pointers, to allow yyoverflow
|
||||
to reallocate them elsewhere. */
|
||||
|
||||
/* The state stack. */
|
||||
yytype_int16 yyssa[YYINITDEPTH];
|
||||
yytype_int16 *yyss = yyssa;
|
||||
yytype_int16 *yyssp;
|
||||
|
||||
/* The semantic value stack. */
|
||||
YYSTYPE yyvsa[YYINITDEPTH];
|
||||
YYSTYPE *yyvs = yyvsa;
|
||||
YYSTYPE *yyvsp;
|
||||
|
||||
/* The location stack. */
|
||||
YYLTYPE yylsa[YYINITDEPTH];
|
||||
YYLTYPE *yyls = yylsa;
|
||||
YYLTYPE *yylsp;
|
||||
/* The locations where the error started and ended. */
|
||||
YYLTYPE yyerror_range[2];
|
||||
|
||||
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
|
||||
|
||||
YYSIZE_T yystacksize = YYINITDEPTH;
|
||||
|
||||
/* The variables used to return semantic value and location from the
|
||||
action routines. */
|
||||
YYSTYPE yyval;
|
||||
YYLTYPE yyloc;
|
||||
|
||||
/* The number of symbols on the RHS of the reduced rule.
|
||||
Keep to zero when no symbol should be popped. */
|
||||
int yylen = 0;
|
||||
|
||||
yytoken = 0;
|
||||
yyss = yyssa;
|
||||
yyvs = yyvsa;
|
||||
yyls = yylsa;
|
||||
yystacksize = YYINITDEPTH;
|
||||
|
||||
YYDPRINTF ((stderr, "Starting parse\n"));
|
||||
|
||||
yystate = 0;
|
||||
yyerrstatus = 0;
|
||||
yynerrs = 0;
|
||||
yychar = YYEMPTY; /* Cause a token to be read. */
|
||||
yychar = YYEMPTY; /* Cause a token to be read. */
|
||||
|
||||
/* Initialize stack pointers.
|
||||
Waste one element of value and location stack
|
||||
so that they stay on the same level as the state stack.
|
||||
The wasted elements are never initialized. */
|
||||
|
||||
yyssp = yyss;
|
||||
yyvsp = yyvs;
|
||||
yylsp = yyls;
|
||||
|
||||
#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
|
||||
#if YYLTYPE_IS_TRIVIAL
|
||||
/* Initialize the default location before parsing starts. */
|
||||
yylloc.first_line = yylloc.last_line = 1;
|
||||
yylloc.first_column = yylloc.last_column = 1;
|
||||
yylloc.first_column = yylloc.last_column = 0;
|
||||
#endif
|
||||
|
||||
goto yysetstate;
|
||||
@@ -1403,7 +1464,6 @@ YYLTYPE yylloc;
|
||||
&yyvs1, yysize * sizeof (*yyvsp),
|
||||
&yyls1, yysize * sizeof (*yylsp),
|
||||
&yystacksize);
|
||||
|
||||
yyls = yyls1;
|
||||
yyss = yyss1;
|
||||
yyvs = yyvs1;
|
||||
@@ -1425,9 +1485,9 @@ YYLTYPE yylloc;
|
||||
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
|
||||
if (! yyptr)
|
||||
goto yyexhaustedlab;
|
||||
YYSTACK_RELOCATE (yyss_alloc, yyss);
|
||||
YYSTACK_RELOCATE (yyvs_alloc, yyvs);
|
||||
YYSTACK_RELOCATE (yyls_alloc, yyls);
|
||||
YYSTACK_RELOCATE (yyss);
|
||||
YYSTACK_RELOCATE (yyvs);
|
||||
YYSTACK_RELOCATE (yyls);
|
||||
# undef YYSTACK_RELOCATE
|
||||
if (yyss1 != yyssa)
|
||||
YYSTACK_FREE (yyss1);
|
||||
@@ -1448,9 +1508,6 @@ YYLTYPE yylloc;
|
||||
|
||||
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
|
||||
|
||||
if (yystate == YYFINAL)
|
||||
YYACCEPT;
|
||||
|
||||
goto yybackup;
|
||||
|
||||
/*-----------.
|
||||
@@ -1459,16 +1516,16 @@ YYLTYPE yylloc;
|
||||
yybackup:
|
||||
|
||||
/* Do appropriate processing given the current state. Read a
|
||||
lookahead token if we need one and don't already have one. */
|
||||
look-ahead token if we need one and don't already have one. */
|
||||
|
||||
/* First try to decide what to do without reference to lookahead token. */
|
||||
/* First try to decide what to do without reference to look-ahead token. */
|
||||
yyn = yypact[yystate];
|
||||
if (yyn == YYPACT_NINF)
|
||||
goto yydefault;
|
||||
|
||||
/* Not known => get a lookahead token if don't already have one. */
|
||||
/* Not known => get a look-ahead token if don't already have one. */
|
||||
|
||||
/* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
|
||||
/* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
|
||||
if (yychar == YYEMPTY)
|
||||
{
|
||||
YYDPRINTF ((stderr, "Reading a token: "));
|
||||
@@ -1500,16 +1557,20 @@ yybackup:
|
||||
goto yyreduce;
|
||||
}
|
||||
|
||||
if (yyn == YYFINAL)
|
||||
YYACCEPT;
|
||||
|
||||
/* Count tokens shifted since error; after three, turn off error
|
||||
status. */
|
||||
if (yyerrstatus)
|
||||
yyerrstatus--;
|
||||
|
||||
/* Shift the lookahead token. */
|
||||
/* Shift the look-ahead token. */
|
||||
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
|
||||
|
||||
/* Discard the shifted token. */
|
||||
yychar = YYEMPTY;
|
||||
/* Discard the shifted token unless it is eof. */
|
||||
if (yychar != YYEOF)
|
||||
yychar = YYEMPTY;
|
||||
|
||||
yystate = yyn;
|
||||
*++yyvsp = yylval;
|
||||
@@ -1817,16 +1878,16 @@ yyreduce:
|
||||
case 36:
|
||||
|
||||
{
|
||||
yyMonthOrdinalIncr = 1;
|
||||
yyMonthOrdinal = (yyvsp[(2) - (2)].Number);
|
||||
yyMonthOrdinal = 1;
|
||||
yyMonth = (yyvsp[(2) - (2)].Number);
|
||||
;}
|
||||
break;
|
||||
|
||||
case 37:
|
||||
|
||||
{
|
||||
yyMonthOrdinalIncr = (yyvsp[(2) - (3)].Number);
|
||||
yyMonthOrdinal = (yyvsp[(3) - (3)].Number);
|
||||
yyMonthOrdinal = (yyvsp[(2) - (3)].Number);
|
||||
yyMonth = (yyvsp[(3) - (3)].Number);
|
||||
;}
|
||||
break;
|
||||
|
||||
@@ -2001,6 +2062,7 @@ yyreduce:
|
||||
break;
|
||||
|
||||
|
||||
/* Line 1267 of yacc.c. */
|
||||
|
||||
default: break;
|
||||
}
|
||||
@@ -2077,7 +2139,7 @@ yyerrlab:
|
||||
|
||||
if (yyerrstatus == 3)
|
||||
{
|
||||
/* If just tried and failed to reuse lookahead token after an
|
||||
/* If just tried and failed to reuse look-ahead token after an
|
||||
error, discard it. */
|
||||
|
||||
if (yychar <= YYEOF)
|
||||
@@ -2094,7 +2156,7 @@ yyerrlab:
|
||||
}
|
||||
}
|
||||
|
||||
/* Else will try to reuse lookahead token after shifting the error
|
||||
/* Else will try to reuse look-ahead token after shifting the error
|
||||
token. */
|
||||
goto yyerrlab1;
|
||||
|
||||
@@ -2152,11 +2214,14 @@ yyerrlab1:
|
||||
YY_STACK_PRINT (yyss, yyssp);
|
||||
}
|
||||
|
||||
if (yyn == YYFINAL)
|
||||
YYACCEPT;
|
||||
|
||||
*++yyvsp = yylval;
|
||||
|
||||
yyerror_range[1] = yylloc;
|
||||
/* Using YYLLOC is tempting, but would change the location of
|
||||
the lookahead. YYLOC is available though. */
|
||||
the look-ahead. YYLOC is available though. */
|
||||
YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
|
||||
*++yylsp = yyloc;
|
||||
|
||||
@@ -2181,7 +2246,7 @@ yyabortlab:
|
||||
yyresult = 1;
|
||||
goto yyreturn;
|
||||
|
||||
#if !defined(yyoverflow) || YYERROR_VERBOSE
|
||||
#ifndef yyoverflow
|
||||
/*-------------------------------------------------.
|
||||
| yyexhaustedlab -- memory exhaustion comes here. |
|
||||
`-------------------------------------------------*/
|
||||
@@ -2192,7 +2257,7 @@ yyexhaustedlab:
|
||||
#endif
|
||||
|
||||
yyreturn:
|
||||
if (yychar != YYEMPTY)
|
||||
if (yychar != YYEOF && yychar != YYEMPTY)
|
||||
yydestruct ("Cleanup: discarding lookahead",
|
||||
yytoken, &yylval, &yylloc, info);
|
||||
/* Do not reclaim the symbols of the rule which action triggered
|
||||
@@ -2448,11 +2513,11 @@ TclDateerror(
|
||||
infoPtr->separatrix = "\n";
|
||||
}
|
||||
|
||||
MODULE_SCOPE int
|
||||
static time_t
|
||||
ToSeconds(
|
||||
int Hours,
|
||||
int Minutes,
|
||||
int Seconds,
|
||||
time_t Hours,
|
||||
time_t Minutes,
|
||||
time_t Seconds,
|
||||
MERIDIAN Meridian)
|
||||
{
|
||||
if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) {
|
||||
@@ -2615,7 +2680,7 @@ TclDatelex(
|
||||
|
||||
location->first_column = yyInput - info->dateStart;
|
||||
for ( ; ; ) {
|
||||
while (isspace(UCHAR(*yyInput))) {
|
||||
while (TclIsSpaceProc(*yyInput)) {
|
||||
yyInput++;
|
||||
}
|
||||
|
||||
@@ -2675,36 +2740,65 @@ TclDatelex(
|
||||
} while (Count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TclClockFreeScan(
|
||||
TclClockOldscanObjCmd(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* Tcl interpreter */
|
||||
DateInfo *info) /* Input and result parameters */
|
||||
int objc, /* Count of paraneters */
|
||||
Tcl_Obj *const *objv) /* Parameters */
|
||||
{
|
||||
Tcl_Obj *result, *resultElement;
|
||||
int yr, mo, da;
|
||||
DateInfo dateInfo;
|
||||
DateInfo* info = &dateInfo;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* yyInput = stringToParse;
|
||||
*
|
||||
* ClockInitDateInfo(info) should be executed to pre-init info;
|
||||
*/
|
||||
if (objc != 5) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
"stringToParse baseYear baseMonth baseDay" );
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
yyDSTmode = DSTmaybe;
|
||||
yyInput = Tcl_GetString( objv[1] );
|
||||
dateInfo.dateStart = yyInput;
|
||||
|
||||
info->messages = Tcl_NewObj();
|
||||
info->separatrix = "";
|
||||
Tcl_IncrRefCount(info->messages);
|
||||
yyHaveDate = 0;
|
||||
if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK
|
||||
|| Tcl_GetIntFromObj(interp, objv[3], &mo) != TCL_OK
|
||||
|| Tcl_GetIntFromObj(interp, objv[4], &da) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
yyYear = yr; yyMonth = mo; yyDay = da;
|
||||
|
||||
info->dateStart = yyInput;
|
||||
status = yyparse(info);
|
||||
yyHaveTime = 0;
|
||||
yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24;
|
||||
|
||||
yyHaveZone = 0;
|
||||
yyTimezone = 0; yyDSTmode = DSTmaybe;
|
||||
|
||||
yyHaveOrdinalMonth = 0;
|
||||
yyMonthOrdinal = 0;
|
||||
|
||||
yyHaveDay = 0;
|
||||
yyDayOrdinal = 0; yyDayNumber = 0;
|
||||
|
||||
yyHaveRel = 0;
|
||||
yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL;
|
||||
|
||||
dateInfo.messages = Tcl_NewObj();
|
||||
dateInfo.separatrix = "";
|
||||
Tcl_IncrRefCount(dateInfo.messages);
|
||||
|
||||
status = yyparse(&dateInfo);
|
||||
if (status == 1) {
|
||||
Tcl_SetObjResult(interp, info->messages);
|
||||
Tcl_DecrRefCount(info->messages);
|
||||
Tcl_SetObjResult(interp, dateInfo.messages);
|
||||
Tcl_DecrRefCount(dateInfo.messages);
|
||||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL);
|
||||
return TCL_ERROR;
|
||||
} else if (status == 2) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1));
|
||||
Tcl_DecrRefCount(info->messages);
|
||||
Tcl_DecrRefCount(dateInfo.messages);
|
||||
Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
|
||||
return TCL_ERROR;
|
||||
} else if (status != 0) {
|
||||
@@ -2712,11 +2806,11 @@ TclClockFreeScan(
|
||||
"from date parser. Please "
|
||||
"report this error as a "
|
||||
"bug in Tcl.", -1));
|
||||
Tcl_DecrRefCount(info->messages);
|
||||
Tcl_DecrRefCount(dateInfo.messages);
|
||||
Tcl_SetErrorCode(interp, "TCL", "BUG", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_DecrRefCount(info->messages);
|
||||
Tcl_DecrRefCount(dateInfo.messages);
|
||||
|
||||
if (yyHaveDate > 1) {
|
||||
Tcl_SetObjResult(interp,
|
||||
@@ -2749,40 +2843,6 @@ TclClockFreeScan(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
int
|
||||
TclClockOldscanObjCmd(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* Tcl interpreter */
|
||||
int objc, /* Count of paraneters */
|
||||
Tcl_Obj *const *objv) /* Parameters */
|
||||
{
|
||||
Tcl_Obj *result, *resultElement;
|
||||
int yr, mo, da;
|
||||
DateInfo dateInfo;
|
||||
DateInfo* info = &dateInfo;
|
||||
|
||||
if (objc != 5) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
"stringToParse baseYear baseMonth baseDay" );
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
yyInput = Tcl_GetString( objv[1] );
|
||||
|
||||
if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK
|
||||
|| Tcl_GetIntFromObj(interp, objv[3], &mo) != TCL_OK
|
||||
|| Tcl_GetIntFromObj(interp, objv[4], &da) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
yyYear = yr; yyMonth = mo; yyDay = da;
|
||||
|
||||
if (TclClockFreeScan(interp, info) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
result = Tcl_NewObj();
|
||||
resultElement = Tcl_NewObj();
|
||||
if (yyHaveDate) {
|
||||
@@ -2833,10 +2893,10 @@ TclClockOldscanObjCmd(
|
||||
|
||||
resultElement = Tcl_NewObj();
|
||||
if (yyHaveOrdinalMonth) {
|
||||
Tcl_ListObjAppendElement(interp, resultElement,
|
||||
Tcl_NewIntObj((int) yyMonthOrdinalIncr));
|
||||
Tcl_ListObjAppendElement(interp, resultElement,
|
||||
Tcl_NewIntObj((int) yyMonthOrdinal));
|
||||
Tcl_ListObjAppendElement(interp, resultElement,
|
||||
Tcl_NewIntObj((int) yyMonth));
|
||||
}
|
||||
Tcl_ListObjAppendElement(interp, result, resultElement);
|
||||
|
||||
|
||||
@@ -1,512 +0,0 @@
|
||||
/*
|
||||
* tclDate.h --
|
||||
*
|
||||
* This header file handles common usage of clock primitives
|
||||
* between tclDate.c (yacc), tclClock.c and tclClockFmt.c.
|
||||
*
|
||||
* Copyright (c) 2014 Serg G. Brester (aka sebres)
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution
|
||||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
|
||||
#ifndef _TCLCLOCK_H
|
||||
#define _TCLCLOCK_H
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
|
||||
#define JULIAN_DAY_POSIX_EPOCH 2440588
|
||||
#define GREGORIAN_CHANGE_DATE 2361222
|
||||
#define SECONDS_PER_DAY 86400
|
||||
#define JULIAN_SEC_POSIX_EPOCH (((Tcl_WideInt) JULIAN_DAY_POSIX_EPOCH) \
|
||||
* SECONDS_PER_DAY)
|
||||
#define FOUR_CENTURIES 146097 /* days */
|
||||
#define JDAY_1_JAN_1_CE_JULIAN 1721424
|
||||
#define JDAY_1_JAN_1_CE_GREGORIAN 1721426
|
||||
#define ONE_CENTURY_GREGORIAN 36524 /* days */
|
||||
#define FOUR_YEARS 1461 /* days */
|
||||
#define ONE_YEAR 365 /* days */
|
||||
|
||||
#define RODDENBERRY 1946 /* Another epoch (Hi, Jeff!) */
|
||||
|
||||
|
||||
#define CLF_OPTIONAL (1 << 0) /* token is non mandatory */
|
||||
#define CLF_POSIXSEC (1 << 1)
|
||||
#define CLF_LOCALSEC (1 << 2)
|
||||
#define CLF_JULIANDAY (1 << 3)
|
||||
#define CLF_TIME (1 << 4)
|
||||
#define CLF_CENTURY (1 << 6)
|
||||
#define CLF_DAYOFMONTH (1 << 7)
|
||||
#define CLF_DAYOFYEAR (1 << 8)
|
||||
#define CLF_MONTH (1 << 9)
|
||||
#define CLF_YEAR (1 << 10)
|
||||
#define CLF_ISO8601YEAR (1 << 12)
|
||||
#define CLF_ISO8601 (1 << 13)
|
||||
#define CLF_ISO8601CENTURY (1 << 14)
|
||||
#define CLF_SIGNED (1 << 15)
|
||||
/* On demand (lazy) assemble flags */
|
||||
#define CLF_ASSEMBLE_DATE (1 << 28) /* assemble year, month, etc. using julianDay */
|
||||
#define CLF_ASSEMBLE_JULIANDAY (1 << 29) /* assemble julianDay using year, month, etc. */
|
||||
#define CLF_ASSEMBLE_SECONDS (1 << 30) /* assemble localSeconds (and seconds at end) */
|
||||
|
||||
#define CLF_DATE (CLF_JULIANDAY | CLF_DAYOFMONTH | CLF_DAYOFYEAR | \
|
||||
CLF_MONTH | CLF_YEAR | CLF_ISO8601YEAR | CLF_ISO8601)
|
||||
|
||||
/*
|
||||
* Enumeration of the string literals used in [clock]
|
||||
*/
|
||||
|
||||
typedef enum ClockLiteral {
|
||||
LIT__NIL,
|
||||
LIT__DEFAULT_FORMAT,
|
||||
LIT_SYSTEM, LIT_CURRENT, LIT_C,
|
||||
LIT_BCE, LIT_CE,
|
||||
LIT_DAYOFMONTH, LIT_DAYOFWEEK, LIT_DAYOFYEAR,
|
||||
LIT_ERA, LIT_GMT, LIT_GREGORIAN,
|
||||
LIT_INTEGER_VALUE_TOO_LARGE,
|
||||
LIT_ISO8601WEEK, LIT_ISO8601YEAR,
|
||||
LIT_JULIANDAY, LIT_LOCALSECONDS,
|
||||
LIT_MONTH,
|
||||
LIT_SECONDS, LIT_TZNAME, LIT_TZOFFSET,
|
||||
LIT_YEAR,
|
||||
LIT_TZDATA,
|
||||
LIT_GETSYSTEMTIMEZONE,
|
||||
LIT_SETUPTIMEZONE,
|
||||
LIT_MCGET,
|
||||
LIT_GETSYSTEMLOCALE, LIT_GETCURRENTLOCALE,
|
||||
LIT_LOCALIZE_FORMAT,
|
||||
LIT__END
|
||||
} ClockLiteral;
|
||||
|
||||
#define CLOCK_LITERAL_ARRAY(litarr) static const char *const litarr[] = { \
|
||||
"", \
|
||||
"%a %b %d %H:%M:%S %Z %Y", \
|
||||
"system", "current", "C", \
|
||||
"BCE", "CE", \
|
||||
"dayOfMonth", "dayOfWeek", "dayOfYear", \
|
||||
"era", ":GMT", "gregorian", \
|
||||
"integer value too large to represent", \
|
||||
"iso8601Week", "iso8601Year", \
|
||||
"julianDay", "localSeconds", \
|
||||
"month", \
|
||||
"seconds", "tzName", "tzOffset", \
|
||||
"year", \
|
||||
"::tcl::clock::TZData", \
|
||||
"::tcl::clock::GetSystemTimeZone", \
|
||||
"::tcl::clock::SetupTimeZone", \
|
||||
"::tcl::clock::mcget", \
|
||||
"::tcl::clock::GetSystemLocale", "::tcl::clock::mclocale", \
|
||||
"::tcl::clock::LocalizeFormat" \
|
||||
}
|
||||
|
||||
/*
|
||||
* Enumeration of the msgcat literals used in [clock]
|
||||
*/
|
||||
|
||||
typedef enum ClockMsgCtLiteral {
|
||||
MCLIT__NIL, /* placeholder */
|
||||
MCLIT_MONTHS_FULL, MCLIT_MONTHS_ABBREV, MCLIT_MONTHS_COMB,
|
||||
MCLIT_DAYS_OF_WEEK_FULL, MCLIT_DAYS_OF_WEEK_ABBREV, MCLIT_DAYS_OF_WEEK_COMB,
|
||||
MCLIT_AM, MCLIT_PM,
|
||||
MCLIT_LOCALE_ERAS,
|
||||
MCLIT_BCE, MCLIT_CE,
|
||||
MCLIT_BCE2, MCLIT_CE2,
|
||||
MCLIT_BCE3, MCLIT_CE3,
|
||||
MCLIT_LOCALE_NUMERALS,
|
||||
MCLIT__END
|
||||
} ClockMsgCtLiteral;
|
||||
|
||||
#define CLOCK_LOCALE_LITERAL_ARRAY(litarr, pref) static const char *const litarr[] = { \
|
||||
pref "", \
|
||||
pref "MONTHS_FULL", pref "MONTHS_ABBREV", pref "MONTHS_COMB", \
|
||||
pref "DAYS_OF_WEEK_FULL", pref "DAYS_OF_WEEK_ABBREV", pref "DAYS_OF_WEEK_COMB", \
|
||||
pref "AM", pref "PM", \
|
||||
pref "LOCALE_ERAS", \
|
||||
pref "BCE", pref "CE", \
|
||||
pref "b.c.e.", pref "c.e.", \
|
||||
pref "b.c.", pref "a.d.", \
|
||||
pref "LOCALE_NUMERALS", \
|
||||
}
|
||||
|
||||
/*
|
||||
* Structure containing the fields used in [clock format] and [clock scan]
|
||||
*/
|
||||
|
||||
typedef struct TclDateFields {
|
||||
|
||||
/* Cacheable fields: */
|
||||
|
||||
Tcl_WideInt seconds; /* Time expressed in seconds from the Posix
|
||||
* epoch */
|
||||
Tcl_WideInt localSeconds; /* Local time expressed in nominal seconds
|
||||
* from the Posix epoch */
|
||||
int tzOffset; /* Time zone offset in seconds east of
|
||||
* Greenwich */
|
||||
int julianDay; /* Julian Day Number in local time zone */
|
||||
enum {BCE=1, CE=0} era; /* Era */
|
||||
int gregorian; /* Flag == 1 if the date is Gregorian */
|
||||
int year; /* Year of the era */
|
||||
int dayOfYear; /* Day of the year (1 January == 1) */
|
||||
int month; /* Month number */
|
||||
int dayOfMonth; /* Day of the month */
|
||||
int iso8601Year; /* ISO8601 week-based year */
|
||||
int iso8601Week; /* ISO8601 week number */
|
||||
int dayOfWeek; /* Day of the week */
|
||||
int hour; /* Hours of day (in-between time only calculation) */
|
||||
int minutes; /* Minutes of day (in-between time only calculation) */
|
||||
int secondOfDay; /* Seconds of day (in-between time only calculation) */
|
||||
|
||||
/* Non cacheable fields: */
|
||||
|
||||
Tcl_Obj *tzName; /* Name (or corresponding DST-abbreviation) of the
|
||||
* time zone, if set the refCount is incremented */
|
||||
} TclDateFields;
|
||||
|
||||
#define ClockCacheableDateFieldsSize \
|
||||
TclOffset(TclDateFields, tzName)
|
||||
|
||||
/*
|
||||
* Structure contains return parsed fields.
|
||||
*/
|
||||
|
||||
typedef struct DateInfo {
|
||||
const char *dateStart;
|
||||
const char *dateInput;
|
||||
const char *dateEnd;
|
||||
|
||||
TclDateFields date;
|
||||
|
||||
int flags;
|
||||
|
||||
int dateHaveDate;
|
||||
|
||||
int dateMeridian;
|
||||
int dateHaveTime;
|
||||
|
||||
int dateTimezone;
|
||||
int dateDSTmode;
|
||||
int dateHaveZone;
|
||||
|
||||
int dateRelMonth;
|
||||
int dateRelDay;
|
||||
int dateRelSeconds;
|
||||
int dateHaveRel;
|
||||
|
||||
int dateMonthOrdinalIncr;
|
||||
int dateMonthOrdinal;
|
||||
int dateHaveOrdinalMonth;
|
||||
|
||||
int dateDayOrdinal;
|
||||
int dateDayNumber;
|
||||
int dateHaveDay;
|
||||
|
||||
int *dateRelPointer;
|
||||
|
||||
int dateSpaceCount;
|
||||
int dateDigitCount;
|
||||
|
||||
int dateCentury;
|
||||
|
||||
Tcl_Obj* messages; /* Error messages */
|
||||
const char* separatrix; /* String separating messages */
|
||||
} DateInfo;
|
||||
|
||||
#define yydate (info->date) /* Date fields used for converting */
|
||||
|
||||
#define yyDay (info->date.dayOfMonth)
|
||||
#define yyMonth (info->date.month)
|
||||
#define yyYear (info->date.year)
|
||||
|
||||
#define yyHour (info->date.hour)
|
||||
#define yyMinutes (info->date.minutes)
|
||||
#define yySeconds (info->date.secondOfDay)
|
||||
|
||||
#define yyDSTmode (info->dateDSTmode)
|
||||
#define yyDayOrdinal (info->dateDayOrdinal)
|
||||
#define yyDayNumber (info->dateDayNumber)
|
||||
#define yyMonthOrdinalIncr (info->dateMonthOrdinalIncr)
|
||||
#define yyMonthOrdinal (info->dateMonthOrdinal)
|
||||
#define yyHaveDate (info->dateHaveDate)
|
||||
#define yyHaveDay (info->dateHaveDay)
|
||||
#define yyHaveOrdinalMonth (info->dateHaveOrdinalMonth)
|
||||
#define yyHaveRel (info->dateHaveRel)
|
||||
#define yyHaveTime (info->dateHaveTime)
|
||||
#define yyHaveZone (info->dateHaveZone)
|
||||
#define yyTimezone (info->dateTimezone)
|
||||
#define yyMeridian (info->dateMeridian)
|
||||
#define yyRelMonth (info->dateRelMonth)
|
||||
#define yyRelDay (info->dateRelDay)
|
||||
#define yyRelSeconds (info->dateRelSeconds)
|
||||
#define yyRelPointer (info->dateRelPointer)
|
||||
#define yyInput (info->dateInput)
|
||||
#define yyDigitCount (info->dateDigitCount)
|
||||
#define yySpaceCount (info->dateSpaceCount)
|
||||
|
||||
static inline void
|
||||
ClockInitDateInfo(DateInfo *info) {
|
||||
memset(info, 0, sizeof(DateInfo));
|
||||
}
|
||||
|
||||
/*
|
||||
* Structure containing the command arguments supplied to [clock format] and [clock scan]
|
||||
*/
|
||||
|
||||
#define CLF_EXTENDED (1 << 4)
|
||||
#define CLF_STRICT (1 << 8)
|
||||
#define CLF_LOCALE_USED (1 << 15)
|
||||
|
||||
typedef struct ClockFmtScnCmdArgs {
|
||||
ClientData clientData; /* Opaque pointer to literal pool, etc. */
|
||||
Tcl_Interp *interp; /* Tcl interpreter */
|
||||
|
||||
Tcl_Obj *formatObj; /* Format */
|
||||
Tcl_Obj *localeObj; /* Name of the locale where the time will be expressed. */
|
||||
Tcl_Obj *timezoneObj; /* Default time zone in which the time will be expressed */
|
||||
Tcl_Obj *baseObj; /* Base (scan and add) or clockValue (format) */
|
||||
int flags; /* Flags control scanning */
|
||||
|
||||
Tcl_Obj *mcDictObj; /* Current dictionary of tcl::clock package for given localeObj*/
|
||||
} ClockFmtScnCmdArgs;
|
||||
|
||||
/*
|
||||
* Structure containing the client data for [clock]
|
||||
*/
|
||||
|
||||
typedef struct ClockClientData {
|
||||
size_t refCount; /* Number of live references. */
|
||||
Tcl_Obj **literals; /* Pool of object literals (common, locale independent). */
|
||||
Tcl_Obj **mcLiterals; /* Msgcat object literals with mc-keys for search with locale. */
|
||||
Tcl_Obj **mcLitIdxs; /* Msgcat object indices prefixed with _IDX_,
|
||||
* used for quick dictionary search */
|
||||
|
||||
/* Cache for current clock parameters, imparted via "configure" */
|
||||
unsigned long LastTZEpoch;
|
||||
int currentYearCentury;
|
||||
int yearOfCenturySwitch;
|
||||
Tcl_Obj *SystemTimeZone;
|
||||
Tcl_Obj *SystemSetupTZData;
|
||||
Tcl_Obj *GMTSetupTimeZone;
|
||||
Tcl_Obj *GMTSetupTZData;
|
||||
Tcl_Obj *AnySetupTimeZone;
|
||||
Tcl_Obj *AnySetupTZData;
|
||||
Tcl_Obj *LastUnnormSetupTimeZone;
|
||||
Tcl_Obj *LastSetupTimeZone;
|
||||
Tcl_Obj *LastSetupTZData;
|
||||
|
||||
Tcl_Obj *CurrentLocale;
|
||||
Tcl_Obj *CurrentLocaleDict;
|
||||
Tcl_Obj *LastUnnormUsedLocale;
|
||||
Tcl_Obj *LastUsedLocale;
|
||||
Tcl_Obj *LastUsedLocaleDict;
|
||||
|
||||
/* Cache for last base (last-second fast convert if base/tz not changed) */
|
||||
struct {
|
||||
Tcl_Obj *timezoneObj;
|
||||
TclDateFields Date;
|
||||
} lastBase;
|
||||
/* Las-period cache for fast UTC2Local conversion */
|
||||
struct {
|
||||
/* keys */
|
||||
Tcl_Obj *timezoneObj;
|
||||
int changeover;
|
||||
Tcl_WideInt seconds;
|
||||
Tcl_WideInt rangesVal[2]; /* Bounds for cached time zone offset */
|
||||
/* values */
|
||||
int tzOffset;
|
||||
Tcl_Obj *tzName;
|
||||
} UTC2Local;
|
||||
/* Las-period cache for fast Local2UTC conversion */
|
||||
struct {
|
||||
/* keys */
|
||||
Tcl_Obj *timezoneObj;
|
||||
int changeover;
|
||||
Tcl_WideInt localSeconds;
|
||||
Tcl_WideInt rangesVal[2]; /* Bounds for cached time zone offset */
|
||||
/* values */
|
||||
int tzOffset;
|
||||
} Local2UTC;
|
||||
} ClockClientData;
|
||||
|
||||
#define ClockDefaultYearCentury 2000
|
||||
#define ClockDefaultCenturySwitch 38
|
||||
|
||||
/*
|
||||
* Meridian: am, pm, or 24-hour style.
|
||||
*/
|
||||
|
||||
typedef enum _MERIDIAN {
|
||||
MERam, MERpm, MER24
|
||||
} MERIDIAN;
|
||||
|
||||
/*
|
||||
* Clock scan and format facilities.
|
||||
*/
|
||||
|
||||
#define CLOCK_FMT_SCN_STORAGE_GC_SIZE 32
|
||||
|
||||
#define CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE 2
|
||||
|
||||
typedef struct ClockScanToken ClockScanToken;
|
||||
|
||||
|
||||
typedef int ClockScanTokenProc(
|
||||
ClockFmtScnCmdArgs *opts,
|
||||
DateInfo *info,
|
||||
ClockScanToken *tok);
|
||||
|
||||
|
||||
typedef enum _CLCKTOK_TYPE {
|
||||
CTOKT_DIGIT = 1, CTOKT_PARSER, CTOKT_SPACE, CTOKT_WORD, CTOKT_CHAR,
|
||||
CFMTT_INT, CFMTT_WIDE, CFMTT_PROC
|
||||
} CLCKTOK_TYPE;
|
||||
|
||||
typedef struct ClockScanTokenMap {
|
||||
unsigned short int type;
|
||||
unsigned short int flags;
|
||||
unsigned short int clearFlags;
|
||||
unsigned short int minSize;
|
||||
unsigned short int maxSize;
|
||||
unsigned short int offs;
|
||||
ClockScanTokenProc *parser;
|
||||
const void *data;
|
||||
} ClockScanTokenMap;
|
||||
|
||||
typedef struct ClockScanToken {
|
||||
ClockScanTokenMap *map;
|
||||
struct {
|
||||
const char *start;
|
||||
const char *end;
|
||||
} tokWord;
|
||||
unsigned short int endDistance;
|
||||
unsigned short int lookAhMin;
|
||||
unsigned short int lookAhMax;
|
||||
unsigned short int lookAhTok;
|
||||
} ClockScanToken;
|
||||
|
||||
|
||||
#define MIN_FMT_RESULT_BLOCK_ALLOC 200
|
||||
|
||||
typedef struct DateFormat {
|
||||
char *resMem;
|
||||
char *resEnd;
|
||||
char *output;
|
||||
|
||||
TclDateFields date;
|
||||
|
||||
Tcl_Obj *localeEra;
|
||||
} DateFormat;
|
||||
|
||||
#define CLFMT_INCR (1 << 3)
|
||||
#define CLFMT_DECR (1 << 4)
|
||||
#define CLFMT_CALC (1 << 5)
|
||||
#define CLFMT_LOCALE_INDX (1 << 8)
|
||||
|
||||
typedef struct ClockFormatToken ClockFormatToken;
|
||||
|
||||
typedef int ClockFormatTokenProc(
|
||||
ClockFmtScnCmdArgs *opts,
|
||||
DateFormat *dateFmt,
|
||||
ClockFormatToken *tok,
|
||||
int *val);
|
||||
|
||||
typedef struct ClockFormatTokenMap {
|
||||
unsigned short int type;
|
||||
const char *tostr;
|
||||
unsigned short int width;
|
||||
unsigned short int flags;
|
||||
unsigned short int divider;
|
||||
unsigned short int divmod;
|
||||
unsigned short int offs;
|
||||
ClockFormatTokenProc *fmtproc;
|
||||
void *data;
|
||||
} ClockFormatTokenMap;
|
||||
typedef struct ClockFormatToken {
|
||||
ClockFormatTokenMap *map;
|
||||
struct {
|
||||
const char *start;
|
||||
const char *end;
|
||||
} tokWord;
|
||||
} ClockFormatToken;
|
||||
|
||||
|
||||
typedef struct ClockFmtScnStorage ClockFmtScnStorage;
|
||||
|
||||
typedef struct ClockFmtScnStorage {
|
||||
int objRefCount; /* Reference count shared across threads */
|
||||
ClockScanToken *scnTok;
|
||||
unsigned int scnTokC;
|
||||
unsigned int scnSpaceCount; /* Count of mandatory spaces used in format */
|
||||
ClockFormatToken *fmtTok;
|
||||
unsigned int fmtTokC;
|
||||
#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
|
||||
ClockFmtScnStorage *nextPtr;
|
||||
ClockFmtScnStorage *prevPtr;
|
||||
#endif
|
||||
#if 0
|
||||
+Tcl_HashEntry hashEntry /* ClockFmtScnStorage is a derivate of Tcl_HashEntry,
|
||||
* stored by offset +sizeof(self) */
|
||||
#endif
|
||||
} ClockFmtScnStorage;
|
||||
|
||||
/*
|
||||
* Prototypes of module functions.
|
||||
*/
|
||||
|
||||
MODULE_SCOPE int ToSeconds(int Hours, int Minutes,
|
||||
int Seconds, MERIDIAN Meridian);
|
||||
MODULE_SCOPE int IsGregorianLeapYear(TclDateFields *);
|
||||
MODULE_SCOPE void
|
||||
GetJulianDayFromEraYearWeekDay(
|
||||
TclDateFields *fields, int changeover);
|
||||
MODULE_SCOPE void
|
||||
GetJulianDayFromEraYearMonthDay(
|
||||
TclDateFields *fields, int changeover);
|
||||
MODULE_SCOPE void
|
||||
GetJulianDayFromEraYearDay(
|
||||
TclDateFields *fields, int changeover);
|
||||
MODULE_SCOPE int ConvertUTCToLocal(ClientData clientData, Tcl_Interp *,
|
||||
TclDateFields *, Tcl_Obj *timezoneObj, int);
|
||||
MODULE_SCOPE Tcl_Obj *
|
||||
LookupLastTransition(Tcl_Interp *, Tcl_WideInt,
|
||||
int, Tcl_Obj *const *, Tcl_WideInt rangesVal[2]);
|
||||
|
||||
MODULE_SCOPE int TclClockFreeScan(Tcl_Interp *interp, DateInfo *info);
|
||||
|
||||
/* tclClock.c module declarations */
|
||||
|
||||
MODULE_SCOPE Tcl_Obj *
|
||||
ClockSetupTimeZone(ClientData clientData,
|
||||
Tcl_Interp *interp, Tcl_Obj *timezoneObj);
|
||||
|
||||
MODULE_SCOPE Tcl_Obj *
|
||||
ClockMCDict(ClockFmtScnCmdArgs *opts);
|
||||
MODULE_SCOPE Tcl_Obj *
|
||||
ClockMCGet(ClockFmtScnCmdArgs *opts, int mcKey);
|
||||
MODULE_SCOPE Tcl_Obj *
|
||||
ClockMCGetIdx(ClockFmtScnCmdArgs *opts, int mcKey);
|
||||
MODULE_SCOPE int ClockMCSetIdx(ClockFmtScnCmdArgs *opts, int mcKey,
|
||||
Tcl_Obj *valObj);
|
||||
|
||||
/* tclClockFmt.c module declarations */
|
||||
|
||||
MODULE_SCOPE Tcl_Obj*
|
||||
ClockFrmObjGetLocFmtKey(Tcl_Interp *interp,
|
||||
Tcl_Obj *objPtr);
|
||||
|
||||
MODULE_SCOPE ClockFmtScnStorage *
|
||||
Tcl_GetClockFrmScnFromObj(Tcl_Interp *interp,
|
||||
Tcl_Obj *objPtr);
|
||||
MODULE_SCOPE Tcl_Obj *
|
||||
ClockLocalizeFormat(ClockFmtScnCmdArgs *opts);
|
||||
|
||||
MODULE_SCOPE int ClockScan(register DateInfo *info,
|
||||
Tcl_Obj *strObj, ClockFmtScnCmdArgs *opts);
|
||||
|
||||
MODULE_SCOPE int ClockFormat(register DateFormat *dateFmt,
|
||||
ClockFmtScnCmdArgs *opts);
|
||||
|
||||
MODULE_SCOPE void ClockFrmScnClearCaches(void);
|
||||
|
||||
#endif /* _TCLCLOCK_H */
|
||||
+7
-109
@@ -51,8 +51,6 @@ static int DictSetCmd(ClientData dummy, Tcl_Interp *interp,
|
||||
int objc, Tcl_Obj *const *objv);
|
||||
static int DictSizeCmd(ClientData dummy, Tcl_Interp *interp,
|
||||
int objc, Tcl_Obj *const *objv);
|
||||
static int DictSmartRefCmd(ClientData dummy, Tcl_Interp *interp,
|
||||
int objc, Tcl_Obj *const *objv);
|
||||
static int DictUnsetCmd(ClientData dummy, Tcl_Interp *interp,
|
||||
int objc, Tcl_Obj *const *objv);
|
||||
static int DictUpdateCmd(ClientData dummy, Tcl_Interp *interp,
|
||||
@@ -100,7 +98,6 @@ static const EnsembleImplMap implementationMap[] = {
|
||||
{"replace", DictReplaceCmd, NULL, NULL, NULL, 0 },
|
||||
{"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 },
|
||||
{"size", DictSizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 },
|
||||
{"smartref",DictSmartRefCmd,NULL, NULL, NULL, 0 },
|
||||
{"unset", DictUnsetCmd, TclCompileDictUnsetCmd, NULL, NULL, 0 },
|
||||
{"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL, 0 },
|
||||
{"values", DictValuesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 },
|
||||
@@ -156,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
|
||||
@@ -490,15 +487,14 @@ static void
|
||||
UpdateStringOfDict(
|
||||
Tcl_Obj *dictPtr)
|
||||
{
|
||||
#define LOCAL_SIZE 20
|
||||
int localFlags[LOCAL_SIZE], *flagPtr = NULL;
|
||||
#define LOCAL_SIZE 64
|
||||
char localFlags[LOCAL_SIZE], *flagPtr = NULL;
|
||||
Dict *dict = DICT(dictPtr);
|
||||
ChainEntry *cPtr;
|
||||
Tcl_Obj *keyPtr, *valuePtr;
|
||||
int i, length, bytesNeeded = 0;
|
||||
const char *elem;
|
||||
char *dst;
|
||||
const int maxFlags = UINT_MAX / sizeof(int);
|
||||
|
||||
/*
|
||||
* This field is the most useful one in the whole hash structure, and it
|
||||
@@ -520,10 +516,8 @@ UpdateStringOfDict(
|
||||
|
||||
if (numElems <= LOCAL_SIZE) {
|
||||
flagPtr = localFlags;
|
||||
} else if (numElems > maxFlags) {
|
||||
Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
|
||||
} else {
|
||||
flagPtr = ckalloc(numElems * sizeof(int));
|
||||
flagPtr = ckalloc(numElems);
|
||||
}
|
||||
for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) {
|
||||
/*
|
||||
@@ -1958,102 +1952,6 @@ DictSizeCmd(
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_DictObjSmartRef --
|
||||
*
|
||||
* This function returns new tcl-object with the smart reference to
|
||||
* dictionary object.
|
||||
*
|
||||
* Object returned with this function is a smart reference (pointer),
|
||||
* so new object of type tclDictType, that directly references given
|
||||
* dictionary object (with internally increased refCount).
|
||||
*
|
||||
* The usage of such pointer objects allows to hold more as one
|
||||
* reference to the same real dictionary object, allows to make a pointer
|
||||
* to part of another dictionary, allows to change the dictionary without
|
||||
* regarding of the "shared" state of the dictionary object.
|
||||
*
|
||||
* Prevents "called with shared object" exception if object is multiple
|
||||
* referenced.
|
||||
*
|
||||
* Results:
|
||||
* The newly create object (contains smart reference) is returned.
|
||||
* The returned object has a ref count of 0.
|
||||
*
|
||||
* Side effects:
|
||||
* Increases ref count of the referenced dictionary.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Tcl_Obj *
|
||||
Tcl_DictObjSmartRef(
|
||||
Tcl_Interp *interp,
|
||||
Tcl_Obj *dictPtr)
|
||||
{
|
||||
Tcl_Obj *result;
|
||||
Dict *dict;
|
||||
|
||||
if (dictPtr->typePtr != &tclDictType
|
||||
&& SetDictFromAny(interp, dictPtr) != TCL_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dict = DICT(dictPtr);
|
||||
|
||||
result = Tcl_NewObj();
|
||||
DICT(result) = dict;
|
||||
dict->refCount++;
|
||||
result->internalRep.twoPtrValue.ptr2 = NULL;
|
||||
result->typePtr = &tclDictType;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* DictSmartRefCmd --
|
||||
*
|
||||
* This function implements the "dict smartref" Tcl command.
|
||||
*
|
||||
* See description of Tcl_DictObjSmartRef for details.
|
||||
*
|
||||
* Results:
|
||||
* A standard Tcl result.
|
||||
*
|
||||
* Side effects:
|
||||
* See the user documentation.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int
|
||||
DictSmartRefCmd(
|
||||
ClientData dummy,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
Tcl_Obj *result;
|
||||
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "dictionary");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
result = Tcl_DictObjSmartRef(interp, objv[1]);
|
||||
if (result == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, result);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -3634,7 +3532,7 @@ TclDictWithFinish(
|
||||
* If the dictionary variable doesn't exist, drop everything silently.
|
||||
*/
|
||||
|
||||
dictPtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr,
|
||||
dictPtr = TclPtrGetVarIdx(interp, varPtr, arrayPtr, part1Ptr, part2Ptr,
|
||||
TCL_LEAVE_ERR_MSG, index);
|
||||
if (dictPtr == NULL) {
|
||||
return TCL_OK;
|
||||
@@ -3717,8 +3615,8 @@ TclDictWithFinish(
|
||||
* Write back the outermost dictionary to the variable.
|
||||
*/
|
||||
|
||||
if (TclPtrSetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, dictPtr,
|
||||
TCL_LEAVE_ERR_MSG, index) == NULL) {
|
||||
if (TclPtrSetVarIdx(interp, varPtr, arrayPtr, part1Ptr, part2Ptr,
|
||||
dictPtr, TCL_LEAVE_ERR_MSG, index) == NULL) {
|
||||
if (allocdict) {
|
||||
TclDecrRefCount(dictPtr);
|
||||
}
|
||||
|
||||
+62
-35
@@ -2296,8 +2296,11 @@ UtfToUtfProc(
|
||||
const char *srcStart, *srcEnd, *srcClose;
|
||||
const char *dstStart, *dstEnd;
|
||||
int result, numChars, charLimit = INT_MAX;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar *chPtr = (Tcl_UniChar *) statePtr;
|
||||
|
||||
if (flags & TCL_ENCODING_START) {
|
||||
*statePtr = 0;
|
||||
}
|
||||
result = TCL_OK;
|
||||
|
||||
srcStart = src;
|
||||
@@ -2329,7 +2332,7 @@ UtfToUtfProc(
|
||||
}
|
||||
if (UCHAR(*src) < 0x80 && !(UCHAR(*src) == 0 && pureNullMode == 0)) {
|
||||
/*
|
||||
* Copy 7bit chatacters, but skip null-bytes when we are in input
|
||||
* Copy 7bit characters, but skip null-bytes when we are in input
|
||||
* mode, so that they get converted to 0xc080.
|
||||
*/
|
||||
|
||||
@@ -2345,16 +2348,23 @@ UtfToUtfProc(
|
||||
} else if (!Tcl_UtfCharComplete(src, srcEnd - src)) {
|
||||
/*
|
||||
* Always check before using TclUtfToUniChar. Not doing can so
|
||||
* cause it run beyond the endof the buffer! If we happen such an
|
||||
* incomplete char its byts are made to represent themselves.
|
||||
* cause it run beyond the end of the buffer! If we happen such an
|
||||
* incomplete char its bytes are made to represent themselves.
|
||||
*/
|
||||
|
||||
ch = (unsigned char) *src;
|
||||
*chPtr = (unsigned char) *src;
|
||||
src += 1;
|
||||
dst += Tcl_UniCharToUtf(ch, dst);
|
||||
dst += Tcl_UniCharToUtf(*chPtr, dst);
|
||||
} else {
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
dst += Tcl_UniCharToUtf(ch, dst);
|
||||
int len = TclUtfToUniChar(src, chPtr);
|
||||
src += len;
|
||||
dst += Tcl_UniCharToUtf(*chPtr, dst);
|
||||
#if TCL_UTF_MAX == 4
|
||||
if (!len) {
|
||||
src += TclUtfToUniChar(src, chPtr);
|
||||
dst += Tcl_UniCharToUtf(*chPtr, dst);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2410,8 +2420,11 @@ UnicodeToUtfProc(
|
||||
const char *srcStart, *srcEnd;
|
||||
const char *dstEnd, *dstStart;
|
||||
int result, numChars, charLimit = INT_MAX;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar *chPtr = (Tcl_UniChar *) statePtr;
|
||||
|
||||
if (flags & TCL_ENCODING_START) {
|
||||
*statePtr = 0;
|
||||
}
|
||||
if (flags & TCL_ENCODING_CHAR_LIMIT) {
|
||||
charLimit = *dstCharsPtr;
|
||||
}
|
||||
@@ -2439,11 +2452,11 @@ UnicodeToUtfProc(
|
||||
* Tcl_UniChar-size data.
|
||||
*/
|
||||
|
||||
ch = *(Tcl_UniChar *)src;
|
||||
if (ch && ch < 0x80) {
|
||||
*dst++ = (ch & 0xFF);
|
||||
*chPtr = *(Tcl_UniChar *)src;
|
||||
if (*chPtr && *chPtr < 0x80) {
|
||||
*dst++ = (*chPtr & 0xFF);
|
||||
} else {
|
||||
dst += Tcl_UniCharToUtf(ch, dst);
|
||||
dst += Tcl_UniCharToUtf(*chPtr, dst);
|
||||
}
|
||||
src += sizeof(Tcl_UniChar);
|
||||
}
|
||||
@@ -2500,8 +2513,11 @@ UtfToUnicodeProc(
|
||||
{
|
||||
const char *srcStart, *srcEnd, *srcClose, *dstStart, *dstEnd;
|
||||
int result, numChars;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar *chPtr = (Tcl_UniChar *) statePtr;
|
||||
|
||||
if (flags & TCL_ENCODING_START) {
|
||||
*statePtr = 0;
|
||||
}
|
||||
srcStart = src;
|
||||
srcEnd = src + srcLen;
|
||||
srcClose = srcEnd;
|
||||
@@ -2527,7 +2543,7 @@ UtfToUnicodeProc(
|
||||
result = TCL_CONVERT_NOSPACE;
|
||||
break;
|
||||
}
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
src += TclUtfToUniChar(src, chPtr);
|
||||
|
||||
/*
|
||||
* Need to handle this in a way that won't cause misalignment by
|
||||
@@ -2536,23 +2552,23 @@ UtfToUnicodeProc(
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#if TCL_UTF_MAX > 4
|
||||
*dst++ = (ch >> 24);
|
||||
*dst++ = ((ch >> 16) & 0xFF);
|
||||
*dst++ = ((ch >> 8) & 0xFF);
|
||||
*dst++ = (ch & 0xFF);
|
||||
*dst++ = (*chPtr >> 24);
|
||||
*dst++ = ((*chPtr >> 16) & 0xFF);
|
||||
*dst++ = ((*chPtr >> 8) & 0xFF);
|
||||
*dst++ = (*chPtr & 0xFF);
|
||||
#else
|
||||
*dst++ = (ch >> 8);
|
||||
*dst++ = (ch & 0xFF);
|
||||
*dst++ = (*chPtr >> 8);
|
||||
*dst++ = (*chPtr & 0xFF);
|
||||
#endif
|
||||
#else
|
||||
#if TCL_UTF_MAX > 4
|
||||
*dst++ = (ch & 0xFF);
|
||||
*dst++ = ((ch >> 8) & 0xFF);
|
||||
*dst++ = ((ch >> 16) & 0xFF);
|
||||
*dst++ = (ch >> 24);
|
||||
*dst++ = (*chPtr & 0xFF);
|
||||
*dst++ = ((*chPtr >> 8) & 0xFF);
|
||||
*dst++ = ((*chPtr >> 16) & 0xFF);
|
||||
*dst++ = (*chPtr >> 24);
|
||||
#else
|
||||
*dst++ = (ch & 0xFF);
|
||||
*dst++ = (ch >> 8);
|
||||
*dst++ = (*chPtr & 0xFF);
|
||||
*dst++ = (*chPtr >> 8);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -2610,7 +2626,7 @@ TableToUtfProc(
|
||||
const char *srcStart, *srcEnd;
|
||||
const char *dstEnd, *dstStart, *prefixBytes;
|
||||
int result, byte, numChars, charLimit = INT_MAX;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
const unsigned short *const *toUnicode;
|
||||
const unsigned short *pageZero;
|
||||
TableEncodingData *dataPtr = clientData;
|
||||
@@ -2722,7 +2738,7 @@ TableFromUtfProc(
|
||||
{
|
||||
const char *srcStart, *srcEnd, *srcClose;
|
||||
const char *dstStart, *dstEnd, *prefixBytes;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
int result, len, word, numChars;
|
||||
TableEncodingData *dataPtr = clientData;
|
||||
const unsigned short *const *fromUnicode;
|
||||
@@ -2754,7 +2770,7 @@ TableFromUtfProc(
|
||||
}
|
||||
len = TclUtfToUniChar(src, &ch);
|
||||
|
||||
#if TCL_UTF_MAX > 3
|
||||
#if TCL_UTF_MAX > 4
|
||||
/*
|
||||
* This prevents a crash condition. More evaluation is required for
|
||||
* full support of int Tcl_UniChar. [Bug 1004065]
|
||||
@@ -2763,6 +2779,10 @@ TableFromUtfProc(
|
||||
if (ch & 0xffff0000) {
|
||||
word = 0;
|
||||
} else
|
||||
#elif TCL_UTF_MAX == 4
|
||||
if (!len) {
|
||||
word = 0;
|
||||
} else
|
||||
#endif
|
||||
word = fromUnicode[(ch >> 8)][ch & 0xff];
|
||||
|
||||
@@ -2856,7 +2876,7 @@ Iso88591ToUtfProc(
|
||||
|
||||
result = TCL_OK;
|
||||
for (numChars = 0; src < srcEnd && numChars <= charLimit; numChars++) {
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
|
||||
if (dst > dstEnd) {
|
||||
result = TCL_CONVERT_NOSPACE;
|
||||
@@ -2942,7 +2962,7 @@ Iso88591FromUtfProc(
|
||||
dstEnd = dst + dstLen - 1;
|
||||
|
||||
for (numChars = 0; src < srcEnd; numChars++) {
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
int len;
|
||||
|
||||
if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) {
|
||||
@@ -2960,11 +2980,18 @@ Iso88591FromUtfProc(
|
||||
* Check for illegal characters.
|
||||
*/
|
||||
|
||||
if (ch > 0xff) {
|
||||
if (ch > 0xff
|
||||
#if TCL_UTF_MAX == 4
|
||||
|| !len
|
||||
#endif
|
||||
) {
|
||||
if (flags & TCL_ENCODING_STOPONERROR) {
|
||||
result = TCL_CONVERT_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
#if TCL_UTF_MAX == 4
|
||||
if (!len) len = 4;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Plunge on, using '?' as a fallback character.
|
||||
@@ -3329,7 +3356,7 @@ EscapeFromUtfProc(
|
||||
for (numChars = 0; src < srcEnd; numChars++) {
|
||||
unsigned len;
|
||||
int word;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
|
||||
if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) {
|
||||
/*
|
||||
@@ -3374,7 +3401,7 @@ EscapeFromUtfProc(
|
||||
|
||||
/*
|
||||
* The state variable has the value of oldState when word is 0.
|
||||
* In this case, the escape sequense should not be copied to dst
|
||||
* In this case, the escape sequence should not be copied to dst
|
||||
* because the current character set is not changed.
|
||||
*/
|
||||
|
||||
|
||||
+193
-170
@@ -55,12 +55,11 @@ enum EnsSubcmds {
|
||||
};
|
||||
|
||||
static const char *const ensembleCreateOptions[] = {
|
||||
"-command", "-compile", "-map", "-parameters", "-prefixes",
|
||||
"-subcommands", "-unknown", NULL
|
||||
"-command", "-map", "-parameters", "-prefixes", "-subcommands",
|
||||
"-unknown", NULL
|
||||
};
|
||||
enum EnsCreateOpts {
|
||||
CRT_CMD, CRT_COMPILE, CRT_MAP, CRT_PARAM, CRT_PREFIX,
|
||||
CRT_SUBCMDS, CRT_UNKNOWN
|
||||
CRT_CMD, CRT_MAP, CRT_PARAM, CRT_PREFIX, CRT_SUBCMDS, CRT_UNKNOWN
|
||||
};
|
||||
|
||||
static const char *const ensembleConfigOptions[] = {
|
||||
@@ -147,10 +146,12 @@ TclNamespaceEnsembleCmd(
|
||||
Tcl_Obj *const objv[])
|
||||
{
|
||||
Tcl_Namespace *namespacePtr;
|
||||
Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
|
||||
Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp), *cxtPtr,
|
||||
*foundNsPtr, *altFoundNsPtr, *actualCxtPtr;
|
||||
Tcl_Command token;
|
||||
Tcl_DictSearch search;
|
||||
Tcl_Obj *listObj;
|
||||
const char *simpleName;
|
||||
int index, done;
|
||||
|
||||
if (nsPtr == NULL || nsPtr->flags & NS_DYING) {
|
||||
@@ -184,7 +185,6 @@ TclNamespaceEnsembleCmd(
|
||||
int permitPrefix = 1;
|
||||
Tcl_Obj *unknownObj = NULL;
|
||||
Tcl_Obj *paramObj = NULL;
|
||||
int ensCompFlag = -1;
|
||||
|
||||
/*
|
||||
* Check that we've got option-value pairs... [Bug 1558654]
|
||||
@@ -197,13 +197,8 @@ TclNamespaceEnsembleCmd(
|
||||
objv += 2;
|
||||
objc -= 2;
|
||||
|
||||
/*
|
||||
* Work out what name to use for the command to create. If supplied,
|
||||
* it is either fully specified or relative to the current namespace.
|
||||
* If not supplied, it is exactly the name of the current namespace.
|
||||
*/
|
||||
|
||||
name = nsPtr->fullName;
|
||||
name = nsPtr->name;
|
||||
cxtPtr = (Namespace *) nsPtr->parentPtr;
|
||||
|
||||
/*
|
||||
* Parse the option list, applying type checks as we go. Note that we
|
||||
@@ -223,6 +218,7 @@ TclNamespaceEnsembleCmd(
|
||||
switch ((enum EnsCreateOpts) index) {
|
||||
case CRT_CMD:
|
||||
name = TclGetString(objv[1]);
|
||||
cxtPtr = nsPtr;
|
||||
continue;
|
||||
case CRT_SUBCMDS:
|
||||
if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
|
||||
@@ -327,12 +323,6 @@ TclNamespaceEnsembleCmd(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
continue;
|
||||
case CRT_COMPILE:
|
||||
if (Tcl_GetBooleanFromObj(interp, objv[1],
|
||||
&ensCompFlag) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
};
|
||||
continue;
|
||||
case CRT_UNKNOWN:
|
||||
if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
|
||||
if (allocatedMapFlag) {
|
||||
@@ -345,6 +335,10 @@ TclNamespaceEnsembleCmd(
|
||||
}
|
||||
}
|
||||
|
||||
TclGetNamespaceForQualName(interp, name, cxtPtr,
|
||||
TCL_CREATE_NS_IF_UNKNOWN, &foundNsPtr, &altFoundNsPtr, &actualCxtPtr,
|
||||
&simpleName);
|
||||
|
||||
/*
|
||||
* Create the ensemble. Note that this might delete another ensemble
|
||||
* linked to the same namespace, so we must be careful. However, we
|
||||
@@ -352,18 +346,13 @@ TclNamespaceEnsembleCmd(
|
||||
* we've created it (and after any deletions have occurred.)
|
||||
*/
|
||||
|
||||
token = Tcl_CreateEnsemble(interp, name, NULL,
|
||||
(permitPrefix ? TCL_ENSEMBLE_PREFIX : 0));
|
||||
token = TclCreateEnsembleInNs(interp, simpleName,
|
||||
(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);
|
||||
Tcl_SetEnsembleParameterList(interp, token, paramObj);
|
||||
/*
|
||||
* Ensemble should be compiled if it has map (performance purposes)
|
||||
*/
|
||||
if (ensCompFlag > 0 && mapObj != NULL) {
|
||||
Tcl_SetEnsembleFlags(interp, token, ENSEMBLE_COMPILE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tricky! Must ensure that the result is not shared (command delete
|
||||
@@ -650,48 +639,38 @@ TclNamespaceEnsembleCmd(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_CreateEnsemble --
|
||||
* TclCreateEnsembleInNs --
|
||||
*
|
||||
* Create a simple ensemble attached to the given namespace.
|
||||
*
|
||||
* Results:
|
||||
* The token for the command created.
|
||||
*
|
||||
* Side effects:
|
||||
* The ensemble is created and marked for compilation.
|
||||
* Like Tcl_CreateEnsemble, but additionally accepts as an argument the
|
||||
* name of the namespace to create the command in.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Tcl_Command
|
||||
Tcl_CreateEnsemble(
|
||||
Tcl_Interp *interp,
|
||||
const char *name,
|
||||
Tcl_Namespace *namespacePtr,
|
||||
int flags)
|
||||
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
|
||||
)
|
||||
{
|
||||
Namespace *nsPtr = (Namespace *) namespacePtr;
|
||||
EnsembleConfig *ensemblePtr = ckalloc(sizeof(EnsembleConfig));
|
||||
Tcl_Obj *nameObj = NULL;
|
||||
Namespace *nsPtr = (Namespace *) ensembleNsPtr;
|
||||
EnsembleConfig *ensemblePtr;
|
||||
Tcl_Command token;
|
||||
|
||||
if (nsPtr == NULL) {
|
||||
nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the name of the ensemble into a fully qualified name. This might
|
||||
* allocate a temporary object.
|
||||
*/
|
||||
|
||||
if (!(name[0] == ':' && name[1] == ':')) {
|
||||
nameObj = NewNsObj((Tcl_Namespace *) nsPtr);
|
||||
if (nsPtr->parentPtr == NULL) {
|
||||
Tcl_AppendStringsToObj(nameObj, name, NULL);
|
||||
} else {
|
||||
Tcl_AppendStringsToObj(nameObj, "::", name, NULL);
|
||||
}
|
||||
Tcl_IncrRefCount(nameObj);
|
||||
name = TclGetString(nameObj);
|
||||
ensemblePtr = ckalloc(sizeof(EnsembleConfig));
|
||||
token = TclNRCreateCommandInNs(interp, name,
|
||||
(Tcl_Namespace *) nameNsPtr, NsEnsembleImplementationCmd,
|
||||
NsEnsembleImplementationCmdNR, ensemblePtr, DeleteEnsembleConfig);
|
||||
if (token == NULL) {
|
||||
ckfree(ensemblePtr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ensemblePtr->nsPtr = nsPtr;
|
||||
@@ -704,9 +683,7 @@ Tcl_CreateEnsemble(
|
||||
ensemblePtr->numParameters = 0;
|
||||
ensemblePtr->parameterList = NULL;
|
||||
ensemblePtr->unknownHandler = NULL;
|
||||
ensemblePtr->token = Tcl_NRCreateCommand(interp, name,
|
||||
NsEnsembleImplementationCmd, NsEnsembleImplementationCmdNR,
|
||||
ensemblePtr, DeleteEnsembleConfig);
|
||||
ensemblePtr->token = token;
|
||||
ensemblePtr->next = (EnsembleConfig *) nsPtr->ensembles;
|
||||
nsPtr->ensembles = (Tcl_Ensemble *) ensemblePtr;
|
||||
|
||||
@@ -723,11 +700,52 @@ Tcl_CreateEnsemble(
|
||||
((Command *) ensemblePtr->token)->compileProc = TclCompileEnsemble;
|
||||
}
|
||||
|
||||
if (nameObj != NULL) {
|
||||
TclDecrRefCount(nameObj);
|
||||
}
|
||||
return ensemblePtr->token;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_CreateEnsemble
|
||||
*
|
||||
* Create a simple ensemble attached to the given namespace.
|
||||
*
|
||||
* Deprecated by TclCreateEnsembleInNs.
|
||||
*
|
||||
* Value
|
||||
*
|
||||
* The token for the command created.
|
||||
*
|
||||
* Effect
|
||||
* The ensemble is created and marked for compilation.
|
||||
*
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Tcl_Command
|
||||
Tcl_CreateEnsemble(
|
||||
Tcl_Interp *interp,
|
||||
const char *name,
|
||||
Tcl_Namespace *namespacePtr,
|
||||
int flags)
|
||||
{
|
||||
Namespace *nsPtr = (Namespace *)namespacePtr, *foundNsPtr, *altNsPtr,
|
||||
*actualNsPtr;
|
||||
const char * simpleName;
|
||||
|
||||
if (nsPtr == NULL) {
|
||||
nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
|
||||
}
|
||||
|
||||
TclGetNamespaceForQualName(interp, name, nsPtr, TCL_CREATE_NS_IF_UNKNOWN,
|
||||
&foundNsPtr, &altNsPtr, &actualNsPtr, &simpleName);
|
||||
return TclCreateEnsembleInNs(interp, simpleName,
|
||||
(Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr, flags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -1899,6 +1917,7 @@ NsEnsembleImplementationCmdNR(
|
||||
|
||||
TclSkipTailcall(interp);
|
||||
Tcl_ListObjGetElements(NULL, copyPtr, ©Objc, ©Objv);
|
||||
((Interp *)interp)->lookupNsPtr = ensemblePtr->nsPtr;
|
||||
return TclNREvalObjv(interp, copyObjc, copyObjv, TCL_EVAL_INVOKE, NULL);
|
||||
}
|
||||
|
||||
@@ -2412,14 +2431,32 @@ MakeCachedEnsembleCommand(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
ClearTable(
|
||||
EnsembleConfig *ensemblePtr)
|
||||
{
|
||||
Tcl_HashTable *hash = &ensemblePtr->subcommandTable;
|
||||
|
||||
if (hash->numEntries != 0) {
|
||||
Tcl_HashSearch search;
|
||||
Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(hash, &search);
|
||||
|
||||
while (hPtr != NULL) {
|
||||
Tcl_Obj *prefixObj = Tcl_GetHashValue(hPtr);
|
||||
Tcl_DecrRefCount(prefixObj);
|
||||
hPtr = Tcl_NextHashEntry(&search);
|
||||
}
|
||||
ckfree((char *) ensemblePtr->subcommandArrayPtr);
|
||||
}
|
||||
Tcl_DeleteHashTable(hash);
|
||||
}
|
||||
|
||||
static void
|
||||
DeleteEnsembleConfig(
|
||||
ClientData clientData)
|
||||
{
|
||||
EnsembleConfig *ensemblePtr = clientData;
|
||||
Namespace *nsPtr = ensemblePtr->nsPtr;
|
||||
Tcl_HashSearch search;
|
||||
Tcl_HashEntry *hEnt;
|
||||
|
||||
/*
|
||||
* Unlink from the ensemble chain if it has not been marked as having been
|
||||
@@ -2453,17 +2490,7 @@ DeleteEnsembleConfig(
|
||||
* Kill the pointer-containing fields.
|
||||
*/
|
||||
|
||||
if (ensemblePtr->subcommandTable.numEntries != 0) {
|
||||
ckfree(ensemblePtr->subcommandArrayPtr);
|
||||
}
|
||||
hEnt = Tcl_FirstHashEntry(&ensemblePtr->subcommandTable, &search);
|
||||
while (hEnt != NULL) {
|
||||
Tcl_Obj *prefixObj = Tcl_GetHashValue(hEnt);
|
||||
|
||||
Tcl_DecrRefCount(prefixObj);
|
||||
hEnt = Tcl_NextHashEntry(&search);
|
||||
}
|
||||
Tcl_DeleteHashTable(&ensemblePtr->subcommandTable);
|
||||
ClearTable(ensemblePtr);
|
||||
if (ensemblePtr->subcmdList != NULL) {
|
||||
Tcl_DecrRefCount(ensemblePtr->subcmdList);
|
||||
}
|
||||
@@ -2493,10 +2520,9 @@ DeleteEnsembleConfig(
|
||||
* BuildEnsembleConfig --
|
||||
*
|
||||
* Create the internal data structures that describe how an ensemble
|
||||
* looks, being a hash mapping from the full command name to the Tcl list
|
||||
* looks, being a hash mapping from the simple command name to the Tcl list
|
||||
* that describes the implementation prefix words, and a sorted array of
|
||||
* all the full command names to allow for reasonably efficient
|
||||
* unambiguous prefix handling.
|
||||
* the names to allow for reasonably efficient unambiguous prefix handling.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
@@ -2519,100 +2545,101 @@ BuildEnsembleConfig(
|
||||
int i, j, isNew;
|
||||
Tcl_HashTable *hash = &ensemblePtr->subcommandTable;
|
||||
Tcl_HashEntry *hPtr;
|
||||
Tcl_Obj *mapDict = ensemblePtr->subcommandDict;
|
||||
Tcl_Obj *subList = ensemblePtr->subcmdList;
|
||||
|
||||
if (hash->numEntries != 0) {
|
||||
/*
|
||||
* Remove pre-existing table.
|
||||
*/
|
||||
ClearTable(ensemblePtr);
|
||||
Tcl_InitHashTable(hash, TCL_STRING_KEYS);
|
||||
|
||||
ckfree(ensemblePtr->subcommandArrayPtr);
|
||||
hPtr = Tcl_FirstHashEntry(hash, &search);
|
||||
while (hPtr != NULL) {
|
||||
Tcl_Obj *prefixObj = Tcl_GetHashValue(hPtr);
|
||||
if (subList) {
|
||||
int subc;
|
||||
Tcl_Obj **subv, *target, *cmdObj, *cmdPrefixObj;
|
||||
char *name;
|
||||
|
||||
Tcl_DecrRefCount(prefixObj);
|
||||
hPtr = Tcl_NextHashEntry(&search);
|
||||
}
|
||||
Tcl_DeleteHashTable(hash);
|
||||
Tcl_InitHashTable(hash, TCL_STRING_KEYS);
|
||||
}
|
||||
/*
|
||||
* There is a list of exactly what subcommands go in the table.
|
||||
* Must determine the target for each.
|
||||
*/
|
||||
|
||||
/*
|
||||
* See if we've got an export list. If so, we will only export exactly
|
||||
* those commands, which may be either implemented by the prefix in the
|
||||
* subcommandDict or mapped directly onto the namespace's commands.
|
||||
*/
|
||||
Tcl_ListObjGetElements(NULL, subList, &subc, &subv);
|
||||
if (subList == mapDict) {
|
||||
/*
|
||||
* Strange case where explicit list of subcommands is same value
|
||||
* as the dict mapping to targets.
|
||||
*/
|
||||
|
||||
if (ensemblePtr->subcmdList != NULL) {
|
||||
Tcl_Obj **subcmdv, *target, *cmdObj, *cmdPrefixObj;
|
||||
int subcmdc;
|
||||
for (i = 0; i < subc; i += 2) {
|
||||
name = TclGetString(subv[i]);
|
||||
hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
|
||||
if (!isNew) {
|
||||
cmdObj = (Tcl_Obj *)Tcl_GetHashValue(hPtr);
|
||||
Tcl_DecrRefCount(cmdObj);
|
||||
}
|
||||
Tcl_SetHashValue(hPtr, subv[i+1]);
|
||||
Tcl_IncrRefCount(subv[i+1]);
|
||||
|
||||
TclListObjGetElements(NULL, ensemblePtr->subcmdList, &subcmdc,
|
||||
&subcmdv);
|
||||
for (i=0 ; i<subcmdc ; i++) {
|
||||
const char *name = TclGetString(subcmdv[i]);
|
||||
name = TclGetString(subv[i+1]);
|
||||
hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
|
||||
if (isNew) {
|
||||
cmdObj = Tcl_NewStringObj(name, -1);
|
||||
cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
|
||||
Tcl_SetHashValue(hPtr, cmdPrefixObj);
|
||||
Tcl_IncrRefCount(cmdPrefixObj);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Usual case where we can freely act on the list and dict. */
|
||||
|
||||
hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
|
||||
for (i = 0; i < subc; i++) {
|
||||
name = TclGetString(subv[i]);
|
||||
hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
|
||||
if (!isNew) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip non-unique cases.
|
||||
*/
|
||||
/* Lookup target in the dictionary */
|
||||
if (mapDict) {
|
||||
Tcl_DictObjGet(NULL, mapDict, subv[i], &target);
|
||||
if (target) {
|
||||
Tcl_SetHashValue(hPtr, target);
|
||||
Tcl_IncrRefCount(target);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNew) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* 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).
|
||||
*/
|
||||
cmdObj = Tcl_NewStringObj(name, -1);
|
||||
cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
|
||||
Tcl_SetHashValue(hPtr, cmdPrefixObj);
|
||||
Tcl_IncrRefCount(cmdPrefixObj);
|
||||
}
|
||||
}
|
||||
} else if (mapDict) {
|
||||
/*
|
||||
* No subcmd list, but we do have a mapping dictionary so we should
|
||||
* use the keys of that. Convert the dictionary's contents into the
|
||||
* form required for the ensemble's internal hashtable.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Look in our dictionary (if present) for the command.
|
||||
*/
|
||||
Tcl_DictSearch dictSearch;
|
||||
Tcl_Obj *keyObj, *valueObj;
|
||||
int done;
|
||||
|
||||
if (ensemblePtr->subcommandDict != NULL) {
|
||||
Tcl_DictObjGet(NULL, ensemblePtr->subcommandDict, subcmdv[i],
|
||||
&target);
|
||||
if (target != NULL) {
|
||||
Tcl_SetHashValue(hPtr, target);
|
||||
Tcl_IncrRefCount(target);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Tcl_DictObjFirst(NULL, ensemblePtr->subcommandDict, &dictSearch,
|
||||
&keyObj, &valueObj, &done);
|
||||
while (!done) {
|
||||
char *name = TclGetString(keyObj);
|
||||
|
||||
/*
|
||||
* Not there, 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).
|
||||
*/
|
||||
|
||||
cmdObj = NewNsObj((Tcl_Namespace *) ensemblePtr->nsPtr);
|
||||
if (ensemblePtr->nsPtr->parentPtr != NULL) {
|
||||
Tcl_AppendStringsToObj(cmdObj, "::", name, NULL);
|
||||
} else {
|
||||
Tcl_AppendStringsToObj(cmdObj, name, NULL);
|
||||
}
|
||||
cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
|
||||
Tcl_SetHashValue(hPtr, cmdPrefixObj);
|
||||
Tcl_IncrRefCount(cmdPrefixObj);
|
||||
}
|
||||
} else if (ensemblePtr->subcommandDict != NULL) {
|
||||
/*
|
||||
* No subcmd list, but we do have a mapping dictionary so we should
|
||||
* use the keys of that. Convert the dictionary's contents into the
|
||||
* form required for the ensemble's internal hashtable.
|
||||
*/
|
||||
|
||||
Tcl_DictSearch dictSearch;
|
||||
Tcl_Obj *keyObj, *valueObj;
|
||||
int done;
|
||||
|
||||
Tcl_DictObjFirst(NULL, ensemblePtr->subcommandDict, &dictSearch,
|
||||
&keyObj, &valueObj, &done);
|
||||
while (!done) {
|
||||
const char *name = TclGetString(keyObj);
|
||||
|
||||
hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
|
||||
Tcl_SetHashValue(hPtr, valueObj);
|
||||
Tcl_IncrRefCount(valueObj);
|
||||
Tcl_DictObjNext(&dictSearch, &keyObj, &valueObj, &done);
|
||||
}
|
||||
hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
|
||||
Tcl_SetHashValue(hPtr, valueObj);
|
||||
Tcl_IncrRefCount(valueObj);
|
||||
Tcl_DictObjNext(&dictSearch, &keyObj, &valueObj, &done);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Discover what commands are actually exported by the namespace.
|
||||
@@ -2648,11 +2675,7 @@ BuildEnsembleConfig(
|
||||
if (isNew) {
|
||||
Tcl_Obj *cmdObj, *cmdPrefixObj;
|
||||
|
||||
TclNewObj(cmdObj);
|
||||
Tcl_AppendStringsToObj(cmdObj,
|
||||
ensemblePtr->nsPtr->fullName,
|
||||
(ensemblePtr->nsPtr->parentPtr ? "::" : ""),
|
||||
nsCmdName, NULL);
|
||||
cmdObj = Tcl_NewStringObj(nsCmdName, -1);
|
||||
cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
|
||||
Tcl_SetHashValue(hPtr, cmdPrefixObj);
|
||||
Tcl_IncrRefCount(cmdPrefixObj);
|
||||
|
||||
+13
-10
@@ -17,11 +17,6 @@
|
||||
|
||||
TCL_DECLARE_MUTEX(envMutex) /* To serialize access to environ. */
|
||||
|
||||
|
||||
/* MODULE_SCOPE */
|
||||
size_t TclEnvEpoch = 0; /* Epoch of the tcl environment
|
||||
* (if changed with tcl-env). */
|
||||
|
||||
static struct {
|
||||
int cacheSize; /* Number of env strings in cache. */
|
||||
char **cache; /* Array containing all of the environment
|
||||
@@ -135,6 +130,7 @@ TclSetupEnv(
|
||||
* '='; ignore the entry.
|
||||
*/
|
||||
|
||||
Tcl_DStringFree(&envString);
|
||||
continue;
|
||||
}
|
||||
p2++;
|
||||
@@ -376,7 +372,6 @@ Tcl_PutEnv(
|
||||
value[0] = '\0';
|
||||
TclSetEnv(name, value+1);
|
||||
}
|
||||
TclEnvEpoch++;
|
||||
|
||||
Tcl_DStringFree(&nameString);
|
||||
return 0;
|
||||
@@ -585,7 +580,6 @@ EnvTraceProc(
|
||||
|
||||
if (flags & TCL_TRACE_ARRAY) {
|
||||
TclSetupEnv(interp);
|
||||
TclEnvEpoch++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -606,7 +600,6 @@ EnvTraceProc(
|
||||
|
||||
value = Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY);
|
||||
TclSetEnv(name2, value);
|
||||
TclEnvEpoch++;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -630,7 +623,6 @@ EnvTraceProc(
|
||||
|
||||
if (flags & TCL_TRACE_UNSETS) {
|
||||
TclUnsetEnv(name2);
|
||||
TclEnvEpoch++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -731,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
|
||||
}
|
||||
|
||||
+151
-200
@@ -1333,12 +1333,12 @@ TclStackAlloc(
|
||||
int numBytes)
|
||||
{
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
int numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *);
|
||||
int numWords;
|
||||
|
||||
if (iPtr == NULL || iPtr->execEnvPtr == NULL) {
|
||||
return (void *) ckalloc(numBytes);
|
||||
}
|
||||
|
||||
numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *);
|
||||
return (void *) StackAllocWords(interp, numWords);
|
||||
}
|
||||
|
||||
@@ -3321,7 +3321,7 @@ TEBCresume(
|
||||
*/
|
||||
|
||||
DECACHE_STACK_INFO();
|
||||
objResultPtr = TclPtrGetVar(interp, varPtr, arrayPtr,
|
||||
objResultPtr = TclPtrGetVarIdx(interp, varPtr, arrayPtr,
|
||||
part1Ptr, part2Ptr, TCL_LEAVE_ERR_MSG, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
if (!objResultPtr) {
|
||||
@@ -3568,7 +3568,7 @@ TEBCresume(
|
||||
|
||||
doCallPtrSetVar:
|
||||
DECACHE_STACK_INFO();
|
||||
objResultPtr = TclPtrSetVar(interp, varPtr, arrayPtr,
|
||||
objResultPtr = TclPtrSetVarIdx(interp, varPtr, arrayPtr,
|
||||
part1Ptr, part2Ptr, valuePtr, storeFlags, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
if (!objResultPtr) {
|
||||
@@ -3704,7 +3704,7 @@ TEBCresume(
|
||||
VarHashRefCount(arrayPtr)++;
|
||||
}
|
||||
DECACHE_STACK_INFO();
|
||||
objResultPtr = TclPtrGetVar(interp, varPtr, arrayPtr,
|
||||
objResultPtr = TclPtrGetVarIdx(interp, varPtr, arrayPtr,
|
||||
part1Ptr, part2Ptr, TCL_LEAVE_ERR_MSG, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
if (TclIsVarInHash(varPtr)) {
|
||||
@@ -3733,7 +3733,7 @@ TEBCresume(
|
||||
}
|
||||
}
|
||||
DECACHE_STACK_INFO();
|
||||
objResultPtr = TclPtrSetVar(interp, varPtr, arrayPtr, part1Ptr,
|
||||
objResultPtr = TclPtrSetVarIdx(interp, varPtr, arrayPtr, part1Ptr,
|
||||
part2Ptr, objResultPtr, TCL_LEAVE_ERR_MSG, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
if (!objResultPtr) {
|
||||
@@ -3997,7 +3997,7 @@ TEBCresume(
|
||||
Tcl_DecrRefCount(incrPtr);
|
||||
} else {
|
||||
DECACHE_STACK_INFO();
|
||||
objResultPtr = TclPtrIncrObjVar(interp, varPtr, arrayPtr,
|
||||
objResultPtr = TclPtrIncrObjVarIdx(interp, varPtr, arrayPtr,
|
||||
part1Ptr, part2Ptr, incrPtr, TCL_LEAVE_ERR_MSG, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
Tcl_DecrRefCount(incrPtr);
|
||||
@@ -4152,7 +4152,7 @@ TEBCresume(
|
||||
|
||||
slowUnsetScalar:
|
||||
DECACHE_STACK_INFO();
|
||||
if (TclPtrUnsetVar(interp, varPtr, NULL, NULL, NULL, flags,
|
||||
if (TclPtrUnsetVarIdx(interp, varPtr, NULL, NULL, NULL, flags,
|
||||
opnd) != TCL_OK && flags) {
|
||||
goto errorInUnset;
|
||||
}
|
||||
@@ -4169,7 +4169,8 @@ TEBCresume(
|
||||
}
|
||||
TRACE(("%s %u \"%.30s\" => ",
|
||||
(flags ? "normal" : "noerr"), opnd, O2S(part2Ptr)));
|
||||
if (TclIsVarArray(arrayPtr) && !UnsetTraced(arrayPtr)) {
|
||||
if (TclIsVarArray(arrayPtr) && !UnsetTraced(arrayPtr)
|
||||
&& !(arrayPtr->flags & VAR_SEARCH_ACTIVE)) {
|
||||
varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
|
||||
if (varPtr && TclIsVarDirectUnsettable(varPtr)) {
|
||||
/*
|
||||
@@ -4204,7 +4205,7 @@ TEBCresume(
|
||||
if (flags & TCL_LEAVE_ERR_MSG) {
|
||||
goto errorInUnset;
|
||||
}
|
||||
} else if (TclPtrUnsetVar(interp, varPtr, arrayPtr, NULL, part2Ptr,
|
||||
} else if (TclPtrUnsetVarIdx(interp, varPtr, arrayPtr, NULL, part2Ptr,
|
||||
flags, opnd) != TCL_OK && (flags & TCL_LEAVE_ERR_MSG)) {
|
||||
goto errorInUnset;
|
||||
}
|
||||
@@ -4261,7 +4262,7 @@ TEBCresume(
|
||||
varPtr->value.objPtr = NULL;
|
||||
} else {
|
||||
DECACHE_STACK_INFO();
|
||||
TclPtrUnsetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
|
||||
TclPtrUnsetVarIdx(interp, varPtr, NULL, NULL, NULL, 0, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
}
|
||||
NEXT_INST_F(5, 0, 0);
|
||||
@@ -4294,17 +4295,12 @@ TEBCresume(
|
||||
varPtr = TclObjLookupVarEx(interp, part1Ptr, NULL, 0, NULL,
|
||||
/*createPart1*/0, /*createPart2*/0, &arrayPtr);
|
||||
doArrayExists:
|
||||
if (varPtr && (varPtr->flags & VAR_TRACED_ARRAY)
|
||||
&& (TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr))) {
|
||||
DECACHE_STACK_INFO();
|
||||
result = TclObjCallVarTraces(iPtr, arrayPtr, varPtr, part1Ptr,
|
||||
NULL, (TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY|
|
||||
TCL_GLOBAL_ONLY|TCL_TRACE_ARRAY), 1, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
if (result == TCL_ERROR) {
|
||||
TRACE_ERROR(interp);
|
||||
goto gotError;
|
||||
}
|
||||
DECACHE_STACK_INFO();
|
||||
result = TclCheckArrayTraces(interp, varPtr, arrayPtr, part1Ptr, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
if (result == TCL_ERROR) {
|
||||
TRACE_ERROR(interp);
|
||||
goto gotError;
|
||||
}
|
||||
if (varPtr && TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) {
|
||||
objResultPtr = TCONST(1);
|
||||
@@ -4477,7 +4473,7 @@ TEBCresume(
|
||||
if (TclIsVarInHash(otherPtr)) {
|
||||
VarHashRefCount(otherPtr)++;
|
||||
}
|
||||
} else if (TclPtrObjMakeUpvar(interp, otherPtr, NULL, 0,
|
||||
} else if (TclPtrObjMakeUpvarIdx(interp, otherPtr, NULL, 0,
|
||||
opnd) != TCL_OK) {
|
||||
TRACE_ERROR(interp);
|
||||
goto gotError;
|
||||
@@ -5089,16 +5085,9 @@ TEBCresume(
|
||||
goto gotError;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the list item based on the index. Negative operand means
|
||||
* end-based indexing.
|
||||
*/
|
||||
/* Decode end-offset index values. */
|
||||
|
||||
if (opnd < -1) {
|
||||
index = opnd+1 + objc;
|
||||
} else {
|
||||
index = opnd;
|
||||
}
|
||||
index = TclIndexDecode(opnd, objc - 1);
|
||||
pcAdjustment = 5;
|
||||
|
||||
lindexFastPath:
|
||||
@@ -5246,60 +5235,64 @@ TEBCresume(
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Adjust the indices for end-based handling.
|
||||
*/
|
||||
|
||||
if (fromIdx < -1) {
|
||||
fromIdx += 1+objc;
|
||||
if (fromIdx < -1) {
|
||||
fromIdx = -1;
|
||||
}
|
||||
} else if (fromIdx > objc) {
|
||||
fromIdx = objc;
|
||||
}
|
||||
if (toIdx < -1) {
|
||||
toIdx += 1 + objc;
|
||||
if (toIdx < -1) {
|
||||
toIdx = -1;
|
||||
}
|
||||
} else if (toIdx > objc) {
|
||||
toIdx = objc;
|
||||
/* Every range of an empty list is an empty list */
|
||||
if (objc == 0) {
|
||||
TRACE_APPEND(("\n"));
|
||||
NEXT_INST_F(9, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we are referring to a valid, non-empty list range, and if
|
||||
* so, build the list of elements in that range.
|
||||
/* Decode index value operands. */
|
||||
|
||||
/*
|
||||
assert ( toIdx != TCL_INDEX_AFTER);
|
||||
*
|
||||
* Extra safety for legacy bytecodes:
|
||||
*/
|
||||
if (toIdx == TCL_INDEX_AFTER) {
|
||||
toIdx = TCL_INDEX_END;
|
||||
}
|
||||
|
||||
if (fromIdx<=toIdx && fromIdx<objc && toIdx>=0) {
|
||||
if (fromIdx < 0) {
|
||||
fromIdx = 0;
|
||||
}
|
||||
if (toIdx >= objc) {
|
||||
toIdx = objc-1;
|
||||
}
|
||||
if (fromIdx == 0 && toIdx != objc-1 && !Tcl_IsShared(valuePtr)) {
|
||||
/*
|
||||
* BEWARE! This is looking inside the implementation of the
|
||||
* list type.
|
||||
*/
|
||||
if ((toIdx == TCL_INDEX_BEFORE) || (fromIdx == TCL_INDEX_AFTER)) {
|
||||
goto emptyList;
|
||||
}
|
||||
toIdx = TclIndexDecode(toIdx, objc - 1);
|
||||
if (toIdx < 0) {
|
||||
goto emptyList;
|
||||
} else if (toIdx >= objc) {
|
||||
toIdx = objc - 1;
|
||||
}
|
||||
|
||||
List *listPtr = valuePtr->internalRep.twoPtrValue.ptr1;
|
||||
assert ( toIdx >= 0 && toIdx < objc);
|
||||
/*
|
||||
assert ( fromIdx != TCL_INDEX_BEFORE );
|
||||
*
|
||||
* Extra safety for legacy bytecodes:
|
||||
*/
|
||||
if (fromIdx == TCL_INDEX_BEFORE) {
|
||||
fromIdx = TCL_INDEX_START;
|
||||
}
|
||||
|
||||
if (listPtr->refCount == 1) {
|
||||
for (index=toIdx+1; index<objc ; index++) {
|
||||
TclDecrRefCount(objv[index]);
|
||||
}
|
||||
listPtr->elemCount = toIdx+1;
|
||||
listPtr->canonicalFlag = 1;
|
||||
TclInvalidateStringRep(valuePtr);
|
||||
TRACE_APPEND(("%.30s\n", O2S(valuePtr)));
|
||||
NEXT_INST_F(9, 0, 0);
|
||||
fromIdx = TclIndexDecode(fromIdx, objc - 1);
|
||||
if (fromIdx < 0) {
|
||||
fromIdx = 0;
|
||||
}
|
||||
|
||||
if (fromIdx <= toIdx) {
|
||||
/* Construct the subsquence list */
|
||||
/* unshared optimization */
|
||||
if (Tcl_IsShared(valuePtr)) {
|
||||
objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, objv+fromIdx);
|
||||
} else {
|
||||
if (toIdx != objc - 1) {
|
||||
Tcl_ListObjReplace(NULL, valuePtr, toIdx + 1, LIST_MAX,
|
||||
0, NULL);
|
||||
}
|
||||
Tcl_ListObjReplace(NULL, valuePtr, 0, fromIdx, 0, NULL);
|
||||
TRACE_APPEND(("%.30s\n", O2S(valuePtr)));
|
||||
NEXT_INST_F(9, 0, 0);
|
||||
}
|
||||
objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, objv+fromIdx);
|
||||
} else {
|
||||
emptyList:
|
||||
TclNewObj(objResultPtr);
|
||||
}
|
||||
|
||||
@@ -5391,88 +5384,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5645,31 +5560,58 @@ TEBCresume(
|
||||
length = Tcl_GetCharLength(valuePtr);
|
||||
TRACE(("\"%.20s\" %d %d => ", O2S(valuePtr), fromIdx, toIdx));
|
||||
|
||||
/*
|
||||
* Adjust indices for end-based indexing.
|
||||
*/
|
||||
|
||||
if (fromIdx < -1) {
|
||||
fromIdx += 1 + length;
|
||||
if (fromIdx < 0) {
|
||||
fromIdx = 0;
|
||||
}
|
||||
} else if (fromIdx >= length) {
|
||||
fromIdx = length;
|
||||
/* Every range of an empty value is an empty value */
|
||||
if (length == 0) {
|
||||
TRACE_APPEND(("\n"));
|
||||
NEXT_INST_F(9, 0, 0);
|
||||
}
|
||||
if (toIdx < -1) {
|
||||
toIdx += 1 + length;
|
||||
|
||||
/* Decode index operands. */
|
||||
|
||||
/*
|
||||
assert ( toIdx != TCL_INDEX_BEFORE );
|
||||
assert ( toIdx != TCL_INDEX_AFTER);
|
||||
*
|
||||
* Extra safety for legacy bytecodes:
|
||||
*/
|
||||
if (toIdx == TCL_INDEX_BEFORE) {
|
||||
goto emptyRange;
|
||||
}
|
||||
if (toIdx == TCL_INDEX_AFTER) {
|
||||
toIdx = TCL_INDEX_END;
|
||||
}
|
||||
|
||||
toIdx = TclIndexDecode(toIdx, length - 1);
|
||||
if (toIdx < 0) {
|
||||
goto emptyRange;
|
||||
} else if (toIdx >= length) {
|
||||
toIdx = length - 1;
|
||||
}
|
||||
|
||||
assert ( toIdx >= 0 && toIdx < length );
|
||||
|
||||
/*
|
||||
* Check if we can do a sane substring.
|
||||
assert ( fromIdx != TCL_INDEX_BEFORE );
|
||||
assert ( fromIdx != TCL_INDEX_AFTER);
|
||||
*
|
||||
* Extra safety for legacy bytecodes:
|
||||
*/
|
||||
if (fromIdx == TCL_INDEX_BEFORE) {
|
||||
fromIdx = TCL_INDEX_START;
|
||||
}
|
||||
if (fromIdx == TCL_INDEX_AFTER) {
|
||||
goto emptyRange;
|
||||
}
|
||||
|
||||
fromIdx = TclIndexDecode(fromIdx, length - 1);
|
||||
if (fromIdx < 0) {
|
||||
fromIdx = 0;
|
||||
}
|
||||
|
||||
if (fromIdx <= toIdx) {
|
||||
objResultPtr = Tcl_GetRange(valuePtr, fromIdx, toIdx);
|
||||
} else {
|
||||
emptyRange:
|
||||
TclNewObj(objResultPtr);
|
||||
}
|
||||
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
|
||||
@@ -5677,18 +5619,18 @@ TEBCresume(
|
||||
|
||||
{
|
||||
Tcl_UniChar *ustring1, *ustring2, *ustring3, *end, *p;
|
||||
int length3;
|
||||
int length3, endIdx;
|
||||
Tcl_Obj *value3Ptr;
|
||||
|
||||
case INST_STR_REPLACE:
|
||||
value3Ptr = POP_OBJECT();
|
||||
valuePtr = OBJ_AT_DEPTH(2);
|
||||
length = Tcl_GetCharLength(valuePtr) - 1;
|
||||
endIdx = Tcl_GetCharLength(valuePtr) - 1;
|
||||
TRACE(("\"%.20s\" %s %s \"%.20s\" => ", O2S(valuePtr),
|
||||
O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), O2S(value3Ptr)));
|
||||
if (TclGetIntForIndexM(interp, OBJ_UNDER_TOS, length,
|
||||
if (TclGetIntForIndexM(interp, OBJ_UNDER_TOS, endIdx,
|
||||
&fromIdx) != TCL_OK
|
||||
|| TclGetIntForIndexM(interp, OBJ_AT_TOS, length,
|
||||
|| TclGetIntForIndexM(interp, OBJ_AT_TOS, endIdx,
|
||||
&toIdx) != TCL_OK) {
|
||||
TclDecrRefCount(value3Ptr);
|
||||
TRACE_ERROR(interp);
|
||||
@@ -5698,21 +5640,24 @@ TEBCresume(
|
||||
(void) POP_OBJECT();
|
||||
TclDecrRefCount(OBJ_AT_TOS);
|
||||
(void) POP_OBJECT();
|
||||
if (fromIdx < 0) {
|
||||
fromIdx = 0;
|
||||
}
|
||||
|
||||
if (fromIdx > toIdx || fromIdx > length) {
|
||||
if ((toIdx < 0) ||
|
||||
(fromIdx > endIdx) ||
|
||||
(toIdx < fromIdx)) {
|
||||
TRACE_APPEND(("\"%.30s\"\n", O2S(valuePtr)));
|
||||
TclDecrRefCount(value3Ptr);
|
||||
NEXT_INST_F(1, 0, 0);
|
||||
}
|
||||
|
||||
if (toIdx > length) {
|
||||
toIdx = length;
|
||||
if (fromIdx < 0) {
|
||||
fromIdx = 0;
|
||||
}
|
||||
|
||||
if (fromIdx == 0 && toIdx == length) {
|
||||
if (toIdx > endIdx) {
|
||||
toIdx = endIdx;
|
||||
}
|
||||
|
||||
if (fromIdx == 0 && toIdx == endIdx) {
|
||||
TclDecrRefCount(OBJ_AT_TOS);
|
||||
OBJ_AT_TOS = value3Ptr;
|
||||
TRACE_APPEND(("\"%.30s\"\n", O2S(value3Ptr)));
|
||||
@@ -5995,12 +5940,7 @@ TEBCresume(
|
||||
value2Ptr = OBJ_AT_TOS; /* TrimSet */
|
||||
string2 = TclGetStringFromObj(value2Ptr, &length2);
|
||||
string1 = TclGetStringFromObj(valuePtr, &length);
|
||||
trim1 = TclTrimLeft(string1, length, string2, length2);
|
||||
if (trim1 < length) {
|
||||
trim2 = TclTrimRight(string1, length, string2, length2);
|
||||
} else {
|
||||
trim2 = 0;
|
||||
}
|
||||
trim1 = TclTrim(string1, length, string2, length2, &trim2);
|
||||
createTrimmedString:
|
||||
/*
|
||||
* Careful here; trim set often contains non-ASCII characters so we
|
||||
@@ -6124,6 +6064,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) {
|
||||
/*
|
||||
@@ -6938,7 +6886,7 @@ TEBCresume(
|
||||
}
|
||||
} else {
|
||||
DECACHE_STACK_INFO();
|
||||
if (TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
|
||||
if (TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
|
||||
valuePtr, TCL_LEAVE_ERR_MSG, varIndex)==NULL){
|
||||
CACHE_STACK_INFO();
|
||||
TRACE_APPEND((
|
||||
@@ -7109,7 +7057,7 @@ TEBCresume(
|
||||
}
|
||||
} else {
|
||||
DECACHE_STACK_INFO();
|
||||
if (TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
|
||||
if (TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
|
||||
valuePtr, TCL_LEAVE_ERR_MSG, varIndex)==NULL){
|
||||
CACHE_STACK_INFO();
|
||||
TRACE_APPEND(("ERROR init. index temp %d: %.30s",
|
||||
@@ -7332,7 +7280,8 @@ TEBCresume(
|
||||
dictPtr = varPtr->value.objPtr;
|
||||
} else {
|
||||
DECACHE_STACK_INFO();
|
||||
dictPtr = TclPtrGetVar(interp, varPtr, NULL,NULL,NULL, 0, opnd2);
|
||||
dictPtr = TclPtrGetVarIdx(interp, varPtr, NULL, NULL, NULL, 0,
|
||||
opnd2);
|
||||
CACHE_STACK_INFO();
|
||||
}
|
||||
if (dictPtr == NULL) {
|
||||
@@ -7406,7 +7355,7 @@ TEBCresume(
|
||||
} else {
|
||||
Tcl_IncrRefCount(dictPtr);
|
||||
DECACHE_STACK_INFO();
|
||||
objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
|
||||
objResultPtr = TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
|
||||
dictPtr, TCL_LEAVE_ERR_MSG, opnd2);
|
||||
CACHE_STACK_INFO();
|
||||
TclDecrRefCount(dictPtr);
|
||||
@@ -7435,7 +7384,8 @@ TEBCresume(
|
||||
dictPtr = varPtr->value.objPtr;
|
||||
} else {
|
||||
DECACHE_STACK_INFO();
|
||||
dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
|
||||
dictPtr = TclPtrGetVarIdx(interp, varPtr, NULL, NULL, NULL, 0,
|
||||
opnd);
|
||||
CACHE_STACK_INFO();
|
||||
}
|
||||
if (dictPtr == NULL) {
|
||||
@@ -7544,7 +7494,7 @@ TEBCresume(
|
||||
} else {
|
||||
Tcl_IncrRefCount(dictPtr);
|
||||
DECACHE_STACK_INFO();
|
||||
objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
|
||||
objResultPtr = TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
|
||||
dictPtr, TCL_LEAVE_ERR_MSG, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
TclDecrRefCount(dictPtr);
|
||||
@@ -7638,7 +7588,7 @@ TEBCresume(
|
||||
dictPtr = varPtr->value.objPtr;
|
||||
} else {
|
||||
DECACHE_STACK_INFO();
|
||||
dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL,
|
||||
dictPtr = TclPtrGetVarIdx(interp, varPtr, NULL, NULL, NULL,
|
||||
TCL_LEAVE_ERR_MSG, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
if (dictPtr == NULL) {
|
||||
@@ -7671,7 +7621,7 @@ TEBCresume(
|
||||
TclObjUnsetVar2(interp,
|
||||
localName(iPtr->varFramePtr, duiPtr->varIndices[i]),
|
||||
NULL, 0);
|
||||
} else if (TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
|
||||
} else if (TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
|
||||
valuePtr, TCL_LEAVE_ERR_MSG,
|
||||
duiPtr->varIndices[i]) == NULL) {
|
||||
CACHE_STACK_INFO();
|
||||
@@ -7698,7 +7648,8 @@ TEBCresume(
|
||||
dictPtr = varPtr->value.objPtr;
|
||||
} else {
|
||||
DECACHE_STACK_INFO();
|
||||
dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
|
||||
dictPtr = TclPtrGetVarIdx(interp, varPtr, NULL, NULL, NULL, 0,
|
||||
opnd);
|
||||
CACHE_STACK_INFO();
|
||||
}
|
||||
if (dictPtr == NULL) {
|
||||
@@ -7728,8 +7679,8 @@ TEBCresume(
|
||||
valuePtr = var2Ptr->value.objPtr;
|
||||
} else {
|
||||
DECACHE_STACK_INFO();
|
||||
valuePtr = TclPtrGetVar(interp, var2Ptr, NULL, NULL, NULL, 0,
|
||||
duiPtr->varIndices[i]);
|
||||
valuePtr = TclPtrGetVarIdx(interp, var2Ptr, NULL, NULL, NULL,
|
||||
0, duiPtr->varIndices[i]);
|
||||
CACHE_STACK_INFO();
|
||||
}
|
||||
if (valuePtr == NULL) {
|
||||
@@ -7747,7 +7698,7 @@ TEBCresume(
|
||||
varPtr->value.objPtr = dictPtr;
|
||||
} else {
|
||||
DECACHE_STACK_INFO();
|
||||
objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
|
||||
objResultPtr = TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
|
||||
dictPtr, TCL_LEAVE_ERR_MSG, opnd);
|
||||
CACHE_STACK_INFO();
|
||||
if (objResultPtr == NULL) {
|
||||
|
||||
+30
-24
@@ -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.
|
||||
*/
|
||||
@@ -363,14 +369,7 @@ TclFileDeleteCmd(
|
||||
*/
|
||||
|
||||
if (Tcl_FSLstat(objv[i], &statBuf) != 0) {
|
||||
/*
|
||||
* Trying to delete a file that does not exist is not considered
|
||||
* an error, just a no-op
|
||||
*/
|
||||
|
||||
if (errno != ENOENT) {
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
result = TCL_ERROR;
|
||||
} else if (S_ISDIR(statBuf.st_mode)) {
|
||||
/*
|
||||
* We own a reference count on errorBuffer, if it was set as a
|
||||
@@ -406,13 +405,20 @@ TclFileDeleteCmd(
|
||||
}
|
||||
|
||||
if (result != TCL_OK) {
|
||||
result = TCL_ERROR;
|
||||
|
||||
/*
|
||||
* Avoid possible race condition (file/directory deleted after call
|
||||
* of lstat), so bypass ENOENT because not an error, just a no-op
|
||||
*/
|
||||
if (errno == ENOENT) {
|
||||
result = TCL_OK;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* It is important that we break on error, otherwise we might end
|
||||
* up owning reference counts on numerous errorBuffers.
|
||||
*/
|
||||
|
||||
result = TCL_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1904,7 +1904,7 @@ TclGlob(
|
||||
}
|
||||
|
||||
/*
|
||||
* To process a [glob] invokation, this function may be called multiple
|
||||
* To process a [glob] invocation, this function may be called multiple
|
||||
* times. Each time, the previously discovered filenames are in the
|
||||
* interpreter result. We stash that away here so the result is free for
|
||||
* error messsages.
|
||||
|
||||
+131
-65
@@ -9,7 +9,6 @@
|
||||
*
|
||||
* Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
|
||||
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
|
||||
* Copyright (c) 2015 Sergey G. Brester aka sebres.
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution of
|
||||
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
@@ -51,11 +50,73 @@
|
||||
* parsed fields will be returned.
|
||||
*/
|
||||
|
||||
#include "tclDate.h"
|
||||
typedef struct DateInfo {
|
||||
|
||||
Tcl_Obj* messages; /* Error messages */
|
||||
const char* separatrix; /* String separating messages */
|
||||
|
||||
time_t dateYear;
|
||||
time_t dateMonth;
|
||||
time_t dateDay;
|
||||
int dateHaveDate;
|
||||
|
||||
time_t dateHour;
|
||||
time_t dateMinutes;
|
||||
time_t dateSeconds;
|
||||
int dateMeridian;
|
||||
int dateHaveTime;
|
||||
|
||||
time_t dateTimezone;
|
||||
int dateDSTmode;
|
||||
int dateHaveZone;
|
||||
|
||||
time_t dateRelMonth;
|
||||
time_t dateRelDay;
|
||||
time_t dateRelSeconds;
|
||||
int dateHaveRel;
|
||||
|
||||
time_t dateMonthOrdinal;
|
||||
int dateHaveOrdinalMonth;
|
||||
|
||||
time_t dateDayOrdinal;
|
||||
time_t dateDayNumber;
|
||||
int dateHaveDay;
|
||||
|
||||
const char *dateStart;
|
||||
const char *dateInput;
|
||||
time_t *dateRelPointer;
|
||||
|
||||
int dateDigitCount;
|
||||
} DateInfo;
|
||||
|
||||
#define YYMALLOC ckalloc
|
||||
#define YYFREE(x) (ckfree((void*) (x)))
|
||||
|
||||
#define yyDSTmode (info->dateDSTmode)
|
||||
#define yyDayOrdinal (info->dateDayOrdinal)
|
||||
#define yyDayNumber (info->dateDayNumber)
|
||||
#define yyMonthOrdinal (info->dateMonthOrdinal)
|
||||
#define yyHaveDate (info->dateHaveDate)
|
||||
#define yyHaveDay (info->dateHaveDay)
|
||||
#define yyHaveOrdinalMonth (info->dateHaveOrdinalMonth)
|
||||
#define yyHaveRel (info->dateHaveRel)
|
||||
#define yyHaveTime (info->dateHaveTime)
|
||||
#define yyHaveZone (info->dateHaveZone)
|
||||
#define yyTimezone (info->dateTimezone)
|
||||
#define yyDay (info->dateDay)
|
||||
#define yyMonth (info->dateMonth)
|
||||
#define yyYear (info->dateYear)
|
||||
#define yyHour (info->dateHour)
|
||||
#define yyMinutes (info->dateMinutes)
|
||||
#define yySeconds (info->dateSeconds)
|
||||
#define yyMeridian (info->dateMeridian)
|
||||
#define yyRelMonth (info->dateRelMonth)
|
||||
#define yyRelDay (info->dateRelDay)
|
||||
#define yyRelSeconds (info->dateRelSeconds)
|
||||
#define yyRelPointer (info->dateRelPointer)
|
||||
#define yyInput (info->dateInput)
|
||||
#define yyDigitCount (info->dateDigitCount)
|
||||
|
||||
#define EPOCH 1970
|
||||
#define START_OF_TIME 1902
|
||||
#define END_OF_TIME 2037
|
||||
@@ -89,6 +150,14 @@ typedef enum _DSTMODE {
|
||||
DSTon, DSToff, DSTmaybe
|
||||
} DSTMODE;
|
||||
|
||||
/*
|
||||
* Meridian: am, pm, or 24-hour style.
|
||||
*/
|
||||
|
||||
typedef enum _MERIDIAN {
|
||||
MERam, MERpm, MER24
|
||||
} MERIDIAN;
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
@@ -107,6 +176,8 @@ static int LookupWord(YYSTYPE* yylvalPtr, char *buff);
|
||||
DateInfo* info, const char *s);
|
||||
static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location,
|
||||
DateInfo* info);
|
||||
static time_t ToSeconds(time_t Hours, time_t Minutes,
|
||||
time_t Seconds, MERIDIAN Meridian);
|
||||
MODULE_SCOPE int yyparse(DateInfo*);
|
||||
|
||||
%}
|
||||
@@ -306,12 +377,12 @@ date : tUNUMBER '/' tUNUMBER {
|
||||
;
|
||||
|
||||
ordMonth: tNEXT tMONTH {
|
||||
yyMonthOrdinalIncr = 1;
|
||||
yyMonthOrdinal = $2;
|
||||
yyMonthOrdinal = 1;
|
||||
yyMonth = $2;
|
||||
}
|
||||
| tNEXT tUNUMBER tMONTH {
|
||||
yyMonthOrdinalIncr = $2;
|
||||
yyMonthOrdinal = $3;
|
||||
yyMonthOrdinal = $2;
|
||||
yyMonth = $3;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -659,11 +730,11 @@ TclDateerror(
|
||||
infoPtr->separatrix = "\n";
|
||||
}
|
||||
|
||||
MODULE_SCOPE int
|
||||
static time_t
|
||||
ToSeconds(
|
||||
int Hours,
|
||||
int Minutes,
|
||||
int Seconds,
|
||||
time_t Hours,
|
||||
time_t Minutes,
|
||||
time_t Seconds,
|
||||
MERIDIAN Meridian)
|
||||
{
|
||||
if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) {
|
||||
@@ -886,36 +957,65 @@ TclDatelex(
|
||||
} while (Count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TclClockFreeScan(
|
||||
TclClockOldscanObjCmd(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* Tcl interpreter */
|
||||
DateInfo *info) /* Input and result parameters */
|
||||
int objc, /* Count of paraneters */
|
||||
Tcl_Obj *const *objv) /* Parameters */
|
||||
{
|
||||
Tcl_Obj *result, *resultElement;
|
||||
int yr, mo, da;
|
||||
DateInfo dateInfo;
|
||||
DateInfo* info = &dateInfo;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* yyInput = stringToParse;
|
||||
*
|
||||
* ClockInitDateInfo(info) should be executed to pre-init info;
|
||||
*/
|
||||
if (objc != 5) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
"stringToParse baseYear baseMonth baseDay" );
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
yyDSTmode = DSTmaybe;
|
||||
yyInput = Tcl_GetString( objv[1] );
|
||||
dateInfo.dateStart = yyInput;
|
||||
|
||||
info->messages = Tcl_NewObj();
|
||||
info->separatrix = "";
|
||||
Tcl_IncrRefCount(info->messages);
|
||||
yyHaveDate = 0;
|
||||
if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK
|
||||
|| Tcl_GetIntFromObj(interp, objv[3], &mo) != TCL_OK
|
||||
|| Tcl_GetIntFromObj(interp, objv[4], &da) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
yyYear = yr; yyMonth = mo; yyDay = da;
|
||||
|
||||
info->dateStart = yyInput;
|
||||
status = yyparse(info);
|
||||
yyHaveTime = 0;
|
||||
yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24;
|
||||
|
||||
yyHaveZone = 0;
|
||||
yyTimezone = 0; yyDSTmode = DSTmaybe;
|
||||
|
||||
yyHaveOrdinalMonth = 0;
|
||||
yyMonthOrdinal = 0;
|
||||
|
||||
yyHaveDay = 0;
|
||||
yyDayOrdinal = 0; yyDayNumber = 0;
|
||||
|
||||
yyHaveRel = 0;
|
||||
yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL;
|
||||
|
||||
dateInfo.messages = Tcl_NewObj();
|
||||
dateInfo.separatrix = "";
|
||||
Tcl_IncrRefCount(dateInfo.messages);
|
||||
|
||||
status = yyparse(&dateInfo);
|
||||
if (status == 1) {
|
||||
Tcl_SetObjResult(interp, info->messages);
|
||||
Tcl_DecrRefCount(info->messages);
|
||||
Tcl_SetObjResult(interp, dateInfo.messages);
|
||||
Tcl_DecrRefCount(dateInfo.messages);
|
||||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL);
|
||||
return TCL_ERROR;
|
||||
} else if (status == 2) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1));
|
||||
Tcl_DecrRefCount(info->messages);
|
||||
Tcl_DecrRefCount(dateInfo.messages);
|
||||
Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
|
||||
return TCL_ERROR;
|
||||
} else if (status != 0) {
|
||||
@@ -923,11 +1023,11 @@ TclClockFreeScan(
|
||||
"from date parser. Please "
|
||||
"report this error as a "
|
||||
"bug in Tcl.", -1));
|
||||
Tcl_DecrRefCount(info->messages);
|
||||
Tcl_DecrRefCount(dateInfo.messages);
|
||||
Tcl_SetErrorCode(interp, "TCL", "BUG", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_DecrRefCount(info->messages);
|
||||
Tcl_DecrRefCount(dateInfo.messages);
|
||||
|
||||
if (yyHaveDate > 1) {
|
||||
Tcl_SetObjResult(interp,
|
||||
@@ -960,40 +1060,6 @@ TclClockFreeScan(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
int
|
||||
TclClockOldscanObjCmd(
|
||||
ClientData clientData, /* Unused */
|
||||
Tcl_Interp *interp, /* Tcl interpreter */
|
||||
int objc, /* Count of paraneters */
|
||||
Tcl_Obj *const *objv) /* Parameters */
|
||||
{
|
||||
Tcl_Obj *result, *resultElement;
|
||||
int yr, mo, da;
|
||||
DateInfo dateInfo;
|
||||
DateInfo* info = &dateInfo;
|
||||
|
||||
if (objc != 5) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
"stringToParse baseYear baseMonth baseDay" );
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
yyInput = Tcl_GetString( objv[1] );
|
||||
|
||||
if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK
|
||||
|| Tcl_GetIntFromObj(interp, objv[3], &mo) != TCL_OK
|
||||
|| Tcl_GetIntFromObj(interp, objv[4], &da) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
yyYear = yr; yyMonth = mo; yyDay = da;
|
||||
|
||||
if (TclClockFreeScan(interp, info) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
result = Tcl_NewObj();
|
||||
resultElement = Tcl_NewObj();
|
||||
if (yyHaveDate) {
|
||||
@@ -1044,10 +1110,10 @@ TclClockOldscanObjCmd(
|
||||
|
||||
resultElement = Tcl_NewObj();
|
||||
if (yyHaveOrdinalMonth) {
|
||||
Tcl_ListObjAppendElement(interp, resultElement,
|
||||
Tcl_NewIntObj((int) yyMonthOrdinalIncr));
|
||||
Tcl_ListObjAppendElement(interp, resultElement,
|
||||
Tcl_NewIntObj((int) yyMonthOrdinal));
|
||||
Tcl_ListObjAppendElement(interp, resultElement,
|
||||
Tcl_NewIntObj((int) yyMonth));
|
||||
}
|
||||
Tcl_ListObjAppendElement(interp, result, resultElement);
|
||||
|
||||
|
||||
+8
-5
@@ -1014,12 +1014,18 @@ static void
|
||||
RebuildTable(
|
||||
register Tcl_HashTable *tablePtr) /* Table to enlarge. */
|
||||
{
|
||||
int oldSize, count, index;
|
||||
Tcl_HashEntry **oldBuckets;
|
||||
int count, index, oldSize = tablePtr->numBuckets;
|
||||
Tcl_HashEntry **oldBuckets = tablePtr->buckets;
|
||||
register Tcl_HashEntry **oldChainPtr, **newChainPtr;
|
||||
register Tcl_HashEntry *hPtr;
|
||||
const Tcl_HashKeyType *typePtr;
|
||||
|
||||
/* Avoid outgrowing capability of the memory allocators */
|
||||
if (oldSize > (int)(UINT_MAX / (4 * sizeof(Tcl_HashEntry *)))) {
|
||||
tablePtr->rebuildSize = INT_MAX;
|
||||
return;
|
||||
}
|
||||
|
||||
if (tablePtr->keyType == TCL_STRING_KEYS) {
|
||||
typePtr = &tclStringHashKeyType;
|
||||
} else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
|
||||
@@ -1031,9 +1037,6 @@ RebuildTable(
|
||||
typePtr = &tclArrayHashKeyType;
|
||||
}
|
||||
|
||||
oldSize = tablePtr->numBuckets;
|
||||
oldBuckets = tablePtr->buckets;
|
||||
|
||||
/*
|
||||
* Allocate and initialize the new bucket array, and set up hashing
|
||||
* constants for new array size.
|
||||
|
||||
+14
-10
@@ -711,17 +711,18 @@ Tcl_SetStdChannel(
|
||||
{
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
|
||||
int init = channel ? 1 : -1;
|
||||
switch (type) {
|
||||
case TCL_STDIN:
|
||||
tsdPtr->stdinInitialized = 1;
|
||||
tsdPtr->stdinInitialized = init;
|
||||
tsdPtr->stdinChannel = channel;
|
||||
break;
|
||||
case TCL_STDOUT:
|
||||
tsdPtr->stdoutInitialized = 1;
|
||||
tsdPtr->stdoutInitialized = init;
|
||||
tsdPtr->stdoutChannel = channel;
|
||||
break;
|
||||
case TCL_STDERR:
|
||||
tsdPtr->stderrInitialized = 1;
|
||||
tsdPtr->stderrInitialized = init;
|
||||
tsdPtr->stderrChannel = channel;
|
||||
break;
|
||||
}
|
||||
@@ -758,8 +759,8 @@ Tcl_GetStdChannel(
|
||||
switch (type) {
|
||||
case TCL_STDIN:
|
||||
if (!tsdPtr->stdinInitialized) {
|
||||
tsdPtr->stdinInitialized = -1;
|
||||
tsdPtr->stdinChannel = TclpGetDefaultStdChannel(TCL_STDIN);
|
||||
tsdPtr->stdinInitialized = 1;
|
||||
|
||||
/*
|
||||
* Artificially bump the refcount to ensure that the channel is
|
||||
@@ -771,6 +772,7 @@ Tcl_GetStdChannel(
|
||||
*/
|
||||
|
||||
if (tsdPtr->stdinChannel != NULL) {
|
||||
tsdPtr->stdinInitialized = 1;
|
||||
Tcl_RegisterChannel(NULL, tsdPtr->stdinChannel);
|
||||
}
|
||||
}
|
||||
@@ -778,9 +780,10 @@ Tcl_GetStdChannel(
|
||||
break;
|
||||
case TCL_STDOUT:
|
||||
if (!tsdPtr->stdoutInitialized) {
|
||||
tsdPtr->stdoutInitialized = -1;
|
||||
tsdPtr->stdoutChannel = TclpGetDefaultStdChannel(TCL_STDOUT);
|
||||
tsdPtr->stdoutInitialized = 1;
|
||||
if (tsdPtr->stdoutChannel != NULL) {
|
||||
tsdPtr->stdoutInitialized = 1;
|
||||
Tcl_RegisterChannel(NULL, tsdPtr->stdoutChannel);
|
||||
}
|
||||
}
|
||||
@@ -788,9 +791,10 @@ Tcl_GetStdChannel(
|
||||
break;
|
||||
case TCL_STDERR:
|
||||
if (!tsdPtr->stderrInitialized) {
|
||||
tsdPtr->stderrInitialized = -1;
|
||||
tsdPtr->stderrChannel = TclpGetDefaultStdChannel(TCL_STDERR);
|
||||
tsdPtr->stderrInitialized = 1;
|
||||
if (tsdPtr->stderrChannel != NULL) {
|
||||
tsdPtr->stderrInitialized = 1;
|
||||
Tcl_RegisterChannel(NULL, tsdPtr->stderrChannel);
|
||||
}
|
||||
}
|
||||
@@ -1058,7 +1062,7 @@ CheckForStdChannelsBeingClosed(
|
||||
ChannelState *statePtr = ((Channel *) chan)->state;
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
|
||||
if (tsdPtr->stdinInitialized
|
||||
if (tsdPtr->stdinInitialized == 1
|
||||
&& tsdPtr->stdinChannel != NULL
|
||||
&& statePtr == ((Channel *)tsdPtr->stdinChannel)->state) {
|
||||
if (statePtr->refCount < 2) {
|
||||
@@ -1066,7 +1070,7 @@ CheckForStdChannelsBeingClosed(
|
||||
tsdPtr->stdinChannel = NULL;
|
||||
return;
|
||||
}
|
||||
} else if (tsdPtr->stdoutInitialized
|
||||
} else if (tsdPtr->stdoutInitialized == 1
|
||||
&& tsdPtr->stdoutChannel != NULL
|
||||
&& statePtr == ((Channel *)tsdPtr->stdoutChannel)->state) {
|
||||
if (statePtr->refCount < 2) {
|
||||
@@ -1074,7 +1078,7 @@ CheckForStdChannelsBeingClosed(
|
||||
tsdPtr->stdoutChannel = NULL;
|
||||
return;
|
||||
}
|
||||
} else if (tsdPtr->stderrInitialized
|
||||
} else if (tsdPtr->stderrInitialized == 1
|
||||
&& tsdPtr->stderrChannel != NULL
|
||||
&& statePtr == ((Channel *)tsdPtr->stderrChannel)->state) {
|
||||
if (statePtr->refCount < 2) {
|
||||
@@ -6660,7 +6664,7 @@ Tcl_Flush(
|
||||
chanPtr = statePtr->topChanPtr;
|
||||
|
||||
if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
|
||||
return -1;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
result = FlushChannel(NULL, chanPtr, 0);
|
||||
|
||||
@@ -41,6 +41,8 @@ static void ReflectWatch(ClientData clientData, int mask);
|
||||
static int ReflectBlock(ClientData clientData, int mode);
|
||||
#ifdef 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);
|
||||
#endif
|
||||
static Tcl_WideInt ReflectSeekWide(ClientData clientData,
|
||||
Tcl_WideInt offset, int mode, int *errorCodePtr);
|
||||
@@ -748,6 +750,7 @@ TclChanCreateObjCmd(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
typedef struct ReflectEvent {
|
||||
Tcl_Event header;
|
||||
ReflectedChannel *rcPtr;
|
||||
@@ -791,6 +794,7 @@ ReflectEventDelete(
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
TclChanPostEventObjCmd(
|
||||
|
||||
+6
-28
@@ -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;
|
||||
|
||||
@@ -412,7 +411,6 @@ Tcl_GetCwd(
|
||||
return Tcl_DStringValue(cwdPtr);
|
||||
}
|
||||
|
||||
/* Obsolete */
|
||||
int
|
||||
Tcl_EvalFile(
|
||||
Tcl_Interp *interp, /* Interpreter in which to process file. */
|
||||
@@ -1762,7 +1760,7 @@ Tcl_FSEvalFileEx(
|
||||
* this cross-platform to allow for scripted documents. [Bug: 2040]
|
||||
*/
|
||||
|
||||
Tcl_SetChannelOption(interp, chan, "-eofchar", "\32");
|
||||
Tcl_SetChannelOption(interp, chan, "-eofchar", "\32 {}");
|
||||
|
||||
/*
|
||||
* If the encoding is specified, set it for the channel. Else don't touch
|
||||
@@ -1896,7 +1894,7 @@ TclNREvalFile(
|
||||
* this cross-platform to allow for scripted documents. [Bug: 2040]
|
||||
*/
|
||||
|
||||
Tcl_SetChannelOption(interp, chan, "-eofchar", "\32");
|
||||
Tcl_SetChannelOption(interp, chan, "-eofchar", "\32 {}");
|
||||
|
||||
/*
|
||||
* If the encoding is specified, set it for the channel. Else don't touch
|
||||
@@ -3160,8 +3158,8 @@ Tcl_FSLoadFile(
|
||||
* present and set to true (any integer > 0) then the unlink is skipped.
|
||||
*/
|
||||
|
||||
int
|
||||
TclSkipUnlink (Tcl_Obj* shlibFile)
|
||||
static int
|
||||
skipUnlink (Tcl_Obj* shlibFile)
|
||||
{
|
||||
/* Order of testing:
|
||||
* 1. On hpux we generally want to skip unlink in general
|
||||
@@ -3415,7 +3413,7 @@ Tcl_LoadFile(
|
||||
*/
|
||||
|
||||
if (
|
||||
!TclSkipUnlink (copyToPtr) &&
|
||||
!skipUnlink (copyToPtr) &&
|
||||
(Tcl_FSDeleteFile(copyToPtr) == TCL_OK)) {
|
||||
Tcl_DecrRefCount(copyToPtr);
|
||||
|
||||
@@ -3684,30 +3682,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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -878,7 +878,8 @@ Tcl_WrongNumArgs(
|
||||
* NULL. */
|
||||
{
|
||||
Tcl_Obj *objPtr;
|
||||
int i, len, elemLen, flags;
|
||||
int i, len, elemLen;
|
||||
char flags;
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
const char *elementStr;
|
||||
|
||||
|
||||
+28
-2
@@ -1011,6 +1011,32 @@ declare 251 {
|
||||
int TclRegisterLiteral(void *envPtr,
|
||||
char *bytes, int length, int flags)
|
||||
}
|
||||
|
||||
# Exporting of the internal API to variables.
|
||||
|
||||
declare 252 {
|
||||
Tcl_Obj *TclPtrGetVar(Tcl_Interp *interp, Tcl_Var varPtr,
|
||||
Tcl_Var arrayPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr,
|
||||
const int flags)
|
||||
}
|
||||
declare 253 {
|
||||
Tcl_Obj *TclPtrSetVar(Tcl_Interp *interp, Tcl_Var varPtr,
|
||||
Tcl_Var arrayPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr,
|
||||
Tcl_Obj *newValuePtr, const int flags)
|
||||
}
|
||||
declare 254 {
|
||||
Tcl_Obj *TclPtrIncrObjVar(Tcl_Interp *interp, Tcl_Var varPtr,
|
||||
Tcl_Var arrayPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr,
|
||||
Tcl_Obj *incrPtr, const int flags)
|
||||
}
|
||||
declare 255 {
|
||||
int TclPtrObjMakeUpvar(Tcl_Interp *interp, Tcl_Var otherPtr,
|
||||
Tcl_Obj *myNamePtr, int myFlags)
|
||||
}
|
||||
declare 256 {
|
||||
int TclPtrUnsetVar(Tcl_Interp *interp, Tcl_Var varPtr, Tcl_Var arrayPtr,
|
||||
Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, const int flags)
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
|
||||
@@ -1062,7 +1088,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 {
|
||||
@@ -1200,7 +1226,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
|
||||
|
||||
+91
-42
@@ -413,7 +413,7 @@ struct NamespacePathEntry {
|
||||
*/
|
||||
|
||||
typedef struct EnsembleConfig {
|
||||
Namespace *nsPtr; /* The namspace backing this ensemble up. */
|
||||
Namespace *nsPtr; /* The namespace backing this ensemble up. */
|
||||
Tcl_Command token; /* The token for the command that provides
|
||||
* ensemble support for the namespace, or NULL
|
||||
* if the command has been deleted (or never
|
||||
@@ -1813,7 +1813,7 @@ typedef struct Interp {
|
||||
* unused space in interp was repurposed for
|
||||
* pluggable bytecode optimizers. The core
|
||||
* contains one optimizer, which can be
|
||||
* selectively overriden by extensions. */
|
||||
* selectively overridden by extensions. */
|
||||
} extra;
|
||||
|
||||
/*
|
||||
@@ -2228,7 +2228,7 @@ typedef struct Interp {
|
||||
* use the rand() or srand() functions.
|
||||
* SAFE_INTERP: Non zero means that the current interp is a safe
|
||||
* interp (i.e. it has only the safe commands installed,
|
||||
* less priviledge than a regular interp).
|
||||
* less privilege than a regular interp).
|
||||
* INTERP_DEBUG_FRAME: Used for switching on various extra interpreter
|
||||
* debug/info mechanisms (e.g. info frame eval/uplevel
|
||||
* tracing) which are performance intensive.
|
||||
@@ -2369,7 +2369,7 @@ typedef struct List {
|
||||
* be ignored if there is no string rep at
|
||||
* all.*/
|
||||
Tcl_Obj *elements; /* First list element; the struct is grown to
|
||||
* accomodate all elements. */
|
||||
* accommodate all elements. */
|
||||
} List;
|
||||
|
||||
#define LIST_MAX \
|
||||
@@ -2422,8 +2422,8 @@ typedef struct List {
|
||||
#define TCL_EACH_COLLECT 1 /* Collect iteration result like [lmap] */
|
||||
|
||||
/*
|
||||
* Macros providing a faster path to integers: Tcl_GetLongFromObj everywhere,
|
||||
* Tcl_GetIntFromObj and TclGetIntForIndex on platforms where longs are ints.
|
||||
* Macros providing a faster path to integers: Tcl_GetLongFromObj,
|
||||
* Tcl_GetIntFromObj and TclGetIntForIndex.
|
||||
*
|
||||
* WARNING: these macros eval their args more than once.
|
||||
*/
|
||||
@@ -2444,9 +2444,17 @@ typedef struct List {
|
||||
: TclGetIntForIndex((interp), (objPtr), (endValue), (idxPtr)))
|
||||
#else
|
||||
#define TclGetIntFromObj(interp, objPtr, intPtr) \
|
||||
Tcl_GetIntFromObj((interp), (objPtr), (intPtr))
|
||||
#define TclGetIntForIndexM(interp, objPtr, ignore, idxPtr) \
|
||||
TclGetIntForIndex(interp, objPtr, ignore, idxPtr)
|
||||
(((objPtr)->typePtr == &tclIntType \
|
||||
&& (objPtr)->internalRep.longValue >= -(Tcl_WideInt)(UINT_MAX) \
|
||||
&& (objPtr)->internalRep.longValue <= (Tcl_WideInt)(UINT_MAX)) \
|
||||
? ((*(intPtr) = (objPtr)->internalRep.longValue), TCL_OK) \
|
||||
: Tcl_GetIntFromObj((interp), (objPtr), (intPtr)))
|
||||
#define TclGetIntForIndexM(interp, objPtr, endValue, idxPtr) \
|
||||
(((objPtr)->typePtr == &tclIntType \
|
||||
&& (objPtr)->internalRep.longValue >= INT_MIN \
|
||||
&& (objPtr)->internalRep.longValue <= INT_MAX) \
|
||||
? ((*(idxPtr) = (objPtr)->internalRep.longValue), TCL_OK) \
|
||||
: TclGetIntForIndex((interp), (objPtr), (endValue), (idxPtr)))
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -2483,13 +2491,13 @@ typedef struct List {
|
||||
* tip of the path, so duplication of shared objects should be done along the
|
||||
* way.
|
||||
*
|
||||
* DICT_PATH_EXISTS indicates that we are performing an existance test and a
|
||||
* DICT_PATH_EXISTS indicates that we are performing an existence test and a
|
||||
* lookup failure should therefore not be an error. If (and only if) this flag
|
||||
* is set, TclTraceDictPath() will return the special value
|
||||
* DICT_PATH_NON_EXISTENT if the path is not traceable.
|
||||
*
|
||||
* DICT_PATH_CREATE (which also requires the DICT_PATH_UPDATE bit to be set)
|
||||
* indicates that we are to create non-existant dictionaries on the path.
|
||||
* indicates that we are to create non-existent dictionaries on the path.
|
||||
*/
|
||||
|
||||
#define DICT_PATH_READ 0
|
||||
@@ -2727,6 +2735,10 @@ MODULE_SCOPE long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS];
|
||||
MODULE_SCOPE char * tclEmptyStringRep;
|
||||
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,
|
||||
@@ -2742,6 +2754,7 @@ MODULE_SCOPE Tcl_ObjCmdProc TclNRForObjCmd;
|
||||
MODULE_SCOPE Tcl_ObjCmdProc TclNRForeachCmd;
|
||||
MODULE_SCOPE Tcl_ObjCmdProc TclNRIfObjCmd;
|
||||
MODULE_SCOPE Tcl_ObjCmdProc TclNRLmapCmd;
|
||||
MODULE_SCOPE Tcl_ObjCmdProc TclNRPackageObjCmd;
|
||||
MODULE_SCOPE Tcl_ObjCmdProc TclNRSourceObjCmd;
|
||||
MODULE_SCOPE Tcl_ObjCmdProc TclNRSubstObjCmd;
|
||||
MODULE_SCOPE Tcl_ObjCmdProc TclNRSwitchObjCmd;
|
||||
@@ -2855,8 +2868,6 @@ MODULE_SCOPE void TclArgumentBCRelease(Tcl_Interp *interp,
|
||||
CmdFrame *cfPtr);
|
||||
MODULE_SCOPE void TclArgumentGet(Tcl_Interp *interp, Tcl_Obj *obj,
|
||||
CmdFrame **cfPtrPtr, int *wordPtr);
|
||||
MODULE_SCOPE int TclArraySet(Tcl_Interp *interp,
|
||||
Tcl_Obj *arrayNameObj, Tcl_Obj *arrayElemObj);
|
||||
MODULE_SCOPE double TclBignumToDouble(const mp_int *bignum);
|
||||
MODULE_SCOPE int TclByteArrayMatch(const unsigned char *string,
|
||||
int strLen, const unsigned char *pattern,
|
||||
@@ -2864,8 +2875,11 @@ MODULE_SCOPE int TclByteArrayMatch(const unsigned char *string,
|
||||
MODULE_SCOPE double TclCeil(const mp_int *a);
|
||||
MODULE_SCOPE void TclChannelPreserve(Tcl_Channel chan);
|
||||
MODULE_SCOPE void TclChannelRelease(Tcl_Channel chan);
|
||||
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;
|
||||
@@ -2879,12 +2893,24 @@ 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,
|
||||
Tcl_CmdDeleteProc *deleteProc);
|
||||
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,
|
||||
const char **elementPtr, const char **nextPtr,
|
||||
int *sizePtr, int *literalPtr);
|
||||
MODULE_SCOPE Tcl_Obj * Tcl_DictObjSmartRef(Tcl_Interp *interp, Tcl_Obj *);
|
||||
/* TIP #280 - Modified token based evulation, with line information. */
|
||||
MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script,
|
||||
int numBytes, int flags, int line,
|
||||
@@ -2908,6 +2934,10 @@ MODULE_SCOPE char * TclDStringAppendDString(Tcl_DString *dsPtr,
|
||||
MODULE_SCOPE Tcl_Obj * TclDStringToObj(Tcl_DString *dsPtr);
|
||||
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,
|
||||
Tcl_Namespace *namespacePtr);
|
||||
|
||||
MODULE_SCOPE void TclFinalizeAllocSubsystem(void);
|
||||
MODULE_SCOPE void TclFinalizeAsync(void);
|
||||
MODULE_SCOPE void TclFinalizeDoubleConversion(void);
|
||||
@@ -2933,6 +2963,15 @@ 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,
|
||||
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);
|
||||
@@ -3099,7 +3138,7 @@ MODULE_SCOPE int TclReToGlob(Tcl_Interp *interp, const char *reStr,
|
||||
int reStrLen, Tcl_DString *dsPtr, int *flagsPtr,
|
||||
int *quantifiersFoundPtr);
|
||||
MODULE_SCOPE int TclScanElement(const char *string, int length,
|
||||
int *flagPtr);
|
||||
char *flagPtr);
|
||||
MODULE_SCOPE void TclSetBgErrorHandler(Tcl_Interp *interp,
|
||||
Tcl_Obj *cmdPrefix);
|
||||
MODULE_SCOPE void TclSetBignumIntRep(Tcl_Obj *objPtr,
|
||||
@@ -3116,6 +3155,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,
|
||||
@@ -3132,6 +3177,8 @@ MODULE_SCOPE void TclSubstParse(Tcl_Interp *interp, const char *bytes,
|
||||
MODULE_SCOPE int TclSubstTokens(Tcl_Interp *interp, Tcl_Token *tokenPtr,
|
||||
int count, int *tokensLeftPtr, int line,
|
||||
int *clNextOuter, const char *outerScript);
|
||||
MODULE_SCOPE int TclTrim(const char *bytes, int numBytes,
|
||||
const char *trim, int numTrim, int *trimRight);
|
||||
MODULE_SCOPE int TclTrimLeft(const char *bytes, int numBytes,
|
||||
const char *trim, int numTrim);
|
||||
MODULE_SCOPE int TclTrimRight(const char *bytes, int numBytes,
|
||||
@@ -3152,22 +3199,10 @@ MODULE_SCOPE int TclpLoadMemory(Tcl_Interp *interp, void *buffer,
|
||||
MODULE_SCOPE void TclInitThreadStorage(void);
|
||||
MODULE_SCOPE void TclFinalizeThreadDataThread(void);
|
||||
MODULE_SCOPE void TclFinalizeThreadStorage(void);
|
||||
|
||||
#ifdef TCL_WIDE_CLICKS
|
||||
MODULE_SCOPE Tcl_WideInt TclpGetWideClicks(void);
|
||||
MODULE_SCOPE double TclpWideClicksToNanoseconds(Tcl_WideInt clicks);
|
||||
MODULE_SCOPE double TclpWideClickInMicrosec(void);
|
||||
#else
|
||||
# ifdef _WIN32
|
||||
# define TCL_WIDE_CLICKS 1
|
||||
MODULE_SCOPE Tcl_WideInt TclpGetWideClicks(void);
|
||||
MODULE_SCOPE double TclpWideClickInMicrosec(void);
|
||||
# define TclpWideClicksToNanoseconds(clicks) \
|
||||
((double)(clicks) * TclpWideClickInMicrosec() * 1000)
|
||||
# endif
|
||||
#endif
|
||||
MODULE_SCOPE Tcl_WideInt TclpGetMicroseconds(void);
|
||||
|
||||
MODULE_SCOPE int TclZlibInit(Tcl_Interp *interp);
|
||||
MODULE_SCOPE void * TclpThreadCreateKey(void);
|
||||
MODULE_SCOPE void TclpThreadDeleteKey(void *keyPtr);
|
||||
@@ -3948,20 +3983,21 @@ MODULE_SCOPE Var * TclLookupArrayElement(Tcl_Interp *interp,
|
||||
const int flags, const char *msg,
|
||||
const int createPart1, const int createPart2,
|
||||
Var *arrayPtr, int index);
|
||||
MODULE_SCOPE Tcl_Obj * TclPtrGetVar(Tcl_Interp *interp,
|
||||
MODULE_SCOPE Tcl_Obj * TclPtrGetVarIdx(Tcl_Interp *interp,
|
||||
Var *varPtr, Var *arrayPtr, Tcl_Obj *part1Ptr,
|
||||
Tcl_Obj *part2Ptr, const int flags, int index);
|
||||
MODULE_SCOPE Tcl_Obj * TclPtrSetVar(Tcl_Interp *interp,
|
||||
MODULE_SCOPE Tcl_Obj * TclPtrSetVarIdx(Tcl_Interp *interp,
|
||||
Var *varPtr, Var *arrayPtr, Tcl_Obj *part1Ptr,
|
||||
Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr,
|
||||
const int flags, int index);
|
||||
MODULE_SCOPE Tcl_Obj * TclPtrIncrObjVar(Tcl_Interp *interp,
|
||||
MODULE_SCOPE Tcl_Obj * TclPtrIncrObjVarIdx(Tcl_Interp *interp,
|
||||
Var *varPtr, Var *arrayPtr, Tcl_Obj *part1Ptr,
|
||||
Tcl_Obj *part2Ptr, Tcl_Obj *incrPtr,
|
||||
const int flags, int index);
|
||||
MODULE_SCOPE int TclPtrObjMakeUpvar(Tcl_Interp *interp, Var *otherPtr,
|
||||
Tcl_Obj *myNamePtr, int myFlags, int index);
|
||||
MODULE_SCOPE int TclPtrUnsetVar(Tcl_Interp *interp, Var *varPtr,
|
||||
MODULE_SCOPE int TclPtrObjMakeUpvarIdx(Tcl_Interp *interp,
|
||||
Var *otherPtr, Tcl_Obj *myNamePtr, int myFlags,
|
||||
int index);
|
||||
MODULE_SCOPE int TclPtrUnsetVarIdx(Tcl_Interp *interp, Var *varPtr,
|
||||
Var *arrayPtr, Tcl_Obj *part1Ptr,
|
||||
Tcl_Obj *part2Ptr, const int flags,
|
||||
int index);
|
||||
@@ -3987,6 +4023,21 @@ MODULE_SCOPE unsigned TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr);
|
||||
|
||||
MODULE_SCOPE int TclFullFinalizationRequested(void);
|
||||
|
||||
/*
|
||||
* Utility routines for encoding index values as integers. Used by both
|
||||
* some of the command compilers and by [lsort] and [lsearch].
|
||||
*/
|
||||
|
||||
MODULE_SCOPE int TclIndexEncode(Tcl_Interp *interp, Tcl_Obj *objPtr,
|
||||
int before, int after, int *indexPtr);
|
||||
MODULE_SCOPE int TclIndexDecode(int encoded, int endValue);
|
||||
|
||||
/* Constants used in index value encoding routines. */
|
||||
#define TCL_INDEX_END (-2)
|
||||
#define TCL_INDEX_BEFORE (-1)
|
||||
#define TCL_INDEX_START (0)
|
||||
#define TCL_INDEX_AFTER (INT_MAX)
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------
|
||||
* Macros used by the Tcl core to create and release Tcl objects.
|
||||
@@ -4371,7 +4422,7 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file,
|
||||
|
||||
#define TclUtfToUniChar(str, chPtr) \
|
||||
((((unsigned char) *(str)) < 0xC0) ? \
|
||||
((*(chPtr) = (Tcl_UniChar) *(str)), 1) \
|
||||
((*(chPtr) = (unsigned char) *(str)), 1) \
|
||||
: Tcl_UtfToUniChar(str, chPtr))
|
||||
|
||||
/*
|
||||
@@ -4415,6 +4466,11 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file,
|
||||
|
||||
#define TclIsPureByteArray(objPtr) \
|
||||
(((objPtr)->typePtr==&tclByteArrayType) && ((objPtr)->bytes==NULL))
|
||||
#define TclIsPureDict(objPtr) \
|
||||
(((objPtr)->bytes==NULL) && ((objPtr)->typePtr==&tclDictType))
|
||||
|
||||
#define TclIsPureList(objPtr) \
|
||||
(((objPtr)->bytes==NULL) && ((objPtr)->typePtr==&tclListType))
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------
|
||||
@@ -4436,7 +4492,7 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file,
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------
|
||||
* Macro used by the Tcl core to increment a namespace's export export epoch
|
||||
* Macro used by the Tcl core to increment a namespace's export epoch
|
||||
* counter. The ANSI C "prototype" for this macro is:
|
||||
*
|
||||
* MODULE_SCOPE void TclInvalidateNsCmdLookup(Namespace *nsPtr);
|
||||
@@ -4871,13 +4927,6 @@ typedef struct NRE_callback {
|
||||
#define Tcl_Free(ptr) TclpFree(ptr)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Other externals.
|
||||
*/
|
||||
|
||||
MODULE_SCOPE size_t TclEnvEpoch; /* Epoch of the tcl environment
|
||||
* (if changed with tcl-env). */
|
||||
|
||||
#endif /* _TCLINT */
|
||||
|
||||
/*
|
||||
|
||||
@@ -617,6 +617,28 @@ EXTERN void TclSetSlaveCancelFlags(Tcl_Interp *interp, int flags,
|
||||
/* 251 */
|
||||
EXTERN int TclRegisterLiteral(void *envPtr, char *bytes,
|
||||
int length, int flags);
|
||||
/* 252 */
|
||||
EXTERN Tcl_Obj * TclPtrGetVar(Tcl_Interp *interp, Tcl_Var varPtr,
|
||||
Tcl_Var arrayPtr, Tcl_Obj *part1Ptr,
|
||||
Tcl_Obj *part2Ptr, const int flags);
|
||||
/* 253 */
|
||||
EXTERN Tcl_Obj * TclPtrSetVar(Tcl_Interp *interp, Tcl_Var varPtr,
|
||||
Tcl_Var arrayPtr, Tcl_Obj *part1Ptr,
|
||||
Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr,
|
||||
const int flags);
|
||||
/* 254 */
|
||||
EXTERN Tcl_Obj * TclPtrIncrObjVar(Tcl_Interp *interp, Tcl_Var varPtr,
|
||||
Tcl_Var arrayPtr, Tcl_Obj *part1Ptr,
|
||||
Tcl_Obj *part2Ptr, Tcl_Obj *incrPtr,
|
||||
const int flags);
|
||||
/* 255 */
|
||||
EXTERN int TclPtrObjMakeUpvar(Tcl_Interp *interp,
|
||||
Tcl_Var otherPtr, Tcl_Obj *myNamePtr,
|
||||
int myFlags);
|
||||
/* 256 */
|
||||
EXTERN int TclPtrUnsetVar(Tcl_Interp *interp, Tcl_Var varPtr,
|
||||
Tcl_Var arrayPtr, Tcl_Obj *part1Ptr,
|
||||
Tcl_Obj *part2Ptr, const int flags);
|
||||
|
||||
typedef struct TclIntStubs {
|
||||
int magic;
|
||||
@@ -874,6 +896,11 @@ typedef struct TclIntStubs {
|
||||
char * (*tclDoubleDigits) (double dv, int ndigits, int flags, int *decpt, int *signum, char **endPtr); /* 249 */
|
||||
void (*tclSetSlaveCancelFlags) (Tcl_Interp *interp, int flags, int force); /* 250 */
|
||||
int (*tclRegisterLiteral) (void *envPtr, char *bytes, int length, int flags); /* 251 */
|
||||
Tcl_Obj * (*tclPtrGetVar) (Tcl_Interp *interp, Tcl_Var varPtr, Tcl_Var arrayPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, const int flags); /* 252 */
|
||||
Tcl_Obj * (*tclPtrSetVar) (Tcl_Interp *interp, Tcl_Var varPtr, Tcl_Var arrayPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, const int flags); /* 253 */
|
||||
Tcl_Obj * (*tclPtrIncrObjVar) (Tcl_Interp *interp, Tcl_Var varPtr, Tcl_Var arrayPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *incrPtr, const int flags); /* 254 */
|
||||
int (*tclPtrObjMakeUpvar) (Tcl_Interp *interp, Tcl_Var otherPtr, Tcl_Obj *myNamePtr, int myFlags); /* 255 */
|
||||
int (*tclPtrUnsetVar) (Tcl_Interp *interp, Tcl_Var varPtr, Tcl_Var arrayPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, const int flags); /* 256 */
|
||||
} TclIntStubs;
|
||||
|
||||
extern const TclIntStubs *tclIntStubsPtr;
|
||||
@@ -1305,6 +1332,16 @@ extern const TclIntStubs *tclIntStubsPtr;
|
||||
(tclIntStubsPtr->tclSetSlaveCancelFlags) /* 250 */
|
||||
#define TclRegisterLiteral \
|
||||
(tclIntStubsPtr->tclRegisterLiteral) /* 251 */
|
||||
#define TclPtrGetVar \
|
||||
(tclIntStubsPtr->tclPtrGetVar) /* 252 */
|
||||
#define TclPtrSetVar \
|
||||
(tclIntStubsPtr->tclPtrSetVar) /* 253 */
|
||||
#define TclPtrIncrObjVar \
|
||||
(tclIntStubsPtr->tclPtrIncrObjVar) /* 254 */
|
||||
#define TclPtrObjMakeUpvar \
|
||||
(tclIntStubsPtr->tclPtrObjMakeUpvar) /* 255 */
|
||||
#define TclPtrUnsetVar \
|
||||
(tclIntStubsPtr->tclPtrUnsetVar) /* 256 */
|
||||
|
||||
#endif /* defined(USE_TCL_STUBS) */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+1
-1
@@ -638,7 +638,7 @@ static Tcl_ObjType invalidRealType = {
|
||||
NULL, /* freeIntRepProc */
|
||||
NULL, /* dupIntRepProc */
|
||||
NULL, /* updateStringProc */
|
||||
SetInvalidRealFromAny /* setFromAnyProc */
|
||||
NULL /* setFromAnyProc */
|
||||
};
|
||||
|
||||
static int
|
||||
|
||||
+285
-310
@@ -55,20 +55,22 @@ const Tcl_ObjType tclListType = {
|
||||
*
|
||||
* NewListIntRep --
|
||||
*
|
||||
* Creates a list internal rep with space for objc elements. objc
|
||||
* must be > 0. If objv!=NULL, initializes with the first objc values
|
||||
* in that array. If objv==NULL, initalize list internal rep to have
|
||||
* 0 elements, with space to add objc more. Flag value "p" indicates
|
||||
* Creates a 'List' structure with space for 'objc' elements. 'objc' must
|
||||
* be > 0. If 'objv' is not NULL, The list is initialized with first
|
||||
* 'objc' values in that array. Otherwise the list is initialized to have
|
||||
* 0 elements, with space to add 'objc' more. Flag value 'p' indicates
|
||||
* how to behave on failure.
|
||||
*
|
||||
* Results:
|
||||
* A new List struct with refCount 0 is returned. If some failure
|
||||
* prevents this then if p=0, NULL is returned and otherwise the
|
||||
* routine panics.
|
||||
* Value
|
||||
*
|
||||
* Side effects:
|
||||
* The ref counts of the elements in objv are incremented since the
|
||||
* resulting list now refers to them.
|
||||
* A new 'List' structure with refCount 0. If some failure
|
||||
* prevents this NULL is returned if 'p' is 0 , and 'Tcl_Panic'
|
||||
* is called if it is not.
|
||||
*
|
||||
* Effect
|
||||
*
|
||||
* The refCount of each value in 'objv' is incremented as it is added
|
||||
* to the list.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -132,22 +134,10 @@ NewListIntRep(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* AttemptNewList --
|
||||
*
|
||||
* Creates a list internal rep with space for objc elements. objc
|
||||
* must be > 0. If objv!=NULL, initializes with the first objc values
|
||||
* in that array. If objv==NULL, initalize list internal rep to have
|
||||
* 0 elements, with space to add objc more.
|
||||
*
|
||||
* Results:
|
||||
* A new List struct with refCount 0 is returned. If some failure
|
||||
* prevents this then NULL is returned, and an error message is left
|
||||
* in the interp result, unless interp is NULL.
|
||||
*
|
||||
* Side effects:
|
||||
* The ref counts of the elements in objv are incremented since the
|
||||
* resulting list now refers to them.
|
||||
* AttemptNewList --
|
||||
*
|
||||
* Like NewListIntRep, but additionally sets an error message on failure.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -179,23 +169,20 @@ AttemptNewList(
|
||||
*
|
||||
* Tcl_NewListObj --
|
||||
*
|
||||
* This function is normally called when not debugging: i.e., when
|
||||
* TCL_MEM_DEBUG is not defined. It creates a new list object from an
|
||||
* (objc,objv) array: that is, each of the objc elements of the array
|
||||
* referenced by objv is inserted as an element into a new Tcl object.
|
||||
* Creates a new list object and adds values to it. When TCL_MEM_DEBUG is
|
||||
* defined, 'Tcl_DbNewListObj' is called instead.
|
||||
*
|
||||
* When TCL_MEM_DEBUG is defined, this function just returns the result
|
||||
* of calling the debugging version Tcl_DbNewListObj.
|
||||
* Value
|
||||
*
|
||||
* Results:
|
||||
* A new list object is returned that is initialized from the object
|
||||
* pointers in objv. If objc is less than or equal to zero, an empty
|
||||
* object is returned. The new object's string representation is left
|
||||
* NULL. The resulting new list object has ref count 0.
|
||||
* A new list 'Tcl_Obj' to which is appended values from 'objv', or if
|
||||
* 'objc' is less than or equal to zero, a list 'Tcl_Obj' having no
|
||||
* elements. The string representation of the new 'Tcl_Obj' is set to
|
||||
* NULL. The refCount of the list is 0.
|
||||
*
|
||||
* Side effects:
|
||||
* The ref counts of the elements in objv are incremented since the
|
||||
* resulting list now refers to them.
|
||||
* Effect
|
||||
*
|
||||
* The refCount of each elements in 'objv' is incremented as it is added
|
||||
* to the list.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -246,28 +233,14 @@ Tcl_NewListObj(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_DbNewListObj --
|
||||
*
|
||||
* This function is normally called when debugging: i.e., when
|
||||
* TCL_MEM_DEBUG is defined. It creates new list objects. It is the same
|
||||
* as the Tcl_NewListObj function above except that it calls
|
||||
* Tcl_DbCkalloc directly with the file name and line number from its
|
||||
* caller. This simplifies debugging since then the [memory active]
|
||||
* command will report the correct file name and line number when
|
||||
* reporting objects that haven't been freed.
|
||||
*
|
||||
* When TCL_MEM_DEBUG is not defined, this function just returns the
|
||||
* result of calling Tcl_NewListObj.
|
||||
*
|
||||
* Results:
|
||||
* A new list object is returned that is initialized from the object
|
||||
* pointers in objv. If objc is less than or equal to zero, an empty
|
||||
* object is returned. The new object's string representation is left
|
||||
* NULL. The new list object has ref count 0.
|
||||
*
|
||||
* Side effects:
|
||||
* The ref counts of the elements in objv are incremented since the
|
||||
* resulting list now refers to them.
|
||||
* Tcl_DbNewListObj --
|
||||
*
|
||||
* Like 'Tcl_NewListObj', but it calls Tcl_DbCkalloc directly with the
|
||||
* file name and line number from its caller. This simplifies debugging
|
||||
* since the [memory active] command will report the correct file
|
||||
* name and line number when reporting objects that haven't been freed.
|
||||
*
|
||||
* When TCL_MEM_DEBUG is not defined, 'Tcl_NewListObj' is called instead.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -328,19 +301,8 @@ Tcl_DbNewListObj(
|
||||
*
|
||||
* Tcl_SetListObj --
|
||||
*
|
||||
* Modify an object to be a list containing each of the objc elements of
|
||||
* the object array referenced by objv.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* The object is made a list object and is initialized from the object
|
||||
* pointers in objv. If objc is less than or equal to zero, an empty
|
||||
* object is returned. The new object's string representation is left
|
||||
* NULL. The ref counts of the elements in objv are incremented since the
|
||||
* list now refers to them. The object's old string and internal
|
||||
* representations are freed and its type is set NULL.
|
||||
* Like 'Tcl_NewListObj', but operates on an existing 'Tcl_Obj'instead of
|
||||
* creating a new one.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -384,18 +346,20 @@ Tcl_SetListObj(
|
||||
*
|
||||
* TclListObjCopy --
|
||||
*
|
||||
* Makes a "pure list" copy of a list value. This provides for the C
|
||||
* level a counterpart of the [lrange $list 0 end] command, while using
|
||||
* internals details to be as efficient as possible.
|
||||
* Creates a new 'Tcl_Obj' which is a pure copy of a list value. This
|
||||
* provides for the C level a counterpart of the [lrange $list 0 end]
|
||||
* command, while using internals details to be as efficient as possible.
|
||||
*
|
||||
* Results:
|
||||
* Normally returns a pointer to a new Tcl_Obj, that contains the same
|
||||
* list value as *listPtr does. The returned Tcl_Obj has a refCount of
|
||||
* zero. If *listPtr does not hold a list, NULL is returned, and if
|
||||
* interp is non-NULL, an error message is recorded there.
|
||||
* Value
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
* The address of the new 'Tcl_Obj' which shares its internal
|
||||
* representation with 'listPtr', and whose refCount is 0. If 'listPtr'
|
||||
* is not actually a list, the value is NULL, and an error message is left
|
||||
* in 'interp' if it is not NULL.
|
||||
*
|
||||
* Effect
|
||||
*
|
||||
* 'listPtr' is converted to a list if it isn't one already.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -425,27 +389,30 @@ TclListObjCopy(
|
||||
*
|
||||
* Tcl_ListObjGetElements --
|
||||
*
|
||||
* This function returns an (objc,objv) array of the elements in a list
|
||||
* object.
|
||||
* Retreive the elements in a list 'Tcl_Obj'.
|
||||
*
|
||||
* Results:
|
||||
* The return value is normally TCL_OK; in this case *objcPtr is set to
|
||||
* the count of list elements and *objvPtr is set to a pointer to an
|
||||
* array of (*objcPtr) pointers to each list element. If listPtr does not
|
||||
* refer to a list object and the object can not be converted to one,
|
||||
* TCL_ERROR is returned and an error message will be left in the
|
||||
* interpreter's result if interp is not NULL.
|
||||
* Value
|
||||
*
|
||||
* The objects referenced by the returned array should be treated as
|
||||
* readonly and their ref counts are _not_ incremented; the caller must
|
||||
* do that if it holds on to a reference. Furthermore, the pointer and
|
||||
* length returned by this function may change as soon as any function is
|
||||
* called on the list object; be careful about retaining the pointer in a
|
||||
* local data structure.
|
||||
* TCL_OK
|
||||
*
|
||||
* Side effects:
|
||||
* The possible conversion of the object referenced by listPtr
|
||||
* to a list object.
|
||||
* A count of list elements is stored, 'objcPtr', And a pointer to the
|
||||
* array of elements in the list is stored in 'objvPtr'.
|
||||
*
|
||||
* The elements accessible via 'objvPtr' should be treated as readonly
|
||||
* and the refCount for each object is _not_ incremented; the caller
|
||||
* must do that if it holds on to a reference. Furthermore, the
|
||||
* pointer and length returned by this function may change as soon as
|
||||
* any function is called on the list object. Be careful about
|
||||
* retaining the pointer in a local data structure.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* 'listPtr' is not a valid list. An error message is left in the
|
||||
* interpreter's result if 'interp' is not NULL.
|
||||
*
|
||||
* Effect
|
||||
*
|
||||
* 'listPtr' is converted to a list object if it isn't one already.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -486,20 +453,27 @@ Tcl_ListObjGetElements(
|
||||
*
|
||||
* Tcl_ListObjAppendList --
|
||||
*
|
||||
* This function appends the elements in the list value referenced by
|
||||
* elemListPtr to the list value referenced by listPtr.
|
||||
* Appends the elements of elemListPtr to those of listPtr.
|
||||
*
|
||||
* Results:
|
||||
* The return value is normally TCL_OK. If listPtr or elemListPtr do not
|
||||
* refer to list values, TCL_ERROR is returned and an error message is
|
||||
* left in the interpreter's result if interp is not NULL.
|
||||
* Value
|
||||
*
|
||||
* Side effects:
|
||||
* The reference counts of the elements in elemListPtr are incremented
|
||||
* since the list now refers to them. listPtr and elemListPtr are
|
||||
* converted, if necessary, to list objects. Also, appending the new
|
||||
* elements may cause listObj's array of element pointers to grow.
|
||||
* listPtr's old string representation, if any, is invalidated.
|
||||
* TCL_OK
|
||||
*
|
||||
* Success.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* 'listPtr' or 'elemListPtr' are not valid lists. An error
|
||||
* message is left in the interpreter's result if 'interp' is not NULL.
|
||||
*
|
||||
* Effect
|
||||
*
|
||||
* The reference count of each element of 'elemListPtr' as it is added to
|
||||
* 'listPtr'. 'listPtr' and 'elemListPtr' are converted to 'tclListType'
|
||||
* if they are not already. Appending the new elements may cause the
|
||||
* array of element pointers in 'listObj' to grow. If any objects are
|
||||
* appended to 'listPtr'. Any preexisting string representation of
|
||||
* 'listPtr' is invalidated.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -538,24 +512,27 @@ Tcl_ListObjAppendList(
|
||||
*
|
||||
* Tcl_ListObjAppendElement --
|
||||
*
|
||||
* This function is a special purpose version of Tcl_ListObjAppendList:
|
||||
* it appends a single object referenced by objPtr to the list object
|
||||
* referenced by listPtr. If listPtr is not already a list object, an
|
||||
* attempt will be made to convert it to one.
|
||||
* Like 'Tcl_ListObjAppendList', but Appends a single value to a list.
|
||||
*
|
||||
* Results:
|
||||
* The return value is normally TCL_OK; in this case objPtr is added to
|
||||
* the end of listPtr's list. If listPtr does not refer to a list object
|
||||
* and the object can not be converted to one, TCL_ERROR is returned and
|
||||
* an error message will be left in the interpreter's result if interp is
|
||||
* not NULL.
|
||||
* Value
|
||||
*
|
||||
* Side effects:
|
||||
* The ref count of objPtr is incremented since the list now refers to
|
||||
* it. listPtr will be converted, if necessary, to a list object. Also,
|
||||
* appending the new element may cause listObj's array of element
|
||||
* pointers to grow. listPtr's old string representation, if any, is
|
||||
* invalidated.
|
||||
* TCL_OK
|
||||
*
|
||||
* 'objPtr' is appended to the elements of 'listPtr'.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* listPtr does not refer to a list object and the object can not be
|
||||
* converted to one. An error message will be left in the
|
||||
* interpreter's result if interp is not NULL.
|
||||
*
|
||||
* Effect
|
||||
*
|
||||
* If 'listPtr' is not already of type 'tclListType', it is converted.
|
||||
* The 'refCount' of 'objPtr' is incremented as it is added to 'listPtr'.
|
||||
* Appending the new element may cause the the array of element pointers
|
||||
* in 'listObj' to grow. Any preexisting string representation of
|
||||
* 'listPtr' is invalidated.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -706,23 +683,27 @@ Tcl_ListObjAppendElement(
|
||||
*
|
||||
* Tcl_ListObjIndex --
|
||||
*
|
||||
* This function returns a pointer to the index'th object from the list
|
||||
* referenced by listPtr. The first element has index 0. If index is
|
||||
* negative or greater than or equal to the number of elements in the
|
||||
* list, a NULL is returned. If listPtr is not a list object, an attempt
|
||||
* will be made to convert it to a list.
|
||||
* Retrieve a pointer to the element of 'listPtr' at 'index'. The index
|
||||
* of the first element is 0.
|
||||
*
|
||||
* Results:
|
||||
* The return value is normally TCL_OK; in this case objPtrPtr is set to
|
||||
* the Tcl_Obj pointer for the index'th list element or NULL if index is
|
||||
* out of range. This object should be treated as readonly and its ref
|
||||
* count is _not_ incremented; the caller must do that if it holds on to
|
||||
* the reference. If listPtr does not refer to a list and can't be
|
||||
* converted to one, TCL_ERROR is returned and an error message is left
|
||||
* in the interpreter's result if interp is not NULL.
|
||||
* Value
|
||||
*
|
||||
* Side effects:
|
||||
* listPtr will be converted, if necessary, to a list object.
|
||||
* TCL_OK
|
||||
*
|
||||
* A pointer to the element at 'index' is stored in 'objPtrPtr'. If
|
||||
* 'index' is out of range, NULL is stored in 'objPtrPtr'. This
|
||||
* object should be treated as readonly and its 'refCount' is _not_
|
||||
* incremented. The caller must do that if it holds on to the
|
||||
* reference.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* 'listPtr' is not a valid list. An an error message is left in the
|
||||
* interpreter's result if 'interp' is not NULL.
|
||||
*
|
||||
* Effect
|
||||
*
|
||||
* If 'listPtr' is not already of type 'tclListType', it is converted.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -764,19 +745,20 @@ Tcl_ListObjIndex(
|
||||
*
|
||||
* Tcl_ListObjLength --
|
||||
*
|
||||
* This function returns the number of elements in a list object. If the
|
||||
* object is not already a list object, an attempt will be made to
|
||||
* convert it to one.
|
||||
* Retrieve the number of elements in a list.
|
||||
*
|
||||
* Results:
|
||||
* The return value is normally TCL_OK; in this case *intPtr will be set
|
||||
* to the integer count of list elements. If listPtr does not refer to a
|
||||
* list object and the object can not be converted to one, TCL_ERROR is
|
||||
* returned and an error message will be left in the interpreter's result
|
||||
* if interp is not NULL.
|
||||
* Value
|
||||
*
|
||||
* Side effects:
|
||||
* The possible conversion of the argument object to a list object.
|
||||
* TCL_OK
|
||||
*
|
||||
* A count of list elements is stored at the address provided by
|
||||
* 'intPtr'. If 'listPtr' is not already of type 'tclListPtr', it is
|
||||
* converted.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* 'listPtr' is not a valid list. An error message will be left in
|
||||
* the interpreter's result if 'interp' is not NULL.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -812,35 +794,36 @@ Tcl_ListObjLength(
|
||||
*
|
||||
* Tcl_ListObjReplace --
|
||||
*
|
||||
* This function replaces zero or more elements of the list referenced by
|
||||
* listPtr with the objects from an (objc,objv) array. The objc elements
|
||||
* of the array referenced by objv replace the count elements in listPtr
|
||||
* starting at first.
|
||||
* Replace values in a list.
|
||||
*
|
||||
* If the argument first is zero or negative, it refers to the first
|
||||
* element. If first is greater than or equal to the number of elements
|
||||
* in the list, then no elements are deleted; the new elements are
|
||||
* appended to the list. Count gives the number of elements to replace.
|
||||
* If count is zero or negative then no elements are deleted; the new
|
||||
* elements are simply inserted before first.
|
||||
* If 'first' is zero or negative, it refers to the first element. If
|
||||
* 'first' outside the range of elements in the list, no elements are
|
||||
* deleted.
|
||||
*
|
||||
* The argument objv refers to an array of objc pointers to the new
|
||||
* elements to be added to listPtr in place of those that were deleted.
|
||||
* If objv is NULL, no new elements are added. If listPtr is not a list
|
||||
* object, an attempt will be made to convert it to one.
|
||||
* If 'count' is zero or negative no elements are deleted, and any new
|
||||
* elements are inserted at the beginning of the list.
|
||||
*
|
||||
* Results:
|
||||
* The return value is normally TCL_OK. If listPtr does not refer to a
|
||||
* list object and can not be converted to one, TCL_ERROR is returned and
|
||||
* an error message will be left in the interpreter's result if interp is
|
||||
* not NULL.
|
||||
* Value
|
||||
*
|
||||
* Side effects:
|
||||
* The ref counts of the objc elements in objv are incremented since the
|
||||
* resulting list now refers to them. Similarly, the ref counts for
|
||||
* replaced objects are decremented. listPtr is converted, if necessary,
|
||||
* to a list object. listPtr's old string representation, if any, is
|
||||
* freed.
|
||||
* TCL_OK
|
||||
*
|
||||
* The first 'objc' values of 'objv' replaced 'count' elements in 'listPtr'
|
||||
* starting at 'first'. If 'objc' 0, no new elements are added.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* 'listPtr' is not a valid list. An error message is left in the
|
||||
* interpreter's result if 'interp' is not NULL.
|
||||
*
|
||||
* Effect
|
||||
*
|
||||
* If 'listPtr' is not of type 'tclListType', it is converted if possible.
|
||||
*
|
||||
* The 'refCount' of each element appended to the list is incremented.
|
||||
* Similarly, the 'refCount' for each replaced element is decremented.
|
||||
*
|
||||
* If 'listPtr' is modified, any previous string representation is
|
||||
* invalidated.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1098,22 +1081,19 @@ Tcl_ListObjReplace(
|
||||
*
|
||||
* TclLindexList --
|
||||
*
|
||||
* This procedure handles the 'lindex' command when objc==3.
|
||||
* Implements the 'lindex' command when objc==3.
|
||||
*
|
||||
* Results:
|
||||
* Returns a pointer to the object extracted, or NULL if an error
|
||||
* occurred. The returned object already includes one reference count for
|
||||
* the pointer returned.
|
||||
* Implemented entirely as a wrapper around 'TclLindexFlat'. Reconfigures
|
||||
* the argument format into required form while taking care to manage
|
||||
* shimmering so as to tend to keep the most useful intreps
|
||||
* and/or avoid the most expensive conversions.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
* Value
|
||||
*
|
||||
* Notes:
|
||||
* This procedure is implemented entirely as a wrapper around
|
||||
* TclLindexFlat. All it does is reconfigure the argument format into the
|
||||
* form required by TclLindexFlat, while taking care to manage shimmering
|
||||
* in such a way that we tend to keep the most useful intreps and/or
|
||||
* avoid the most expensive conversions.
|
||||
* A pointer to the specified element, with its 'refCount' incremented, or
|
||||
* NULL if an error occurred.
|
||||
*
|
||||
* Notes
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1165,17 +1145,11 @@ TclLindexList(
|
||||
return TclLindexFlat(interp, listPtr, 1, &argPtr);
|
||||
}
|
||||
|
||||
if (indexListCopy->typePtr == &tclListType) {
|
||||
List *listRepPtr = ListRepPtr(indexListCopy);
|
||||
{
|
||||
int indexCount = -1; /* Size of the array of list indices. */
|
||||
Tcl_Obj **indices = NULL; /* Array of list indices. */
|
||||
|
||||
listPtr = TclLindexFlat(interp, listPtr, listRepPtr->elemCount,
|
||||
&listRepPtr->elements);
|
||||
} else {
|
||||
int indexCount = -1; /* Size of the array of list indices. */
|
||||
Tcl_Obj **indices = NULL;
|
||||
/* Array of list indices. */
|
||||
|
||||
Tcl_ListObjGetElements(NULL, indexListCopy, &indexCount, &indices);
|
||||
TclListObjGetElements(NULL, indexListCopy, &indexCount, &indices);
|
||||
listPtr = TclLindexFlat(interp, listPtr, indexCount, indices);
|
||||
}
|
||||
Tcl_DecrRefCount(indexListCopy);
|
||||
@@ -1185,25 +1159,20 @@ TclLindexList(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclLindexFlat --
|
||||
* TclLindexFlat --
|
||||
*
|
||||
* This procedure is the core of the 'lindex' command, with all index
|
||||
* arguments presented as a flat list.
|
||||
* The core of the 'lindex' command, with all index
|
||||
* arguments presented as a flat list.
|
||||
*
|
||||
* Results:
|
||||
* Returns a pointer to the object extracted, or NULL if an error
|
||||
* occurred. The returned object already includes one reference count for
|
||||
* the pointer returned.
|
||||
* Value
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
* A pointer to the object extracted, with its 'refCount' incremented, or
|
||||
* NULL if an error occurred. Thus, the calling code will usually do
|
||||
* something like:
|
||||
*
|
||||
* Tcl_SetObjResult(interp, result);
|
||||
* Tcl_DecrRefCount(result);
|
||||
*
|
||||
* Notes:
|
||||
* The reference count of the returned object includes one reference
|
||||
* corresponding to the pointer returned. Thus, the calling code will
|
||||
* usually do something like:
|
||||
* Tcl_SetObjResult(interp, result);
|
||||
* Tcl_DecrRefCount(result);
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1279,23 +1248,16 @@ TclLindexFlat(
|
||||
*
|
||||
* TclLsetList --
|
||||
*
|
||||
* Core of the 'lset' command when objc == 4. Objv[2] may be either a
|
||||
* The core of [lset] when objc == 4. Objv[2] may be either a
|
||||
* scalar index or a list of indices.
|
||||
*
|
||||
* Results:
|
||||
* Returns the new value of the list variable, or NULL if there was an
|
||||
* error. The returned object includes one reference count for the
|
||||
* pointer returned.
|
||||
* Implemented entirely as a wrapper around 'TclLindexFlat', as described
|
||||
* for 'TclLindexList'.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
* Value
|
||||
*
|
||||
* Notes:
|
||||
* This procedure is implemented entirely as a wrapper around
|
||||
* TclLsetFlat. All it does is reconfigure the argument format into the
|
||||
* form required by TclLsetFlat, while taking care to manage shimmering
|
||||
* in such a way that we tend to keep the most useful intreps and/or
|
||||
* avoid the most expensive conversions.
|
||||
* The new list, with the 'refCount' of 'valuPtr' incremented, or NULL if
|
||||
* there was an error.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1357,36 +1319,39 @@ TclLsetList(
|
||||
*
|
||||
* Core engine of the 'lset' command.
|
||||
*
|
||||
* Results:
|
||||
* Returns the new value of the list variable, or NULL if an error
|
||||
* occurred. The returned object includes one reference count for the
|
||||
* pointer returned.
|
||||
* Value
|
||||
*
|
||||
* Side effects:
|
||||
* On entry, the reference count of the variable value does not reflect
|
||||
* any references held on the stack. The first action of this function is
|
||||
* to determine whether the object is shared, and to duplicate it if it
|
||||
* is. The reference count of the duplicate is incremented. At this
|
||||
* point, the reference count will be 1 for either case, so that the
|
||||
* object will appear to be unshared.
|
||||
* The resulting list
|
||||
*
|
||||
* If an error occurs, and the object has been duplicated, the reference
|
||||
* count on the duplicate is decremented so that it is now 0: this
|
||||
* dismisses any memory that was allocated by this function.
|
||||
* The 'refCount' of 'valuePtr' is incremented. If 'listPtr' was not
|
||||
* duplicated, its 'refCount' is incremented. The reference count of
|
||||
* an unduplicated object is therefore 2 (one for the returned pointer
|
||||
* and one for the variable that holds it). The reference count of a
|
||||
* duplicate object is 1, reflecting that result is the only active
|
||||
* reference. The caller is expected to store the result in the
|
||||
* variable and decrement its reference count. (INST_STORE_* does
|
||||
* exactly this.)
|
||||
*
|
||||
* NULL
|
||||
*
|
||||
* An error occurred. If 'listPtr' was duplicated, the reference
|
||||
* count on the duplicate is decremented so that it is 0, causing any
|
||||
* memory allocated by this function to be freed.
|
||||
*
|
||||
* If no error occurs, the reference count of the original object is
|
||||
* incremented if the object has not been duplicated, and nothing is done
|
||||
* to a reference count of the duplicate. Now the reference count of an
|
||||
* unduplicated object is 2 (the returned pointer, plus the one stored in
|
||||
* the variable). The reference count of a duplicate object is 1,
|
||||
* reflecting that the returned pointer is the only active reference. The
|
||||
* caller is expected to store the returned value back in the variable
|
||||
* and decrement its reference count. (INST_STORE_* does exactly this.)
|
||||
*
|
||||
* Surgery is performed on the unshared list value to produce the result.
|
||||
* TclLsetFlat maintains a linked list of Tcl_Obj's whose string
|
||||
* Effect
|
||||
*
|
||||
* On entry, the reference count of 'listPtr' does not reflect any
|
||||
* references held on the stack. The first action of this function is to
|
||||
* determine whether 'listPtr' is shared and to create a duplicate
|
||||
* unshared copy if it is. The reference count of the duplicate is
|
||||
* incremented. At this point, the reference count is 1 in either case so
|
||||
* that the object is considered unshared.
|
||||
*
|
||||
* The unshared list is altered directly to produce the result.
|
||||
* 'TclLsetFlat' maintains a linked list of 'Tcl_Obj' values whose string
|
||||
* representations must be spoilt by threading via 'ptr2' of the
|
||||
* two-pointer internal representation. On entry to TclLsetFlat, the
|
||||
* two-pointer internal representation. On entry to 'TclLsetFlat', the
|
||||
* values of 'ptr2' are immaterial; on exit, the 'ptr2' field of any
|
||||
* Tcl_Obj that has been modified is set to NULL.
|
||||
*
|
||||
@@ -1601,26 +1566,38 @@ TclLsetFlat(
|
||||
*
|
||||
* TclListObjSetElement --
|
||||
*
|
||||
* Set a single element of a list to a specified value
|
||||
*
|
||||
* Results:
|
||||
* The return value is normally TCL_OK. If listPtr does not refer to a
|
||||
* list object and cannot be converted to one, TCL_ERROR is returned and
|
||||
* an error message will be left in the interpreter result if interp is
|
||||
* not NULL. Similarly, if index designates an element outside the range
|
||||
* [0..listLength-1], where listLength is the count of elements in the
|
||||
* list object designated by listPtr, TCL_ERROR is returned and an error
|
||||
* message is left in the interpreter result.
|
||||
*
|
||||
* Side effects:
|
||||
* Tcl_Panic if listPtr designates a shared object. Otherwise, attempts
|
||||
* to convert it to a list with a non-shared internal rep. Decrements the
|
||||
* ref count of the object at the specified index within the list,
|
||||
* replaces with the object designated by valuePtr, and increments the
|
||||
* ref count of the replacement object.
|
||||
* Set a single element of a list to a specified value.
|
||||
*
|
||||
* It is the caller's responsibility to invalidate the string
|
||||
* representation of the object.
|
||||
* representation of the 'listPtr'.
|
||||
*
|
||||
* Value
|
||||
*
|
||||
* TCL_OK
|
||||
*
|
||||
* Success.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* 'listPtr' does not refer to a list object and cannot be converted
|
||||
* to one. An error message will be left in the interpreter result if
|
||||
* interp is not NULL.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* An index designates an element outside the range [0..listLength-1],
|
||||
* where 'listLength' is the count of elements in the list object
|
||||
* designated by 'listPtr'. An error message is left in the
|
||||
* interpreter result.
|
||||
*
|
||||
* Effect
|
||||
*
|
||||
* If 'listPtr' designates a shared object, 'Tcl_Panic' is called. If
|
||||
* 'listPtr' is not already of type 'tclListType', it is converted and the
|
||||
* internal representation is unshared. The 'refCount' of the element at
|
||||
* 'index' is decremented and replaced in the list with the 'valuePtr',
|
||||
* whose 'refCount' in turn is incremented.
|
||||
*
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1738,16 +1715,14 @@ TclListObjSetElement(
|
||||
*
|
||||
* FreeListInternalRep --
|
||||
*
|
||||
* Deallocate the storage associated with a list object's internal
|
||||
* representation.
|
||||
* Deallocate the storage associated with the internal representation of a
|
||||
* a list object.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
* Effect
|
||||
*
|
||||
* Side effects:
|
||||
* Frees listPtr's List* internal representation and sets listPtr's
|
||||
* internalRep.twoPtrValue.ptr1 to NULL. Decrements the ref counts of all
|
||||
* element objects, which may free them.
|
||||
* The storage for the internal 'List' pointer of 'listPtr' is freed, the
|
||||
* 'internalRep.twoPtrValue.ptr1' of 'listPtr' is set to NULL, and the 'refCount'
|
||||
* of each element of the list is decremented.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1776,14 +1751,12 @@ FreeListInternalRep(
|
||||
*
|
||||
* DupListInternalRep --
|
||||
*
|
||||
* Initialize the internal representation of a list Tcl_Obj to share the
|
||||
* Initialize the internal representation of a list 'Tcl_Obj' to share the
|
||||
* internal representation of an existing list object.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
* Effect
|
||||
*
|
||||
* Side effects:
|
||||
* The reference count of the List internal rep is incremented.
|
||||
* The 'refCount' of the List internal rep is incremented.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1803,16 +1776,20 @@ DupListInternalRep(
|
||||
*
|
||||
* SetListFromAny --
|
||||
*
|
||||
* Attempt to generate a list internal form for the Tcl object "objPtr".
|
||||
* Convert any object to a list.
|
||||
*
|
||||
* Results:
|
||||
* The return value is TCL_OK or TCL_ERROR. If an error occurs during
|
||||
* conversion, an error message is left in the interpreter's result
|
||||
* unless "interp" is NULL.
|
||||
* Value
|
||||
*
|
||||
* TCL_OK
|
||||
*
|
||||
* Success. The internal representation of 'objPtr' is set, and the type
|
||||
* of 'objPtr' is 'tclListType'.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* An error occured during conversion. An error message is left in the
|
||||
* interpreter's result if 'interp' is not NULL.
|
||||
*
|
||||
* Side effects:
|
||||
* If no error occurs, a list is stored as "objPtr"s internal
|
||||
* representation.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1937,18 +1914,16 @@ SetListFromAny(
|
||||
*
|
||||
* UpdateStringOfList --
|
||||
*
|
||||
* Update the string representation for a list object. Note: This
|
||||
* function does not invalidate an existing old string rep so storage
|
||||
* will be lost if this has not already been done.
|
||||
* Update the string representation for a list object.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
* Any previously-exising string representation is not invalidated, so
|
||||
* storage is lost if this has not been taken care of.
|
||||
*
|
||||
* Side effects:
|
||||
* The object's string is set to a valid string that results from the
|
||||
* list-to-string conversion. This string will be empty if the list has
|
||||
* no elements. The list internal representation should not be NULL and
|
||||
* we assume it is not NULL.
|
||||
* Effect
|
||||
*
|
||||
* The string representation of 'listPtr' is set to the resulting string.
|
||||
* This string will be empty if the list has no elements. It is assumed
|
||||
* that the list internal representation is not NULL.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1957,8 +1932,8 @@ static void
|
||||
UpdateStringOfList(
|
||||
Tcl_Obj *listPtr) /* List object with string rep to update. */
|
||||
{
|
||||
# define LOCAL_SIZE 20
|
||||
int localFlags[LOCAL_SIZE], *flagPtr = NULL;
|
||||
# define LOCAL_SIZE 64
|
||||
char localFlags[LOCAL_SIZE], *flagPtr = NULL;
|
||||
List *listRepPtr = ListRepPtr(listPtr);
|
||||
int numElems = listRepPtr->elemCount;
|
||||
int i, length, bytesNeeded = 0;
|
||||
@@ -1995,7 +1970,7 @@ UpdateStringOfList(
|
||||
* We know numElems <= LIST_MAX, so this is safe.
|
||||
*/
|
||||
|
||||
flagPtr = ckalloc(numElems * sizeof(int));
|
||||
flagPtr = ckalloc(numElems);
|
||||
}
|
||||
elemPtrs = &listRepPtr->elements;
|
||||
for (i = 0; i < numElems; i++) {
|
||||
|
||||
+1
-1
@@ -130,7 +130,7 @@ Tcl_LoadObjCmd(
|
||||
Tcl_PackageInitProc *initProc;
|
||||
const char *p, *fullFileName, *packageName;
|
||||
Tcl_LoadHandle loadHandle;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
unsigned len;
|
||||
int index, flags = 0;
|
||||
Tcl_Obj *const *savedobjv = objv;
|
||||
|
||||
+37
-11
@@ -915,6 +915,11 @@ Tcl_DeleteNamespace(
|
||||
Tcl_HashSearch search;
|
||||
Command *cmdPtr;
|
||||
|
||||
/*
|
||||
* Ensure that this namespace doesn't get deallocated in the meantime.
|
||||
*/
|
||||
nsPtr->refCount++;
|
||||
|
||||
/*
|
||||
* Give anyone interested - notably TclOO - a chance to use this namespace
|
||||
* normally despite the fact that the namespace is going to go. Allows the
|
||||
@@ -1047,16 +1052,7 @@ Tcl_DeleteNamespace(
|
||||
#endif
|
||||
Tcl_DeleteHashTable(&nsPtr->cmdTable);
|
||||
|
||||
/*
|
||||
* If the reference count is 0, then discard the namespace.
|
||||
* Otherwise, mark it as "dead" so that it can't be used.
|
||||
*/
|
||||
|
||||
if (nsPtr->refCount == 0) {
|
||||
NamespaceFree(nsPtr);
|
||||
} else {
|
||||
nsPtr->flags |= NS_DEAD;
|
||||
}
|
||||
nsPtr ->flags |= NS_DEAD;
|
||||
} else {
|
||||
/*
|
||||
* Restore the ::errorInfo and ::errorCode traces.
|
||||
@@ -1073,6 +1069,7 @@ Tcl_DeleteNamespace(
|
||||
nsPtr->flags &= ~(NS_DYING|NS_KILLED);
|
||||
}
|
||||
}
|
||||
TclNsDecrRefCount(nsPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2422,6 +2419,35 @@ TclGetNamespaceForQualName(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclEnsureNamespace --
|
||||
*
|
||||
* Provide a namespace that is not deleted.
|
||||
*
|
||||
* Value
|
||||
*
|
||||
* namespacePtr, if it is not scheduled for deletion, or a pointer to a
|
||||
* new namespace with the same name otherwise.
|
||||
*
|
||||
* Effect
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
Tcl_Namespace *
|
||||
TclEnsureNamespace(
|
||||
Tcl_Interp *interp,
|
||||
Tcl_Namespace *namespacePtr)
|
||||
{
|
||||
Namespace *nsPtr = (Namespace *) namespacePtr;
|
||||
if (!(nsPtr->flags & NS_DYING)) {
|
||||
return namespacePtr;
|
||||
}
|
||||
return Tcl_CreateNamespace(interp, nsPtr->fullName, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -2639,7 +2665,7 @@ Tcl_FindCommand(
|
||||
Namespace *nsPtr[2];
|
||||
register int search;
|
||||
|
||||
TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr,
|
||||
TclGetNamespaceForQualName(interp, name, cxtNsPtr,
|
||||
flags, &nsPtr[0], &nsPtr[1], &cxtNsPtr, &simpleName);
|
||||
|
||||
/*
|
||||
|
||||
+535
-607
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -24,7 +24,7 @@
|
||||
* win/tclooConfig.sh
|
||||
*/
|
||||
|
||||
#define TCLOO_VERSION "1.0.5"
|
||||
#define TCLOO_VERSION "1.1.0"
|
||||
#define TCLOO_PATCHLEVEL TCLOO_VERSION
|
||||
|
||||
#include "tcl.h"
|
||||
|
||||
+26
-17
@@ -1183,8 +1183,9 @@ TclOOCopyObjectCmd(
|
||||
{
|
||||
Tcl_Object oPtr, o2Ptr;
|
||||
|
||||
if (objc < 2 || objc > 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "sourceName ?targetName?");
|
||||
if (objc < 2 || objc > 4) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
"sourceName ?targetName? ?targetNamespace?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -1204,24 +1205,32 @@ TclOOCopyObjectCmd(
|
||||
if (objc == 2) {
|
||||
o2Ptr = Tcl_CopyObjectInstance(interp, oPtr, NULL, NULL);
|
||||
} else {
|
||||
const char *name;
|
||||
Tcl_DString buffer;
|
||||
const char *name, *namespaceName;
|
||||
|
||||
name = TclGetString(objv[2]);
|
||||
Tcl_DStringInit(&buffer);
|
||||
if (name[0]!=':' || name[1]!=':') {
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
|
||||
if (iPtr->varFramePtr != NULL) {
|
||||
Tcl_DStringAppend(&buffer,
|
||||
iPtr->varFramePtr->nsPtr->fullName, -1);
|
||||
}
|
||||
TclDStringAppendLiteral(&buffer, "::");
|
||||
Tcl_DStringAppend(&buffer, name, -1);
|
||||
name = Tcl_DStringValue(&buffer);
|
||||
if (name[0] == '\0') {
|
||||
name = NULL;
|
||||
}
|
||||
o2Ptr = Tcl_CopyObjectInstance(interp, oPtr, name, NULL);
|
||||
Tcl_DStringFree(&buffer);
|
||||
|
||||
/*
|
||||
* Choose a unique namespace name if the user didn't supply one.
|
||||
*/
|
||||
|
||||
namespaceName = NULL;
|
||||
if (objc == 4) {
|
||||
namespaceName = TclGetString(objv[3]);
|
||||
|
||||
if (namespaceName[0] == '\0') {
|
||||
namespaceName = NULL;
|
||||
} else if (Tcl_FindNamespace(interp, namespaceName, NULL,
|
||||
0) != NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"%s refers to an existing namespace", namespaceName));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
o2Ptr = Tcl_CopyObjectInstance(interp, oPtr, name, namespaceName);
|
||||
}
|
||||
|
||||
if (o2Ptr == NULL) {
|
||||
|
||||
+63
-25
@@ -53,7 +53,8 @@ static void AddClassFiltersToCallContext(Object *const oPtr,
|
||||
Class *clsPtr, struct ChainBuilder *const cbPtr,
|
||||
Tcl_HashTable *const doneFilters, int flags);
|
||||
static void AddClassMethodNames(Class *clsPtr, const int flags,
|
||||
Tcl_HashTable *const namesPtr);
|
||||
Tcl_HashTable *const namesPtr,
|
||||
Tcl_HashTable *const examinedClassesPtr);
|
||||
static inline void AddMethodToCallChain(Method *const mPtr,
|
||||
struct ChainBuilder *const cbPtr,
|
||||
Tcl_HashTable *const doneFilters,
|
||||
@@ -109,7 +110,8 @@ TclOODeleteContext(
|
||||
TclOODeleteChain(contextPtr->callPtr);
|
||||
if (oPtr != NULL) {
|
||||
TclStackFree(oPtr->fPtr->interp, contextPtr);
|
||||
DelRef(oPtr);
|
||||
/* Corresponding AddRef() in TclOO.c/TclOOObjectCmdCore */
|
||||
TclOODecrRefCount(oPtr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +234,7 @@ FreeMethodNameRep(
|
||||
* TclOOInvokeContext --
|
||||
*
|
||||
* Invokes a single step along a method call-chain context. Note that the
|
||||
* invokation of a step along the chain can cause further steps along the
|
||||
* invocation of a step along the chain can cause further steps along the
|
||||
* chain to be invoked. Note that this function is written to be as light
|
||||
* in stack usage as possible.
|
||||
*
|
||||
@@ -367,6 +369,10 @@ TclOOGetSortedMethodList(
|
||||
{
|
||||
Tcl_HashTable names; /* Tcl_Obj* method name to "wanted in list"
|
||||
* mapping. */
|
||||
Tcl_HashTable examinedClasses;
|
||||
/* Used to track what classes have been looked
|
||||
* at. Is set-like in nature and keyed by
|
||||
* pointer to class. */
|
||||
FOREACH_HASH_DECLS;
|
||||
int i;
|
||||
Class *mixinPtr;
|
||||
@@ -376,6 +382,7 @@ TclOOGetSortedMethodList(
|
||||
void *isWanted;
|
||||
|
||||
Tcl_InitObjHashTable(&names);
|
||||
Tcl_InitHashTable(&examinedClasses, TCL_ONE_WORD_KEYS);
|
||||
|
||||
/*
|
||||
* Name the bits used in the names table values.
|
||||
@@ -436,11 +443,14 @@ TclOOGetSortedMethodList(
|
||||
* hierarchy.
|
||||
*/
|
||||
|
||||
AddClassMethodNames(oPtr->selfCls, flags, &names);
|
||||
AddClassMethodNames(oPtr->selfCls, flags, &names, &examinedClasses);
|
||||
FOREACH(mixinPtr, oPtr->mixins) {
|
||||
AddClassMethodNames(mixinPtr, flags|TRAVERSED_MIXIN, &names);
|
||||
AddClassMethodNames(mixinPtr, flags|TRAVERSED_MIXIN, &names,
|
||||
&examinedClasses);
|
||||
}
|
||||
|
||||
Tcl_DeleteHashTable(&examinedClasses);
|
||||
|
||||
/*
|
||||
* See how many (visible) method names there are. If none, we do not (and
|
||||
* should not) try to sort the list of them.
|
||||
@@ -495,18 +505,24 @@ TclOOGetSortedClassMethodList(
|
||||
{
|
||||
Tcl_HashTable names; /* Tcl_Obj* method name to "wanted in list"
|
||||
* mapping. */
|
||||
Tcl_HashTable examinedClasses;
|
||||
/* Used to track what classes have been looked
|
||||
* at. Is set-like in nature and keyed by
|
||||
* pointer to class. */
|
||||
FOREACH_HASH_DECLS;
|
||||
int i;
|
||||
Tcl_Obj *namePtr;
|
||||
void *isWanted;
|
||||
|
||||
Tcl_InitObjHashTable(&names);
|
||||
Tcl_InitHashTable(&examinedClasses, TCL_ONE_WORD_KEYS);
|
||||
|
||||
/*
|
||||
* Process method names from the class hierarchy and the mixin hierarchy.
|
||||
*/
|
||||
|
||||
AddClassMethodNames(clsPtr, flags, &names);
|
||||
AddClassMethodNames(clsPtr, flags, &names, &examinedClasses);
|
||||
Tcl_DeleteHashTable(&examinedClasses);
|
||||
|
||||
/*
|
||||
* See how many (visible) method names there are. If none, we do not (and
|
||||
@@ -581,14 +597,28 @@ AddClassMethodNames(
|
||||
Class *clsPtr, /* Class to get method names from. */
|
||||
const int flags, /* Whether we are interested in just the
|
||||
* public method names. */
|
||||
Tcl_HashTable *const namesPtr)
|
||||
Tcl_HashTable *const namesPtr,
|
||||
/* Reference to the hash table to put the
|
||||
* information in. The hash table maps the
|
||||
* Tcl_Obj * method name to an integral value
|
||||
* describing whether the method is wanted.
|
||||
* This ensures that public/private override
|
||||
* semantics are handled correctly.*/
|
||||
* semantics are handled correctly. */
|
||||
Tcl_HashTable *const examinedClassesPtr)
|
||||
/* Hash table that tracks what classes have
|
||||
* already been looked at. The keys are the
|
||||
* pointers to the classes, and the values are
|
||||
* immaterial. */
|
||||
{
|
||||
/*
|
||||
* If we've already started looking at this class, stop working on it now
|
||||
* to prevent repeated work.
|
||||
*/
|
||||
|
||||
if (Tcl_FindHashEntry(examinedClassesPtr, (char *) clsPtr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scope all declarations so that the compiler can stand a good chance of
|
||||
* making the recursive step highly efficient. We also hand-implement the
|
||||
@@ -596,24 +626,31 @@ AddClassMethodNames(
|
||||
* tail-recursion optimization usefully.
|
||||
*/
|
||||
|
||||
if (clsPtr->mixins.num != 0) {
|
||||
Class *mixinPtr;
|
||||
int i;
|
||||
|
||||
/* TODO: Beware of infinite loops! */
|
||||
FOREACH(mixinPtr, clsPtr->mixins) {
|
||||
AddClassMethodNames(mixinPtr, flags|TRAVERSED_MIXIN, namesPtr);
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
FOREACH_HASH_DECLS;
|
||||
Tcl_Obj *namePtr;
|
||||
Method *mPtr;
|
||||
int isNew;
|
||||
|
||||
(void) Tcl_CreateHashEntry(examinedClassesPtr, (char *) clsPtr,
|
||||
&isNew);
|
||||
if (!isNew) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (clsPtr->mixins.num != 0) {
|
||||
Class *mixinPtr;
|
||||
int i;
|
||||
|
||||
FOREACH(mixinPtr, clsPtr->mixins) {
|
||||
if (mixinPtr != clsPtr) {
|
||||
AddClassMethodNames(mixinPtr, flags|TRAVERSED_MIXIN,
|
||||
namesPtr, examinedClassesPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FOREACH_HASH(namePtr, mPtr, &clsPtr->classMethods) {
|
||||
int isNew;
|
||||
|
||||
hPtr = Tcl_CreateHashEntry(namesPtr, (char *) namePtr, &isNew);
|
||||
if (isNew) {
|
||||
int isWanted = (!(flags & PUBLIC_METHOD)
|
||||
@@ -640,7 +677,8 @@ AddClassMethodNames(
|
||||
int i;
|
||||
|
||||
FOREACH(superPtr, clsPtr->superclasses) {
|
||||
AddClassMethodNames(superPtr, flags, namesPtr);
|
||||
AddClassMethodNames(superPtr, flags, namesPtr,
|
||||
examinedClassesPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -793,7 +831,7 @@ AddMethodToCallChain(
|
||||
* Call chain semantics states that methods come as *late* in the
|
||||
* call chain as possible. This is done by copying down the
|
||||
* following methods. Note that this does not change the number of
|
||||
* method invokations in the call chain; it just rearranges them.
|
||||
* method invocations in the call chain; it just rearranges them.
|
||||
*/
|
||||
|
||||
Class *declCls = callPtr->chain[i].filterDeclarer;
|
||||
@@ -898,7 +936,7 @@ IsStillValid(
|
||||
* TclOOGetCallContext --
|
||||
*
|
||||
* Responsible for constructing the call context, an ordered list of all
|
||||
* method implementations to be called as part of a method invokation.
|
||||
* method implementations to be called as part of a method invocation.
|
||||
* This method is central to the whole operation of the OO system.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
@@ -1134,6 +1172,7 @@ TclOOGetCallContext(
|
||||
returnContext:
|
||||
contextPtr = TclStackAlloc(oPtr->fPtr->interp, sizeof(CallContext));
|
||||
contextPtr->oPtr = oPtr;
|
||||
/* Corresponding TclOODecrRefCount() in TclOODeleteContext */
|
||||
AddRef(oPtr);
|
||||
contextPtr->callPtr = callPtr;
|
||||
contextPtr->skip = 2;
|
||||
@@ -1405,7 +1444,6 @@ AddSimpleClassChainToCallContext(
|
||||
if (flags & CONSTRUCTOR) {
|
||||
AddMethodToCallChain(classPtr->constructorPtr, cbPtr, doneFilters,
|
||||
filterDecl, flags);
|
||||
|
||||
} else if (flags & DESTRUCTOR) {
|
||||
AddMethodToCallChain(classPtr->destructorPtr, cbPtr, doneFilters,
|
||||
filterDecl, flags);
|
||||
@@ -1480,7 +1518,7 @@ TclOORenderCallChain(
|
||||
/*
|
||||
* Do the actual construction of the descriptions. They consist of a list
|
||||
* of triples that describe the details of how a method is understood. For
|
||||
* each triple, the first word is the type of invokation ("method" is
|
||||
* each triple, the first word is the type of invocation ("method" is
|
||||
* normal, "unknown" is special because it adds the method name as an
|
||||
* extra argument when handled by some method types, and "filter" is
|
||||
* special because it's a filter method). The second word is the name of
|
||||
|
||||
+130
-213
@@ -47,8 +47,11 @@ struct DeclaredSlot {
|
||||
static inline void BumpGlobalEpoch(Tcl_Interp *interp, Class *classPtr);
|
||||
static Tcl_Command FindCommand(Tcl_Interp *interp, Tcl_Obj *stringObj,
|
||||
Tcl_Namespace *const namespacePtr);
|
||||
static void GenerateErrorInfo(Tcl_Interp *interp, Object *oPtr,
|
||||
static inline void GenerateErrorInfo(Tcl_Interp *interp, Object *oPtr,
|
||||
Tcl_Obj *savedNameObj, const char *typeOfSubject);
|
||||
static inline int MagicDefinitionInvoke(Tcl_Interp *interp,
|
||||
Tcl_Namespace *nsPtr, int cmdIndex,
|
||||
int objc, Tcl_Obj *const *objv);
|
||||
static inline Class * GetClassInOuterContext(Tcl_Interp *interp,
|
||||
Tcl_Obj *className, const char *errMsg);
|
||||
static inline int InitDefineContext(Tcl_Interp *interp,
|
||||
@@ -323,9 +326,8 @@ TclOOObjectSetMixins(
|
||||
if (numMixins == 0) {
|
||||
if (oPtr->mixins.num != 0) {
|
||||
FOREACH(mixinPtr, oPtr->mixins) {
|
||||
if (mixinPtr) {
|
||||
TclOORemoveFromInstances(oPtr, mixinPtr);
|
||||
}
|
||||
TclOORemoveFromInstances(oPtr, mixinPtr);
|
||||
TclOODecrRefCount(mixinPtr->thisPtr);
|
||||
}
|
||||
ckfree(oPtr->mixins.list);
|
||||
oPtr->mixins.num = 0;
|
||||
@@ -337,6 +339,7 @@ TclOOObjectSetMixins(
|
||||
if (mixinPtr && mixinPtr != oPtr->selfCls) {
|
||||
TclOORemoveFromInstances(oPtr, mixinPtr);
|
||||
}
|
||||
TclOODecrRefCount(mixinPtr->thisPtr);
|
||||
}
|
||||
oPtr->mixins.list = ckrealloc(oPtr->mixins.list,
|
||||
sizeof(Class *) * numMixins);
|
||||
@@ -349,6 +352,8 @@ TclOOObjectSetMixins(
|
||||
FOREACH(mixinPtr, oPtr->mixins) {
|
||||
if (mixinPtr != oPtr->selfCls) {
|
||||
TclOOAddToInstances(oPtr, mixinPtr);
|
||||
/* For the new copy created by memcpy */
|
||||
AddRef(mixinPtr->thisPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -378,6 +383,7 @@ TclOOClassSetMixins(
|
||||
if (classPtr->mixins.num != 0) {
|
||||
FOREACH(mixinPtr, classPtr->mixins) {
|
||||
TclOORemoveFromMixinSubs(classPtr, mixinPtr);
|
||||
TclOODecrRefCount(mixinPtr->thisPtr);
|
||||
}
|
||||
ckfree(classPtr->mixins.list);
|
||||
classPtr->mixins.num = 0;
|
||||
@@ -386,6 +392,7 @@ TclOOClassSetMixins(
|
||||
if (classPtr->mixins.num != 0) {
|
||||
FOREACH(mixinPtr, classPtr->mixins) {
|
||||
TclOORemoveFromMixinSubs(classPtr, mixinPtr);
|
||||
TclOODecrRefCount(mixinPtr->thisPtr);
|
||||
}
|
||||
classPtr->mixins.list = ckrealloc(classPtr->mixins.list,
|
||||
sizeof(Class *) * numMixins);
|
||||
@@ -396,6 +403,8 @@ TclOOClassSetMixins(
|
||||
memcpy(classPtr->mixins.list, mixins, sizeof(Class *) * numMixins);
|
||||
FOREACH(mixinPtr, classPtr->mixins) {
|
||||
TclOOAddToMixinSubs(classPtr, mixinPtr);
|
||||
/* For the new copy created by memcpy */
|
||||
AddRef(mixinPtr->thisPtr);
|
||||
}
|
||||
}
|
||||
BumpGlobalEpoch(interp, classPtr);
|
||||
@@ -755,7 +764,7 @@ GetClassInOuterContext(
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
static inline void
|
||||
GenerateErrorInfo(
|
||||
Tcl_Interp *interp, /* Where to store the error info trace. */
|
||||
Object *oPtr, /* What object (or class) was being configured
|
||||
@@ -784,6 +793,69 @@ GenerateErrorInfo(
|
||||
(overflow ? "..." : ""), Tcl_GetErrorLine(interp)));
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* MagicDefinitionInvoke --
|
||||
* Part of the implementation of the "oo::define" and "oo::objdefine"
|
||||
* commands that is used to implement the more-than-one-argument case,
|
||||
* applying ensemble-like tricks with dispatch so that error messages are
|
||||
* clearer. Doesn't handle the management of the stack frame.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static inline int
|
||||
MagicDefinitionInvoke(
|
||||
Tcl_Interp *interp,
|
||||
Tcl_Namespace *nsPtr,
|
||||
int cmdIndex,
|
||||
int objc,
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
Tcl_Obj *objPtr, *obj2Ptr, **objs;
|
||||
Tcl_Command cmd;
|
||||
int isRoot, dummy, result, offset = cmdIndex + 1;
|
||||
|
||||
/*
|
||||
* More than one argument: fire them through the ensemble processing
|
||||
* engine so that everything appears to be good and proper in error
|
||||
* messages. Note that we cannot just concatenate and send through
|
||||
* Tcl_EvalObjEx, as that doesn't do ensemble processing, and we cannot go
|
||||
* through Tcl_EvalObjv without the extra work to pre-find the command, as
|
||||
* that finds command names in the wrong namespace at the moment. Ugly!
|
||||
*/
|
||||
|
||||
isRoot = TclInitRewriteEnsemble(interp, offset, 1, objv);
|
||||
|
||||
/*
|
||||
* Build the list of arguments using a Tcl_Obj as a workspace. See
|
||||
* comments above for why these contortions are necessary.
|
||||
*/
|
||||
|
||||
objPtr = Tcl_NewObj();
|
||||
obj2Ptr = Tcl_NewObj();
|
||||
cmd = FindCommand(interp, objv[cmdIndex], nsPtr);
|
||||
if (cmd == NULL) {
|
||||
/* punt this case! */
|
||||
Tcl_AppendObjToObj(obj2Ptr, objv[cmdIndex]);
|
||||
} else {
|
||||
Tcl_GetCommandFullName(interp, cmd, obj2Ptr);
|
||||
}
|
||||
Tcl_ListObjAppendElement(NULL, objPtr, obj2Ptr);
|
||||
/* TODO: overflow? */
|
||||
Tcl_ListObjReplace(NULL, objPtr, 1, 0, objc-offset, objv+offset);
|
||||
Tcl_ListObjGetElements(NULL, objPtr, &dummy, &objs);
|
||||
|
||||
result = Tcl_EvalObjv(interp, objc-cmdIndex, objs, TCL_EVAL_INVOKE);
|
||||
if (isRoot) {
|
||||
TclResetRewriteEnsemble(interp, 1);
|
||||
}
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
@@ -805,8 +877,8 @@ TclOODefineObjCmd(
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
Foundation *fPtr = TclOOGetFoundation(interp);
|
||||
int result;
|
||||
Object *oPtr;
|
||||
int result;
|
||||
|
||||
if (objc < 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "className arg ?arg ...?");
|
||||
@@ -846,48 +918,9 @@ TclOODefineObjCmd(
|
||||
}
|
||||
TclDecrRefCount(objNameObj);
|
||||
} else {
|
||||
Tcl_Obj *objPtr, *obj2Ptr, **objs;
|
||||
Tcl_Command cmd;
|
||||
int isRoot, dummy;
|
||||
|
||||
/*
|
||||
* More than one argument: fire them through the ensemble processing
|
||||
* engine so that everything appears to be good and proper in error
|
||||
* messages. Note that we cannot just concatenate and send through
|
||||
* Tcl_EvalObjEx, as that doesn't do ensemble processing, and we
|
||||
* cannot go through Tcl_EvalObjv without the extra work to pre-find
|
||||
* the command, as that finds command names in the wrong namespace at
|
||||
* the moment. Ugly!
|
||||
*/
|
||||
|
||||
isRoot = TclInitRewriteEnsemble(interp, 3, 1, objv);
|
||||
|
||||
/*
|
||||
* Build the list of arguments using a Tcl_Obj as a workspace. See
|
||||
* comments above for why these contortions are necessary.
|
||||
*/
|
||||
|
||||
objPtr = Tcl_NewObj();
|
||||
obj2Ptr = Tcl_NewObj();
|
||||
cmd = FindCommand(interp, objv[2], fPtr->defineNs);
|
||||
if (cmd == NULL) {
|
||||
/* punt this case! */
|
||||
Tcl_AppendObjToObj(obj2Ptr, objv[2]);
|
||||
} else {
|
||||
Tcl_GetCommandFullName(interp, cmd, obj2Ptr);
|
||||
}
|
||||
Tcl_ListObjAppendElement(NULL, objPtr, obj2Ptr);
|
||||
/* TODO: overflow? */
|
||||
Tcl_ListObjReplace(NULL, objPtr, 1, 0, objc-3, objv+3);
|
||||
Tcl_ListObjGetElements(NULL, objPtr, &dummy, &objs);
|
||||
|
||||
result = Tcl_EvalObjv(interp, objc-2, objs, TCL_EVAL_INVOKE);
|
||||
if (isRoot) {
|
||||
TclResetRewriteEnsemble(interp, 1);
|
||||
}
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
result = MagicDefinitionInvoke(interp, fPtr->defineNs, 2, objc, objv);
|
||||
}
|
||||
DelRef(oPtr);
|
||||
TclOODecrRefCount(oPtr);
|
||||
|
||||
/*
|
||||
* Restore the previous "current" namespace.
|
||||
@@ -918,8 +951,8 @@ TclOOObjDefObjCmd(
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
Foundation *fPtr = TclOOGetFoundation(interp);
|
||||
int isRoot, result;
|
||||
Object *oPtr;
|
||||
int result;
|
||||
|
||||
if (objc < 3) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "objectName arg ?arg ...?");
|
||||
@@ -952,49 +985,9 @@ TclOOObjDefObjCmd(
|
||||
}
|
||||
TclDecrRefCount(objNameObj);
|
||||
} else {
|
||||
Tcl_Obj *objPtr, *obj2Ptr, **objs;
|
||||
Tcl_Command cmd;
|
||||
int dummy;
|
||||
|
||||
/*
|
||||
* More than one argument: fire them through the ensemble processing
|
||||
* engine so that everything appears to be good and proper in error
|
||||
* messages. Note that we cannot just concatenate and send through
|
||||
* Tcl_EvalObjEx, as that doesn't do ensemble processing, and we
|
||||
* cannot go through Tcl_EvalObjv without the extra work to pre-find
|
||||
* the command, as that finds command names in the wrong namespace at
|
||||
* the moment. Ugly!
|
||||
*/
|
||||
|
||||
isRoot = TclInitRewriteEnsemble(interp, 3, 1, objv);
|
||||
|
||||
/*
|
||||
* Build the list of arguments using a Tcl_Obj as a workspace. See
|
||||
* comments above for why these contortions are necessary.
|
||||
*/
|
||||
|
||||
objPtr = Tcl_NewObj();
|
||||
obj2Ptr = Tcl_NewObj();
|
||||
cmd = FindCommand(interp, objv[2], fPtr->objdefNs);
|
||||
if (cmd == NULL) {
|
||||
/* punt this case! */
|
||||
Tcl_AppendObjToObj(obj2Ptr, objv[2]);
|
||||
} else {
|
||||
Tcl_GetCommandFullName(interp, cmd, obj2Ptr);
|
||||
}
|
||||
Tcl_ListObjAppendElement(NULL, objPtr, obj2Ptr);
|
||||
/* TODO: overflow? */
|
||||
Tcl_ListObjReplace(NULL, objPtr, 1, 0, objc-3, objv+3);
|
||||
Tcl_ListObjGetElements(NULL, objPtr, &dummy, &objs);
|
||||
|
||||
result = Tcl_EvalObjv(interp, objc-2, objs, TCL_EVAL_INVOKE);
|
||||
|
||||
if (isRoot) {
|
||||
TclResetRewriteEnsemble(interp, 1);
|
||||
}
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
result = MagicDefinitionInvoke(interp, fPtr->objdefNs, 2, objc, objv);
|
||||
}
|
||||
DelRef(oPtr);
|
||||
TclOODecrRefCount(oPtr);
|
||||
|
||||
/*
|
||||
* Restore the previous "current" namespace.
|
||||
@@ -1025,8 +1018,8 @@ TclOODefineSelfObjCmd(
|
||||
Tcl_Obj *const *objv)
|
||||
{
|
||||
Foundation *fPtr = TclOOGetFoundation(interp);
|
||||
int result;
|
||||
Object *oPtr;
|
||||
int result;
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "arg ?arg ...?");
|
||||
@@ -1059,48 +1052,9 @@ TclOODefineSelfObjCmd(
|
||||
}
|
||||
TclDecrRefCount(objNameObj);
|
||||
} else {
|
||||
Tcl_Obj *objPtr, *obj2Ptr, **objs;
|
||||
Tcl_Command cmd;
|
||||
int isRoot, dummy;
|
||||
|
||||
/*
|
||||
* More than one argument: fire them through the ensemble processing
|
||||
* engine so that everything appears to be good and proper in error
|
||||
* messages. Note that we cannot just concatenate and send through
|
||||
* Tcl_EvalObjEx, as that doesn't do ensemble processing, and we
|
||||
* cannot go through Tcl_EvalObjv without the extra work to pre-find
|
||||
* the command, as that finds command names in the wrong namespace at
|
||||
* the moment. Ugly!
|
||||
*/
|
||||
|
||||
isRoot = TclInitRewriteEnsemble(interp, 2, 1, objv);
|
||||
|
||||
/*
|
||||
* Build the list of arguments using a Tcl_Obj as a workspace. See
|
||||
* comments above for why these contortions are necessary.
|
||||
*/
|
||||
|
||||
objPtr = Tcl_NewObj();
|
||||
obj2Ptr = Tcl_NewObj();
|
||||
cmd = FindCommand(interp, objv[1], fPtr->objdefNs);
|
||||
if (cmd == NULL) {
|
||||
/* punt this case! */
|
||||
Tcl_AppendObjToObj(obj2Ptr, objv[1]);
|
||||
} else {
|
||||
Tcl_GetCommandFullName(interp, cmd, obj2Ptr);
|
||||
}
|
||||
Tcl_ListObjAppendElement(NULL, objPtr, obj2Ptr);
|
||||
/* TODO: overflow? */
|
||||
Tcl_ListObjReplace(NULL, objPtr, 1, 0, objc-2, objv+2);
|
||||
Tcl_ListObjGetElements(NULL, objPtr, &dummy, &objs);
|
||||
|
||||
result = Tcl_EvalObjv(interp, objc-1, objs, TCL_EVAL_INVOKE);
|
||||
if (isRoot) {
|
||||
TclResetRewriteEnsemble(interp, 1);
|
||||
}
|
||||
Tcl_DecrRefCount(objPtr);
|
||||
result = MagicDefinitionInvoke(interp, fPtr->objdefNs, 1, objc, objv);
|
||||
}
|
||||
DelRef(oPtr);
|
||||
TclOODecrRefCount(oPtr);
|
||||
|
||||
/*
|
||||
* Restore the previous "current" namespace.
|
||||
@@ -1130,6 +1084,7 @@ TclOODefineClassObjCmd(
|
||||
Object *oPtr;
|
||||
Class *clsPtr;
|
||||
Foundation *fPtr = TclOOGetFoundation(interp);
|
||||
int wasClass, willBeClass;
|
||||
|
||||
/*
|
||||
* Parse the context to get the object to operate on.
|
||||
@@ -1165,19 +1120,10 @@ TclOODefineClassObjCmd(
|
||||
if (clsPtr == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply semantic checks. In particular, classes and non-classes are not
|
||||
* interchangable (too complicated to do the conversion!) so we must
|
||||
* produce an error if any attempt is made to swap from one to the other.
|
||||
*/
|
||||
|
||||
if ((oPtr->classPtr==NULL) == TclOOIsReachable(fPtr->classCls, clsPtr)) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"may not change a %sclass object into a %sclass object",
|
||||
(oPtr->classPtr==NULL ? "non-" : ""),
|
||||
(oPtr->classPtr==NULL ? "" : "non-")));
|
||||
Tcl_SetErrorCode(interp, "TCL", "OO", "TRANSMUTATION", NULL);
|
||||
if (oPtr == clsPtr->thisPtr) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
"may not change classes into an instance of themselves", -1));
|
||||
Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -1185,13 +1131,36 @@ TclOODefineClassObjCmd(
|
||||
* Set the object's class.
|
||||
*/
|
||||
|
||||
wasClass = (oPtr->classPtr != NULL);
|
||||
willBeClass = (TclOOIsReachable(fPtr->classCls, clsPtr));
|
||||
|
||||
if (oPtr->selfCls != clsPtr) {
|
||||
TclOORemoveFromInstances(oPtr, oPtr->selfCls);
|
||||
TclOODecrRefCount(oPtr->selfCls->thisPtr);
|
||||
oPtr->selfCls = clsPtr;
|
||||
AddRef(oPtr->selfCls->thisPtr);
|
||||
TclOOAddToInstances(oPtr, oPtr->selfCls);
|
||||
if (!(clsPtr->thisPtr->flags & OBJECT_DELETED)) {
|
||||
oPtr->flags &= ~CLASS_GONE;
|
||||
|
||||
/*
|
||||
* Create or delete the class guts if necessary.
|
||||
*/
|
||||
|
||||
if (wasClass && !willBeClass) {
|
||||
/*
|
||||
* This is the most global of all epochs. Bump it! No cache can be
|
||||
* trusted!
|
||||
*/
|
||||
|
||||
TclOORemoveFromMixins(oPtr->classPtr, oPtr);
|
||||
oPtr->fPtr->epoch++;
|
||||
oPtr->flags |= DONT_DELETE;
|
||||
TclOODeleteDescendants(interp, oPtr);
|
||||
oPtr->flags &= ~DONT_DELETE;
|
||||
TclOOReleaseClassContents(interp, oPtr);
|
||||
} else if (!wasClass && willBeClass) {
|
||||
TclOOAllocClass(interp, oPtr);
|
||||
}
|
||||
|
||||
if (oPtr->classPtr != NULL) {
|
||||
BumpGlobalEpoch(interp, oPtr->classPtr);
|
||||
} else {
|
||||
@@ -1600,69 +1569,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;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
@@ -2074,6 +1980,7 @@ ClassMixinSet(
|
||||
mixins[i] = GetClassInOuterContext(interp, mixinv[i],
|
||||
"may only mix in classes");
|
||||
if (mixins[i] == NULL) {
|
||||
i--;
|
||||
goto freeAndError;
|
||||
}
|
||||
if (TclOOIsReachable(oPtr->classPtr, mixins[i])) {
|
||||
@@ -2191,16 +2098,19 @@ ClassSuperSet(
|
||||
|
||||
if (superc == 0) {
|
||||
superclasses = ckrealloc(superclasses, sizeof(Class *));
|
||||
superclasses[0] = oPtr->fPtr->objectCls;
|
||||
superc = 1;
|
||||
if (TclOOIsReachable(oPtr->fPtr->classCls, oPtr->classPtr)) {
|
||||
superclasses[0] = oPtr->fPtr->classCls;
|
||||
} else {
|
||||
superclasses[0] = oPtr->fPtr->objectCls;
|
||||
}
|
||||
superc = 1;
|
||||
AddRef(superclasses[0]->thisPtr);
|
||||
} else {
|
||||
for (i=0 ; i<superc ; i++) {
|
||||
superclasses[i] = GetClassInOuterContext(interp, superv[i],
|
||||
"only a class can be a superclass");
|
||||
if (superclasses[i] == NULL) {
|
||||
i--;
|
||||
goto failedAfterAlloc;
|
||||
}
|
||||
for (j=0 ; j<i ; j++) {
|
||||
@@ -2217,9 +2127,15 @@ ClassSuperSet(
|
||||
"attempt to form circular dependency graph", -1));
|
||||
Tcl_SetErrorCode(interp, "TCL", "OO", "CIRCULARITY", NULL);
|
||||
failedAfterAlloc:
|
||||
ckfree((char *) superclasses);
|
||||
for (; i > 0; i--) {
|
||||
TclOODecrRefCount(superclasses[i]->thisPtr);
|
||||
}
|
||||
ckfree(superclasses);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
/* Corresponding TclOODecrRefCount() is near the end of this
|
||||
* function */
|
||||
AddRef(superclasses[i]->thisPtr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2233,6 +2149,7 @@ ClassSuperSet(
|
||||
if (oPtr->classPtr->superclasses.num != 0) {
|
||||
FOREACH(superPtr, oPtr->classPtr->superclasses) {
|
||||
TclOORemoveFromSubclasses(oPtr->classPtr, superPtr);
|
||||
TclOODecrRefCount(superPtr->thisPtr);
|
||||
}
|
||||
ckfree((char *) oPtr->classPtr->superclasses.list);
|
||||
}
|
||||
|
||||
+38
-36
@@ -149,8 +149,8 @@ typedef struct Object {
|
||||
struct Foundation *fPtr; /* The basis for the object system. Putting
|
||||
* this here allows the avoidance of quite a
|
||||
* lot of hash lookups on the critical path
|
||||
* for object invokation and creation. */
|
||||
Tcl_Namespace *namespacePtr;/* This object's tame namespace. */
|
||||
* for object invocation and creation. */
|
||||
Tcl_Namespace *namespacePtr;/* This object's namespace. */
|
||||
Tcl_Command command; /* Reference to this object's public
|
||||
* command. */
|
||||
Tcl_Command myCommand; /* Reference to this object's internal
|
||||
@@ -162,12 +162,12 @@ typedef struct Object {
|
||||
/* Classes mixed into this object. */
|
||||
LIST_STATIC(Tcl_Obj *) filters;
|
||||
/* List of filter names. */
|
||||
struct Class *classPtr; /* All classes have this non-NULL; it points
|
||||
* to the class structure. Everything else has
|
||||
* this NULL. */
|
||||
struct Class *classPtr; /* This is non-NULL for all classes, and NULL
|
||||
* for everything else. It points to the class
|
||||
* structure. */
|
||||
int refCount; /* Number of strong references to this object.
|
||||
* Note that there may be many more weak
|
||||
* references; this mechanism is there to
|
||||
* references; this mechanism exists to
|
||||
* avoid Tcl_Preserve. */
|
||||
int flags;
|
||||
int creationEpoch; /* Unique value to make comparisons of objects
|
||||
@@ -193,9 +193,10 @@ typedef struct Object {
|
||||
* destroyed. */
|
||||
#define DESTRUCTOR_CALLED 2 /* Flag to say that the destructor has been
|
||||
* called. */
|
||||
#define CLASS_GONE 4 /* Indicates that the class of this object has
|
||||
* been deleted, and so the object should not
|
||||
* attempt to remove itself from its class. */
|
||||
#define CLASS_GONE 4 /* Obsolete. Indicates that the class of this
|
||||
* object has been deleted, and so the object
|
||||
* should not attempt to remove itself from its
|
||||
* class. */
|
||||
#define ROOT_OBJECT 0x1000 /* Flag to say that this object is the root of
|
||||
* the class hierarchy and should be treated
|
||||
* specially during teardown. */
|
||||
@@ -213,6 +214,7 @@ typedef struct Object {
|
||||
* other spots). */
|
||||
#define FORCE_UNKNOWN 0x10000 /* States that we are *really* looking up the
|
||||
* unknown method handler at that point. */
|
||||
#define DONT_DELETE 0x20000 /* Inhibit deletion of this object. */
|
||||
|
||||
/*
|
||||
* And the definition of a class. Note that every class also has an associated
|
||||
@@ -222,10 +224,6 @@ typedef struct Object {
|
||||
typedef struct Class {
|
||||
Object *thisPtr; /* Reference to the object associated with
|
||||
* this class. */
|
||||
int refCount; /* Number of strong references to this class.
|
||||
* Weak references are not counted; the
|
||||
* purpose of this is to avoid Tcl_Preserve as
|
||||
* that is quite slow. */
|
||||
int flags; /* Assorted flags. */
|
||||
LIST_STATIC(struct Class *) superclasses;
|
||||
/* List of superclasses, used for generation
|
||||
@@ -323,7 +321,7 @@ typedef struct Foundation {
|
||||
} Foundation;
|
||||
|
||||
/*
|
||||
* A call context structure is built when a method is called. They contain the
|
||||
* A call context structure is built when a method is called. It contains the
|
||||
* chain of method implementations that are to be invoked by a particular
|
||||
* call, and the process of calling walks the chain, with the [next] command
|
||||
* proceeding to the next entry in the chain.
|
||||
@@ -334,7 +332,7 @@ typedef struct Foundation {
|
||||
struct MInvoke {
|
||||
Method *mPtr; /* Reference to the method implementation
|
||||
* record. */
|
||||
int isFilter; /* Whether this is a filter invokation. */
|
||||
int isFilter; /* Whether this is a filter invocation. */
|
||||
Class *filterDeclarer; /* What class decided to add the filter; if
|
||||
* NULL, it was added by the object. */
|
||||
};
|
||||
@@ -487,15 +485,24 @@ MODULE_SCOPE int TclOO_Object_VarName(ClientData clientData,
|
||||
MODULE_SCOPE void TclOOAddToInstances(Object *oPtr, Class *clsPtr);
|
||||
MODULE_SCOPE void TclOOAddToMixinSubs(Class *subPtr, Class *mixinPtr);
|
||||
MODULE_SCOPE void TclOOAddToSubclasses(Class *subPtr, Class *superPtr);
|
||||
MODULE_SCOPE Class * TclOOAllocClass(Tcl_Interp *interp,
|
||||
Object *useThisObj);
|
||||
MODULE_SCOPE int TclNRNewObjectInstance(Tcl_Interp *interp,
|
||||
Tcl_Class cls, const char *nameStr,
|
||||
const char *nsNameStr, int objc,
|
||||
Tcl_Obj *const *objv, int skip,
|
||||
Tcl_Object *objectPtr);
|
||||
MODULE_SCOPE Object * TclNewObjectInstanceCommon(Tcl_Interp *interp,
|
||||
Class *classPtr,
|
||||
const char *nameStr,
|
||||
const char *nsNameStr);
|
||||
MODULE_SCOPE int TclOODecrRefCount(Object *oPtr);
|
||||
MODULE_SCOPE int TclOODefineSlots(Foundation *fPtr);
|
||||
MODULE_SCOPE void TclOODeleteChain(CallChain *callPtr);
|
||||
MODULE_SCOPE void TclOODeleteChainCache(Tcl_HashTable *tablePtr);
|
||||
MODULE_SCOPE void TclOODeleteContext(CallContext *contextPtr);
|
||||
MODULE_SCOPE void TclOODeleteDescendants(Tcl_Interp *interp,
|
||||
Object *oPtr);
|
||||
MODULE_SCOPE void TclOODelMethodRef(Method *method);
|
||||
MODULE_SCOPE CallContext *TclOOGetCallContext(Object *oPtr,
|
||||
Tcl_Obj *methodNameObj, int flags,
|
||||
@@ -521,10 +528,13 @@ MODULE_SCOPE int TclNRObjectContextInvokeNext(Tcl_Interp *interp,
|
||||
MODULE_SCOPE void TclOONewBasicMethod(Tcl_Interp *interp, Class *clsPtr,
|
||||
const DeclaredClassMethod *dcm);
|
||||
MODULE_SCOPE Tcl_Obj * TclOOObjectName(Tcl_Interp *interp, Object *oPtr);
|
||||
MODULE_SCOPE void TclOORemoveFromInstances(Object *oPtr, Class *clsPtr);
|
||||
MODULE_SCOPE void TclOORemoveFromMixinSubs(Class *subPtr,
|
||||
MODULE_SCOPE void TclOOReleaseClassContents(Tcl_Interp *interp,
|
||||
Object *oPtr);
|
||||
MODULE_SCOPE int TclOORemoveFromInstances(Object *oPtr, Class *clsPtr);
|
||||
MODULE_SCOPE int TclOORemoveFromMixins(Class *mixinPtr, Object *oPtr);
|
||||
MODULE_SCOPE int TclOORemoveFromMixinSubs(Class *subPtr,
|
||||
Class *mixinPtr);
|
||||
MODULE_SCOPE void TclOORemoveFromSubclasses(Class *subPtr,
|
||||
MODULE_SCOPE int TclOORemoveFromSubclasses(Class *subPtr,
|
||||
Class *superPtr);
|
||||
MODULE_SCOPE Tcl_Obj * TclOORenderCallChain(Tcl_Interp *interp,
|
||||
CallChain *callPtr);
|
||||
@@ -538,19 +548,22 @@ MODULE_SCOPE void TclOOSetupVariableResolver(Tcl_Namespace *nsPtr);
|
||||
|
||||
#include "tclOOIntDecls.h"
|
||||
|
||||
/*
|
||||
* Alternatives to Tcl_Preserve/Tcl_EventuallyFree/Tcl_Release.
|
||||
*/
|
||||
|
||||
#define AddRef(ptr) ((ptr)->refCount++)
|
||||
|
||||
/*
|
||||
* A convenience macro for iterating through the lists used in the internal
|
||||
* memory management of objects. This is a bit gnarly because we want to do
|
||||
* the assignment of the picked-out value only when the body test succeeds,
|
||||
* but we cannot rely on the assigned value being useful, forcing us to do
|
||||
* some nasty stuff with the comma operator. The compiler's optimizer should
|
||||
* be able to sort it all out!
|
||||
*
|
||||
* memory management of objects.
|
||||
* REQUIRES DECLARATION: int i;
|
||||
*/
|
||||
|
||||
#define FOREACH(var,ary) \
|
||||
for(i=0 ; (i<(ary).num?((var=(ary).list[i]),1):0) ; i++)
|
||||
for(i=0 ; i<(ary).num; i++) if ((ary).list[i] == NULL) { \
|
||||
continue; \
|
||||
} else if (var = (ary).list[i], 1)
|
||||
|
||||
/*
|
||||
* Convenience macros for iterating through hash tables. FOREACH_HASH_DECLS
|
||||
@@ -585,17 +598,6 @@ MODULE_SCOPE void TclOOSetupVariableResolver(Tcl_Namespace *nsPtr);
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* Alternatives to Tcl_Preserve/Tcl_EventuallyFree/Tcl_Release.
|
||||
*/
|
||||
|
||||
#define AddRef(ptr) ((ptr)->refCount++)
|
||||
#define DelRef(ptr) do { \
|
||||
if ((ptr)->refCount-- <= 1) { \
|
||||
ckfree((char *) (ptr)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#endif /* TCL_OO_INTERNAL_H */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1314,6 +1314,7 @@ CloneProcedureMethod(
|
||||
*/
|
||||
|
||||
bodyObj = Tcl_DuplicateObj(pmPtr->procPtr->bodyPtr);
|
||||
Tcl_GetString(bodyObj);
|
||||
TclFreeIntRep(bodyObj);
|
||||
|
||||
/*
|
||||
|
||||
+35
-14
@@ -2467,23 +2467,26 @@ Tcl_SetIntObj(
|
||||
*
|
||||
* Tcl_GetIntFromObj --
|
||||
*
|
||||
* Attempt to return an int from the Tcl object "objPtr". If the object
|
||||
* is not already an int, an attempt will be made to convert it to one.
|
||||
* Retrieve the integer value of 'objPtr'.
|
||||
*
|
||||
* Integer and long integer objects share the same "integer" type
|
||||
* implementation. We store all integers as longs and Tcl_GetIntFromObj
|
||||
* checks whether the current value of the long can be represented by an
|
||||
* int.
|
||||
* Value
|
||||
*
|
||||
* Results:
|
||||
* The return value is a standard Tcl object result. If an error occurs
|
||||
* during conversion or if the long integer held by the object can not be
|
||||
* represented by an int, an error message is left in the interpreter's
|
||||
* result unless "interp" is NULL.
|
||||
* TCL_OK
|
||||
*
|
||||
* Side effects:
|
||||
* If the object is not already an int, the conversion will free any old
|
||||
* internal representation.
|
||||
* Success.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* An error occurred during conversion or the integral value can not
|
||||
* be represented as an integer (it might be too large). An error
|
||||
* message is left in the interpreter's result if 'interp' is not
|
||||
* NULL.
|
||||
*
|
||||
* Effect
|
||||
*
|
||||
* 'objPtr' is converted to an integer if necessary if it is not one
|
||||
* already. The conversion frees any previously-existing internal
|
||||
* representation.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -4488,6 +4491,24 @@ Tcl_RepresentationCmd(
|
||||
objv[1]->typePtr ? objv[1]->typePtr->name : "pure string",
|
||||
objv[1]->refCount, ptrBuffer);
|
||||
|
||||
/*
|
||||
* This is a workaround to silence reports from `make valgrind`
|
||||
* on 64-bit systems. The problem is that the test suite
|
||||
* includes calling the [represenation] command on values of
|
||||
* &tclDoubleType. When these values are created, the "doubleValue"
|
||||
* is set, but when the "twoPtrValue" is examined, its "ptr2"
|
||||
* field has never been initialized. Since [representation]
|
||||
* presents the value of the ptr2 value in its output, valgrind
|
||||
* alerts about the read of uninitialized memory.
|
||||
*
|
||||
* The general problem with [representation], that it can read
|
||||
* and report uninitialized fields, is still present. This is
|
||||
* just the minimal workaround to silence one particular test.
|
||||
*/
|
||||
|
||||
if ((sizeof(void *) > 4) && objv[1]->typePtr == &tclDoubleType) {
|
||||
objv[1]->internalRep.twoPtrValue.ptr2 = NULL;
|
||||
}
|
||||
if (objv[1]->typePtr) {
|
||||
sprintf(ptrBuffer, "%p:%p",
|
||||
(void *) objv[1]->internalRep.twoPtrValue.ptr1,
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ Tcl_PanicVA(
|
||||
__builtin_trap();
|
||||
# elif defined(_WIN64)
|
||||
__debugbreak();
|
||||
# elif defined(_MSC_VER)
|
||||
# elif defined(_MSC_VER) && defined (_M_IX86)
|
||||
_asm {int 3}
|
||||
# else
|
||||
DebugBreak();
|
||||
|
||||
+8
-2
@@ -841,7 +841,7 @@ TclParseBackslash(
|
||||
* written there. */
|
||||
{
|
||||
register const char *p = src+1;
|
||||
Tcl_UniChar unichar;
|
||||
Tcl_UniChar unichar = 0;
|
||||
int result;
|
||||
int count;
|
||||
char buf[TCL_UTF_MAX];
|
||||
@@ -991,7 +991,13 @@ TclParseBackslash(
|
||||
if (readPtr != NULL) {
|
||||
*readPtr = count;
|
||||
}
|
||||
return Tcl_UniCharToUtf(result, dst);
|
||||
count = Tcl_UniCharToUtf(result, dst);
|
||||
#if TCL_UTF_MAX > 3
|
||||
if (!count) {
|
||||
count = Tcl_UniCharToUtf(-1, dst);
|
||||
}
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+32
-33
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "tclInt.h"
|
||||
#include "tclFileSystem.h"
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* Prototypes for functions defined later in this file.
|
||||
@@ -849,18 +850,20 @@ TclJoinPath(
|
||||
int elements,
|
||||
Tcl_Obj * const objv[])
|
||||
{
|
||||
Tcl_Obj *res;
|
||||
Tcl_Obj *res = NULL;
|
||||
int i;
|
||||
const Tcl_Filesystem *fsPtr = NULL;
|
||||
|
||||
res = NULL;
|
||||
assert ( elements >= 0 );
|
||||
|
||||
for (i = 0; i < elements; i++) {
|
||||
int driveNameLength, strEltLen, length;
|
||||
Tcl_PathType type;
|
||||
char *strElt, *ptr;
|
||||
Tcl_Obj *driveName = NULL;
|
||||
Tcl_Obj *elt = objv[i];
|
||||
if (elements == 0) {
|
||||
return Tcl_NewObj();
|
||||
}
|
||||
|
||||
assert ( elements > 0 );
|
||||
|
||||
if (elements == 2) {
|
||||
Tcl_Obj *elt = objv[0];
|
||||
|
||||
/*
|
||||
* This is a special case where we can be much more efficient, where
|
||||
@@ -869,18 +872,17 @@ TclJoinPath(
|
||||
* object which can be normalized more efficiently. Currently we only
|
||||
* use the special case when we have exactly two elements, but we
|
||||
* could expand that in the future.
|
||||
*
|
||||
* Bugfix [a47641a0]. TclNewFSPathObj requires first argument
|
||||
* to be an absolute path. Added a check for that elt is absolute.
|
||||
*
|
||||
* Bugfix [a47641a0]. TclNewFSPathObj requires first argument
|
||||
* to be an absolute path. Added a check for that elt is absolute.
|
||||
*/
|
||||
|
||||
if ((i == (elements-2)) && (i == 0)
|
||||
&& (elt->typePtr == &tclFsPathType)
|
||||
if ((elt->typePtr == &tclFsPathType)
|
||||
&& !((elt->bytes != NULL) && (elt->bytes[0] == '\0'))
|
||||
&& TclGetPathType(elt, NULL, NULL, NULL) == TCL_PATH_ABSOLUTE) {
|
||||
Tcl_Obj *tailObj = objv[i+1];
|
||||
Tcl_Obj *tailObj = objv[1];
|
||||
Tcl_PathType type = TclGetPathType(tailObj, NULL, NULL, NULL);
|
||||
|
||||
type = TclGetPathType(tailObj, NULL, NULL, NULL);
|
||||
if (type == TCL_PATH_RELATIVE) {
|
||||
const char *str;
|
||||
int len;
|
||||
@@ -893,9 +895,6 @@ TclJoinPath(
|
||||
* the base itself is just fine!
|
||||
*/
|
||||
|
||||
if (res != NULL) {
|
||||
TclDecrRefCount(res);
|
||||
}
|
||||
return elt;
|
||||
}
|
||||
|
||||
@@ -918,9 +917,6 @@ TclJoinPath(
|
||||
|
||||
if ((tclPlatform != TCL_PLATFORM_WINDOWS)
|
||||
|| (strchr(Tcl_GetString(elt), '\\') == NULL)) {
|
||||
if (res != NULL) {
|
||||
TclDecrRefCount(res);
|
||||
}
|
||||
|
||||
if (PATHFLAGS(elt)) {
|
||||
return TclNewFSPathObj(elt, str, len);
|
||||
@@ -940,23 +936,28 @@ TclJoinPath(
|
||||
* more general code below handle things.
|
||||
*/
|
||||
} else if (tclPlatform == TCL_PLATFORM_UNIX) {
|
||||
if (res != NULL) {
|
||||
TclDecrRefCount(res);
|
||||
}
|
||||
return tailObj;
|
||||
} else {
|
||||
const char *str = TclGetString(tailObj);
|
||||
|
||||
if (tclPlatform == TCL_PLATFORM_WINDOWS) {
|
||||
if (strchr(str, '\\') == NULL) {
|
||||
if (res != NULL) {
|
||||
TclDecrRefCount(res);
|
||||
}
|
||||
return tailObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert ( res == NULL );
|
||||
|
||||
for (i = 0; i < elements; i++) {
|
||||
int driveNameLength, strEltLen, length;
|
||||
Tcl_PathType type;
|
||||
char *strElt, *ptr;
|
||||
Tcl_Obj *driveName = NULL;
|
||||
Tcl_Obj *elt = objv[i];
|
||||
|
||||
strElt = Tcl_GetStringFromObj(elt, &strEltLen);
|
||||
driveNameLength = 0;
|
||||
type = TclGetPathType(elt, &fsPtr, &driveNameLength, &driveName);
|
||||
@@ -1087,6 +1088,7 @@ TclJoinPath(
|
||||
|
||||
if (sep != NULL) {
|
||||
separator = TclGetString(sep)[0];
|
||||
Tcl_DecrRefCount(sep);
|
||||
}
|
||||
/* Safety check in case the VFS driver caused sharing */
|
||||
if (Tcl_IsShared(res)) {
|
||||
@@ -1122,9 +1124,7 @@ TclJoinPath(
|
||||
Tcl_SetObjLength(res, length);
|
||||
}
|
||||
}
|
||||
if (res == NULL) {
|
||||
res = Tcl_NewObj();
|
||||
}
|
||||
assert ( res != NULL );
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1811,7 +1811,6 @@ Tcl_FSGetNormalizedPath(
|
||||
*/
|
||||
|
||||
(void) Tcl_GetStringFromObj(dir, &cwdLen);
|
||||
cwdLen += (Tcl_GetString(copy)[cwdLen] == '/');
|
||||
|
||||
/* Normalize the combined string. */
|
||||
|
||||
@@ -1833,12 +1832,12 @@ Tcl_FSGetNormalizedPath(
|
||||
* normalized head, we can more efficiently normalize the combined
|
||||
* path by passing over only the unnormalized tail portion. When
|
||||
* this is sufficient, prior developers claim this should be much
|
||||
* faster. We use 'cwdLen-1' so that we are already pointing at
|
||||
* faster. We use 'cwdLen' so that we are already pointing at
|
||||
* the dir-separator that we know about. The normalization code
|
||||
* will actually start off directly after that separator.
|
||||
*/
|
||||
|
||||
TclFSNormalizeToUniquePath(interp, copy, cwdLen-1);
|
||||
TclFSNormalizeToUniquePath(interp, copy, cwdLen);
|
||||
}
|
||||
|
||||
/* Now we need to construct the new path object. */
|
||||
|
||||
+7
-1
@@ -668,7 +668,13 @@ TclCreatePipeline(
|
||||
if (*p == '>') {
|
||||
p++;
|
||||
atOK = 0;
|
||||
flags = O_WRONLY | O_CREAT;
|
||||
|
||||
/*
|
||||
* Note that the O_APPEND flag only has an effect on POSIX
|
||||
* platforms. On Windows, we just have to carry on regardless.
|
||||
*/
|
||||
|
||||
flags = O_WRONLY | O_CREAT | O_APPEND;
|
||||
}
|
||||
if (errorClose != 0) {
|
||||
errorClose = 0;
|
||||
|
||||
+444
-297
@@ -49,6 +49,18 @@ typedef struct Package {
|
||||
const void *clientData; /* Client data. */
|
||||
} Package;
|
||||
|
||||
typedef struct Require {
|
||||
void * clientDataPtr;
|
||||
const char *name;
|
||||
Package *pkgPtr;
|
||||
char *versionToProvide;
|
||||
} Require;
|
||||
|
||||
typedef struct RequireProcArgs {
|
||||
const char *name;
|
||||
void *clientDataPtr;
|
||||
} RequireProcArgs;
|
||||
|
||||
/*
|
||||
* Prototypes for functions defined in this file:
|
||||
*/
|
||||
@@ -69,9 +81,15 @@ static void AddRequirementsToResult(Tcl_Interp *interp, int reqc,
|
||||
static void AddRequirementsToDString(Tcl_DString *dstring,
|
||||
int reqc, Tcl_Obj *const reqv[]);
|
||||
static Package * FindPackage(Tcl_Interp *interp, const char *name);
|
||||
static const char * PkgRequireCore(Tcl_Interp *interp, const char *name,
|
||||
int reqc, Tcl_Obj *const reqv[],
|
||||
void *clientDataPtr);
|
||||
static int PkgRequireCore(ClientData data[], Tcl_Interp *interp, int result);
|
||||
static int PkgRequireCoreFinal(ClientData data[], Tcl_Interp *interp, int result);
|
||||
static int PkgRequireCoreCleanup(ClientData data[], Tcl_Interp *interp, int result);
|
||||
static int PkgRequireCoreStep1(ClientData data[], Tcl_Interp *interp, int result);
|
||||
static int PkgRequireCoreStep2(ClientData data[], Tcl_Interp *interp, int result);
|
||||
static int TclNRPkgRequireProc(ClientData clientData, Tcl_Interp *interp, int reqc, Tcl_Obj *const reqv[]);
|
||||
static int SelectPackage(ClientData data[], Tcl_Interp *interp, int result);
|
||||
static int SelectPackageFinal(ClientData data[], Tcl_Interp *interp, int result);
|
||||
static int TclNRPackageObjCmdCleanup(ClientData data[], Tcl_Interp *interp, int result);
|
||||
|
||||
/*
|
||||
* Helper macros.
|
||||
@@ -299,7 +317,10 @@ Tcl_PkgRequireEx(
|
||||
*/
|
||||
|
||||
if (version == NULL) {
|
||||
result = PkgRequireCore(interp, name, 0, NULL, clientDataPtr);
|
||||
if (Tcl_PkgRequireProc(interp, name, 0, NULL, clientDataPtr) == TCL_OK) {
|
||||
result = Tcl_GetStringResult(interp);
|
||||
Tcl_ResetResult(interp);
|
||||
}
|
||||
} else {
|
||||
if (exact && TCL_OK
|
||||
!= CheckVersionAndConvert(interp, version, NULL, NULL)) {
|
||||
@@ -310,10 +331,12 @@ Tcl_PkgRequireEx(
|
||||
Tcl_AppendStringsToObj(ov, "-", version, NULL);
|
||||
}
|
||||
Tcl_IncrRefCount(ov);
|
||||
result = PkgRequireCore(interp, name, 1, &ov, clientDataPtr);
|
||||
if (Tcl_PkgRequireProc(interp, name, 1, &ov, clientDataPtr) == TCL_OK) {
|
||||
result = Tcl_GetStringResult(interp);
|
||||
Tcl_ResetResult(interp);
|
||||
}
|
||||
TclDecrRefCount(ov);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -328,306 +351,130 @@ Tcl_PkgRequireProc(
|
||||
* available. */
|
||||
void *clientDataPtr)
|
||||
{
|
||||
const char *result =
|
||||
PkgRequireCore(interp, name, reqc, reqv, clientDataPtr);
|
||||
RequireProcArgs args;
|
||||
args.name = name;
|
||||
args.clientDataPtr = clientDataPtr;
|
||||
return Tcl_NRCallObjProc(interp, TclNRPkgRequireProc, (void *)&args, reqc, reqv);
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(result, -1));
|
||||
static int
|
||||
TclNRPkgRequireProc(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
int reqc,
|
||||
Tcl_Obj *const reqv[]) {
|
||||
RequireProcArgs *args = clientData;
|
||||
Tcl_NRAddCallback(interp, PkgRequireCore, (void *)args->name, INT2PTR(reqc), (void *)reqv, args->clientDataPtr);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static const char *
|
||||
PkgRequireCore(
|
||||
Tcl_Interp *interp, /* Interpreter in which package is now
|
||||
* available. */
|
||||
const char *name, /* Name of desired package. */
|
||||
int reqc, /* Requirements constraining the desired
|
||||
* version. */
|
||||
Tcl_Obj *const reqv[], /* 0 means to use the latest version
|
||||
* available. */
|
||||
void *clientDataPtr)
|
||||
static int
|
||||
PkgRequireCore(ClientData data[], Tcl_Interp *interp, int result)
|
||||
{
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
Package *pkgPtr;
|
||||
PkgAvail *availPtr, *bestPtr, *bestStablePtr;
|
||||
char *availVersion, *bestVersion;
|
||||
/* Internal rep. of versions */
|
||||
int availStable, code, satisfies, pass;
|
||||
char *script, *pkgVersionI;
|
||||
const char *name = data[0];
|
||||
int reqc = PTR2INT(data[1]);
|
||||
Tcl_Obj *const *reqv = data[2];
|
||||
int code = CheckAllRequirements(interp, reqc, reqv);
|
||||
Require *reqPtr;
|
||||
if (code != TCL_OK) {
|
||||
return code;
|
||||
}
|
||||
reqPtr = ckalloc(sizeof(Require));
|
||||
Tcl_NRAddCallback(interp, PkgRequireCoreCleanup, reqPtr, NULL, NULL, NULL);
|
||||
reqPtr->clientDataPtr = data[3];
|
||||
reqPtr->name = name;
|
||||
reqPtr->pkgPtr = FindPackage(interp, name);
|
||||
if (reqPtr->pkgPtr->version == NULL) {
|
||||
Tcl_NRAddCallback(interp, SelectPackage, reqPtr, INT2PTR(reqc), (void *)reqv, PkgRequireCoreStep1);
|
||||
} else {
|
||||
Tcl_NRAddCallback(interp, PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
PkgRequireCoreStep1(ClientData data[], Tcl_Interp *interp, int result) {
|
||||
Tcl_DString command;
|
||||
char *script;
|
||||
Require *reqPtr = data[0];
|
||||
int reqc = PTR2INT(data[1]);
|
||||
Tcl_Obj **const reqv = data[2];
|
||||
const char *name = reqPtr->name /* Name of desired package. */;
|
||||
if (reqPtr->pkgPtr->version == NULL) {
|
||||
/*
|
||||
* The package is not in the database. If there is a "package unknown"
|
||||
* command, invoke it.
|
||||
*/
|
||||
|
||||
if (TCL_OK != CheckAllRequirements(interp, reqc, reqv)) {
|
||||
return NULL;
|
||||
script = ((Interp *) interp)->packageUnknown;
|
||||
if (script == NULL) {
|
||||
Tcl_NRAddCallback(interp, PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
|
||||
} else {
|
||||
Tcl_DStringInit(&command);
|
||||
Tcl_DStringAppend(&command, script, -1);
|
||||
Tcl_DStringAppendElement(&command, name);
|
||||
AddRequirementsToDString(&command, reqc, reqv);
|
||||
|
||||
Tcl_NRAddCallback(interp, PkgRequireCoreStep2, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
|
||||
Tcl_NREvalObj(interp,
|
||||
Tcl_NewStringObj(Tcl_DStringValue(&command), Tcl_DStringLength(&command)),
|
||||
TCL_EVAL_GLOBAL
|
||||
);
|
||||
Tcl_DStringFree(&command);
|
||||
}
|
||||
return TCL_OK;
|
||||
} else {
|
||||
Tcl_NRAddCallback(interp, PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* It can take up to three passes to find the package: one pass to run the
|
||||
* "package unknown" script, one to run the "package ifneeded" script for
|
||||
* a specific version, and a final pass to lookup the package loaded by
|
||||
* the "package ifneeded" script.
|
||||
*/
|
||||
|
||||
for (pass=1 ;; pass++) {
|
||||
pkgPtr = FindPackage(interp, name);
|
||||
if (pkgPtr->version != NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether we're already attempting to load some version of this
|
||||
* package (circular dependency detection).
|
||||
*/
|
||||
|
||||
if (pkgPtr->clientData != NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"circular package dependency:"
|
||||
" attempt to provide %s %s requires %s",
|
||||
name, (char *) pkgPtr->clientData, name));
|
||||
AddRequirementsToResult(interp, reqc, reqv);
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "CIRCULARITY", NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The package isn't yet present. Search the list of available
|
||||
* versions and invoke the script for the best available version. We
|
||||
* are actually locating the best, and the best stable version. One of
|
||||
* them is then chosen based on the selection mode.
|
||||
*/
|
||||
|
||||
bestPtr = NULL;
|
||||
bestStablePtr = NULL;
|
||||
bestVersion = NULL;
|
||||
|
||||
for (availPtr = pkgPtr->availPtr; availPtr != NULL;
|
||||
availPtr = availPtr->nextPtr) {
|
||||
if (CheckVersionAndConvert(interp, availPtr->version,
|
||||
&availVersion, &availStable) != TCL_OK) {
|
||||
/*
|
||||
* The provided version number has invalid syntax. This
|
||||
* should not happen. This should have been caught by the
|
||||
* 'package ifneeded' registering the package.
|
||||
*/
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bestPtr != NULL) {
|
||||
int res = CompareVersions(availVersion, bestVersion, NULL);
|
||||
|
||||
/*
|
||||
* Note: Use internal reps!
|
||||
*/
|
||||
|
||||
if (res <= 0) {
|
||||
/*
|
||||
* The version of the package sought is not as good as the
|
||||
* currently selected version. Ignore it.
|
||||
*/
|
||||
|
||||
ckfree(availVersion);
|
||||
availVersion = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We have found a version which is better than our max.
|
||||
*/
|
||||
|
||||
if (reqc > 0) {
|
||||
/* Check satisfaction of requirements. */
|
||||
|
||||
satisfies = SomeRequirementSatisfied(availVersion, reqc, reqv);
|
||||
if (!satisfies) {
|
||||
ckfree(availVersion);
|
||||
availVersion = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bestPtr = availPtr;
|
||||
|
||||
if (bestVersion != NULL) {
|
||||
ckfree(bestVersion);
|
||||
}
|
||||
bestVersion = availVersion;
|
||||
|
||||
/*
|
||||
* If this new best version is stable then it also has to be
|
||||
* better than the max stable version found so far.
|
||||
*/
|
||||
|
||||
if (availStable) {
|
||||
bestStablePtr = availPtr;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestVersion != NULL) {
|
||||
ckfree(bestVersion);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now choose a version among the two best. For 'latest' we simply
|
||||
* take (actually keep) the best. For 'stable' we take the best
|
||||
* stable, if there is any, or the best if there is nothing stable.
|
||||
*/
|
||||
|
||||
if ((iPtr->packagePrefer == PKG_PREFER_STABLE)
|
||||
&& (bestStablePtr != NULL)) {
|
||||
bestPtr = bestStablePtr;
|
||||
}
|
||||
|
||||
if (bestPtr != NULL) {
|
||||
/*
|
||||
* We found an ifneeded script for the package. Be careful while
|
||||
* executing it: this could cause reentrancy, so (a) protect the
|
||||
* script itself from deletion and (b) don't assume that bestPtr
|
||||
* will still exist when the script completes.
|
||||
*/
|
||||
|
||||
char *versionToProvide = bestPtr->version;
|
||||
script = bestPtr->script;
|
||||
|
||||
pkgPtr->clientData = versionToProvide;
|
||||
Tcl_Preserve(script);
|
||||
Tcl_Preserve(versionToProvide);
|
||||
code = Tcl_EvalEx(interp, script, -1, TCL_EVAL_GLOBAL);
|
||||
Tcl_Release(script);
|
||||
|
||||
pkgPtr = FindPackage(interp, name);
|
||||
if (code == TCL_OK) {
|
||||
Tcl_ResetResult(interp);
|
||||
if (pkgPtr->version == NULL) {
|
||||
code = TCL_ERROR;
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"attempt to provide package %s %s failed:"
|
||||
" no version of package %s provided",
|
||||
name, versionToProvide, name));
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "UNPROVIDED",
|
||||
NULL);
|
||||
} else {
|
||||
char *pvi, *vi;
|
||||
|
||||
if (CheckVersionAndConvert(interp, pkgPtr->version, &pvi,
|
||||
NULL) != TCL_OK) {
|
||||
code = TCL_ERROR;
|
||||
} else if (CheckVersionAndConvert(interp,
|
||||
versionToProvide, &vi, NULL) != TCL_OK) {
|
||||
ckfree(pvi);
|
||||
code = TCL_ERROR;
|
||||
} else {
|
||||
int res = CompareVersions(pvi, vi, NULL);
|
||||
|
||||
ckfree(pvi);
|
||||
ckfree(vi);
|
||||
if (res != 0) {
|
||||
code = TCL_ERROR;
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"attempt to provide package %s %s failed:"
|
||||
" package %s %s provided instead",
|
||||
name, versionToProvide,
|
||||
name, pkgPtr->version));
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE",
|
||||
"WRONGPROVIDE", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (code != TCL_ERROR) {
|
||||
Tcl_Obj *codePtr = Tcl_NewIntObj(code);
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"attempt to provide package %s %s failed:"
|
||||
" bad return code: %s",
|
||||
name, versionToProvide, TclGetString(codePtr)));
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "BADRESULT", NULL);
|
||||
TclDecrRefCount(codePtr);
|
||||
code = TCL_ERROR;
|
||||
}
|
||||
|
||||
if (code == TCL_ERROR) {
|
||||
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
|
||||
"\n (\"package ifneeded %s %s\" script)",
|
||||
name, versionToProvide));
|
||||
}
|
||||
Tcl_Release(versionToProvide);
|
||||
|
||||
if (code != TCL_OK) {
|
||||
/*
|
||||
* Take a non-TCL_OK code from the script as an indication the
|
||||
* package wasn't loaded properly, so the package system
|
||||
* should not remember an improper load.
|
||||
*
|
||||
* This is consistent with our returning NULL. If we're not
|
||||
* willing to tell our caller we got a particular version, we
|
||||
* shouldn't store that version for telling future callers
|
||||
* either.
|
||||
*/
|
||||
|
||||
if (pkgPtr->version != NULL) {
|
||||
ckfree(pkgPtr->version);
|
||||
pkgPtr->version = NULL;
|
||||
}
|
||||
pkgPtr->clientData = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* The package is not in the database. If there is a "package unknown"
|
||||
* command, invoke it (but only on the first pass; after that, we
|
||||
* should not get here in the first place).
|
||||
*/
|
||||
|
||||
if (pass > 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
script = ((Interp *) interp)->packageUnknown;
|
||||
if (script != NULL) {
|
||||
Tcl_DStringInit(&command);
|
||||
Tcl_DStringAppend(&command, script, -1);
|
||||
Tcl_DStringAppendElement(&command, name);
|
||||
AddRequirementsToDString(&command, reqc, reqv);
|
||||
|
||||
code = Tcl_EvalEx(interp, Tcl_DStringValue(&command),
|
||||
Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
|
||||
Tcl_DStringFree(&command);
|
||||
|
||||
if ((code != TCL_OK) && (code != TCL_ERROR)) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"bad return code: %d", code));
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "BADRESULT", NULL);
|
||||
code = TCL_ERROR;
|
||||
}
|
||||
if (code == TCL_ERROR) {
|
||||
Tcl_AddErrorInfo(interp,
|
||||
"\n (\"package unknown\" script)");
|
||||
return NULL;
|
||||
}
|
||||
Tcl_ResetResult(interp);
|
||||
}
|
||||
static int
|
||||
PkgRequireCoreStep2(ClientData data[], Tcl_Interp *interp, int result) {
|
||||
Require *reqPtr = data[0];
|
||||
int reqc = PTR2INT(data[1]);
|
||||
Tcl_Obj **const reqv = data[2];
|
||||
const char *name = reqPtr->name /* Name of desired package. */;
|
||||
if ((result != TCL_OK) && (result != TCL_ERROR)) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"bad return code: %d", result));
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "BADRESULT", NULL);
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
if (result == TCL_ERROR) {
|
||||
Tcl_AddErrorInfo(interp,
|
||||
"\n (\"package unknown\" script)");
|
||||
return result;
|
||||
}
|
||||
Tcl_ResetResult(interp);
|
||||
/* pkgPtr may now be invalid, so refresh it. */
|
||||
reqPtr->pkgPtr = FindPackage(interp, name);
|
||||
Tcl_NRAddCallback(interp, SelectPackage, reqPtr, INT2PTR(reqc), (void *)reqv, PkgRequireCoreFinal);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
if (pkgPtr->version == NULL) {
|
||||
static int
|
||||
PkgRequireCoreFinal(ClientData data[], Tcl_Interp *interp, int result) {
|
||||
Require *reqPtr = data[0];
|
||||
int reqc = PTR2INT(data[1]), satisfies;
|
||||
Tcl_Obj **const reqv = data[2];
|
||||
char *pkgVersionI;
|
||||
void *clientDataPtr = reqPtr->clientDataPtr;
|
||||
const char *name = reqPtr->name /* Name of desired package. */;
|
||||
if (reqPtr->pkgPtr->version == NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"can't find package %s", name));
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "UNFOUND", NULL);
|
||||
AddRequirementsToResult(interp, reqc, reqv);
|
||||
return NULL;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point we know that the package is present. Make sure that the
|
||||
* provided version meets the current requirements.
|
||||
* Ensure that the provided version meets the current requirements.
|
||||
*/
|
||||
|
||||
if (reqc != 0) {
|
||||
CheckVersionAndConvert(interp, pkgPtr->version, &pkgVersionI, NULL);
|
||||
CheckVersionAndConvert(interp, reqPtr->pkgPtr->version, &pkgVersionI, NULL);
|
||||
satisfies = SomeRequirementSatisfied(pkgVersionI, reqc, reqv);
|
||||
|
||||
ckfree(pkgVersionI);
|
||||
@@ -635,20 +482,283 @@ PkgRequireCore(
|
||||
if (!satisfies) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"version conflict for package \"%s\": have %s, need",
|
||||
name, pkgPtr->version));
|
||||
name, reqPtr->pkgPtr->version));
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "VERSIONCONFLICT",
|
||||
NULL);
|
||||
AddRequirementsToResult(interp, reqc, reqv);
|
||||
return NULL;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (clientDataPtr) {
|
||||
const void **ptr = (const void **) clientDataPtr;
|
||||
|
||||
*ptr = pkgPtr->clientData;
|
||||
*ptr = reqPtr->pkgPtr->clientData;
|
||||
}
|
||||
return pkgPtr->version;
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(reqPtr->pkgPtr->version, -1));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
PkgRequireCoreCleanup(ClientData data[], Tcl_Interp *interp, int result) {
|
||||
ckfree(data[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
|
||||
PkgAvail *availPtr, *bestPtr, *bestStablePtr;
|
||||
char *availVersion, *bestVersion, *bestStableVersion;
|
||||
/* Internal rep. of versions */
|
||||
int availStable, satisfies;
|
||||
Require *reqPtr = data[0];
|
||||
int reqc = PTR2INT(data[1]);
|
||||
Tcl_Obj **const reqv = data[2];
|
||||
const char *name = reqPtr->name;
|
||||
Package *pkgPtr = reqPtr->pkgPtr;
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
|
||||
/*
|
||||
* Check whether we're already attempting to load some version of this
|
||||
* package (circular dependency detection).
|
||||
*/
|
||||
|
||||
if (pkgPtr->clientData != NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"circular package dependency:"
|
||||
" attempt to provide %s %s requires %s",
|
||||
name, (char *) pkgPtr->clientData, name));
|
||||
AddRequirementsToResult(interp, reqc, reqv);
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "CIRCULARITY", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* The package isn't yet present. Search the list of available
|
||||
* versions and invoke the script for the best available version. We
|
||||
* are actually locating the best, and the best stable version. One of
|
||||
* them is then chosen based on the selection mode.
|
||||
*/
|
||||
|
||||
bestPtr = NULL;
|
||||
bestStablePtr = NULL;
|
||||
bestVersion = NULL;
|
||||
bestStableVersion = NULL;
|
||||
|
||||
for (availPtr = pkgPtr->availPtr; availPtr != NULL;
|
||||
availPtr = availPtr->nextPtr) {
|
||||
if (CheckVersionAndConvert(interp, availPtr->version,
|
||||
&availVersion, &availStable) != TCL_OK) {
|
||||
/*
|
||||
* The provided version number has invalid syntax. This
|
||||
* should not happen. This should have been caught by the
|
||||
* 'package ifneeded' registering the package.
|
||||
*/
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check satisfaction of requirements before considering the current version further. */
|
||||
if (reqc > 0) {
|
||||
satisfies = SomeRequirementSatisfied(availVersion, reqc, reqv);
|
||||
if (!satisfies) {
|
||||
ckfree(availVersion);
|
||||
availVersion = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestPtr != NULL) {
|
||||
int res = CompareVersions(availVersion, bestVersion, NULL);
|
||||
|
||||
/*
|
||||
* Note: Used internal reps in the comparison!
|
||||
*/
|
||||
|
||||
if (res > 0) {
|
||||
/*
|
||||
* The version of the package sought is better than the
|
||||
* currently selected version.
|
||||
*/
|
||||
ckfree(bestVersion);
|
||||
bestVersion = NULL;
|
||||
goto newbest;
|
||||
}
|
||||
} else {
|
||||
newbest:
|
||||
/* We have found a version which is better than our max. */
|
||||
|
||||
bestPtr = availPtr;
|
||||
CheckVersionAndConvert(interp, bestPtr->version, &bestVersion, NULL);
|
||||
}
|
||||
|
||||
if (!availStable) {
|
||||
ckfree(availVersion);
|
||||
availVersion = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bestStablePtr != NULL) {
|
||||
int res = CompareVersions(availVersion, bestStableVersion, NULL);
|
||||
|
||||
/*
|
||||
* Note: Used internal reps in the comparison!
|
||||
*/
|
||||
|
||||
if (res > 0) {
|
||||
/*
|
||||
* This stable version of the package sought is better
|
||||
* than the currently selected stable version.
|
||||
*/
|
||||
ckfree(bestStableVersion);
|
||||
bestStableVersion = NULL;
|
||||
goto newstable;
|
||||
}
|
||||
} else {
|
||||
newstable:
|
||||
/* We have found a stable version which is better than our max stable. */
|
||||
bestStablePtr = availPtr;
|
||||
CheckVersionAndConvert(interp, bestStablePtr->version, &bestStableVersion, NULL);
|
||||
}
|
||||
|
||||
ckfree(availVersion);
|
||||
availVersion = NULL;
|
||||
} /* end for */
|
||||
|
||||
/*
|
||||
* Clean up memorized internal reps, if any.
|
||||
*/
|
||||
|
||||
if (bestVersion != NULL) {
|
||||
ckfree(bestVersion);
|
||||
bestVersion = NULL;
|
||||
}
|
||||
|
||||
if (bestStableVersion != NULL) {
|
||||
ckfree(bestStableVersion);
|
||||
bestStableVersion = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now choose a version among the two best. For 'latest' we simply
|
||||
* take (actually keep) the best. For 'stable' we take the best
|
||||
* stable, if there is any, or the best if there is nothing stable.
|
||||
*/
|
||||
|
||||
if ((iPtr->packagePrefer == PKG_PREFER_STABLE)
|
||||
&& (bestStablePtr != NULL)) {
|
||||
bestPtr = bestStablePtr;
|
||||
}
|
||||
|
||||
if (bestPtr == NULL) {
|
||||
Tcl_NRAddCallback(interp, data[3], reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
|
||||
} else {
|
||||
/*
|
||||
* We found an ifneeded script for the package. Be careful while
|
||||
* executing it: this could cause reentrancy, so (a) protect the
|
||||
* script itself from deletion and (b) don't assume that bestPtr
|
||||
* will still exist when the script completes.
|
||||
*/
|
||||
|
||||
char *versionToProvide = bestPtr->version;
|
||||
|
||||
pkgPtr->clientData = versionToProvide;
|
||||
Tcl_Preserve(versionToProvide);
|
||||
reqPtr->versionToProvide = versionToProvide;
|
||||
Tcl_NRAddCallback(interp, SelectPackageFinal, reqPtr, INT2PTR(reqc), (void *)reqv, data[3]);
|
||||
Tcl_NREvalObj(interp, Tcl_NewStringObj(bestPtr->script, -1), TCL_EVAL_GLOBAL);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
SelectPackageFinal(ClientData data[], Tcl_Interp *interp, int result) {
|
||||
Require *reqPtr = data[0];
|
||||
int reqc = PTR2INT(data[1]);
|
||||
Tcl_Obj **const reqv = data[2];
|
||||
const char *name = reqPtr->name;
|
||||
char *versionToProvide = reqPtr->versionToProvide;
|
||||
|
||||
reqPtr->pkgPtr = FindPackage(interp, name);
|
||||
if (result == TCL_OK) {
|
||||
Tcl_ResetResult(interp);
|
||||
if (reqPtr->pkgPtr->version == NULL) {
|
||||
result = TCL_ERROR;
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"attempt to provide package %s %s failed:"
|
||||
" no version of package %s provided",
|
||||
name, versionToProvide, name));
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "UNPROVIDED",
|
||||
NULL);
|
||||
} else {
|
||||
char *pvi, *vi;
|
||||
|
||||
if (CheckVersionAndConvert(interp, reqPtr->pkgPtr->version, &pvi,
|
||||
NULL) != TCL_OK) {
|
||||
result = TCL_ERROR;
|
||||
} else if (CheckVersionAndConvert(interp,
|
||||
versionToProvide, &vi, NULL) != TCL_OK) {
|
||||
ckfree(pvi);
|
||||
result = TCL_ERROR;
|
||||
} else {
|
||||
int res = CompareVersions(pvi, vi, NULL);
|
||||
|
||||
ckfree(pvi);
|
||||
ckfree(vi);
|
||||
if (res != 0) {
|
||||
result = TCL_ERROR;
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"attempt to provide package %s %s failed:"
|
||||
" package %s %s provided instead",
|
||||
name, versionToProvide,
|
||||
name, reqPtr->pkgPtr->version));
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE",
|
||||
"WRONGPROVIDE", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (result != TCL_ERROR) {
|
||||
Tcl_Obj *codePtr = Tcl_NewIntObj(result);
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"attempt to provide package %s %s failed:"
|
||||
" bad return code: %s",
|
||||
name, versionToProvide, TclGetString(codePtr)));
|
||||
Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "BADRESULT", NULL);
|
||||
TclDecrRefCount(codePtr);
|
||||
result = TCL_ERROR;
|
||||
}
|
||||
|
||||
if (result == TCL_ERROR) {
|
||||
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
|
||||
"\n (\"package ifneeded %s %s\" script)",
|
||||
name, versionToProvide));
|
||||
}
|
||||
Tcl_Release(versionToProvide);
|
||||
|
||||
if (result != TCL_OK) {
|
||||
/*
|
||||
* Take a non-TCL_OK code from the script as an indication the
|
||||
* package wasn't loaded properly, so the package system
|
||||
* should not remember an improper load.
|
||||
*
|
||||
* This is consistent with our returning NULL. If we're not
|
||||
* willing to tell our caller we got a particular version, we
|
||||
* shouldn't store that version for telling future callers
|
||||
* either.
|
||||
*/
|
||||
|
||||
if (reqPtr->pkgPtr->version != NULL) {
|
||||
ckfree(reqPtr->pkgPtr->version);
|
||||
reqPtr->pkgPtr->version = NULL;
|
||||
}
|
||||
reqPtr->pkgPtr->clientData = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
Tcl_NRAddCallback(interp, data[3], reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -754,10 +864,19 @@ Tcl_PkgPresentEx(
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
Tcl_PackageObjCmd(
|
||||
ClientData dummy, /* Not used. */
|
||||
Tcl_Interp *interp, /* Current interpreter. */
|
||||
int objc, /* Number of arguments. */
|
||||
Tcl_Obj *const objv[]) /* Argument objects. */
|
||||
{
|
||||
return Tcl_NRCallObjProc(interp, TclNRPackageObjCmd, NULL, objc, objv);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
Tcl_PackageObjCmd(
|
||||
TclNRPackageObjCmd(
|
||||
ClientData dummy, /* Not used. */
|
||||
Tcl_Interp *interp, /* Current interpreter. */
|
||||
int objc, /* Number of arguments. */
|
||||
@@ -774,7 +893,7 @@ Tcl_PackageObjCmd(
|
||||
PKG_VSATISFIES
|
||||
};
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
int optionIndex, exact, i, satisfies;
|
||||
int optionIndex, exact, i, newobjc, satisfies;
|
||||
PkgAvail *availPtr, *prevPtr;
|
||||
Package *pkgPtr;
|
||||
Tcl_HashEntry *hPtr;
|
||||
@@ -783,6 +902,7 @@ Tcl_PackageObjCmd(
|
||||
const char *version;
|
||||
const char *argv2, *argv3, *argv4;
|
||||
char *iva = NULL, *ivb = NULL;
|
||||
Tcl_Obj *objvListPtr, **newObjvPtr;
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
|
||||
@@ -989,7 +1109,6 @@ Tcl_PackageObjCmd(
|
||||
argv2 = TclGetString(objv[2]);
|
||||
if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) {
|
||||
Tcl_Obj *ov;
|
||||
int res;
|
||||
|
||||
if (objc != 5) {
|
||||
goto requireSyntax;
|
||||
@@ -1009,17 +1128,38 @@ Tcl_PackageObjCmd(
|
||||
Tcl_AppendStringsToObj(ov, "-", version, NULL);
|
||||
version = NULL;
|
||||
argv3 = TclGetString(objv[3]);
|
||||
Tcl_IncrRefCount(objv[3]);
|
||||
|
||||
Tcl_IncrRefCount(ov);
|
||||
res = Tcl_PkgRequireProc(interp, argv3, 1, &ov, NULL);
|
||||
TclDecrRefCount(ov);
|
||||
return res;
|
||||
objvListPtr = Tcl_NewListObj(0, NULL);
|
||||
Tcl_IncrRefCount(objvListPtr);
|
||||
Tcl_ListObjAppendElement(interp, objvListPtr, ov);
|
||||
Tcl_ListObjGetElements(interp, objvListPtr, &newobjc, &newObjvPtr);
|
||||
|
||||
Tcl_NRAddCallback(interp, TclNRPackageObjCmdCleanup, objv[3], objvListPtr, NULL, NULL);
|
||||
Tcl_NRAddCallback(interp, PkgRequireCore, (void *)argv3, INT2PTR(newobjc), newObjvPtr, NULL);
|
||||
return TCL_OK;
|
||||
} else {
|
||||
int i, newobjc = objc-3;
|
||||
Tcl_Obj *const *newobjv = objv + 3;
|
||||
if (CheckAllRequirements(interp, objc-3, objv+3) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
objvListPtr = Tcl_NewListObj(0, NULL);
|
||||
Tcl_IncrRefCount(objvListPtr);
|
||||
Tcl_IncrRefCount(objv[2]);
|
||||
for (i = 0; i < newobjc; i++) {
|
||||
|
||||
return Tcl_PkgRequireProc(interp, argv2, objc-3, objv+3, NULL);
|
||||
/*
|
||||
* Tcl_Obj structures may have come from another interpreter,
|
||||
* so duplicate them.
|
||||
*/
|
||||
|
||||
Tcl_ListObjAppendElement(interp, objvListPtr, Tcl_DuplicateObj(newobjv[i]));
|
||||
}
|
||||
Tcl_ListObjGetElements(interp, objvListPtr, &newobjc, &newObjvPtr);
|
||||
Tcl_NRAddCallback(interp, TclNRPackageObjCmdCleanup, objv[2], objvListPtr, NULL, NULL);
|
||||
Tcl_NRAddCallback(interp, PkgRequireCore, (void *)argv2, INT2PTR(newobjc), newObjvPtr, NULL);
|
||||
return TCL_OK;
|
||||
}
|
||||
break;
|
||||
case PKG_UNKNOWN: {
|
||||
@@ -1159,6 +1299,13 @@ Tcl_PackageObjCmd(
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
TclNRPackageObjCmdCleanup(ClientData data[], Tcl_Interp *interp, int result) {
|
||||
TclDecrRefCount((Tcl_Obj *)data[0]);
|
||||
TclDecrRefCount((Tcl_Obj *)data[1]);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
|
||||
+71
-105
@@ -124,11 +124,10 @@ Tcl_ProcObjCmd(
|
||||
{
|
||||
register Interp *iPtr = (Interp *) interp;
|
||||
Proc *procPtr;
|
||||
const char *fullName;
|
||||
const char *procName, *procArgs, *procBody;
|
||||
const char *procName;
|
||||
const char *simpleName, *procArgs, *procBody;
|
||||
Namespace *nsPtr, *altNsPtr, *cxtNsPtr;
|
||||
Tcl_Command cmd;
|
||||
Tcl_DString ds;
|
||||
|
||||
if (objc != 4) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "name args body");
|
||||
@@ -141,29 +140,21 @@ Tcl_ProcObjCmd(
|
||||
* namespace.
|
||||
*/
|
||||
|
||||
fullName = TclGetString(objv[1]);
|
||||
TclGetNamespaceForQualName(interp, fullName, NULL, 0,
|
||||
&nsPtr, &altNsPtr, &cxtNsPtr, &procName);
|
||||
procName = TclGetString(objv[1]);
|
||||
TclGetNamespaceForQualName(interp, procName, NULL, 0,
|
||||
&nsPtr, &altNsPtr, &cxtNsPtr, &simpleName);
|
||||
|
||||
if (nsPtr == NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"can't create procedure \"%s\": unknown namespace",
|
||||
fullName));
|
||||
procName));
|
||||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (procName == NULL) {
|
||||
if (simpleName == NULL) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"can't create procedure \"%s\": bad procedure name",
|
||||
fullName));
|
||||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if ((nsPtr != iPtr->globalNsPtr)
|
||||
&& (procName != NULL) && (procName[0] == ':')) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"can't create procedure \"%s\" in non-global namespace with"
|
||||
" name starting with \":\"", procName));
|
||||
procName));
|
||||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -172,31 +163,16 @@ Tcl_ProcObjCmd(
|
||||
* Create the data structure to represent the procedure.
|
||||
*/
|
||||
|
||||
if (TclCreateProc(interp, nsPtr, procName, objv[2], objv[3],
|
||||
if (TclCreateProc(interp, nsPtr, simpleName, objv[2], objv[3],
|
||||
&procPtr) != TCL_OK) {
|
||||
Tcl_AddErrorInfo(interp, "\n (creating proc \"");
|
||||
Tcl_AddErrorInfo(interp, procName);
|
||||
Tcl_AddErrorInfo(interp, simpleName);
|
||||
Tcl_AddErrorInfo(interp, "\")");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now create a command for the procedure. This will initially be in the
|
||||
* current namespace unless the procedure's name included namespace
|
||||
* qualifiers. To create the new command in the right namespace, we
|
||||
* generate a fully qualified name for it.
|
||||
*/
|
||||
|
||||
Tcl_DStringInit(&ds);
|
||||
if (nsPtr != iPtr->globalNsPtr) {
|
||||
Tcl_DStringAppend(&ds, nsPtr->fullName, -1);
|
||||
TclDStringAppendLiteral(&ds, "::");
|
||||
}
|
||||
Tcl_DStringAppend(&ds, procName, -1);
|
||||
|
||||
cmd = Tcl_NRCreateCommand(interp, Tcl_DStringValue(&ds), TclObjInterpProc,
|
||||
TclNRInterpProc, procPtr, TclProcDeleteProc);
|
||||
Tcl_DStringFree(&ds);
|
||||
cmd = TclNRCreateCommandInNs(interp, simpleName, (Tcl_Namespace *) nsPtr,
|
||||
TclObjInterpProc, TclNRInterpProc, procPtr, TclProcDeleteProc);
|
||||
|
||||
/*
|
||||
* Now initialize the new procedure's cmdPtr field. This will be used
|
||||
@@ -393,13 +369,13 @@ TclCreateProc(
|
||||
Proc **procPtrPtr) /* Returns: pointer to proc data. */
|
||||
{
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
const char **argArray = NULL;
|
||||
|
||||
register Proc *procPtr;
|
||||
int i, length, result, numArgs;
|
||||
const char *args, *bytes, *p;
|
||||
int i, result, numArgs, plen;
|
||||
const char *bytes, *argname, *argnamei;
|
||||
char argnamelast;
|
||||
register CompiledLocal *localPtr = NULL;
|
||||
Tcl_Obj *defPtr;
|
||||
Tcl_Obj *defPtr, *errorObj, **argArray;
|
||||
int precompiled = 0;
|
||||
|
||||
if (bodyPtr->typePtr == &tclProcBodyType) {
|
||||
@@ -436,6 +412,7 @@ TclCreateProc(
|
||||
*/
|
||||
|
||||
if (Tcl_IsShared(bodyPtr)) {
|
||||
int length;
|
||||
Tcl_Obj *sharedBodyPtr = bodyPtr;
|
||||
|
||||
bytes = TclGetStringFromObj(bodyPtr, &length);
|
||||
@@ -473,12 +450,9 @@ TclCreateProc(
|
||||
* argument specifier. If the body is precompiled, processing is limited
|
||||
* to checking that the parsed argument is consistent with the one stored
|
||||
* in the Proc.
|
||||
*
|
||||
* THIS FAILS IF THE ARG LIST OBJECT'S STRING REP CONTAINS NULS.
|
||||
*/
|
||||
|
||||
args = TclGetStringFromObj(argsPtr, &length);
|
||||
result = Tcl_SplitList(interp, args, &numArgs, &argArray);
|
||||
result = Tcl_ListObjGetElements(interp , argsPtr ,&numArgs ,&argArray);
|
||||
if (result != TCL_OK) {
|
||||
goto procError;
|
||||
}
|
||||
@@ -501,28 +475,28 @@ TclCreateProc(
|
||||
|
||||
for (i = 0; i < numArgs; i++) {
|
||||
int fieldCount, nameLength, valueLength;
|
||||
const char **fieldValues;
|
||||
Tcl_Obj **fieldValues;
|
||||
|
||||
/*
|
||||
* Now divide the specifier up into name and default.
|
||||
*/
|
||||
|
||||
result = Tcl_SplitList(interp, argArray[i], &fieldCount,
|
||||
result = Tcl_ListObjGetElements(interp, argArray[i], &fieldCount,
|
||||
&fieldValues);
|
||||
if (result != TCL_OK) {
|
||||
goto procError;
|
||||
}
|
||||
if (fieldCount > 2) {
|
||||
ckfree(fieldValues);
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"too many fields in argument specifier \"%s\"",
|
||||
argArray[i]));
|
||||
errorObj = Tcl_NewStringObj(
|
||||
"too many fields in argument specifier \"", -1);
|
||||
Tcl_AppendObjToObj(errorObj, argArray[i]);
|
||||
Tcl_AppendToObj(errorObj, "\"", -1);
|
||||
Tcl_SetObjResult(interp, errorObj);
|
||||
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
|
||||
"FORMALARGUMENTFORMAT", NULL);
|
||||
goto procError;
|
||||
}
|
||||
if ((fieldCount == 0) || (*fieldValues[0] == 0)) {
|
||||
ckfree(fieldValues);
|
||||
if ((fieldCount == 0) || (fieldValues[0]->length == 0)) {
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
"argument with no name", -1));
|
||||
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
|
||||
@@ -530,9 +504,11 @@ TclCreateProc(
|
||||
goto procError;
|
||||
}
|
||||
|
||||
nameLength = strlen(fieldValues[0]);
|
||||
argname = Tcl_GetStringFromObj(fieldValues[0], &plen);
|
||||
nameLength = Tcl_NumUtfChars(argname, plen);
|
||||
if (fieldCount == 2) {
|
||||
valueLength = strlen(fieldValues[1]);
|
||||
const char * value = TclGetString(fieldValues[1]);
|
||||
valueLength = Tcl_NumUtfChars(value, fieldValues[1]->length);
|
||||
} else {
|
||||
valueLength = 0;
|
||||
}
|
||||
@@ -541,33 +517,28 @@ TclCreateProc(
|
||||
* Check that the formal parameter name is a scalar.
|
||||
*/
|
||||
|
||||
p = fieldValues[0];
|
||||
while (*p != '\0') {
|
||||
if (*p == '(') {
|
||||
const char *q = p;
|
||||
do {
|
||||
q++;
|
||||
} while (*q != '\0');
|
||||
q--;
|
||||
if (*q == ')') { /* We have an array element. */
|
||||
argnamei = argname;
|
||||
argnamelast = argname[plen-1];
|
||||
while (plen--) {
|
||||
if (argnamei[0] == '(') {
|
||||
if (argnamelast == ')') { /* We have an array element. */
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"formal parameter \"%s\" is an array element",
|
||||
fieldValues[0]));
|
||||
ckfree(fieldValues);
|
||||
Tcl_GetString(fieldValues[0])));
|
||||
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
|
||||
"FORMALARGUMENTFORMAT", NULL);
|
||||
goto procError;
|
||||
}
|
||||
} else if ((*p == ':') && (*(p+1) == ':')) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"formal parameter \"%s\" is not a simple name",
|
||||
fieldValues[0]));
|
||||
ckfree(fieldValues);
|
||||
} else if ((argnamei[0] == ':') && (argnamei[1] == ':')) {
|
||||
errorObj = Tcl_NewStringObj("formal parameter \"", -1);
|
||||
Tcl_AppendObjToObj(errorObj, fieldValues[0]);
|
||||
Tcl_AppendToObj(errorObj, "\" is not a simple name", -1);
|
||||
Tcl_SetObjResult(interp, errorObj);
|
||||
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
|
||||
"FORMALARGUMENTFORMAT", NULL);
|
||||
goto procError;
|
||||
}
|
||||
p++;
|
||||
argnamei = Tcl_UtfNext(argnamei);
|
||||
}
|
||||
|
||||
if (precompiled) {
|
||||
@@ -583,7 +554,7 @@ TclCreateProc(
|
||||
*/
|
||||
|
||||
if ((localPtr->nameLength != nameLength)
|
||||
|| (strcmp(localPtr->name, fieldValues[0]))
|
||||
|| (Tcl_UtfNcmp(localPtr->name, argname, nameLength))
|
||||
|| (localPtr->frameIndex != i)
|
||||
|| !(localPtr->flags & VAR_ARGUMENT)
|
||||
|| (localPtr->defValuePtr == NULL && fieldCount == 2)
|
||||
@@ -591,7 +562,6 @@ TclCreateProc(
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"procedure \"%s\": formal parameter %d is "
|
||||
"inconsistent with precompiled body", procName, i));
|
||||
ckfree(fieldValues);
|
||||
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
|
||||
"BYTECODELIES", NULL);
|
||||
goto procError;
|
||||
@@ -607,12 +577,13 @@ TclCreateProc(
|
||||
&tmpLength);
|
||||
|
||||
if ((valueLength != tmpLength) ||
|
||||
strncmp(fieldValues[1], tmpPtr, (size_t) tmpLength)) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"procedure \"%s\": formal parameter \"%s\" has "
|
||||
"default value inconsistent with precompiled body",
|
||||
procName, fieldValues[0]));
|
||||
ckfree(fieldValues);
|
||||
Tcl_UtfNcmp(Tcl_GetString(fieldValues[1]), tmpPtr, tmpLength)) {
|
||||
errorObj = Tcl_ObjPrintf(
|
||||
"procedure \"%s\": formal parameter \"" ,procName);
|
||||
Tcl_AppendObjToObj(errorObj, fieldValues[0]);
|
||||
Tcl_AppendToObj(errorObj, "\" has "
|
||||
"default value inconsistent with precompiled body", -1);
|
||||
Tcl_SetObjResult(interp, errorObj);
|
||||
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
|
||||
"BYTECODELIES", NULL);
|
||||
goto procError;
|
||||
@@ -632,7 +603,7 @@ TclCreateProc(
|
||||
* local variables for the argument.
|
||||
*/
|
||||
|
||||
localPtr = ckalloc(TclOffset(CompiledLocal, name) + nameLength+1);
|
||||
localPtr = ckalloc(TclOffset(CompiledLocal, name) + fieldValues[0]->length +1);
|
||||
if (procPtr->firstLocalPtr == NULL) {
|
||||
procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
|
||||
} else {
|
||||
@@ -646,13 +617,12 @@ TclCreateProc(
|
||||
localPtr->resolveInfo = NULL;
|
||||
|
||||
if (fieldCount == 2) {
|
||||
localPtr->defValuePtr =
|
||||
Tcl_NewStringObj(fieldValues[1], valueLength);
|
||||
localPtr->defValuePtr = fieldValues[1];
|
||||
Tcl_IncrRefCount(localPtr->defValuePtr);
|
||||
} else {
|
||||
localPtr->defValuePtr = NULL;
|
||||
}
|
||||
memcpy(localPtr->name, fieldValues[0], nameLength + 1);
|
||||
memcpy(localPtr->name, argname, fieldValues[0]->length + 1);
|
||||
if ((i == numArgs - 1)
|
||||
&& (localPtr->nameLength == 4)
|
||||
&& (localPtr->name[0] == 'a')
|
||||
@@ -660,12 +630,9 @@ TclCreateProc(
|
||||
localPtr->flags |= VAR_IS_ARGS;
|
||||
}
|
||||
}
|
||||
|
||||
ckfree(fieldValues);
|
||||
}
|
||||
|
||||
*procPtrPtr = procPtr;
|
||||
ckfree(argArray);
|
||||
return TCL_OK;
|
||||
|
||||
procError:
|
||||
@@ -686,9 +653,6 @@ TclCreateProc(
|
||||
}
|
||||
ckfree(procPtr);
|
||||
}
|
||||
if (argArray != NULL) {
|
||||
ckfree(argArray);
|
||||
}
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
@@ -1071,7 +1035,6 @@ ProcWrongNumArgs(
|
||||
{
|
||||
CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
|
||||
register Proc *procPtr = framePtr->procPtr;
|
||||
register Var *defPtr;
|
||||
int localCt = procPtr->numCompiledLocals, numArgs, i;
|
||||
Tcl_Obj **desiredObjs;
|
||||
const char *final = NULL;
|
||||
@@ -1095,23 +1058,26 @@ ProcWrongNumArgs(
|
||||
}
|
||||
Tcl_IncrRefCount(desiredObjs[0]);
|
||||
|
||||
defPtr = (Var *) (&framePtr->localCachePtr->varName0 + localCt);
|
||||
for (i=1 ; i<=numArgs ; i++, defPtr++) {
|
||||
Tcl_Obj *argObj;
|
||||
Tcl_Obj *namePtr = localName(framePtr, i-1);
|
||||
if (localCt > 0) {
|
||||
register Var *defPtr = (Var *) (&framePtr->localCachePtr->varName0 + localCt);
|
||||
|
||||
if (defPtr->value.objPtr != NULL) {
|
||||
TclNewObj(argObj);
|
||||
Tcl_AppendStringsToObj(argObj, "?", TclGetString(namePtr), "?", NULL);
|
||||
} else if (defPtr->flags & VAR_IS_ARGS) {
|
||||
numArgs--;
|
||||
final = "?arg ...?";
|
||||
break;
|
||||
} else {
|
||||
argObj = namePtr;
|
||||
Tcl_IncrRefCount(namePtr);
|
||||
for (i=1 ; i<=numArgs ; i++, defPtr++) {
|
||||
Tcl_Obj *argObj;
|
||||
Tcl_Obj *namePtr = localName(framePtr, i-1);
|
||||
|
||||
if (defPtr->value.objPtr != NULL) {
|
||||
TclNewObj(argObj);
|
||||
Tcl_AppendStringsToObj(argObj, "?", TclGetString(namePtr), "?", NULL);
|
||||
} else if (defPtr->flags & VAR_IS_ARGS) {
|
||||
numArgs--;
|
||||
final = "?arg ...?";
|
||||
break;
|
||||
} else {
|
||||
argObj = namePtr;
|
||||
Tcl_IncrRefCount(namePtr);
|
||||
}
|
||||
desiredObjs[i] = argObj;
|
||||
}
|
||||
desiredObjs[i] = argObj;
|
||||
}
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
|
||||
+11
-4
@@ -502,10 +502,17 @@ Tcl_RegExpMatchObj(
|
||||
{
|
||||
Tcl_RegExp re;
|
||||
|
||||
re = Tcl_GetRegExpFromObj(interp, patternObj,
|
||||
TCL_REG_ADVANCED | TCL_REG_NOSUB);
|
||||
if (re == NULL) {
|
||||
return -1;
|
||||
/*
|
||||
* For performance reasons, first try compiling the RE without support for
|
||||
* subexpressions. On failure, try again without TCL_REG_NOSUB in case the
|
||||
* RE has backreferences in it. Closely related to [Bug 1366683]. If this
|
||||
* still fails, an error message will be left in the interpreter.
|
||||
*/
|
||||
|
||||
if (!(re = Tcl_GetRegExpFromObj(interp, patternObj,
|
||||
TCL_REG_ADVANCED | TCL_REG_NOSUB))
|
||||
&& !(re = Tcl_GetRegExpFromObj(interp, patternObj, TCL_REG_ADVANCED))) {
|
||||
return -1;
|
||||
}
|
||||
return Tcl_RegExpExecObj(interp, re, textObj, 0 /* offset */,
|
||||
0 /* nmatches */, 0 /* flags */);
|
||||
|
||||
+13
-5
@@ -72,7 +72,7 @@ BuildCharSet(
|
||||
CharSet *cset,
|
||||
const char *format) /* Points to first char of set. */
|
||||
{
|
||||
Tcl_UniChar ch, start;
|
||||
Tcl_UniChar ch = 0, start;
|
||||
int offset, nranges;
|
||||
const char *end;
|
||||
|
||||
@@ -257,7 +257,7 @@ ValidateFormat(
|
||||
{
|
||||
int gotXpg, gotSequential, value, i, flags;
|
||||
char *end;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
int objIndex, xpgSize, nspace = numVars;
|
||||
int *nassign = TclStackAlloc(interp, nspace * sizeof(int));
|
||||
char buf[TCL_UTF_MAX+1];
|
||||
@@ -582,7 +582,7 @@ Tcl_ScanObjCmd(
|
||||
char op = 0;
|
||||
int width, underflow = 0;
|
||||
Tcl_WideInt wideValue;
|
||||
Tcl_UniChar ch, sch;
|
||||
Tcl_UniChar ch = 0, sch = 0;
|
||||
Tcl_Obj **objs = NULL, *objPtr = NULL;
|
||||
int flags;
|
||||
char buf[513]; /* Temporary buffer to hold scanned number
|
||||
@@ -885,9 +885,17 @@ Tcl_ScanObjCmd(
|
||||
* Scan a single Unicode character.
|
||||
*/
|
||||
|
||||
string += TclUtfToUniChar(string, &sch);
|
||||
offset = TclUtfToUniChar(string, &sch);
|
||||
i = (int)sch;
|
||||
#if TCL_UTF_MAX == 4
|
||||
if (!offset) {
|
||||
offset = Tcl_UtfToUniChar(string, &sch);
|
||||
i = (((i<<10) & 0x0FFC00) + 0x10000) + (sch & 0x3FF);
|
||||
}
|
||||
#endif
|
||||
string += offset;
|
||||
if (!(flags & SCAN_SUPPRESS)) {
|
||||
objPtr = Tcl_NewIntObj((int)sch);
|
||||
objPtr = Tcl_NewIntObj(i);
|
||||
Tcl_IncrRefCount(objPtr);
|
||||
CLANG_ASSERT(objs);
|
||||
objs[objIndex++] = objPtr;
|
||||
|
||||
@@ -1,527 +0,0 @@
|
||||
/*
|
||||
* tclStrIdxTree.c --
|
||||
*
|
||||
* Contains the routines for managing string index tries in Tcl.
|
||||
*
|
||||
* This code is back-ported from the tclSE engine, by Serg G. Brester.
|
||||
*
|
||||
* Copyright (c) 2016 by Sergey G. Brester aka sebres. All rights reserved.
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution of
|
||||
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*
|
||||
* -----------------------------------------------------------------------
|
||||
*
|
||||
* String index tries are prepaired structures used for fast greedy search of the string
|
||||
* (index) by unique string prefix as key.
|
||||
*
|
||||
* Index tree build for two lists together can be explained in the following datagram
|
||||
*
|
||||
* Lists:
|
||||
*
|
||||
* {Januar Februar Maerz April Mai Juni Juli August September Oktober November Dezember}
|
||||
* {Jnr Fbr Mrz Apr Mai Jni Jli Agt Spt Okt Nvb Dzb}
|
||||
*
|
||||
* Index-Tree:
|
||||
*
|
||||
* j 0 * ...
|
||||
* anuar 1 *
|
||||
* u 0 * a 0
|
||||
* ni 6 * pril 4
|
||||
* li 7 * ugust 8
|
||||
* n 0 * gt 8
|
||||
* r 1 * s 9
|
||||
* i 6 * eptember 9
|
||||
* li 7 * pt 9
|
||||
* f 2 * oktober 10
|
||||
* ebruar 2 * n 11
|
||||
* br 2 * ovember 11
|
||||
* m 0 * vb 11
|
||||
* a 0 * d 12
|
||||
* erz 3 * ezember 12
|
||||
* i 5 * zb 12
|
||||
* rz 3 *
|
||||
* ...
|
||||
*
|
||||
* Thereby value 0 shows pure group items (corresponding ambigous matches).
|
||||
* But the group may have a value if it contains only same values
|
||||
* (see for example group "f" above).
|
||||
*
|
||||
* StrIdxTree's are very fast, so:
|
||||
* build of above-mentioned tree takes about 10 microseconds.
|
||||
* search of string index in this tree takes fewer as 0.1 microseconds.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tclInt.h"
|
||||
#include "tclStrIdxTree.h"
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclStrIdxTreeSearch --
|
||||
*
|
||||
* Find largest part of string "start" in indexed tree (case sensitive).
|
||||
*
|
||||
* Also used for building of string index tree.
|
||||
*
|
||||
* Results:
|
||||
* Return position of UTF character in start after last equal character
|
||||
* and found item (with parent).
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MODULE_SCOPE const char*
|
||||
TclStrIdxTreeSearch(
|
||||
TclStrIdxTree **foundParent, /* Return value of found sub tree (used for tree build) */
|
||||
TclStrIdx **foundItem, /* Return value of found item */
|
||||
TclStrIdxTree *tree, /* Index tree will be browsed */
|
||||
const char *start, /* UTF string to find in tree */
|
||||
const char *end) /* End of string */
|
||||
{
|
||||
TclStrIdxTree *parent = tree, *prevParent = tree;
|
||||
TclStrIdx *item = tree->firstPtr, *prevItem = NULL;
|
||||
const char *s = start, *f, *cin, *cinf, *prevf;
|
||||
int offs = 0;
|
||||
|
||||
if (item == NULL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* search in tree */
|
||||
do {
|
||||
cinf = cin = TclGetString(item->key) + offs;
|
||||
f = TclUtfFindEqualNCInLwr(s, end, cin, cin + item->length, &cinf);
|
||||
/* if something was found */
|
||||
if (f > s) {
|
||||
/* if whole string was found */
|
||||
if (f >= end) {
|
||||
start = f;
|
||||
goto done;
|
||||
};
|
||||
/* set new offset and shift start string */
|
||||
offs += cinf - cin;
|
||||
s = f;
|
||||
/* if match item, go deeper as long as possible */
|
||||
if (offs >= item->length && item->childTree.firstPtr) {
|
||||
/* save previuosly found item (if not ambigous) for
|
||||
* possible fallback (few greedy match) */
|
||||
if (item->value != NULL) {
|
||||
prevf = f;
|
||||
prevItem = item;
|
||||
prevParent = parent;
|
||||
}
|
||||
parent = &item->childTree;
|
||||
item = item->childTree.firstPtr;
|
||||
continue;
|
||||
}
|
||||
/* no children - return this item and current chars found */
|
||||
start = f;
|
||||
goto done;
|
||||
}
|
||||
|
||||
item = item->nextPtr;
|
||||
|
||||
} while (item != NULL);
|
||||
|
||||
/* fallback (few greedy match) not ambigous (has a value) */
|
||||
if (prevItem != NULL) {
|
||||
item = prevItem;
|
||||
parent = prevParent;
|
||||
start = prevf;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (foundParent)
|
||||
*foundParent = parent;
|
||||
if (foundItem)
|
||||
*foundItem = item;
|
||||
return start;
|
||||
}
|
||||
|
||||
MODULE_SCOPE void
|
||||
TclStrIdxTreeFree(
|
||||
TclStrIdx *tree)
|
||||
{
|
||||
while (tree != NULL) {
|
||||
TclStrIdx *t;
|
||||
Tcl_DecrRefCount(tree->key);
|
||||
if (tree->childTree.firstPtr != NULL) {
|
||||
TclStrIdxTreeFree(tree->childTree.firstPtr);
|
||||
}
|
||||
t = tree, tree = tree->nextPtr;
|
||||
ckfree(t);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Several bidirectional list primitives
|
||||
*/
|
||||
inline void
|
||||
TclStrIdxTreeInsertBranch(
|
||||
TclStrIdxTree *parent,
|
||||
register TclStrIdx *item,
|
||||
register TclStrIdx *child)
|
||||
{
|
||||
if (parent->firstPtr == child)
|
||||
parent->firstPtr = item;
|
||||
if (parent->lastPtr == child)
|
||||
parent->lastPtr = item;
|
||||
if ( (item->nextPtr = child->nextPtr) ) {
|
||||
item->nextPtr->prevPtr = item;
|
||||
child->nextPtr = NULL;
|
||||
}
|
||||
if ( (item->prevPtr = child->prevPtr) ) {
|
||||
item->prevPtr->nextPtr = item;
|
||||
child->prevPtr = NULL;
|
||||
}
|
||||
item->childTree.firstPtr = child;
|
||||
item->childTree.lastPtr = child;
|
||||
}
|
||||
|
||||
inline void
|
||||
TclStrIdxTreeAppend(
|
||||
register TclStrIdxTree *parent,
|
||||
register TclStrIdx *item)
|
||||
{
|
||||
if (parent->lastPtr != NULL) {
|
||||
parent->lastPtr->nextPtr = item;
|
||||
}
|
||||
item->prevPtr = parent->lastPtr;
|
||||
item->nextPtr = NULL;
|
||||
parent->lastPtr = item;
|
||||
if (parent->firstPtr == NULL) {
|
||||
parent->firstPtr = item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclStrIdxTreeBuildFromList --
|
||||
*
|
||||
* Build or extend string indexed tree from tcl list.
|
||||
* If the values not given the values of built list are indices starts with 1.
|
||||
* Value of 0 is thereby reserved to the ambigous values.
|
||||
*
|
||||
* Important: by multiple lists, optimal tree can be created only if list with
|
||||
* larger strings used firstly.
|
||||
*
|
||||
* Results:
|
||||
* Returns a standard Tcl result.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MODULE_SCOPE int
|
||||
TclStrIdxTreeBuildFromList(
|
||||
TclStrIdxTree *idxTree,
|
||||
int lstc,
|
||||
Tcl_Obj **lstv,
|
||||
ClientData *values)
|
||||
{
|
||||
Tcl_Obj **lwrv;
|
||||
int i, ret = TCL_ERROR;
|
||||
ClientData val;
|
||||
const char *s, *e, *f;
|
||||
TclStrIdx *item;
|
||||
|
||||
/* create lowercase reflection of the list keys */
|
||||
|
||||
lwrv = ckalloc(sizeof(Tcl_Obj*) * lstc);
|
||||
if (lwrv == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
for (i = 0; i < lstc; i++) {
|
||||
lwrv[i] = Tcl_DuplicateObj(lstv[i]);
|
||||
if (lwrv[i] == NULL) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_IncrRefCount(lwrv[i]);
|
||||
lwrv[i]->length = Tcl_UtfToLower(TclGetString(lwrv[i]));
|
||||
}
|
||||
|
||||
/* build index tree of the list keys */
|
||||
for (i = 0; i < lstc; i++) {
|
||||
TclStrIdxTree *foundParent = idxTree;
|
||||
e = s = TclGetString(lwrv[i]);
|
||||
e += lwrv[i]->length;
|
||||
val = values ? values[i] : INT2PTR(i+1);
|
||||
|
||||
/* ignore empty keys (impossible to index it) */
|
||||
if (lwrv[i]->length == 0) continue;
|
||||
|
||||
item = NULL;
|
||||
if (idxTree->firstPtr != NULL) {
|
||||
TclStrIdx *foundItem;
|
||||
f = TclStrIdxTreeSearch(&foundParent, &foundItem,
|
||||
idxTree, s, e);
|
||||
/* if common prefix was found */
|
||||
if (f > s) {
|
||||
/* ignore element if fulfilled or ambigous */
|
||||
if (f == e) {
|
||||
continue;
|
||||
}
|
||||
/* if shortest key was found with the same value,
|
||||
* just replace its current key with longest key */
|
||||
if ( foundItem->value == val
|
||||
&& foundItem->length < lwrv[i]->length
|
||||
&& foundItem->childTree.firstPtr == NULL
|
||||
) {
|
||||
Tcl_SetObjRef(foundItem->key, lwrv[i]);
|
||||
foundItem->length = lwrv[i]->length;
|
||||
continue;
|
||||
}
|
||||
/* split tree (e. g. j->(jan,jun) + jul == j->(jan,ju->(jun,jul)) )
|
||||
* but don't split by fulfilled child of found item ( ii->iii->iiii ) */
|
||||
if (foundItem->length != (f - s)) {
|
||||
/* first split found item (insert one between parent and found + new one) */
|
||||
item = ckalloc(sizeof(*item));
|
||||
if (item == NULL) {
|
||||
goto done;
|
||||
}
|
||||
Tcl_InitObjRef(item->key, foundItem->key);
|
||||
item->length = f - s;
|
||||
/* set value or mark as ambigous if not the same value of both */
|
||||
item->value = (foundItem->value == val) ? val : NULL;
|
||||
/* insert group item between foundParent and foundItem */
|
||||
TclStrIdxTreeInsertBranch(foundParent, item, foundItem);
|
||||
foundParent = &item->childTree;
|
||||
} else {
|
||||
/* the new item should be added as child of found item */
|
||||
foundParent = &foundItem->childTree;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* append item at end of found parent */
|
||||
item = ckalloc(sizeof(*item));
|
||||
if (item == NULL) {
|
||||
goto done;
|
||||
}
|
||||
item->childTree.lastPtr = item->childTree.firstPtr = NULL;
|
||||
Tcl_InitObjRef(item->key, lwrv[i]);
|
||||
item->length = lwrv[i]->length;
|
||||
item->value = val;
|
||||
TclStrIdxTreeAppend(foundParent, item);
|
||||
};
|
||||
|
||||
ret = TCL_OK;
|
||||
|
||||
done:
|
||||
|
||||
if (lwrv != NULL) {
|
||||
for (i = 0; i < lstc; i++) {
|
||||
Tcl_DecrRefCount(lwrv[i]);
|
||||
}
|
||||
ckfree(lwrv);
|
||||
}
|
||||
|
||||
if (ret != TCL_OK) {
|
||||
if (idxTree->firstPtr != NULL) {
|
||||
TclStrIdxTreeFree(idxTree->firstPtr);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
StrIdxTreeObj_DupIntRepProc(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
|
||||
static void
|
||||
StrIdxTreeObj_FreeIntRepProc(Tcl_Obj *objPtr);
|
||||
static void
|
||||
StrIdxTreeObj_UpdateStringProc(Tcl_Obj *objPtr);
|
||||
|
||||
Tcl_ObjType StrIdxTreeObjType = {
|
||||
"str-idx-tree", /* name */
|
||||
StrIdxTreeObj_FreeIntRepProc, /* freeIntRepProc */
|
||||
StrIdxTreeObj_DupIntRepProc, /* dupIntRepProc */
|
||||
StrIdxTreeObj_UpdateStringProc, /* updateStringProc */
|
||||
NULL /* setFromAnyProc */
|
||||
};
|
||||
|
||||
MODULE_SCOPE Tcl_Obj*
|
||||
TclStrIdxTreeNewObj()
|
||||
{
|
||||
Tcl_Obj *objPtr = Tcl_NewObj();
|
||||
objPtr->internalRep.twoPtrValue.ptr1 = NULL;
|
||||
objPtr->internalRep.twoPtrValue.ptr2 = NULL;
|
||||
objPtr->typePtr = &StrIdxTreeObjType;
|
||||
/* return tree root in internal representation */
|
||||
return objPtr;
|
||||
}
|
||||
|
||||
static void
|
||||
StrIdxTreeObj_DupIntRepProc(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)
|
||||
{
|
||||
/* follow links (smart pointers) */
|
||||
if ( srcPtr->internalRep.twoPtrValue.ptr1 != NULL
|
||||
&& srcPtr->internalRep.twoPtrValue.ptr2 == NULL
|
||||
) {
|
||||
srcPtr = (Tcl_Obj*)srcPtr->internalRep.twoPtrValue.ptr1;
|
||||
}
|
||||
/* create smart pointer to it (ptr1 != NULL, ptr2 = NULL) */
|
||||
Tcl_InitObjRef(*((Tcl_Obj **)©Ptr->internalRep.twoPtrValue.ptr1),
|
||||
srcPtr);
|
||||
copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
|
||||
copyPtr->typePtr = &StrIdxTreeObjType;
|
||||
}
|
||||
|
||||
static void
|
||||
StrIdxTreeObj_FreeIntRepProc(Tcl_Obj *objPtr)
|
||||
{
|
||||
/* follow links (smart pointers) */
|
||||
if ( objPtr->internalRep.twoPtrValue.ptr1 != NULL
|
||||
&& objPtr->internalRep.twoPtrValue.ptr2 == NULL
|
||||
) {
|
||||
/* is a link */
|
||||
Tcl_UnsetObjRef(*((Tcl_Obj **)&objPtr->internalRep.twoPtrValue.ptr1));
|
||||
} else {
|
||||
/* is a tree */
|
||||
TclStrIdxTree *tree = (TclStrIdxTree*)&objPtr->internalRep.twoPtrValue.ptr1;
|
||||
if (tree->firstPtr != NULL) {
|
||||
TclStrIdxTreeFree(tree->firstPtr);
|
||||
}
|
||||
objPtr->internalRep.twoPtrValue.ptr1 = NULL;
|
||||
objPtr->internalRep.twoPtrValue.ptr2 = NULL;
|
||||
}
|
||||
objPtr->typePtr = NULL;
|
||||
};
|
||||
|
||||
static void
|
||||
StrIdxTreeObj_UpdateStringProc(Tcl_Obj *objPtr)
|
||||
{
|
||||
/* currently only dummy empty string possible */
|
||||
objPtr->length = 0;
|
||||
objPtr->bytes = &tclEmptyString;
|
||||
};
|
||||
|
||||
MODULE_SCOPE TclStrIdxTree *
|
||||
TclStrIdxTreeGetFromObj(Tcl_Obj *objPtr) {
|
||||
/* follow links (smart pointers) */
|
||||
if (objPtr->typePtr != &StrIdxTreeObjType) {
|
||||
return NULL;
|
||||
}
|
||||
if ( objPtr->internalRep.twoPtrValue.ptr1 != NULL
|
||||
&& objPtr->internalRep.twoPtrValue.ptr2 == NULL
|
||||
) {
|
||||
objPtr = (Tcl_Obj*)objPtr->internalRep.twoPtrValue.ptr1;
|
||||
}
|
||||
/* return tree root in internal representation */
|
||||
return (TclStrIdxTree*)&objPtr->internalRep.twoPtrValue.ptr1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Several debug primitives
|
||||
*/
|
||||
#if 0
|
||||
/* currently unused, debug resp. test purposes only */
|
||||
|
||||
void
|
||||
TclStrIdxTreePrint(
|
||||
Tcl_Interp *interp,
|
||||
TclStrIdx *tree,
|
||||
int offs)
|
||||
{
|
||||
Tcl_Obj *obj[2];
|
||||
const char *s;
|
||||
Tcl_InitObjRef(obj[0], Tcl_NewStringObj("::puts", -1));
|
||||
while (tree != NULL) {
|
||||
s = TclGetString(tree->key) + offs;
|
||||
Tcl_InitObjRef(obj[1], Tcl_ObjPrintf("%*s%.*s\t:%d",
|
||||
offs, "", tree->length - offs, s, tree->value));
|
||||
Tcl_PutsObjCmd(NULL, interp, 2, obj);
|
||||
Tcl_UnsetObjRef(obj[1]);
|
||||
if (tree->childTree.firstPtr != NULL) {
|
||||
TclStrIdxTreePrint(interp, tree->childTree.firstPtr, tree->length);
|
||||
}
|
||||
tree = tree->nextPtr;
|
||||
}
|
||||
Tcl_UnsetObjRef(obj[0]);
|
||||
}
|
||||
|
||||
|
||||
MODULE_SCOPE int
|
||||
TclStrIdxTreeTestObjCmd(
|
||||
ClientData clientData, Tcl_Interp *interp,
|
||||
int objc, Tcl_Obj *const objv[])
|
||||
{
|
||||
const char *cs, *cin, *ret;
|
||||
|
||||
static const char *const options[] = {
|
||||
"index", "puts-index", "findequal",
|
||||
NULL
|
||||
};
|
||||
enum optionInd {
|
||||
O_INDEX, O_PUTS_INDEX, O_FINDEQUAL
|
||||
};
|
||||
int optionIndex;
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (Tcl_GetIndexFromObj(interp, objv[1], options,
|
||||
"option", 0, &optionIndex) != TCL_OK) {
|
||||
Tcl_SetErrorCode(interp, "CLOCK", "badOption",
|
||||
Tcl_GetString(objv[1]), NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
switch (optionIndex) {
|
||||
case O_FINDEQUAL:
|
||||
if (objc < 4) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
cs = TclGetString(objv[2]);
|
||||
cin = TclGetString(objv[3]);
|
||||
ret = TclUtfFindEqual(
|
||||
cs, cs + objv[1]->length, cin, cin + objv[2]->length);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(ret - cs));
|
||||
break;
|
||||
case O_INDEX:
|
||||
case O_PUTS_INDEX:
|
||||
|
||||
if (1) {
|
||||
Tcl_Obj **lstv;
|
||||
int i, lstc;
|
||||
TclStrIdxTree idxTree = {NULL, NULL};
|
||||
i = 1;
|
||||
while (++i < objc) {
|
||||
if (TclListObjGetElements(interp, objv[i],
|
||||
&lstc, &lstv) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
};
|
||||
TclStrIdxTreeBuildFromList(&idxTree, lstc, lstv, NULL);
|
||||
}
|
||||
if (optionIndex == O_PUTS_INDEX) {
|
||||
TclStrIdxTreePrint(interp, idxTree.firstPtr, 0);
|
||||
}
|
||||
TclStrIdxTreeFree(idxTree.firstPtr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: c
|
||||
* c-basic-offset: 4
|
||||
* fill-column: 78
|
||||
* End:
|
||||
*/
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* tclStrIdxTree.h --
|
||||
*
|
||||
* Declarations of string index tries and other primitives currently
|
||||
* back-ported from tclSE.
|
||||
*
|
||||
* Copyright (c) 2016 Serg G. Brester (aka sebres)
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution
|
||||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
*/
|
||||
|
||||
#ifndef _TCLSTRIDXTREE_H
|
||||
#define _TCLSTRIDXTREE_H
|
||||
|
||||
|
||||
/*
|
||||
* Main structures declarations of index tree and entry
|
||||
*/
|
||||
|
||||
typedef struct TclStrIdxTree {
|
||||
struct TclStrIdx *firstPtr;
|
||||
struct TclStrIdx *lastPtr;
|
||||
} TclStrIdxTree;
|
||||
|
||||
typedef struct TclStrIdx {
|
||||
struct TclStrIdxTree childTree;
|
||||
struct TclStrIdx *nextPtr;
|
||||
struct TclStrIdx *prevPtr;
|
||||
Tcl_Obj *key;
|
||||
int length;
|
||||
ClientData value;
|
||||
} TclStrIdx;
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclUtfFindEqual, TclUtfFindEqualNC --
|
||||
*
|
||||
* Find largest part of string cs in string cin (case sensitive and not).
|
||||
*
|
||||
* Results:
|
||||
* Return position of UTF character in cs after last equal character.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static inline const char *
|
||||
TclUtfFindEqual(
|
||||
register const char *cs, /* UTF string to find in cin. */
|
||||
register const char *cse, /* End of cs */
|
||||
register const char *cin, /* UTF string will be browsed. */
|
||||
register const char *cine) /* End of cin */
|
||||
{
|
||||
register const char *ret = cs;
|
||||
Tcl_UniChar ch1, ch2;
|
||||
do {
|
||||
cs += TclUtfToUniChar(cs, &ch1);
|
||||
cin += TclUtfToUniChar(cin, &ch2);
|
||||
if (ch1 != ch2) break;
|
||||
} while ((ret = cs) < cse && cin < cine);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
TclUtfFindEqualNC(
|
||||
register const char *cs, /* UTF string to find in cin. */
|
||||
register const char *cse, /* End of cs */
|
||||
register const char *cin, /* UTF string will be browsed. */
|
||||
register const char *cine, /* End of cin */
|
||||
const char **cinfnd) /* Return position in cin */
|
||||
{
|
||||
register const char *ret = cs;
|
||||
Tcl_UniChar ch1, ch2;
|
||||
do {
|
||||
cs += TclUtfToUniChar(cs, &ch1);
|
||||
cin += TclUtfToUniChar(cin, &ch2);
|
||||
if (ch1 != ch2) {
|
||||
ch1 = Tcl_UniCharToLower(ch1);
|
||||
ch2 = Tcl_UniCharToLower(ch2);
|
||||
if (ch1 != ch2) break;
|
||||
}
|
||||
*cinfnd = cin;
|
||||
} while ((ret = cs) < cse && cin < cine);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
TclUtfFindEqualNCInLwr(
|
||||
register const char *cs, /* UTF string (in anycase) to find in cin. */
|
||||
register const char *cse, /* End of cs */
|
||||
register const char *cin, /* UTF string (in lowercase) will be browsed. */
|
||||
register const char *cine, /* End of cin */
|
||||
const char **cinfnd) /* Return position in cin */
|
||||
{
|
||||
register const char *ret = cs;
|
||||
Tcl_UniChar ch1, ch2;
|
||||
do {
|
||||
cs += TclUtfToUniChar(cs, &ch1);
|
||||
cin += TclUtfToUniChar(cin, &ch2);
|
||||
if (ch1 != ch2) {
|
||||
ch1 = Tcl_UniCharToLower(ch1);
|
||||
if (ch1 != ch2) break;
|
||||
}
|
||||
*cinfnd = cin;
|
||||
} while ((ret = cs) < cse && cin < cine);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
TclUtfNext(
|
||||
register const char *src) /* The current location in the string. */
|
||||
{
|
||||
if (((unsigned char) *(src)) < 0xC0) {
|
||||
return ++src;
|
||||
} else {
|
||||
Tcl_UniChar ch;
|
||||
return src + TclUtfToUniChar(src, &ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Primitives to safe set, reset and free references.
|
||||
*/
|
||||
|
||||
#define Tcl_UnsetObjRef(obj) \
|
||||
if (obj != NULL) { Tcl_DecrRefCount(obj); obj = NULL; }
|
||||
#define Tcl_InitObjRef(obj, val) \
|
||||
obj = val; if (obj) { Tcl_IncrRefCount(obj); }
|
||||
#define Tcl_SetObjRef(obj, val) \
|
||||
if (1) { \
|
||||
Tcl_Obj *nval = val; \
|
||||
if (obj != nval) { \
|
||||
Tcl_Obj *prev = obj; \
|
||||
Tcl_InitObjRef(obj, nval); \
|
||||
if (prev != NULL) { Tcl_DecrRefCount(prev); }; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
* Prototypes of module functions.
|
||||
*/
|
||||
|
||||
MODULE_SCOPE const char*
|
||||
TclStrIdxTreeSearch(TclStrIdxTree **foundParent,
|
||||
TclStrIdx **foundItem, TclStrIdxTree *tree,
|
||||
const char *start, const char *end);
|
||||
|
||||
MODULE_SCOPE int TclStrIdxTreeBuildFromList(TclStrIdxTree *idxTree,
|
||||
int lstc, Tcl_Obj **lstv, ClientData *values);
|
||||
|
||||
MODULE_SCOPE Tcl_Obj*
|
||||
TclStrIdxTreeNewObj();
|
||||
|
||||
MODULE_SCOPE TclStrIdxTree*
|
||||
TclStrIdxTreeGetFromObj(Tcl_Obj *objPtr);
|
||||
|
||||
#if 1
|
||||
|
||||
MODULE_SCOPE int TclStrIdxTreeTestObjCmd(ClientData, Tcl_Interp *,
|
||||
int, Tcl_Obj *const objv[]);
|
||||
#endif
|
||||
|
||||
#endif /* _TCLSTRIDXTREE_H */
|
||||
+27
-27
@@ -1183,9 +1183,9 @@ TclParseNumber(
|
||||
case sNA:
|
||||
case sNANPAREN:
|
||||
case sNANHEX:
|
||||
#endif
|
||||
Tcl_Panic("TclParseNumber: bad acceptState %d parsing '%s'",
|
||||
acceptState, bytes);
|
||||
#endif
|
||||
case BINARY:
|
||||
shift = numTrailZeros;
|
||||
if (!significandOverflow && significandWide != 0 &&
|
||||
@@ -1973,7 +1973,7 @@ RefineApproximation(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static void
|
||||
static inline void
|
||||
MulPow5(
|
||||
mp_int *base, /* Number to multiply. */
|
||||
unsigned n, /* Power of 5 to multiply by. */
|
||||
@@ -2018,7 +2018,7 @@ MulPow5(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static int
|
||||
static inline int
|
||||
NormalizeRightward(
|
||||
Tcl_WideUInt *wPtr) /* INOUT: Number to shift. */
|
||||
{
|
||||
@@ -2109,7 +2109,7 @@ RequiredPrecision(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static void
|
||||
static inline void
|
||||
DoubleToExpAndSig(
|
||||
double dv, /* Number to convert. */
|
||||
Tcl_WideUInt *significand, /* OUTPUT: Significand of the number. */
|
||||
@@ -2157,7 +2157,7 @@ DoubleToExpAndSig(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static void
|
||||
static inline void
|
||||
TakeAbsoluteValue(
|
||||
Double *d, /* Number to replace with absolute value. */
|
||||
int *sign) /* Place to put the signum. */
|
||||
@@ -2188,7 +2188,7 @@ TakeAbsoluteValue(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
FormatInfAndNaN(
|
||||
Double *d, /* Exceptional number to format. */
|
||||
int *decpt, /* Decimal point to set to a bogus value. */
|
||||
@@ -2230,7 +2230,7 @@ FormatInfAndNaN(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
FormatZero(
|
||||
int *decpt, /* Location of the decimal point. */
|
||||
char **endPtr) /* Pointer to the end of the formatted data */
|
||||
@@ -2260,7 +2260,7 @@ FormatZero(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static int
|
||||
static inline int
|
||||
ApproximateLog10(
|
||||
Tcl_WideUInt bw, /* Integer significand of the number. */
|
||||
int be, /* Power of two to scale bw. */
|
||||
@@ -2308,7 +2308,7 @@ ApproximateLog10(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static int
|
||||
static inline int
|
||||
BetterLog10(
|
||||
double d, /* Original number to format. */
|
||||
int k, /* Characteristic(Log base 10) of the
|
||||
@@ -2351,7 +2351,7 @@ BetterLog10(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static void
|
||||
static inline void
|
||||
ComputeScale(
|
||||
int be, /* Exponent part of number: d = bw * 2**be. */
|
||||
int k, /* Characteristic of log10(number). */
|
||||
@@ -2414,7 +2414,7 @@ ComputeScale(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static void
|
||||
static inline void
|
||||
SetPrecisionLimits(
|
||||
int convType, /* Type of conversion: TCL_DD_SHORTEST,
|
||||
* TCL_DD_STEELE0, TCL_DD_E_FMT,
|
||||
@@ -2475,7 +2475,7 @@ SetPrecisionLimits(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
BumpUp(
|
||||
char *s, /* Cursor pointing one past the end of the
|
||||
* string. */
|
||||
@@ -2509,7 +2509,7 @@ BumpUp(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static int
|
||||
static inline int
|
||||
AdjustRange(
|
||||
double *dPtr, /* INOUT: Number to adjust. */
|
||||
int k) /* IN: floor(log10(d)) */
|
||||
@@ -2582,7 +2582,7 @@ AdjustRange(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
ShorteningQuickFormat(
|
||||
double d, /* Number to convert. */
|
||||
int k, /* floor(log10(d)) */
|
||||
@@ -2657,7 +2657,7 @@ ShorteningQuickFormat(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
StrictQuickFormat(
|
||||
double d, /* Number to convert. */
|
||||
int k, /* floor(log10(d)) */
|
||||
@@ -2731,7 +2731,7 @@ StrictQuickFormat(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
QuickConversion(
|
||||
double e, /* Number to format. */
|
||||
int k, /* floor(log10(d)), approximately. */
|
||||
@@ -2836,7 +2836,7 @@ QuickConversion(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static void
|
||||
static inline void
|
||||
CastOutPowersOf2(
|
||||
int *b2, /* Power of 2 to multiply the significand. */
|
||||
int *m2, /* Power of 2 to multiply 1/2 ulp. */
|
||||
@@ -2880,7 +2880,7 @@ CastOutPowersOf2(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
ShorteningInt64Conversion(
|
||||
Double *dPtr, /* Original number to convert. */
|
||||
int convType, /* Type of conversion (shortest, Steele,
|
||||
@@ -3049,7 +3049,7 @@ ShorteningInt64Conversion(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
StrictInt64Conversion(
|
||||
Double *dPtr, /* Original number to convert. */
|
||||
int convType, /* Type of conversion (shortest, Steele,
|
||||
@@ -3155,7 +3155,7 @@ StrictInt64Conversion(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static int
|
||||
static inline int
|
||||
ShouldBankerRoundUpPowD(
|
||||
mp_int *b, /* Numerator of the fraction. */
|
||||
int sd, /* Denominator is 2**(sd*DIGIT_BIT). */
|
||||
@@ -3193,7 +3193,7 @@ ShouldBankerRoundUpPowD(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static int
|
||||
static inline int
|
||||
ShouldBankerRoundUpToNextPowD(
|
||||
mp_int *b, /* Numerator of the fraction. */
|
||||
mp_int *m, /* Numerator of the rounding tolerance. */
|
||||
@@ -3256,7 +3256,7 @@ ShouldBankerRoundUpToNextPowD(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
ShorteningBignumConversionPowD(
|
||||
Double *dPtr, /* Original number to convert. */
|
||||
int convType, /* Type of conversion (shortest, Steele,
|
||||
@@ -3449,7 +3449,7 @@ ShorteningBignumConversionPowD(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
StrictBignumConversionPowD(
|
||||
Double *dPtr, /* Original number to convert. */
|
||||
int convType, /* Type of conversion (shortest, Steele,
|
||||
@@ -3565,7 +3565,7 @@ StrictBignumConversionPowD(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static int
|
||||
static inline int
|
||||
ShouldBankerRoundUp(
|
||||
mp_int *twor, /* 2x the remainder from thd division that
|
||||
* produced the last digit. */
|
||||
@@ -3600,7 +3600,7 @@ ShouldBankerRoundUp(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static int
|
||||
static inline int
|
||||
ShouldBankerRoundUpToNext(
|
||||
mp_int *b, /* Remainder from the division that produced
|
||||
* the last digit. */
|
||||
@@ -3654,7 +3654,7 @@ ShouldBankerRoundUpToNext(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
ShorteningBignumConversion(
|
||||
Double *dPtr, /* Original number being converted. */
|
||||
int convType, /* Conversion type. */
|
||||
@@ -3870,7 +3870,7 @@ ShorteningBignumConversion(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
inline static char *
|
||||
static inline char *
|
||||
StrictBignumConversion(
|
||||
Double *dPtr, /* Original number being converted. */
|
||||
int convType, /* Conversion type. */
|
||||
|
||||
+90
-20
@@ -418,18 +418,23 @@ Tcl_GetCharLength(
|
||||
int numChars;
|
||||
|
||||
/*
|
||||
* Optimize the case where we're really dealing with a bytearray object
|
||||
* without string representation; we don't need to convert to a string to
|
||||
* perform the get-length operation.
|
||||
* Optimize the case where we're really dealing with a bytearray object;
|
||||
* we don't need to convert to a string to perform the get-length operation.
|
||||
*
|
||||
* NOTE that we do not need the bytearray to be "pure". A ByteArray value
|
||||
* with a string rep cannot be trusted to represent the same value as the
|
||||
* string rep, but it *can* be trusted to have the same character length
|
||||
* as the string rep, which is all this routine cares about.
|
||||
*/
|
||||
|
||||
if (TclIsPureByteArray(objPtr)) {
|
||||
if (objPtr->typePtr == &tclByteArrayType) {
|
||||
int length;
|
||||
|
||||
(void) Tcl_GetByteArrayFromObj(objPtr, &length);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* OK, need to work with the object as a string.
|
||||
*/
|
||||
@@ -460,6 +465,50 @@ 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 == tclEmptyStringRep) {
|
||||
return TCL_EMPTYSTRING_YES;
|
||||
}
|
||||
|
||||
if (TclIsPureList(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;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -529,7 +578,7 @@ Tcl_GetUniChar(
|
||||
*
|
||||
* Get the Unicode form of the String object. If the object is not
|
||||
* already a String object, it will be converted to one. If the String
|
||||
* object does not have a Unicode rep, then one is create from the UTF
|
||||
* object does not have a Unicode rep, then one is created from the UTF
|
||||
* string format.
|
||||
*
|
||||
* Results:
|
||||
@@ -663,6 +712,17 @@ Tcl_GetRange(
|
||||
stringPtr = GET_STRING(objPtr);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
#endif
|
||||
return Tcl_NewUnicodeObj(stringPtr->unicode + first, last-first+1);
|
||||
}
|
||||
|
||||
@@ -1682,6 +1742,7 @@ Tcl_AppendFormatToObj(
|
||||
const char *span = format, *msg, *errCode;
|
||||
int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
|
||||
int originalLength, limit;
|
||||
Tcl_UniChar ch = 0;
|
||||
static const char *mixedXPG =
|
||||
"cannot mix \"%\" and \"%n$\" conversion specifiers";
|
||||
static const char *const badIndex[2] = {
|
||||
@@ -1709,7 +1770,6 @@ Tcl_AppendFormatToObj(
|
||||
#endif
|
||||
int newXpg, numChars, allocSegment = 0, segmentLimit, segmentNumBytes;
|
||||
Tcl_Obj *segment;
|
||||
Tcl_UniChar ch;
|
||||
int step = TclUtfToUniChar(format, &ch);
|
||||
|
||||
format += step;
|
||||
@@ -1816,6 +1876,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 == '*') {
|
||||
@@ -1936,6 +2001,12 @@ Tcl_AppendFormatToObj(
|
||||
goto error;
|
||||
}
|
||||
length = Tcl_UniCharToUtf(code, buf);
|
||||
#if TCL_UTF_MAX > 3
|
||||
if (!length) {
|
||||
/* Special case for handling upper surrogates. */
|
||||
length = Tcl_UniCharToUtf(-1, buf);
|
||||
}
|
||||
#endif
|
||||
segment = Tcl_NewStringObj(buf, length);
|
||||
Tcl_IncrRefCount(segment);
|
||||
allocSegment = 1;
|
||||
@@ -2027,8 +2098,11 @@ Tcl_AppendFormatToObj(
|
||||
segmentLimit -= 1;
|
||||
precision--;
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
Tcl_AppendToObj(segment, "0X", 2);
|
||||
segmentLimit -= 2;
|
||||
break;
|
||||
case 'x':
|
||||
Tcl_AppendToObj(segment, "0x", 2);
|
||||
segmentLimit -= 2;
|
||||
break;
|
||||
@@ -2192,7 +2266,11 @@ Tcl_AppendFormatToObj(
|
||||
}
|
||||
digitOffset = (int) (bits % base);
|
||||
if (digitOffset > 9) {
|
||||
bytes[numDigits] = 'a' + digitOffset - 10;
|
||||
if (ch == 'X') {
|
||||
bytes[numDigits] = 'A' + digitOffset - 10;
|
||||
} else {
|
||||
bytes[numDigits] = 'a' + digitOffset - 10;
|
||||
}
|
||||
} else {
|
||||
bytes[numDigits] = '0' + digitOffset;
|
||||
}
|
||||
@@ -2314,14 +2392,6 @@ Tcl_AppendFormatToObj(
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case 'E':
|
||||
case 'G':
|
||||
case 'X': {
|
||||
Tcl_SetObjLength(segment, Tcl_UtfToUpper(TclGetString(segment)));
|
||||
}
|
||||
}
|
||||
|
||||
if (width>0 && numChars<0) {
|
||||
numChars = Tcl_GetCharLength(segment);
|
||||
}
|
||||
@@ -2693,7 +2763,7 @@ TclStringObjReverse(
|
||||
Tcl_Obj *objPtr)
|
||||
{
|
||||
String *stringPtr;
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
|
||||
if (TclIsPureByteArray(objPtr)) {
|
||||
int numBytes;
|
||||
@@ -2721,7 +2791,6 @@ TclStringObjReverse(
|
||||
* Tcl_SetObjLength into growing the unicode rep buffer.
|
||||
*/
|
||||
|
||||
ch = 0;
|
||||
objPtr = Tcl_NewUnicodeObj(&ch, 1);
|
||||
Tcl_SetObjLength(objPtr, stringPtr->numChars);
|
||||
to = Tcl_GetUnicode(objPtr);
|
||||
@@ -2824,7 +2893,7 @@ ExtendUnicodeRepWithString(
|
||||
{
|
||||
String *stringPtr = GET_STRING(objPtr);
|
||||
int needed, numOrigChars = 0;
|
||||
Tcl_UniChar *dst;
|
||||
Tcl_UniChar *dst, unichar = 0;
|
||||
|
||||
if (stringPtr->hasUnicode) {
|
||||
numOrigChars = stringPtr->numChars;
|
||||
@@ -2847,7 +2916,8 @@ ExtendUnicodeRepWithString(
|
||||
numAppendChars = 0;
|
||||
}
|
||||
for (dst=stringPtr->unicode + numOrigChars; numAppendChars-- > 0; dst++) {
|
||||
bytes += TclUtfToUniChar(bytes, dst);
|
||||
bytes += TclUtfToUniChar(bytes, &unichar);
|
||||
*dst = unichar;
|
||||
}
|
||||
*dst = 0;
|
||||
}
|
||||
|
||||
+23
-11
@@ -12,6 +12,10 @@
|
||||
#include "tclInt.h"
|
||||
#include "tommath.h"
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
# include <wchar.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC dependency "tcl.decls"
|
||||
#pragma GCC dependency "tclInt.decls"
|
||||
@@ -106,8 +110,6 @@ static unsigned short TclWinNToHS(unsigned short ns) {
|
||||
# define TclWinFlushDirtyChannels doNothing
|
||||
# define TclWinResetInterfaces doNothing
|
||||
|
||||
static Tcl_Encoding winTCharEncoding;
|
||||
|
||||
static int
|
||||
TclpIsAtty(int fd)
|
||||
{
|
||||
@@ -127,7 +129,7 @@ void *TclWinGetTclInstance()
|
||||
{
|
||||
void *hInstance = NULL;
|
||||
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
(const char *)&winTCharEncoding, &hInstance);
|
||||
(const char *)&TclpIsAtty, &hInstance);
|
||||
return hInstance;
|
||||
}
|
||||
|
||||
@@ -186,11 +188,11 @@ Tcl_WinUtfToTChar(
|
||||
int len,
|
||||
Tcl_DString *dsPtr)
|
||||
{
|
||||
if (!winTCharEncoding) {
|
||||
winTCharEncoding = Tcl_GetEncoding(0, "unicode");
|
||||
Tcl_DStringInit(dsPtr);
|
||||
if (!string) {
|
||||
return NULL;
|
||||
}
|
||||
return Tcl_UtfToExternalDString(winTCharEncoding,
|
||||
string, len, dsPtr);
|
||||
return (char *)Tcl_UtfToUniCharDString(string, len, dsPtr);
|
||||
}
|
||||
|
||||
char *
|
||||
@@ -199,11 +201,16 @@ Tcl_WinTCharToUtf(
|
||||
int len,
|
||||
Tcl_DString *dsPtr)
|
||||
{
|
||||
if (!winTCharEncoding) {
|
||||
winTCharEncoding = Tcl_GetEncoding(0, "unicode");
|
||||
Tcl_DStringInit(dsPtr);
|
||||
if (!string) {
|
||||
return NULL;
|
||||
}
|
||||
return Tcl_ExternalToUtfDString(winTCharEncoding,
|
||||
string, len, dsPtr);
|
||||
if (len < 0) {
|
||||
len = wcslen((wchar_t *)string);
|
||||
} else {
|
||||
len /= 2;
|
||||
}
|
||||
return Tcl_UniCharToUtfDString((Tcl_UniChar *)string, len, dsPtr);
|
||||
}
|
||||
|
||||
#if defined(TCL_WIDE_INT_IS_LONG)
|
||||
@@ -560,6 +567,11 @@ static const TclIntStubs tclIntStubs = {
|
||||
TclDoubleDigits, /* 249 */
|
||||
TclSetSlaveCancelFlags, /* 250 */
|
||||
TclRegisterLiteral, /* 251 */
|
||||
TclPtrGetVar, /* 252 */
|
||||
TclPtrSetVar, /* 253 */
|
||||
TclPtrIncrObjVar, /* 254 */
|
||||
TclPtrObjMakeUpvar, /* 255 */
|
||||
TclPtrUnsetVar, /* 256 */
|
||||
};
|
||||
|
||||
static const TclIntPlatStubs tclIntPlatStubs = {
|
||||
|
||||
+58
-4
@@ -407,6 +407,12 @@ static Tcl_FSMatchInDirectoryProc SimpleMatchInDirectory;
|
||||
static int TestNumUtfCharsCmd(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const objv[]);
|
||||
static int TestFindFirstCmd(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const objv[]);
|
||||
static int TestFindLastCmd(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const objv[]);
|
||||
static int TestHashSystemHashCmd(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const objv[]);
|
||||
@@ -668,6 +674,10 @@ Tcltest_Init(
|
||||
TestsetobjerrorcodeCmd, NULL, NULL);
|
||||
Tcl_CreateObjCommand(interp, "testnumutfchars",
|
||||
TestNumUtfCharsCmd, NULL, NULL);
|
||||
Tcl_CreateObjCommand(interp, "testfindfirst",
|
||||
TestFindFirstCmd, NULL, NULL);
|
||||
Tcl_CreateObjCommand(interp, "testfindlast",
|
||||
TestFindLastCmd, NULL, NULL);
|
||||
Tcl_CreateCommand(interp, "testsetplatform", TestsetplatformCmd,
|
||||
NULL, NULL);
|
||||
Tcl_CreateCommand(interp, "teststaticpkg", TeststaticpkgCmd,
|
||||
@@ -5224,7 +5234,7 @@ TestmainthreadCmd(
|
||||
const char **argv) /* Argument strings. */
|
||||
{
|
||||
if (argc == 1) {
|
||||
Tcl_Obj *idObj = Tcl_NewLongObj((long)(size_t)Tcl_GetCurrentThread());
|
||||
Tcl_Obj *idObj = Tcl_NewWideIntObj((Tcl_WideInt)(size_t)Tcl_GetCurrentThread());
|
||||
|
||||
Tcl_SetObjResult(interp, idObj);
|
||||
return TCL_OK;
|
||||
@@ -5621,8 +5631,8 @@ TestChannelCmd(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
TclFormatInt(buf, (size_t) Tcl_GetChannelThread(chan));
|
||||
Tcl_AppendResult(interp, buf, NULL);
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(
|
||||
(Tcl_WideInt) (size_t) Tcl_GetChannelThread(chan)));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -6672,7 +6682,7 @@ TestNumUtfCharsCmd(
|
||||
int len = -1;
|
||||
|
||||
if (objc > 2) {
|
||||
(void) Tcl_GetStringFromObj(objv[1], &len);
|
||||
(void) Tcl_GetIntFromObj(interp, objv[2], &len);
|
||||
}
|
||||
len = Tcl_NumUtfChars(Tcl_GetString(objv[1]), len);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(len));
|
||||
@@ -6680,6 +6690,50 @@ TestNumUtfCharsCmd(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to check correct operation of Tcl_UtfFindFirst
|
||||
*/
|
||||
|
||||
static int
|
||||
TestFindFirstCmd(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *const objv[])
|
||||
{
|
||||
if (objc > 1) {
|
||||
int len = -1;
|
||||
|
||||
if (objc > 2) {
|
||||
(void) Tcl_GetIntFromObj(interp, objv[2], &len);
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_UtfFindFirst(Tcl_GetString(objv[1]), len), -1));
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to check correct operation of Tcl_UtfFindLast
|
||||
*/
|
||||
|
||||
static int
|
||||
TestFindLastCmd(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *const objv[])
|
||||
{
|
||||
if (objc > 1) {
|
||||
int len = -1;
|
||||
|
||||
if (objc > 2) {
|
||||
(void) Tcl_GetIntFromObj(interp, objv[2], &len);
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_UtfFindLast(Tcl_GetString(objv[1]), len), -1));
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#if defined(HAVE_CPUID) || defined(_WIN32)
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
|
||||
+10
-3
@@ -174,7 +174,6 @@ TclThread_Init(
|
||||
Tcl_CreateObjCommand(interp, "testthread", ThreadObjCmd, NULL, NULL);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -248,7 +247,7 @@ ThreadObjCmd(
|
||||
|
||||
switch ((enum options)option) {
|
||||
case THREAD_CANCEL: {
|
||||
long id;
|
||||
Tcl_WideInt id;
|
||||
const char *result;
|
||||
int flags, arg;
|
||||
|
||||
@@ -264,7 +263,7 @@ ThreadObjCmd(
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
if (Tcl_GetLongFromObj(interp, objv[arg], &id) != TCL_OK) {
|
||||
if (Tcl_GetWideIntFromObj(interp, objv[arg], &id) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
arg++;
|
||||
@@ -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;
|
||||
|
||||
+52
-1
@@ -191,8 +191,10 @@ Tcl_TraceObjCmd(
|
||||
Tcl_Obj *const objv[]) /* Argument objects. */
|
||||
{
|
||||
int optionIndex;
|
||||
#ifndef TCL_REMOVE_OBSOLETE_TRACES
|
||||
const char *name;
|
||||
const char *flagOps, *p;
|
||||
#endif
|
||||
/* Main sub commands to 'trace' */
|
||||
static const char *const traceOptions[] = {
|
||||
"add", "info", "remove",
|
||||
@@ -365,12 +367,14 @@ Tcl_TraceObjCmd(
|
||||
}
|
||||
return TCL_OK;
|
||||
|
||||
#ifndef TCL_REMOVE_OBSOLETE_TRACES
|
||||
badVarOps:
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"bad operations \"%s\": should be one or more of rwua",
|
||||
flagOps));
|
||||
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRACE", "BADOPS", NULL);
|
||||
return TCL_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -912,9 +916,11 @@ TraceVariableObjCmd(
|
||||
+ 1 + length);
|
||||
|
||||
ctvarPtr->traceCmdInfo.flags = flags;
|
||||
#ifndef TCL_REMOVE_OBSOLETE_TRACES
|
||||
if (objv[0] == NULL) {
|
||||
ctvarPtr->traceCmdInfo.flags |= TCL_TRACE_OLD_STYLE;
|
||||
}
|
||||
#endif
|
||||
ctvarPtr->traceCmdInfo.length = length;
|
||||
flags |= TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT;
|
||||
memcpy(ctvarPtr->traceCmdInfo.command, command, length+1);
|
||||
@@ -939,7 +945,11 @@ TraceVariableObjCmd(
|
||||
TraceVarInfo *tvarPtr = clientData;
|
||||
|
||||
if ((tvarPtr->length == length)
|
||||
&& ((tvarPtr->flags & ~TCL_TRACE_OLD_STYLE)==flags)
|
||||
&& ((tvarPtr->flags
|
||||
#ifndef TCL_REMOVE_OBSOLETE_TRACES
|
||||
& ~TCL_TRACE_OLD_STYLE
|
||||
#endif
|
||||
)==flags)
|
||||
&& (strncmp(command, tvarPtr->command,
|
||||
(size_t) length) == 0)) {
|
||||
Tcl_UntraceVar2(interp, name, NULL,
|
||||
@@ -2465,6 +2475,47 @@ TclVarTraceExists(
|
||||
return varPtr;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclCheckArrayTraces --
|
||||
*
|
||||
* This function is invoked to when we operate on an array variable,
|
||||
* to allow any array traces to fire.
|
||||
*
|
||||
* Results:
|
||||
* Returns TCL_OK to indicate normal operation. Returns TCL_ERROR if
|
||||
* invocation of a trace function indicated an error. When TCL_ERROR is
|
||||
* returned, then error information is left in interp.
|
||||
*
|
||||
* Side effects:
|
||||
* Almost anything can happen, depending on trace; this function itself
|
||||
* doesn't have any side effects.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
TclCheckArrayTraces(
|
||||
Tcl_Interp *interp,
|
||||
Var *varPtr,
|
||||
Var *arrayPtr,
|
||||
Tcl_Obj *name,
|
||||
int index)
|
||||
{
|
||||
int code = TCL_OK;
|
||||
|
||||
if (varPtr && (varPtr->flags & VAR_TRACED_ARRAY)
|
||||
&& (TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr))) {
|
||||
Interp *iPtr = (Interp *)interp;
|
||||
|
||||
code = TclObjCallVarTraces(iPtr, arrayPtr, varPtr, name, NULL,
|
||||
(TCL_NAMESPACE_ONLY|TCL_GLOBAL_ONLY| TCL_TRACE_ARRAY),
|
||||
/* leaveErrMsg */ 1, index);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
+1032
-999
File diff suppressed because it is too large
Load Diff
+205
-94
@@ -98,9 +98,9 @@ static int UtfCount(int ch);
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
INLINE static int
|
||||
static inline int
|
||||
UtfCount(
|
||||
int ch) /* The Tcl_UniChar whose size is returned. */
|
||||
int ch) /* The Unicode character whose size is returned. */
|
||||
{
|
||||
if ((unsigned)(ch - 1) < (UNICODE_SELF - 1)) {
|
||||
return 1;
|
||||
@@ -109,7 +109,7 @@ UtfCount(
|
||||
return 2;
|
||||
}
|
||||
#if TCL_UTF_MAX > 3
|
||||
if (((unsigned)(ch - 0x10000) <= 0xfffff)) {
|
||||
if (((unsigned)(ch - 0x10000) <= 0xFFFFF)) {
|
||||
return 4;
|
||||
}
|
||||
#endif
|
||||
@@ -134,7 +134,7 @@ UtfCount(
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
INLINE int
|
||||
int
|
||||
Tcl_UniCharToUtf(
|
||||
int ch, /* The Tcl_UniChar to be stored in the
|
||||
* buffer. */
|
||||
@@ -154,19 +154,26 @@ Tcl_UniCharToUtf(
|
||||
return 2;
|
||||
}
|
||||
if (ch <= 0xFFFF) {
|
||||
#if TCL_UTF_MAX == 4
|
||||
#if TCL_UTF_MAX > 3
|
||||
if ((ch & 0xF800) == 0xD800) {
|
||||
if (ch & 0x0400) {
|
||||
/* Low surrogate */
|
||||
buf[3] = (char) ((ch | 0x80) & 0xBF);
|
||||
buf[2] |= (char) (((ch >> 6) | 0x80) & 0x8F);
|
||||
return 4;
|
||||
if (((buf[0] & 0xF8) == 0xF0) && ((buf[1] & 0xC0) == 0x80)
|
||||
&& ((buf[2] & 0xCF) == 0)) {
|
||||
/* Previous Tcl_UniChar was a High surrogate, so combine */
|
||||
buf[3] = (char) ((ch & 0x3F) | 0x80);
|
||||
buf[2] |= (char) (((ch >> 6) & 0x0F) | 0x80);
|
||||
return 4;
|
||||
}
|
||||
/* Previous Tcl_UniChar was not a High surrogate, so just output */
|
||||
} else {
|
||||
/* High surrogate */
|
||||
ch += 0x40;
|
||||
buf[2] = (char) (((ch << 4) | 0x80) & 0xB0);
|
||||
buf[1] = (char) (((ch >> 2) | 0x80) & 0xBF);
|
||||
buf[0] = (char) (((ch >> 8) | 0xF0) & 0xF7);
|
||||
/* Fill buffer with specific 3-byte (invalid) byte combination,
|
||||
so following Low surrogate can recognize it and combine */
|
||||
buf[2] = (char) ((ch << 4) & 0x30);
|
||||
buf[1] = (char) (((ch >> 2) & 0x3F) | 0x80);
|
||||
buf[0] = (char) (((ch >> 8) & 0x07) | 0xF0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -182,6 +189,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;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -229,7 +243,7 @@ Tcl_UniCharToUtfDString(
|
||||
*/
|
||||
|
||||
oldLength = Tcl_DStringLength(dsPtr);
|
||||
Tcl_DStringSetLength(dsPtr, (oldLength + uniLength + 1) * TCL_UTF_MAX);
|
||||
Tcl_DStringSetLength(dsPtr, oldLength + (uniLength + 1) * TCL_UTF_MAX);
|
||||
string = Tcl_DStringValue(dsPtr) + oldLength;
|
||||
|
||||
p = string;
|
||||
@@ -259,6 +273,15 @@ Tcl_UniCharToUtfDString(
|
||||
* Tcl_UtfCharComplete() before calling this routine to ensure that
|
||||
* enough bytes remain in the string.
|
||||
*
|
||||
* If TCL_UTF_MAX == 4, special handling of Surrogate pairs is done:
|
||||
* For any UTF-8 string containing a character outside of the BMP, the
|
||||
* first call to this function will fill *chPtr with the high surrogate
|
||||
* and generate a return value of 0. Calling Tcl_UtfToUniChar again
|
||||
* will produce the low surrogate and a return value of 4. Because *chPtr
|
||||
* is used to remember whether the high surrogate is already produced, it
|
||||
* is recommended to initialize the variable it points to as 0 before
|
||||
* the first call to Tcl_UtfToUniChar is done.
|
||||
*
|
||||
* Results:
|
||||
* *chPtr is filled with the Tcl_UniChar, and the return value is the
|
||||
* number of bytes from the UTF-8 string that were consumed.
|
||||
@@ -278,7 +301,7 @@ Tcl_UtfToUniChar(
|
||||
register int byte;
|
||||
|
||||
/*
|
||||
* Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones.
|
||||
* Unroll 1 to 3 (or 4) byte UTF-8 sequences.
|
||||
*/
|
||||
|
||||
byte = *((unsigned char *) src);
|
||||
@@ -298,7 +321,7 @@ Tcl_UtfToUniChar(
|
||||
*/
|
||||
|
||||
*chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6) | (src[1] & 0x3F));
|
||||
if ((*chPtr == 0) || (*chPtr > 0x7f)) {
|
||||
if ((unsigned)(*chPtr - 1) >= (UNICODE_SELF - 1)) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@@ -315,7 +338,7 @@ Tcl_UtfToUniChar(
|
||||
|
||||
*chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12)
|
||||
| ((src[1] & 0x3F) << 6) | (src[2] & 0x3F));
|
||||
if (*chPtr > 0x7ff) {
|
||||
if (*chPtr > 0x7FF) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
@@ -331,16 +354,34 @@ Tcl_UtfToUniChar(
|
||||
/*
|
||||
* Four-byte-character lead byte followed by three trail bytes.
|
||||
*/
|
||||
#if TCL_UTF_MAX == 4
|
||||
Tcl_UniChar surrogate;
|
||||
|
||||
*chPtr = (Tcl_UniChar) (((byte & 0x0E) << 18) | ((src[1] & 0x3F) << 12)
|
||||
| ((src[2] & 0x3F) << 6) | (src[3] & 0x3F));
|
||||
if ((*chPtr <= 0x10ffff) && (*chPtr > 0xffff)) {
|
||||
byte = (((byte & 0x07) << 18) | ((src[1] & 0x3F) << 12)
|
||||
| ((src[2] & 0x3F) << 6) | (src[3] & 0x3F)) - 0x10000;
|
||||
surrogate = (Tcl_UniChar) (0xD800 + (byte >> 10));
|
||||
if (byte & 0x100000) {
|
||||
/* out of range, < 0x10000 or > 0x10ffff */
|
||||
} else if (*chPtr != surrogate) {
|
||||
/* produce high surrogate, but don't advance source pointer */
|
||||
*chPtr = surrogate;
|
||||
return 0;
|
||||
} else {
|
||||
/* produce low surrogate, and advance source pointer */
|
||||
*chPtr = (Tcl_UniChar) (0xDC00 | (byte & 0x3FF));
|
||||
return 4;
|
||||
}
|
||||
#else
|
||||
*chPtr = (Tcl_UniChar) (((byte & 0x07) << 18) | ((src[1] & 0x3F) << 12)
|
||||
| ((src[2] & 0x3F) << 6) | (src[3] & 0x3F));
|
||||
if ((unsigned)(*chPtr - 0x10000) <= 0xFFFFF) {
|
||||
return 4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* A three-byte-character lead-byte not followed by two trail-bytes
|
||||
* A four-byte-character lead-byte not followed by two trail-bytes
|
||||
* represents itself.
|
||||
*/
|
||||
}
|
||||
@@ -377,7 +418,7 @@ Tcl_UtfToUniCharDString(
|
||||
* appended to this previously initialized
|
||||
* DString. */
|
||||
{
|
||||
Tcl_UniChar *w, *wString;
|
||||
Tcl_UniChar ch = 0, *w, *wString;
|
||||
const char *p, *end;
|
||||
int oldLength;
|
||||
|
||||
@@ -391,16 +432,26 @@ Tcl_UtfToUniCharDString(
|
||||
*/
|
||||
|
||||
oldLength = Tcl_DStringLength(dsPtr);
|
||||
/* TODO: fix overreach! */
|
||||
|
||||
Tcl_DStringSetLength(dsPtr,
|
||||
(int) ((oldLength + length + 1) * sizeof(Tcl_UniChar)));
|
||||
oldLength + (int) ((length + 1) * sizeof(Tcl_UniChar)));
|
||||
wString = (Tcl_UniChar *) (Tcl_DStringValue(dsPtr) + oldLength);
|
||||
|
||||
w = wString;
|
||||
end = src + length;
|
||||
for (p = src; p < end; ) {
|
||||
p += TclUtfToUniChar(p, w);
|
||||
w++;
|
||||
p = src;
|
||||
end = src + length - TCL_UTF_MAX;
|
||||
while (p < end) {
|
||||
p += TclUtfToUniChar(p, &ch);
|
||||
*w++ = ch;
|
||||
}
|
||||
end += TCL_UTF_MAX;
|
||||
while (p < end) {
|
||||
if (Tcl_UtfCharComplete(p, end-p)) {
|
||||
p += TclUtfToUniChar(p, &ch);
|
||||
} else {
|
||||
ch = UCHAR(*p++);
|
||||
}
|
||||
*w++ = ch;
|
||||
}
|
||||
*w = '\0';
|
||||
Tcl_DStringSetLength(dsPtr,
|
||||
@@ -434,10 +485,7 @@ Tcl_UtfCharComplete(
|
||||
* a complete UTF-8 character. */
|
||||
int length) /* Length of above string in bytes. */
|
||||
{
|
||||
int ch;
|
||||
|
||||
ch = *((unsigned char *) src);
|
||||
return length >= totalBytes[ch];
|
||||
return length >= totalBytes[(unsigned char)*src];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -464,9 +512,8 @@ Tcl_NumUtfChars(
|
||||
int length) /* The length of the string in bytes, or -1
|
||||
* for strlen(string). */
|
||||
{
|
||||
Tcl_UniChar ch;
|
||||
register Tcl_UniChar *chPtr = &ch;
|
||||
register int i;
|
||||
Tcl_UniChar ch = 0;
|
||||
register int i = 0;
|
||||
|
||||
/*
|
||||
* The separate implementations are faster.
|
||||
@@ -475,26 +522,27 @@ Tcl_NumUtfChars(
|
||||
* single-byte char case specially.
|
||||
*/
|
||||
|
||||
i = 0;
|
||||
if (length < 0) {
|
||||
while (*src != '\0') {
|
||||
src += TclUtfToUniChar(src, chPtr);
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
i++;
|
||||
}
|
||||
if (i < 0) i = INT_MAX; /* Bug [2738427] */
|
||||
} else {
|
||||
register int n;
|
||||
register const char *endPtr = src + length - TCL_UTF_MAX;
|
||||
|
||||
while (length > 0) {
|
||||
if (UCHAR(*src) < 0xC0) {
|
||||
length--;
|
||||
src++;
|
||||
} else {
|
||||
n = Tcl_UtfToUniChar(src, chPtr);
|
||||
length -= n;
|
||||
src += n;
|
||||
}
|
||||
while (src < endPtr) {
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
i++;
|
||||
}
|
||||
endPtr += TCL_UTF_MAX;
|
||||
while ((src < endPtr) && Tcl_UtfCharComplete(src, endPtr - src)) {
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
i++;
|
||||
}
|
||||
if (src < endPtr) {
|
||||
i += endPtr - src;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -504,13 +552,13 @@ Tcl_NumUtfChars(
|
||||
*
|
||||
* Tcl_UtfFindFirst --
|
||||
*
|
||||
* Returns a pointer to the first occurance of the given Tcl_UniChar in
|
||||
* the NULL-terminated UTF-8 string. The NULL terminator is considered
|
||||
* Returns a pointer to the first occurance of the given Unicode character
|
||||
* in the NULL-terminated UTF-8 string. The NULL terminator is considered
|
||||
* part of the UTF-8 string. Equivalent to Plan 9 utfrune().
|
||||
*
|
||||
* Results:
|
||||
* As above. If the Tcl_UniChar does not exist in the given string, the
|
||||
* return value is NULL.
|
||||
* As above. If the Unicode character does not exist in the given string,
|
||||
* the return value is NULL.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
@@ -521,14 +569,21 @@ Tcl_NumUtfChars(
|
||||
const char *
|
||||
Tcl_UtfFindFirst(
|
||||
const char *src, /* The UTF-8 string to be searched. */
|
||||
int ch) /* The Tcl_UniChar to search for. */
|
||||
int ch) /* The Unicode character to search for. */
|
||||
{
|
||||
int len;
|
||||
Tcl_UniChar find;
|
||||
int len, fullchar;
|
||||
Tcl_UniChar find = 0;
|
||||
|
||||
while (1) {
|
||||
len = TclUtfToUniChar(src, &find);
|
||||
if (find == ch) {
|
||||
fullchar = find;
|
||||
#if TCL_UTF_MAX == 4
|
||||
if (!len) {
|
||||
len += TclUtfToUniChar(src, &find);
|
||||
fullchar = (((fullchar & 0x3ff) << 10) | (find & 0x3ff)) + 0x10000;
|
||||
}
|
||||
#endif
|
||||
if (fullchar == ch) {
|
||||
return src;
|
||||
}
|
||||
if (*src == '\0') {
|
||||
@@ -543,12 +598,12 @@ Tcl_UtfFindFirst(
|
||||
*
|
||||
* Tcl_UtfFindLast --
|
||||
*
|
||||
* Returns a pointer to the last occurance of the given Tcl_UniChar in
|
||||
* the NULL-terminated UTF-8 string. The NULL terminator is considered
|
||||
* Returns a pointer to the last occurance of the given Unicode character
|
||||
* in the NULL-terminated UTF-8 string. The NULL terminator is considered
|
||||
* part of the UTF-8 string. Equivalent to Plan 9 utfrrune().
|
||||
*
|
||||
* Results:
|
||||
* As above. If the Tcl_UniChar does not exist in the given string, the
|
||||
* As above. If the Unicode character does not exist in the given string, the
|
||||
* return value is NULL.
|
||||
*
|
||||
* Side effects:
|
||||
@@ -560,16 +615,23 @@ Tcl_UtfFindFirst(
|
||||
const char *
|
||||
Tcl_UtfFindLast(
|
||||
const char *src, /* The UTF-8 string to be searched. */
|
||||
int ch) /* The Tcl_UniChar to search for. */
|
||||
int ch) /* The Unicode character to search for. */
|
||||
{
|
||||
int len;
|
||||
Tcl_UniChar find;
|
||||
int len, fullchar;
|
||||
Tcl_UniChar find = 0;
|
||||
const char *last;
|
||||
|
||||
last = NULL;
|
||||
while (1) {
|
||||
len = TclUtfToUniChar(src, &find);
|
||||
if (find == ch) {
|
||||
fullchar = find;
|
||||
#if TCL_UTF_MAX == 4
|
||||
if (!len) {
|
||||
len += TclUtfToUniChar(src, &find);
|
||||
fullchar = (((fullchar & 0x3ff) << 10) | (find & 0x3ff)) + 0x10000;
|
||||
}
|
||||
#endif
|
||||
if (fullchar == ch) {
|
||||
last = src;
|
||||
}
|
||||
if (*src == '\0') {
|
||||
@@ -603,9 +665,15 @@ const char *
|
||||
Tcl_UtfNext(
|
||||
const char *src) /* The current location in the string. */
|
||||
{
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
int len = TclUtfToUniChar(src, &ch);
|
||||
|
||||
return src + TclUtfToUniChar(src, &ch);
|
||||
#if TCL_UTF_MAX == 4
|
||||
if (len == 0) {
|
||||
len = TclUtfToUniChar(src, &ch);
|
||||
}
|
||||
#endif
|
||||
return src + len;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -638,8 +706,7 @@ Tcl_UtfPrev(
|
||||
const char *look;
|
||||
int i, byte;
|
||||
|
||||
src--;
|
||||
look = src;
|
||||
look = --src;
|
||||
for (i = 0; i < TCL_UTF_MAX; i++) {
|
||||
if (look < start) {
|
||||
if (src < start) {
|
||||
@@ -664,7 +731,7 @@ Tcl_UtfPrev(
|
||||
*
|
||||
* Tcl_UniCharAtIndex --
|
||||
*
|
||||
* Returns the Unicode character represented at the specified character
|
||||
* Returns the Tcl_UniChar represented at the specified character
|
||||
* (not byte) position in the UTF-8 string.
|
||||
*
|
||||
* Results:
|
||||
@@ -683,8 +750,7 @@ Tcl_UniCharAtIndex(
|
||||
{
|
||||
Tcl_UniChar ch = 0;
|
||||
|
||||
while (index >= 0) {
|
||||
index--;
|
||||
while (index-- >= 0) {
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
}
|
||||
return ch;
|
||||
@@ -712,12 +778,19 @@ Tcl_UtfAtIndex(
|
||||
register const char *src, /* The UTF-8 string. */
|
||||
register int index) /* The position of the desired character. */
|
||||
{
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
int len = 1;
|
||||
|
||||
while (index > 0) {
|
||||
index--;
|
||||
while (index-- > 0) {
|
||||
len = TclUtfToUniChar(src, &ch);
|
||||
src += len;
|
||||
}
|
||||
#if TCL_UTF_MAX == 4
|
||||
if (!len) {
|
||||
/* Index points at character following High Surrogate */
|
||||
src += TclUtfToUniChar(src, &ch);
|
||||
}
|
||||
#endif
|
||||
return src;
|
||||
}
|
||||
|
||||
@@ -796,7 +869,7 @@ int
|
||||
Tcl_UtfToUpper(
|
||||
char *str) /* String to convert in place. */
|
||||
{
|
||||
Tcl_UniChar ch, upChar;
|
||||
Tcl_UniChar ch = 0, upChar;
|
||||
char *src, *dst;
|
||||
int bytes;
|
||||
|
||||
@@ -849,7 +922,7 @@ int
|
||||
Tcl_UtfToLower(
|
||||
char *str) /* String to convert in place. */
|
||||
{
|
||||
Tcl_UniChar ch, lowChar;
|
||||
Tcl_UniChar ch = 0, lowChar;
|
||||
char *src, *dst;
|
||||
int bytes;
|
||||
|
||||
@@ -903,7 +976,7 @@ int
|
||||
Tcl_UtfToTitle(
|
||||
char *str) /* String to convert in place. */
|
||||
{
|
||||
Tcl_UniChar ch, titleChar, lowChar;
|
||||
Tcl_UniChar ch = 0, titleChar, lowChar;
|
||||
char *src, *dst;
|
||||
int bytes;
|
||||
|
||||
@@ -928,7 +1001,11 @@ Tcl_UtfToTitle(
|
||||
}
|
||||
while (*src) {
|
||||
bytes = TclUtfToUniChar(src, &ch);
|
||||
lowChar = Tcl_UniCharToLower(ch);
|
||||
lowChar = ch;
|
||||
/* Special exception for Georgian Asomtavruli chars, no titlecase. */
|
||||
if ((unsigned)(lowChar - 0x1C90) >= 0x30) {
|
||||
lowChar = Tcl_UniCharToLower(lowChar);
|
||||
}
|
||||
|
||||
if (bytes < UtfCount(lowChar)) {
|
||||
memcpy(dst, src, (size_t) bytes);
|
||||
@@ -1012,11 +1089,11 @@ Tcl_UtfNcmp(
|
||||
const char *ct, /* UTF string cs is compared to. */
|
||||
unsigned long numChars) /* Number of UTF chars to compare. */
|
||||
{
|
||||
Tcl_UniChar ch1, ch2;
|
||||
Tcl_UniChar ch1 = 0, ch2 = 0;
|
||||
|
||||
/*
|
||||
* Cannot use 'memcmp(cs, ct, n);' as byte representation of \u0000 (the
|
||||
* pair of bytes 0xc0,0x80) is larger than byte representation of \u0001
|
||||
* pair of bytes 0xC0,0x80) is larger than byte representation of \u0001
|
||||
* (the byte 0x01.)
|
||||
*/
|
||||
|
||||
@@ -1030,6 +1107,16 @@ Tcl_UtfNcmp(
|
||||
cs += TclUtfToUniChar(cs, &ch1);
|
||||
ct += TclUtfToUniChar(ct, &ch2);
|
||||
if (ch1 != ch2) {
|
||||
#if TCL_UTF_MAX == 4
|
||||
/* Surrogates always report higher than non-surrogates */
|
||||
if (((ch1 & 0xFC00) == 0xD800)) {
|
||||
if ((ch2 & 0xFC00) != 0xD800) {
|
||||
return ch1;
|
||||
}
|
||||
} else if ((ch2 & 0xFC00) == 0xD800) {
|
||||
return -ch2;
|
||||
}
|
||||
#endif
|
||||
return (ch1 - ch2);
|
||||
}
|
||||
}
|
||||
@@ -1060,7 +1147,8 @@ Tcl_UtfNcasecmp(
|
||||
const char *ct, /* UTF string cs is compared to. */
|
||||
unsigned long numChars) /* Number of UTF chars to compare. */
|
||||
{
|
||||
Tcl_UniChar ch1, ch2;
|
||||
Tcl_UniChar ch1 = 0, ch2 = 0;
|
||||
|
||||
while (numChars-- > 0) {
|
||||
/*
|
||||
* n must be interpreted as chars, not bytes.
|
||||
@@ -1070,6 +1158,16 @@ Tcl_UtfNcasecmp(
|
||||
cs += TclUtfToUniChar(cs, &ch1);
|
||||
ct += TclUtfToUniChar(ct, &ch2);
|
||||
if (ch1 != ch2) {
|
||||
#if TCL_UTF_MAX == 4
|
||||
/* Surrogates always report higher than non-surrogates */
|
||||
if (((ch1 & 0xFC00) == 0xD800)) {
|
||||
if ((ch2 & 0xFC00) != 0xD800) {
|
||||
return ch1;
|
||||
}
|
||||
} else if ((ch2 & 0xFC00) == 0xD800) {
|
||||
return -ch2;
|
||||
}
|
||||
#endif
|
||||
ch1 = Tcl_UniCharToLower(ch1);
|
||||
ch2 = Tcl_UniCharToLower(ch2);
|
||||
if (ch1 != ch2) {
|
||||
@@ -1083,7 +1181,7 @@ Tcl_UtfNcasecmp(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_UtfNcasecmp --
|
||||
* TclUtfCasecmp --
|
||||
*
|
||||
* Compare UTF chars of string cs to string ct case insensitively.
|
||||
* Replacement for strcasecmp in Tcl core, in places where UTF-8 should
|
||||
@@ -1103,12 +1201,22 @@ TclUtfCasecmp(
|
||||
const char *cs, /* UTF string to compare to ct. */
|
||||
const char *ct) /* UTF string cs is compared to. */
|
||||
{
|
||||
while (*cs && *ct) {
|
||||
Tcl_UniChar ch1, ch2;
|
||||
Tcl_UniChar ch1 = 0, ch2 = 0;
|
||||
|
||||
while (*cs && *ct) {
|
||||
cs += TclUtfToUniChar(cs, &ch1);
|
||||
ct += TclUtfToUniChar(ct, &ch2);
|
||||
if (ch1 != ch2) {
|
||||
#if TCL_UTF_MAX == 4
|
||||
/* Surrogates always report higher than non-surrogates */
|
||||
if (((ch1 & 0xFC00) == 0xD800)) {
|
||||
if ((ch2 & 0xFC00) != 0xD800) {
|
||||
return ch1;
|
||||
}
|
||||
} else if ((ch2 & 0xFC00) == 0xD800) {
|
||||
return -ch2;
|
||||
}
|
||||
#endif
|
||||
ch1 = Tcl_UniCharToLower(ch1);
|
||||
ch2 = Tcl_UniCharToLower(ch2);
|
||||
if (ch1 != ch2) {
|
||||
@@ -1169,8 +1277,9 @@ Tcl_UniCharToLower(
|
||||
int ch) /* Unicode character to convert. */
|
||||
{
|
||||
int info = GetUniCharInfo(ch);
|
||||
int mode = GetCaseType(info);
|
||||
|
||||
if (GetCaseType(info) & 0x02) {
|
||||
if ((mode & 0x02) && (mode != 0x7)) {
|
||||
ch += GetDelta(info);
|
||||
}
|
||||
return (Tcl_UniChar) ch;
|
||||
@@ -1204,7 +1313,9 @@ Tcl_UniCharToTitle(
|
||||
* Subtract or add one depending on the original case.
|
||||
*/
|
||||
|
||||
ch += ((mode & 0x4) ? -1 : 1);
|
||||
if (mode != 0x7) {
|
||||
ch += ((mode & 0x4) ? -1 : 1);
|
||||
}
|
||||
} else if (mode == 0x4) {
|
||||
ch -= GetDelta(info);
|
||||
}
|
||||
@@ -1400,11 +1511,11 @@ Tcl_UniCharIsControl(
|
||||
{
|
||||
#if TCL_UTF_MAX > 3
|
||||
if (UNICODE_OUT_OF_RANGE(ch)) {
|
||||
ch &= 0x1fffff;
|
||||
if ((ch == 0xe0001) || ((ch >= 0xe0020) && (ch <= 0xe007f))) {
|
||||
ch &= 0x1FFFFF;
|
||||
if ((ch == 0xE0001) || ((ch >= 0xE0020) && (ch <= 0xE007f))) {
|
||||
return 1;
|
||||
}
|
||||
if ((ch >= 0xf0000) && ((ch & 0xffff) <= 0xfffd)) {
|
||||
if ((ch >= 0xF0000) && ((ch & 0xFFFF) <= 0xFFFD)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -1463,8 +1574,8 @@ Tcl_UniCharIsGraph(
|
||||
{
|
||||
#if TCL_UTF_MAX > 3
|
||||
if (UNICODE_OUT_OF_RANGE(ch)) {
|
||||
ch &= 0x1fffff;
|
||||
return (ch >= 0xe0100) && (ch <= 0xe01ef);
|
||||
ch &= 0x1FFFFF;
|
||||
return (ch >= 0xE0100) && (ch <= 0xE01EF);
|
||||
}
|
||||
#endif
|
||||
return ((GRAPH_BITS >> GetCategory(ch)) & 1);
|
||||
@@ -1520,8 +1631,8 @@ Tcl_UniCharIsPrint(
|
||||
{
|
||||
#if TCL_UTF_MAX > 3
|
||||
if (UNICODE_OUT_OF_RANGE(ch)) {
|
||||
ch &= 0x1fffff;
|
||||
return (ch >= 0xe0100) && (ch <= 0xe01ef);
|
||||
ch &= 0x1FFFFF;
|
||||
return (ch >= 0xE0100) && (ch <= 0xE01EF);
|
||||
}
|
||||
#endif
|
||||
return (((GRAPH_BITS|SPACE_BITS) >> GetCategory(ch)) & 1);
|
||||
@@ -1577,10 +1688,10 @@ Tcl_UniCharIsSpace(
|
||||
{
|
||||
#if TCL_UTF_MAX > 3
|
||||
/* Ignore upper 11 bits. */
|
||||
ch &= 0x1fffff;
|
||||
ch &= 0x1FFFFF;
|
||||
#else
|
||||
/* Ignore upper 16 bits. */
|
||||
ch &= 0xffff;
|
||||
ch &= 0xFFFF;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1594,8 +1705,8 @@ Tcl_UniCharIsSpace(
|
||||
} else if (UNICODE_OUT_OF_RANGE(ch)) {
|
||||
return 0;
|
||||
#endif
|
||||
} else if (ch == 0x0085 || ch == 0x180e || ch == 0x200b
|
||||
|| ch == 0x202f || ch == 0x2060 || ch == 0xfeff) {
|
||||
} else if (ch == 0x0085 || ch == 0x180E || ch == 0x200B
|
||||
|| ch == 0x202F || ch == 0x2060 || ch == 0xFEFF) {
|
||||
return 1;
|
||||
} else {
|
||||
return ((SPACE_BITS >> GetCategory(ch)) & 1);
|
||||
@@ -1689,7 +1800,7 @@ Tcl_UniCharCaseMatch(
|
||||
* characters. */
|
||||
int nocase) /* 0 for case sensitive, 1 for insensitive */
|
||||
{
|
||||
Tcl_UniChar ch1, p;
|
||||
Tcl_UniChar ch1 = 0, p;
|
||||
|
||||
while (1) {
|
||||
p = *uniPattern;
|
||||
|
||||
+389
-117
@@ -107,6 +107,8 @@ static Tcl_ThreadDataKey precisionKey;
|
||||
static void ClearHash(Tcl_HashTable *tablePtr);
|
||||
static void FreeProcessGlobalValue(ClientData clientData);
|
||||
static void FreeThreadHash(ClientData clientData);
|
||||
static int GetEndOffsetFromObj(Tcl_Obj *objPtr, int endValue,
|
||||
int *indexPtr);
|
||||
static Tcl_HashTable * GetThreadHash(Tcl_ThreadDataKey *keyPtr);
|
||||
static int SetEndOffsetFromAny(Tcl_Interp *interp,
|
||||
Tcl_Obj *objPtr);
|
||||
@@ -974,7 +976,7 @@ Tcl_ScanCountedElement(
|
||||
int *flagPtr) /* Where to store information to guide
|
||||
* Tcl_ConvertElement. */
|
||||
{
|
||||
int flags = CONVERT_ANY;
|
||||
char flags = CONVERT_ANY;
|
||||
int numBytes = TclScanElement(src, length, &flags);
|
||||
|
||||
*flagPtr = flags;
|
||||
@@ -1015,7 +1017,7 @@ int
|
||||
TclScanElement(
|
||||
const char *src, /* String to convert to Tcl list element. */
|
||||
int length, /* Number of bytes in src, or -1. */
|
||||
int *flagPtr) /* Where to store information to guide
|
||||
char *flagPtr) /* Where to store information to guide
|
||||
* Tcl_ConvertElement. */
|
||||
{
|
||||
const char *p = src;
|
||||
@@ -1547,11 +1549,10 @@ Tcl_Merge(
|
||||
int argc, /* How many strings to merge. */
|
||||
const char *const *argv) /* Array of string values. */
|
||||
{
|
||||
#define LOCAL_SIZE 20
|
||||
int localFlags[LOCAL_SIZE], *flagPtr = NULL;
|
||||
#define LOCAL_SIZE 64
|
||||
char localFlags[LOCAL_SIZE], *flagPtr = NULL;
|
||||
int i, bytesNeeded = 0;
|
||||
char *result, *dst;
|
||||
const int maxFlags = UINT_MAX / sizeof(int);
|
||||
|
||||
/*
|
||||
* Handle empty list case first, so logic of the general case can be
|
||||
@@ -1570,22 +1571,8 @@ Tcl_Merge(
|
||||
|
||||
if (argc <= LOCAL_SIZE) {
|
||||
flagPtr = localFlags;
|
||||
} else if (argc > maxFlags) {
|
||||
/*
|
||||
* We cannot allocate a large enough flag array to format this list in
|
||||
* one pass. We could imagine converting this routine to a multi-pass
|
||||
* implementation, but for sizeof(int) == 4, the limit is a max of
|
||||
* 2^30 list elements and since each element is at least one byte
|
||||
* formatted, and requires one byte space between it and the next one,
|
||||
* that a minimum space requirement of 2^31 bytes, which is already
|
||||
* INT_MAX. If we tried to format a list of > maxFlags elements, we're
|
||||
* just going to overflow the size limits on the formatted string
|
||||
* anyway, so just issue that same panic early.
|
||||
*/
|
||||
|
||||
Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
|
||||
} else {
|
||||
flagPtr = ckalloc(argc * sizeof(int));
|
||||
flagPtr = ckalloc(argc);
|
||||
}
|
||||
for (i = 0; i < argc; i++) {
|
||||
flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 );
|
||||
@@ -1646,7 +1633,7 @@ Tcl_Backslash(
|
||||
* src, unless NULL. */
|
||||
{
|
||||
char buf[TCL_UTF_MAX];
|
||||
Tcl_UniChar ch;
|
||||
Tcl_UniChar ch = 0;
|
||||
|
||||
Tcl_UtfBackslash(src, readPtr, buf);
|
||||
TclUtfToUniChar(buf, &ch);
|
||||
@@ -1656,11 +1643,46 @@ Tcl_Backslash(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclTrimRight --
|
||||
* UtfWellFormedEnd --
|
||||
* Checks the end of utf string is malformed, if yes - wraps bytes
|
||||
* to the given buffer (as well-formed NTS string). The buffer
|
||||
* argument should be initialized by the caller and ready to use.
|
||||
*
|
||||
* Takes two counted strings in the Tcl encoding which must both be null
|
||||
* terminated. Conceptually trims from the right side of the first string
|
||||
* all characters found in the second string.
|
||||
* Results:
|
||||
* The bytes with well-formed end of the string.
|
||||
*
|
||||
* Side effects:
|
||||
* Buffer (DString) may be allocated, so must be released.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static inline const char*
|
||||
UtfWellFormedEnd(
|
||||
Tcl_DString *buffer, /* Buffer used to hold well-formed string. */
|
||||
const char *bytes, /* Pointer to the beginning of the string. */
|
||||
int length) /* Length of the string. */
|
||||
{
|
||||
const char *l = bytes + length;
|
||||
const char *p = Tcl_UtfPrev(l, bytes);
|
||||
|
||||
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.
|
||||
*/
|
||||
Tcl_DStringAppend(buffer, bytes, length);
|
||||
return Tcl_DStringValue(buffer);
|
||||
}
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclTrimRight --
|
||||
* Takes two counted strings in the Tcl encoding. Conceptually
|
||||
* finds the sub string (offset) to trim from the right side of the
|
||||
* first string all characters found in the second string.
|
||||
*
|
||||
* Results:
|
||||
* The number of bytes to be removed from the end of the string.
|
||||
@@ -1671,8 +1693,8 @@ Tcl_Backslash(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
TclTrimRight(
|
||||
static inline int
|
||||
TrimRight(
|
||||
const char *bytes, /* String to be trimmed... */
|
||||
int numBytes, /* ...and its length in bytes */
|
||||
const char *trim, /* String of trim characters... */
|
||||
@@ -1681,18 +1703,6 @@ TclTrimRight(
|
||||
const char *p = bytes + numBytes;
|
||||
int pInc;
|
||||
|
||||
if ((bytes[numBytes] != '\0') || (trim[numTrim] != '\0')) {
|
||||
Tcl_Panic("TclTrimRight works only on null-terminated strings");
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty strings -> nothing to do.
|
||||
*/
|
||||
|
||||
if ((numBytes == 0) || (numTrim == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Outer loop: iterate over string to be trimmed.
|
||||
*/
|
||||
@@ -1733,15 +1743,46 @@ TclTrimRight(
|
||||
|
||||
return numBytes - (p - bytes);
|
||||
}
|
||||
|
||||
int
|
||||
TclTrimRight(
|
||||
const char *bytes, /* String to be trimmed... */
|
||||
int numBytes, /* ...and its length in bytes */
|
||||
const char *trim, /* String of trim characters... */
|
||||
int numTrim) /* ...and its length in bytes */
|
||||
{
|
||||
int res;
|
||||
Tcl_DString bytesBuf, trimBuf;
|
||||
|
||||
/* Empty strings -> nothing to do */
|
||||
if ((numBytes == 0) || (numTrim == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Tcl_DStringInit(&bytesBuf);
|
||||
Tcl_DStringInit(&trimBuf);
|
||||
bytes = UtfWellFormedEnd(&bytesBuf, bytes, numBytes);
|
||||
trim = UtfWellFormedEnd(&trimBuf, trim, numTrim);
|
||||
|
||||
res = TrimRight(bytes, numBytes, trim, numTrim);
|
||||
if (res > numBytes) {
|
||||
res = numBytes;
|
||||
}
|
||||
|
||||
Tcl_DStringFree(&bytesBuf);
|
||||
Tcl_DStringFree(&trimBuf);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclTrimLeft --
|
||||
*
|
||||
* Takes two counted strings in the Tcl encoding which must both be null
|
||||
* terminated. Conceptually trims from the left side of the first string
|
||||
* all characters found in the second string.
|
||||
* Takes two counted strings in the Tcl encoding. Conceptually
|
||||
* finds the sub string (offset) to trim from the left side of the
|
||||
* first string all characters found in the second string.
|
||||
*
|
||||
* Results:
|
||||
* The number of bytes to be removed from the start of the string.
|
||||
@@ -1752,8 +1793,8 @@ TclTrimRight(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
TclTrimLeft(
|
||||
static inline int
|
||||
TrimLeft(
|
||||
const char *bytes, /* String to be trimmed... */
|
||||
int numBytes, /* ...and its length in bytes */
|
||||
const char *trim, /* String of trim characters... */
|
||||
@@ -1761,18 +1802,6 @@ TclTrimLeft(
|
||||
{
|
||||
const char *p = bytes;
|
||||
|
||||
if ((bytes[numBytes] != '\0') || (trim[numTrim] != '\0')) {
|
||||
Tcl_Panic("TclTrimLeft works only on null-terminated strings");
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty strings -> nothing to do.
|
||||
*/
|
||||
|
||||
if ((numBytes == 0) || (numTrim == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Outer loop: iterate over string to be trimmed.
|
||||
*/
|
||||
@@ -1809,10 +1838,99 @@ TclTrimLeft(
|
||||
|
||||
p += pInc;
|
||||
numBytes -= pInc;
|
||||
} while (numBytes);
|
||||
} while (numBytes > 0);
|
||||
|
||||
return p - bytes;
|
||||
}
|
||||
|
||||
int
|
||||
TclTrimLeft(
|
||||
const char *bytes, /* String to be trimmed... */
|
||||
int numBytes, /* ...and its length in bytes */
|
||||
const char *trim, /* String of trim characters... */
|
||||
int numTrim) /* ...and its length in bytes */
|
||||
{
|
||||
int res;
|
||||
Tcl_DString bytesBuf, trimBuf;
|
||||
|
||||
/* Empty strings -> nothing to do */
|
||||
if ((numBytes == 0) || (numTrim == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Tcl_DStringInit(&bytesBuf);
|
||||
Tcl_DStringInit(&trimBuf);
|
||||
bytes = UtfWellFormedEnd(&bytesBuf, bytes, numBytes);
|
||||
trim = UtfWellFormedEnd(&trimBuf, trim, numTrim);
|
||||
|
||||
res = TrimLeft(bytes, numBytes, trim, numTrim);
|
||||
if (res > numBytes) {
|
||||
res = numBytes;
|
||||
}
|
||||
|
||||
Tcl_DStringFree(&bytesBuf);
|
||||
Tcl_DStringFree(&trimBuf);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclTrim --
|
||||
* Finds the sub string (offset) to trim from both sides of the
|
||||
* first string all characters found in the second string.
|
||||
*
|
||||
* Results:
|
||||
* The number of bytes to be removed from the start of the string
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
TclTrim(
|
||||
const char *bytes, /* String to be trimmed... */
|
||||
int numBytes, /* ...and its length in bytes */
|
||||
const char *trim, /* String of trim characters... */
|
||||
int numTrim, /* ...and its length in bytes */
|
||||
int *trimRight) /* Offset from the end of the string. */
|
||||
{
|
||||
int trimLeft;
|
||||
Tcl_DString bytesBuf, trimBuf;
|
||||
|
||||
*trimRight = 0;
|
||||
/* Empty strings -> nothing to do */
|
||||
if ((numBytes == 0) || (numTrim == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Tcl_DStringInit(&bytesBuf);
|
||||
Tcl_DStringInit(&trimBuf);
|
||||
bytes = UtfWellFormedEnd(&bytesBuf, bytes, numBytes);
|
||||
trim = UtfWellFormedEnd(&trimBuf, trim, numTrim);
|
||||
|
||||
trimLeft = TrimLeft(bytes, numBytes, trim, numTrim);
|
||||
if (trimLeft > numBytes) {
|
||||
trimLeft = numBytes;
|
||||
}
|
||||
numBytes -= trimLeft;
|
||||
/* have to trim yet (first char was already verified within TrimLeft) */
|
||||
if (numBytes > 1) {
|
||||
bytes += trimLeft;
|
||||
*trimRight = TrimRight(bytes, numBytes, trim, numTrim);
|
||||
if (*trimRight > numBytes) {
|
||||
*trimRight = numBytes;
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_DStringFree(&bytesBuf);
|
||||
Tcl_DStringFree(&trimBuf);
|
||||
|
||||
return trimLeft;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -1880,30 +1998,20 @@ Tcl_Concat(
|
||||
result = ckalloc((unsigned) (bytesNeeded + argc));
|
||||
|
||||
for (p = result, i = 0; i < argc; i++) {
|
||||
int trim, elemLength;
|
||||
int triml, trimr, elemLength;
|
||||
const char *element;
|
||||
|
||||
element = argv[i];
|
||||
elemLength = strlen(argv[i]);
|
||||
|
||||
/*
|
||||
* Trim away the leading whitespace.
|
||||
*/
|
||||
/* Trim away the leading/trailing whitespace. */
|
||||
triml = TclTrim(element, elemLength, CONCAT_TRIM_SET,
|
||||
CONCAT_WS_SIZE, &trimr);
|
||||
element += triml;
|
||||
elemLength -= triml + trimr;
|
||||
|
||||
trim = TclTrimLeft(element, elemLength, CONCAT_TRIM_SET,
|
||||
CONCAT_WS_SIZE);
|
||||
element += trim;
|
||||
elemLength -= trim;
|
||||
|
||||
/*
|
||||
* Trim away the trailing whitespace. Do not permit trimming to expose
|
||||
* a final backslash character.
|
||||
*/
|
||||
|
||||
trim = TclTrimRight(element, elemLength, CONCAT_TRIM_SET,
|
||||
CONCAT_WS_SIZE);
|
||||
trim -= trim && (element[elemLength - trim - 1] == '\\');
|
||||
elemLength -= trim;
|
||||
/* Do not permit trimming to expose a final backslash character. */
|
||||
elemLength += trimr && (element[elemLength - 1] == '\\');
|
||||
|
||||
/*
|
||||
* If we're left with empty element after trimming, do nothing.
|
||||
@@ -2023,28 +2131,18 @@ Tcl_ConcatObj(
|
||||
Tcl_SetObjLength(resPtr, 0);
|
||||
|
||||
for (i = 0; i < objc; i++) {
|
||||
int trim;
|
||||
int triml, trimr;
|
||||
|
||||
element = TclGetStringFromObj(objv[i], &elemLength);
|
||||
|
||||
/*
|
||||
* Trim away the leading whitespace.
|
||||
*/
|
||||
/* Trim away the leading/trailing whitespace. */
|
||||
triml = TclTrim(element, elemLength, CONCAT_TRIM_SET,
|
||||
CONCAT_WS_SIZE, &trimr);
|
||||
element += triml;
|
||||
elemLength -= triml + trimr;
|
||||
|
||||
trim = TclTrimLeft(element, elemLength, CONCAT_TRIM_SET,
|
||||
CONCAT_WS_SIZE);
|
||||
element += trim;
|
||||
elemLength -= trim;
|
||||
|
||||
/*
|
||||
* Trim away the trailing whitespace. Do not permit trimming to expose
|
||||
* a final backslash character.
|
||||
*/
|
||||
|
||||
trim = TclTrimRight(element, elemLength, CONCAT_TRIM_SET,
|
||||
CONCAT_WS_SIZE);
|
||||
trim -= trim && (element[elemLength - trim - 1] == '\\');
|
||||
elemLength -= trim;
|
||||
/* Do not permit trimming to expose a final backslash character. */
|
||||
elemLength += trimr && (element[elemLength - 1] == '\\');
|
||||
|
||||
/*
|
||||
* If we're left with empty element after trimming, do nothing.
|
||||
@@ -2545,7 +2643,8 @@ TclStringMatchObj(
|
||||
udata = Tcl_GetUnicodeFromObj(strObj, &length);
|
||||
uptn = Tcl_GetUnicodeFromObj(ptnObj, &plen);
|
||||
match = TclUniCharMatch(udata, length, uptn, plen, flags);
|
||||
} else if (TclIsPureByteArray(strObj) && !flags) {
|
||||
} else if (TclIsPureByteArray(strObj) && TclIsPureByteArray(ptnObj)
|
||||
&& !flags) {
|
||||
unsigned char *data, *ptn;
|
||||
|
||||
data = Tcl_GetByteArrayFromObj(strObj, &length);
|
||||
@@ -2717,7 +2816,7 @@ Tcl_DStringAppendElement(
|
||||
{
|
||||
char *dst = dsPtr->string + dsPtr->length;
|
||||
int needSpace = TclNeedSpace(dsPtr->string, dst);
|
||||
int flags = needSpace ? TCL_DONT_QUOTE_HASH : 0;
|
||||
char flags = needSpace ? TCL_DONT_QUOTE_HASH : 0;
|
||||
int newSize = dsPtr->length + needSpace
|
||||
+ TclScanElement(element, -1, &flags);
|
||||
|
||||
@@ -3545,22 +3644,27 @@ TclFormatInt(
|
||||
*
|
||||
* TclGetIntForIndex --
|
||||
*
|
||||
* This function returns an integer corresponding to the list index held
|
||||
* in a Tcl object. The Tcl object's value is expected to be in the
|
||||
* format integer([+-]integer)? or the format end([+-]integer)?.
|
||||
*
|
||||
* Results:
|
||||
* The return value is normally TCL_OK, which means that the index was
|
||||
* successfully stored into the location referenced by "indexPtr". If the
|
||||
* Tcl object referenced by "objPtr" has the value "end", the value
|
||||
* stored is "endValue". If "objPtr"s values is not of one of the
|
||||
* expected formats, TCL_ERROR is returned and, if "interp" is non-NULL,
|
||||
* an error message is left in the interpreter's result object.
|
||||
*
|
||||
* Side effects:
|
||||
* The object referenced by "objPtr" might be converted to an integer,
|
||||
* wide integer, or end-based-index object.
|
||||
* Provides an integer corresponding to the list index held in a Tcl
|
||||
* object. The string value 'objPtr' is expected have the format
|
||||
* integer([+-]integer)? or end([+-]integer)?.
|
||||
*
|
||||
* Value
|
||||
* TCL_OK
|
||||
*
|
||||
* The index is stored at the address given by by 'indexPtr'. If
|
||||
* 'objPtr' has the value "end", the value stored is 'endValue'.
|
||||
*
|
||||
* TCL_ERROR
|
||||
*
|
||||
* The value of 'objPtr' does not have one of the expected formats. If
|
||||
* 'interp' is non-NULL, an error message is left in the interpreter's
|
||||
* result object.
|
||||
*
|
||||
* Effect
|
||||
*
|
||||
* The object referenced by 'objPtr' is converted, as needed, to an
|
||||
* integer, wide integer, or end-based-index object.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -3584,13 +3688,7 @@ TclGetIntForIndex(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) {
|
||||
/*
|
||||
* If the object is already an offset from the end of the list, or can
|
||||
* be converted to one, use it.
|
||||
*/
|
||||
|
||||
*indexPtr = endValue + objPtr->internalRep.longValue;
|
||||
if (GetEndOffsetFromObj(objPtr, endValue, indexPtr) == TCL_OK) {
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -3690,6 +3788,41 @@ UpdateStringOfEndOffset(
|
||||
objPtr->length = len;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* GetEndOffsetFromObj --
|
||||
*
|
||||
* Look for a string of the form "end[+-]offset" and convert it to an
|
||||
* internal representation holding the offset.
|
||||
*
|
||||
* Results:
|
||||
* Tcl return code.
|
||||
*
|
||||
* Side effects:
|
||||
* May store a Tcl_ObjType.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int
|
||||
GetEndOffsetFromObj(
|
||||
Tcl_Obj *objPtr, /* Pointer to the object to parse */
|
||||
int endValue, /* The value to be stored at "indexPtr" if
|
||||
* "objPtr" holds "end". */
|
||||
int *indexPtr) /* Location filled in with an integer
|
||||
* representing an index. */
|
||||
{
|
||||
if (SetEndOffsetFromAny(NULL, objPtr) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* TODO: Handle overflow cases sensibly */
|
||||
*indexPtr = endValue + (int)objPtr->internalRep.longValue;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -3759,6 +3892,8 @@ SetEndOffsetFromAny(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (bytes[3] == '-') {
|
||||
|
||||
/* TODO: Review overflow concerns here! */
|
||||
offset = -offset;
|
||||
}
|
||||
} else {
|
||||
@@ -3787,6 +3922,143 @@ SetEndOffsetFromAny(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclIndexEncode --
|
||||
*
|
||||
* Parse objPtr to determine if it is an index value. Two cases
|
||||
* are possible. The value objPtr might be parsed as an absolute
|
||||
* index value in the C signed int range. Note that this includes
|
||||
* index values that are integers as presented and it includes index
|
||||
* arithmetic expressions. The absolute index values that can be
|
||||
* directly meaningful as an index into either a list or a string are
|
||||
* those integer values >= TCL_INDEX_START (0)
|
||||
* and < TCL_INDEX_AFTER (INT_MAX).
|
||||
* The largest string supported in Tcl 8 has bytelength INT_MAX.
|
||||
* This means the largest supported character length is also INT_MAX,
|
||||
* and the index of the last character in a string of length INT_MAX
|
||||
* is INT_MAX-1.
|
||||
*
|
||||
* Any absolute index value parsed outside that range is encoded
|
||||
* using the before and after values passed in by the
|
||||
* caller as the encoding to use for indices that are either
|
||||
* less than or greater than the usable index range. TCL_INDEX_AFTER
|
||||
* is available as a good choice for most callers to use for
|
||||
* after. Likewise, the value TCL_INDEX_BEFORE is good for
|
||||
* most callers to use for before. Other values are possible
|
||||
* when the caller knows it is helpful in producing its own behavior
|
||||
* for indices before and after the indexed item.
|
||||
*
|
||||
* A token can also be parsed as an end-relative index expression.
|
||||
* All end-relative expressions that indicate an index larger
|
||||
* than end (end+2, end--5) point beyond the end of the indexed
|
||||
* collection, and can be encoded as after. The end-relative
|
||||
* expressions that indicate an index less than or equal to end
|
||||
* are encoded relative to the value TCL_INDEX_END (-2). The
|
||||
* index "end" is encoded as -2, down to the index "end-0x7ffffffe"
|
||||
* which is encoded as INT_MIN. Since the largest index into a
|
||||
* string possible in Tcl 8 is 0x7ffffffe, the interpretation of
|
||||
* "end-0x7ffffffe" for that largest string would be 0. Thus,
|
||||
* if the tokens "end-0x7fffffff" or "end+-0x80000000" are parsed,
|
||||
* they can be encoded with the before value.
|
||||
*
|
||||
* These details will require re-examination whenever string and
|
||||
* list length limits are increased, but that will likely also
|
||||
* mean a revised routine capable of returning Tcl_WideInt values.
|
||||
*
|
||||
* Returns:
|
||||
* TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
|
||||
*
|
||||
* Side effects:
|
||||
* When TCL_OK is returned, the encoded index value is written
|
||||
* to *indexPtr.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
TclIndexEncode(
|
||||
Tcl_Interp *interp, /* For error reporting, may be NULL */
|
||||
Tcl_Obj *objPtr, /* Index value to parse */
|
||||
int before, /* Value to return for index before beginning */
|
||||
int after, /* Value to return for index after end */
|
||||
int *indexPtr) /* Where to write the encoded answer, not NULL */
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (TCL_OK == TclGetIntFromObj(NULL, objPtr, &idx)) {
|
||||
/* We parsed a value in the range INT_MIN...INT_MAX */
|
||||
integerEncode:
|
||||
if (idx < TCL_INDEX_START) {
|
||||
/* All negative absolute indices are "before the beginning" */
|
||||
idx = before;
|
||||
} else if (idx == INT_MAX) {
|
||||
/* This index value is always "after the end" */
|
||||
idx = after;
|
||||
}
|
||||
/* usual case, the absolute index value encodes itself */
|
||||
} else if (TCL_OK == GetEndOffsetFromObj(objPtr, 0, &idx)) {
|
||||
/*
|
||||
* 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
|
||||
* always indicate "after the end".
|
||||
*/
|
||||
idx = after;
|
||||
} else if (idx < INT_MIN - TCL_INDEX_END) {
|
||||
/* These indices always indicate "before the beginning */
|
||||
idx = before;
|
||||
} else {
|
||||
/* Encoded end-positive (or end+negative) are offset */
|
||||
idx += TCL_INDEX_END;
|
||||
}
|
||||
|
||||
/* TODO: Consider flag to suppress repeated end-offset parse. */
|
||||
} else if (TCL_OK == TclGetIntForIndexM(interp, objPtr, 0, &idx)) {
|
||||
/*
|
||||
* Only reach this case when the index value is a
|
||||
* constant index arithmetic expression, and idx
|
||||
* holds the result. Treat it the same as if it were
|
||||
* parsed as an absolute integer value.
|
||||
*/
|
||||
goto integerEncode;
|
||||
} else {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
*indexPtr = idx;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclIndexDecode --
|
||||
*
|
||||
* Decodes a value previously encoded by TclIndexEncode. The argument
|
||||
* endValue indicates what value of "end" should be used in the
|
||||
* decoding.
|
||||
*
|
||||
* Results:
|
||||
* The decoded index value.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
TclIndexDecode(
|
||||
int encoded, /* Value to decode */
|
||||
int endValue) /* Meaning of "end" to use, > TCL_INDEX_END */
|
||||
{
|
||||
if (encoded <= TCL_INDEX_END) {
|
||||
return (encoded - TCL_INDEX_END) + endValue;
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
+510
-559
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -203,7 +203,7 @@ proc auto_mkindex {dir args} {
|
||||
}
|
||||
|
||||
auto_mkindex_parser::init
|
||||
foreach file [glob -- {*}$args] {
|
||||
foreach file [lsort [glob -- {*}$args]] {
|
||||
try {
|
||||
append index [auto_mkindex_parser::mkindex $file]
|
||||
} on error {msg opts} {
|
||||
@@ -236,7 +236,7 @@ proc auto_mkindex_old {dir args} {
|
||||
if {![llength $args]} {
|
||||
set args *.tcl
|
||||
}
|
||||
foreach file [glob -- {*}$args] {
|
||||
foreach file [lsort [glob -- {*}$args]] {
|
||||
set f ""
|
||||
set error [catch {
|
||||
set f [open $file]
|
||||
|
||||
+2673
-239
File diff suppressed because it is too large
Load Diff
+2179
-335
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
||||
if {![package vsatisfies [package provide Tcl] 8.6-]} {return}
|
||||
package ifneeded http 2.8.11 [list tclPkgSetup $dir http 2.8.11 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}]
|
||||
package ifneeded http 2.9.0 [list tclPkgSetup $dir http 2.9.0 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}]
|
||||
|
||||
+70
-88
@@ -16,7 +16,7 @@
|
||||
if {[info commands package] == ""} {
|
||||
error "version mismatch: library\nscripts expect Tcl version 7.5b1 or later but the loaded version is\nonly [info patchlevel]"
|
||||
}
|
||||
package require -exact Tcl 8.6.6
|
||||
package require -exact Tcl 8.6.8
|
||||
|
||||
# Compute the auto path to use in this interpreter.
|
||||
# The values on the path come from several locations:
|
||||
@@ -45,7 +45,6 @@ if {![info exists auto_path]} {
|
||||
set auto_path ""
|
||||
}
|
||||
}
|
||||
|
||||
namespace eval tcl {
|
||||
variable Dir
|
||||
foreach Dir [list $::tcl_library [file dirname $::tcl_library]] {
|
||||
@@ -67,12 +66,12 @@ namespace eval tcl {
|
||||
}
|
||||
|
||||
if {![interp issafe]} {
|
||||
variable Path [encoding dirs]
|
||||
set Dir [file join $::tcl_library encoding]
|
||||
if {$Dir ni $Path} {
|
||||
variable Path [encoding dirs]
|
||||
set Dir [file join $::tcl_library encoding]
|
||||
if {$Dir ni $Path} {
|
||||
lappend Path $Dir
|
||||
encoding dirs $Path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# TIP #255 min and max functions
|
||||
@@ -156,17 +155,6 @@ if {(![interp issafe]) && ($tcl_platform(platform) eq "windows")} {
|
||||
if {[interp issafe]} {
|
||||
package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
|
||||
} else {
|
||||
# Default known auto_index (avoid loading auto index implicit after interp create):
|
||||
|
||||
array set ::auto_index {
|
||||
::tcl::tm::UnknownHandler {source [info library]/tm.tcl}
|
||||
::tclPkgUnknown {source [info library]/package.tcl}
|
||||
::history {source [info library]/history.tcl}
|
||||
}
|
||||
|
||||
# The newest possibility to load whole namespace:
|
||||
array set ::auto_index_ns {}
|
||||
|
||||
# Set up search for Tcl Modules (TIP #189).
|
||||
# and setup platform specific unknown package handlers
|
||||
if {$tcl_platform(os) eq "Darwin"
|
||||
@@ -179,21 +167,22 @@ if {[interp issafe]} {
|
||||
|
||||
# Set up the 'clock' ensemble
|
||||
|
||||
proc clock args {
|
||||
set cmdmap [dict create]
|
||||
foreach cmd {add clicks format microseconds milliseconds scan seconds configure} {
|
||||
dict set cmdmap $cmd ::tcl::clock::$cmd
|
||||
}
|
||||
namespace inscope ::tcl::clock [list namespace ensemble create -command \
|
||||
[uplevel 1 [list ::namespace origin [::lindex [info level 0] 0]]] \
|
||||
-map $cmdmap -compile 1]
|
||||
namespace eval ::tcl::clock [list variable TclLibDir $::tcl_library]
|
||||
|
||||
uplevel 1 [info level 0]
|
||||
proc ::tcl::initClock {} {
|
||||
# Auto-loading stubs for 'clock.tcl'
|
||||
|
||||
foreach cmd {add format scan} {
|
||||
proc ::tcl::clock::$cmd args {
|
||||
variable TclLibDir
|
||||
source -encoding utf-8 [file join $TclLibDir clock.tcl]
|
||||
return [uplevel 1 [info level 0]]
|
||||
}
|
||||
}
|
||||
|
||||
rename ::tcl::initClock {}
|
||||
}
|
||||
# Auto-loading stubs for 'clock.tcl'
|
||||
set ::auto_index_ns(::tcl::clock) {::namespace inscope ::tcl::clock {
|
||||
::source -encoding utf-8 [::file join [info library] clock.tcl]
|
||||
}}
|
||||
::tcl::initClock
|
||||
}
|
||||
|
||||
# Conditionalize for presence of exec.
|
||||
@@ -295,14 +284,9 @@ proc unknown args {
|
||||
}
|
||||
append cinfo ...
|
||||
}
|
||||
append cinfo "\"\n (\"uplevel\" body line 1)"
|
||||
append cinfo "\n invoked from within"
|
||||
append cinfo "\n\"uplevel 1 \$args\""
|
||||
#
|
||||
# Try each possible form of the stack trace
|
||||
# and trim the extra contribution from the matching case
|
||||
#
|
||||
set expect "$msg\n while executing\n\"$cinfo"
|
||||
set tail "\n (\"uplevel\" body line 1)\n invoked\
|
||||
from within\n\"uplevel 1 \$args\""
|
||||
set expect "$msg\n while executing\n\"$cinfo\"$tail"
|
||||
if {$errInfo eq $expect} {
|
||||
#
|
||||
# The stack has only the eval from the expanded command
|
||||
@@ -316,21 +300,32 @@ proc unknown args {
|
||||
# Stack trace is nested, trim off just the contribution
|
||||
# from the extra "eval" of $args due to the "catch" above.
|
||||
#
|
||||
set expect "\n invoked from within\n\"$cinfo"
|
||||
set exlen [string length $expect]
|
||||
set eilen [string length $errInfo]
|
||||
set i [expr {$eilen - $exlen - 1}]
|
||||
set einfo [string range $errInfo 0 $i]
|
||||
#
|
||||
# For now verify that $errInfo consists of what we are about
|
||||
# to return plus what we expected to trim off.
|
||||
#
|
||||
if {$errInfo ne "$einfo$expect"} {
|
||||
error "Tcl bug: unexpected stack trace in \"unknown\"" {} \
|
||||
[list CORE UNKNOWN BADTRACE $einfo $expect $errInfo]
|
||||
set last [string last $tail $errInfo]
|
||||
if {$last + [string length $tail] != [string length $errInfo]} {
|
||||
# Very likely cannot happen
|
||||
return -options $opts $msg
|
||||
}
|
||||
return -code error -errorcode $errCode \
|
||||
-errorinfo $einfo $msg
|
||||
set errInfo [string range $errInfo 0 $last-1]
|
||||
set tail "\"$cinfo\""
|
||||
set last [string last $tail $errInfo]
|
||||
if {$last + [string length $tail] != [string length $errInfo]} {
|
||||
return -code error -errorcode $errCode \
|
||||
-errorinfo $errInfo $msg
|
||||
}
|
||||
set errInfo [string range $errInfo 0 $last-1]
|
||||
set tail "\n invoked from within\n"
|
||||
set last [string last $tail $errInfo]
|
||||
if {$last + [string length $tail] == [string length $errInfo]} {
|
||||
return -code error -errorcode $errCode \
|
||||
-errorinfo [string range $errInfo 0 $last-1] $msg
|
||||
}
|
||||
set tail "\n while executing\n"
|
||||
set last [string last $tail $errInfo]
|
||||
if {$last + [string length $tail] == [string length $errInfo]} {
|
||||
return -code error -errorcode $errCode \
|
||||
-errorinfo [string range $errInfo 0 $last-1] $msg
|
||||
}
|
||||
return -options $opts $msg
|
||||
} else {
|
||||
dict incr opts -level
|
||||
return -options $opts $msg
|
||||
@@ -421,22 +416,18 @@ proc unknown args {
|
||||
# for instance. If not given, namespace current is used.
|
||||
|
||||
proc auto_load {cmd {namespace {}}} {
|
||||
global auto_index auto_index_ns auto_path
|
||||
global auto_index auto_path
|
||||
|
||||
# qualify names:
|
||||
if {$namespace eq ""} {
|
||||
set namespace [uplevel 1 [list ::namespace current]]
|
||||
}
|
||||
set nameList [auto_qualify $cmd $namespace]
|
||||
# workaround non canonical auto_index entries that might be around
|
||||
# from older auto_mkindex versions
|
||||
if {$cmd ni $nameList} {lappend nameList $cmd}
|
||||
|
||||
# try to load (and create sub-cmd handler "_sub_load_cmd" for further usage):
|
||||
foreach name $nameList [set _sub_load_cmd {
|
||||
# via auto_index:
|
||||
lappend nameList $cmd
|
||||
foreach name $nameList {
|
||||
if {[info exists auto_index($name)]} {
|
||||
namespace inscope :: $auto_index($name)
|
||||
namespace eval :: $auto_index($name)
|
||||
# There's a couple of ways to look for a command of a given
|
||||
# name. One is to use
|
||||
# info commands $name
|
||||
@@ -448,31 +439,22 @@ proc auto_load {cmd {namespace {}}} {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
# via auto_index_ns - resolver for the whole namespace loaders
|
||||
if {[set ns [::namespace qualifiers $name]] ni {"" "::"} &&
|
||||
[info exists auto_index_ns($ns)]
|
||||
} {
|
||||
# remove handler before loading (prevents several self-recursion cases):
|
||||
set ldr $auto_index_ns($ns); unset auto_index_ns($ns)
|
||||
namespace inscope :: $ldr
|
||||
# if got it:
|
||||
}
|
||||
if {![info exists auto_path]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
if {![auto_load_index]} {
|
||||
return 0
|
||||
}
|
||||
foreach name $nameList {
|
||||
if {[info exists auto_index($name)]} {
|
||||
namespace eval :: $auto_index($name)
|
||||
if {[namespace which -command $name] ne ""} {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
# load auto_index if possible:
|
||||
if {![info exists auto_path]} {
|
||||
return 0
|
||||
}
|
||||
if {![auto_load_index]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
# try again (something new could be loaded):
|
||||
foreach name $nameList $_sub_load_cmd
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -619,12 +601,12 @@ proc auto_import {pattern} {
|
||||
auto_load_index
|
||||
|
||||
foreach pattern $patternList {
|
||||
foreach name [array names auto_index $pattern] {
|
||||
if {([namespace which -command $name] eq "")
|
||||
foreach name [array names auto_index $pattern] {
|
||||
if {([namespace which -command $name] eq "")
|
||||
&& ([namespace qualifiers $pattern] eq [namespace qualifiers $name])} {
|
||||
namespace inscope :: $auto_index($name)
|
||||
}
|
||||
}
|
||||
namespace eval :: $auto_index($name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,7 +624,7 @@ proc auto_import {pattern} {
|
||||
if {$tcl_platform(platform) eq "windows"} {
|
||||
# Windows version.
|
||||
#
|
||||
# Note that info executable doesn't work under Windows, so we have to
|
||||
# Note that file executable doesn't work under Windows, so we have to
|
||||
# look for files with .exe, .com, or .bat extensions. Also, the path
|
||||
# may be in the Path or PATH environment variables, and path
|
||||
# components are separated with semicolons, not colons as under Unix.
|
||||
@@ -655,8 +637,8 @@ proc auto_execok name {
|
||||
}
|
||||
set auto_execs($name) ""
|
||||
|
||||
set shellBuiltins [list cls copy date del dir echo erase md mkdir \
|
||||
mklink rd ren rename rmdir start time type ver vol]
|
||||
set shellBuiltins [list assoc cls copy date del dir echo erase ftype \
|
||||
md mkdir mklink move rd ren rename rmdir start time type ver vol]
|
||||
if {[info exists env(PATHEXT)]} {
|
||||
# Add an initial ; to have the {} extension check first.
|
||||
set execExtensions [split ";$env(PATHEXT)" ";"]
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
package require Tcl 8.5-
|
||||
# When the version number changes, be sure to update the pkgIndex.tcl file,
|
||||
# and the installation directory in the Makefiles.
|
||||
package provide msgcat 1.6.0
|
||||
package provide msgcat 1.6.1
|
||||
|
||||
namespace eval msgcat {
|
||||
namespace export mc mcexists mcload mclocale mcmax mcmset mcpreferences mcset\
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
if {![package vsatisfies [package provide Tcl] 8.5]} {return}
|
||||
package ifneeded msgcat 1.6.0 [list source [file join $dir msgcat.tcl]]
|
||||
if {![package vsatisfies [package provide Tcl] 8.5-]} {return}
|
||||
package ifneeded msgcat 1.6.1 [list source [file join $dir msgcat.tcl]]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
if {([info commands ::tcl::pkgconfig] eq "")
|
||||
|| ([info sharedlibextension] ne ".dll")} return
|
||||
if {[::tcl::pkgconfig get debug]} {
|
||||
package ifneeded registry 1.3.2 \
|
||||
package ifneeded registry 1.3.3 \
|
||||
[list load [file join $dir tclreg13g.dll] registry]
|
||||
} else {
|
||||
package ifneeded registry 1.3.2 \
|
||||
package ifneeded registry 1.3.3 \
|
||||
[list load [file join $dir tclreg13.dll] registry]
|
||||
}
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
# full path name of this file's directory.
|
||||
|
||||
if {![package vsatisfies [package provide Tcl] 8.5]} {return}
|
||||
package ifneeded tcltest 2.4.0 [list source [file join $dir tcltest.tcl]]
|
||||
package ifneeded tcltest 2.4.1 [list source [file join $dir tcltest.tcl]]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user