Compare commits

...
Author SHA1 Message Date
dkf 7bfc294816 merge core-8-branch 2019-06-10 20:08:52 +00:00
dkf 10da290cf9 merge more expr doc tweaks 2019-06-10 20:02:56 +00:00
dkf 44d4c7f793 General improvements to the expr manpage 2019-06-10 19:43:59 +00:00
dkf 1cab268c94 General improvements to the expr manpage 2019-06-10 19:27:31 +00:00
dgp 555291ab91 merge 8.7 2019-06-10 19:09:36 +00:00
dgp f627e6922c more formatting 2019-06-10 19:09:16 +00:00
dgp b4a301e016 merge 8.7 2019-06-10 19:06:47 +00:00
dgp 6a3773f611 Doc formatting and advice about double substitution in expressions. 2019-06-10 18:58:44 +00:00
dgp c6cb158e39 merge 8.6 2019-06-10 18:53:29 +00:00
dgp 39fba10b45 More localized documentation of lazy operators. 2019-06-10 18:44:18 +00:00
dgp 5f72a5554c More bytecodes are non-throwing. 2019-06-10 18:33:28 +00:00
dgp 3fe6dfccc1 Remove declarations that are never defined. 2019-06-10 18:31:09 +00:00
dgp 774c2050f1 Remove declarations that are never defined. 2019-06-10 18:24:05 +00:00
dgp 1217d3e0d3 merge 8.7 2019-06-10 16:00:21 +00:00
dkf 95d4ef2aae merge 8.6 2019-06-09 11:36:44 +00:00
dkf ab3a73bf75 minor cleanup of source code formatting 2019-06-09 11:28:58 +00:00
bch b4e34defb1 merge fork 2019-06-09 05:10:31 +00:00
bch c18dcfc96c cast to correct size, stop faulting 2019-06-09 05:07:53 +00:00
sebres eea593cd75 amend to close [c3a211e8a5], fixes can't read "major": no such variable 2019-06-08 10:46:22 +00:00
sebres ee5696ef47 closes [c3a211e8a5995018c82e]: search of tcl/tk is more backwards compatible now + make some errors more verbose (e. g. if scan found nothing and no tcl/tk build expected) 2019-06-07 22:09:32 +00:00
jan.nijtmans a1b2390c0f More usage of TCL_INDEX_NONE in stead of -1. More internal use of size_t, mainly in memory statistics (debug-mode only), and TCL_Z_MODIFIER. This gives broader memory statistics on win64. 2019-06-07 14:09:35 +00:00
dkf 9541b1276b Tests and docs 2019-06-06 17:58:33 +00:00
jan.nijtmans bd4765cf50 Squelch compiler warnings, but make refCount of type unsigned int. 2019-06-06 07:59:21 +00:00
bch 9d7e696016 squelch int vs. long int (size_t) warings in comparison, format specifiers 2019-06-06 03:47:33 +00:00
dkf 9843b108c9 And fix the silly error 2019-06-05 20:42:32 +00:00
dkf 89aeb7f43d And the command version of the new operators too. 2019-06-05 20:35:02 +00:00
dkf 85539b66a0 Start of implementation of string comparison operators. 2019-06-05 19:34:11 +00:00
jan.nijtmans 10e31bc252 Merge 8.6 2019-05-31 23:14:11 +00:00
jan.nijtmans d23bb9578a In tools/*, use the single-argument version of "expr" always. Making it robust against TIP #526. Those tools generally are the same among all Tcl versions. 2019-05-31 23:13:21 +00:00
jan.nijtmans a8f9285bd0 TIP #544 implementation: Export TclGetIntForIndex() 2019-05-31 12:20:40 +00:00
jan.nijtmans e80cd8e284 Merge 8.6 2019-05-31 11:51:58 +00:00
jan.nijtmans be861c2430 Rename mp_get_bit to s_mp_get_bit, rename mp_tc_div_2d to mp_signed_rsh, remove mp_tc_(add|or|xor) functions in favor of mp_(add|or|xor) which can now handle twos-complement. Following ongoing changes in libtommath development. 2019-05-31 11:28:39 +00:00
jan.nijtmans 4b67509c24 Merge 8.6 2019-05-29 23:10:09 +00:00
jan.nijtmans 984c717026 Merge 8.5 2019-05-29 23:08:11 +00:00
jan.nijtmans 7a1b66b00d Update some libtommath functions to the latest trunk versions. Small step forward in the upgrade to (upcoming) libtommath 1.2.
Advantage: simplify Tcl code accessing those functions.
2019-05-29 22:48:50 +00:00
jan.nijtmans da4e8a7253 Merge 8.6 2019-05-28 22:50:35 +00:00
jan.nijtmans 6c6bec6689 Fix build status in README.md 2019-05-28 22:48:52 +00:00
jan.nijtmans 31899401b7 Merge 8.6 2019-05-28 22:20:34 +00:00
jan.nijtmans 372248583f Rename README to README.md, and reformat 2019-05-28 22:17:37 +00:00
jan.nijtmans cf3e58c339 Merge 8.6 2019-05-28 21:42:50 +00:00
jan.nijtmans 4ff1524f2a Merge 8.5 2019-05-28 21:41:23 +00:00
jan.nijtmans 4e994192a1 Eliminate a set of libtommath-related files that don't do anything. There's no sense in it, keeping track of those files in the Tcl repository. 2019-05-28 21:38:58 +00:00
jan.nijtmans c70641a878 Fix "make dist" for the README -> README.md renaming 2019-05-27 21:18:01 +00:00
dkf 9290e6c1ac TIP 383: [coroinject] and [coroprobe] 2019-05-25 08:06:25 +00:00
dkf f4fbdbee8e Add to error info when passing an error out of [coroprobe] 2019-05-25 08:01:08 +00:00
dkf ef5c0e282a Implement TIP 431: [file tempdir] 2019-05-25 07:46:24 +00:00
jan.nijtmans 1805ed5823 Merge 8.6 2019-05-24 20:12:47 +00:00
jan.nijtmans b15a6a700f end-of-line spacing 2019-05-24 20:10:14 +00:00
jan.nijtmans ffdd95d4a3 Missing keyword: "static" 2019-05-24 20:03:03 +00:00
sebres 3bf5bf3079 merge 8.6 2019-05-24 17:00:46 +00:00
sebres d249b0629d merge 8.5 2019-05-24 16:56:29 +00:00
sebres cb9018a721 fixes typo ("net" instead of outdated term "nett") 2019-05-24 16:49:32 +00:00
sebres c230bbb7b4 merge 8.6 2019-05-21 18:04:05 +00:00
sebres e298c2595d merge 8.5 (timerate unsigned calc) 2019-05-21 18:01:07 +00:00
sebres 3ab1f672a4 timerate: be more precise using unsigned wide (for total execution time), avoid signed vs unsigned comparison warning (if compiled with VS). 2019-05-21 17:52:14 +00:00
dgp cacd1146d0 merge 8.6 2019-05-21 16:43:00 +00:00
dgp 7db84b0155 Knock VOID back down 2019-05-21 16:42:11 +00:00
sebres e94891207a merge 8.6 (fixed optimization for create/search hash entries with the same keys) 2019-05-21 11:40:37 +00:00
sebres e2f5de73e3 fixed mistake in optimization of [3f693cdfe9c875c4] (bypass of compareKeysProc if keys pointers/objects are equal) - it should compare given key with entry key (not with a hash entry) 2019-05-21 11:34:13 +00:00
sebres 57c23073f7 small amend (no cast needed) 2019-05-21 11:29:09 +00:00
sebres 245ed0c3c3 cherry-picing of [3f693cdfe9c875c4] to be more compatible across version, resolve mistake with "key objects/pointers comparison by the hash entry" firstly introduced there. 2019-05-21 11:22:36 +00:00
dgp 543703d4ee comment typo 2019-05-17 18:33:49 +00:00
sebres a68f7032b3 merge 8.6 2019-05-17 10:40:17 +00:00
dkf cfff0de87e Remove misleading comment in nroff source 2019-05-17 08:13:32 +00:00
dkf cbd3fd20bd Add test for what happens when the directory in the template doesn't exist; doc it too. 2019-05-17 08:09:29 +00:00
dkf c54b6957b8 merge core-8-branch 2019-05-17 07:31:47 +00:00
sebres 1f5c7c693b merge 8.5 2019-05-16 18:19:25 +00:00
sebres 2865a8da13 small amend to [ac566e9df84daeab] with rollback of done/continue optimization 2019-05-16 18:17:52 +00:00
sebres 8af3fb7317 merge 8.5 (timerate fix to avoid impact of object duplication on shared interp result by the measurement) 2019-05-16 17:56:37 +00:00
sebres ccc592df50 timerate: allow continue from measurement cycle (used for conditional flow control of iterations);
more gentle evaluation behaviour, similar to a cycle now (also avoids extra overhead to set result to interp, etc.);
todo: rewrite optimization of INST_DONE using last-instruction pointer or optimization flags for compile of iteration (if sebres's perf-branch gets merged).
2019-05-16 17:49:25 +00:00
jan.nijtmans bbcbb88d88 Add documentation, don't overwrite earlier stub entry! 2019-05-15 15:18:22 +00:00
jan.nijtmans 642d303548 TIP #544 implementation. Documentation still missing. 2019-05-15 14:58:03 +00:00
jan.nijtmans 503da2614f Merge 8.6 2019-05-14 19:26:55 +00:00
jan.nijtmans de4f571baa Merge 8.5 2019-05-14 19:13:01 +00:00
jan.nijtmans 8094d33e43 DIGIT_BIT -> MP_DIGIT_BIT, since DIGIT_BIT is deprecated in future libtommath versions. So, better stop using it at all.
Also add some other defines/typdefs for future libtommath compatibility.
2019-05-14 18:42:59 +00:00
dkf ec265aa929 Tweak the unix build instructions; general cleanup of a few bits and fixing of old maintainer-only targets 2019-05-14 10:31:01 +00:00
fvogel 0f34d49b76 Fix new tests cmdAH-33.[45] by making them pass on Windows 2019-05-13 17:56:36 +00:00
fvogel 6b6e030ea4 Fix crashing bug in tempdir name creation 2019-05-13 09:54:49 +00:00
fvogel 6902811461 Let branch compile with MSVC 2008 2019-05-13 04:00:48 +00:00
dgp 923a6774f6 merge 8.6 2019-05-11 12:57:35 +00:00
dgp 9ca29b09ae merge 8.5 2019-05-11 12:49:46 +00:00
dgp 95d2a7f7c0 Revised documented advice that made obsolete reference to interp->result. 2019-05-11 12:48:53 +00:00
sebres 0d1ffc0968 testlinkarray: fixed cast to pointer from integer (and eliminate warning) 2019-05-10 18:32:09 +00:00
jan.nijtmans b1139d3d20 If compiling with -DTCL_NO_DEPRECATED, make Tcl_GetStringResult() a macro. This opens up one more simplification for Tcl 9.
Compile the load-test dll's/so's with -DTCL_NO_DEPRECATED
2019-05-09 20:06:34 +00:00
jan.nijtmans 67ba502f34 Merge 8.6.
Fix compilation warning. No longer return linked adress as interp result in Tcl_LinkArra(): This is not documented, not tested, and simply dangerous: It leaks pointer values into the Tcl space.
2019-05-09 15:52:01 +00:00
jan.nijtmans d232a6d28e Minor compiler warning 2019-05-09 15:32:51 +00:00
dgp b8b9618102 merge 8.6 2019-05-08 18:07:51 +00:00
dgp 5419f8e0ba For historical/hysterical reasons, the (unused??) public routines Tcl_UpVar()
and Tcl_UpVar2() accept random garbage for a level argument (treat it as 1)
while the [upvar] command has come to reject such values as bad levels.
Add a test to call it to our attention if we ever change that disparity
so we do so only on purpose.
2019-05-08 18:06:23 +00:00
jan.nijtmans 9d68b2dbd1 Make more clear that TCL_INDEX_END|TCL_INDEX_NONE not necessary are int's (in Tcl 9 they are not).
Eliminate use of (local) list_index_t type
2019-05-08 06:53:00 +00:00
jan.nijtmans f218c1f1eb (cherry-pick from8.6): Japanese Reiwa (令和) era 2019-05-07 07:19:10 +00:00
dgp a5482cc2a7 merge mark 2019-05-04 22:49:04 +00:00
dgp cb411d059b close fork 2019-05-04 22:46:58 +00:00
dgp 84f4682378 close fork 2019-05-04 22:44:47 +00:00
dgp 7ce4c19aa0 merge mark 2019-05-04 18:33:44 +00:00
dgp 06124df7de merge 8.5 2019-05-04 18:32:39 +00:00
dgp 4909a5cc24 Plug memleak when deleting a namespace destroys a linked Tcl var. 2019-05-04 18:25:40 +00:00
Kevin B Kenny 845ae36548 merge 8.6 - missed basic.test on prior merge 2019-05-04 15:04:23 +00:00
Kevin B Kenny 951df2e52a Japanese Reiwa (令和) era 2019-05-04 14:58:11 +00:00
Kevin B Kenny 55b6550aaa Japanese Reiwa (令和) era 2019-05-04 14:49:58 +00:00
dkf cd6fdc6976 Make sure we test [2c154a40be] explicitly. Part of [cc191552c] 2019-05-04 07:10:34 +00:00
dgp a35dd18036 merge 8.6 2019-05-03 20:06:09 +00:00
dgp 48891ff56a memleak demo test 2019-05-03 18:54:46 +00:00
dgp 5ee08fdf00 memleak demo test 2019-05-03 18:50:13 +00:00
dgp 79ac1a3b19 Plug memleak when deleting a namespace destroys a linked Tcl var. 2019-05-03 15:28:23 +00:00
dgp 8510dda2ac missed bit of type revision. 2019-05-03 15:15:21 +00:00
dgp 7a0e892768 leak plug completed 2019-05-03 14:57:04 +00:00
dgp 915cd6b667 WIP 2019-05-01 22:37:36 +00:00
dkf cedf26696f Tests 2019-05-01 18:36:30 +00:00
dgp d2dd1bf17d Use exit handlers to prevent memleak of ZipFile struct in zipfs mounts. 2019-05-01 17:16:13 +00:00
dgp 057bc4e640 duplicate test names 2019-05-01 14:25:40 +00:00
dgp b67323b4d4 merge 8.7 2019-05-01 13:54:27 +00:00
dgp d1faa9b2b1 now testing.... 2019-05-01 13:52:26 +00:00
pooryorick f50dfbd504 merge bug-de232b49f2 2019-05-01 10:44:55 +00:00
pooryorick 89c677d626 Check for BG_FLUSH_SCHEDULED inside ChannelTimerProc 2019-05-01 10:44:10 +00:00
dkf 6937b4c670 Document it 2019-04-30 20:18:11 +00:00
dkf fd0444bf94 Implementation of [file tempdir]; hand-tested on OSX... 2019-04-30 18:31:47 +00:00
dkf ae1d2d2d40 Export API 2019-04-30 13:35:53 +00:00
dkf 688e4e8545 Windows implementation of TclpCreateTemporaryDirectory 2019-04-30 13:31:59 +00:00
dkf c0c8a1cbd0 Starting to implement a temporary directory creator. 2019-04-30 07:44:20 +00:00
dgp b3676ba87c more WIP 2019-04-29 19:26:40 +00:00
dkf 3db1b8bbad Advanced feature tests 2019-04-28 16:17:05 +00:00
dkf 7f8f3b946d Basic tests 2019-04-28 16:01:57 +00:00
dkf 5bb0cef260 Documenting, both internally and in manpage 2019-04-28 07:11:39 +00:00
dkf cd37605bd0 Remove unused variables 2019-04-27 18:08:53 +00:00
dkf 0710d7d955 Implement 383 as two commands for two scenarios: injection and probing 2019-04-27 17:56:49 +00:00
pooryorick 36073e502b Fix for de232b49f2, write-only nonblocking refchan and Tcl internal buffers. 2019-04-27 07:19:49 +00:00
dgp 59a2032b5d Track memory lifetimes in the zip mount/unmount. 2019-04-24 19:29:18 +00:00
dgp b21bc1e84f Plug memleak in [lpop] due to mishandling the unconventional recounting
practices of TclLsetFlat().
2019-04-24 14:29:41 +00:00
pooryorick 35396a7f5c merge bug-67a5eabbd3d1 2019-04-24 04:52:22 +00:00
pooryorick a0465a4be2 Add missed timer cleanup in tclIORChan.c/ReflectClose. 2019-04-24 04:04:46 +00:00
dkf e42fbc68b9 Added primitive to allow working coroutine deep introspection 2019-04-23 14:24:53 +00:00
dkf ba3eca6d7e Minor code style cleanup. 2019-04-23 13:47:52 +00:00
pooryorick 2a04ff4dd5 Ensure that Tcl_CreateTimerHandler is not called if there is an existing timer
already scheduled.
2019-04-23 12:59:20 +00:00
pooryorick 70d68cb355 Fix for [67a5eabbd3d1], refchan, coroutine, and postevent from the "watch"
proc.
2019-04-23 11:29:16 +00:00
dkf 2306d12442 timerate: code style, doc style 2019-04-23 06:50:02 +00:00
dkf eaf90743ee timerate: code style, doc style 2019-04-23 06:43:08 +00:00
dkf 1e9a4512c7 timerate: code style, doc style 2019-04-23 06:28:28 +00:00
dgp 0f9539f838 Stop leaking ZipFile in MountBuffer() 2019-04-22 15:15:47 +00:00
dgp e240d7269b Prevent reads of uninitalized memory. 2019-04-22 14:56:31 +00:00
dgp e85c55bb57 [zipfs mount_data] should not accept three arguments. 2019-04-22 14:09:48 +00:00
dkf 8b9a3558a4 Compilation for [dict getwithdefault]. 2019-04-18 22:57:12 +00:00
dkf 9cf9c0a5e5 Style corrections and warning elimination 2019-04-18 08:31:11 +00:00
sebres 407ebf2899 merge 8.5 2019-04-17 20:00:37 +00:00
sebres 0cced28f38 extend performance test-suite, allow several (repeatable) execution of _test_run (if encosed in _test_start/_test_out_total) to produce same summary; provide possibility for measure of single iterators, etc.
small code review
2019-04-17 19:59:13 +00:00
dgp 522f29c7cc Replace memcpy() calls with memmove() to avoid undefined behavior when
source and destination overlap.
2019-04-17 19:23:56 +00:00
dgp 80d050ece4 Do not access allocated memory before initializing it. 2019-04-17 17:45:55 +00:00
dgp dadad672af test file hygiene 2019-04-17 16:56:55 +00:00
dgp d227a324cd Duplicate test names. 2019-04-17 16:32:53 +00:00
dgp 12486f233f The [namespace delete ::httpTest] at the end of httpPipeline.test failed to
also undo the custom [::http::Log] command it put in place. This dangling
command was left broken and made much failure.
Revised httpTest.tcl to use a trace to tidy up after itself.
2019-04-17 16:26:03 +00:00
dgp 1d896481cf [60559fd4a6] Test more robust against frame contexts of testing environment. 2019-04-17 15:08:25 +00:00
dgp 05509bdd77 Revise coroutines tests so they do not leave behind frame footprints that
can interfere with other tests.
2019-04-17 14:34:42 +00:00
dgp 68c28bd274 Isolate tests of [info frame] results from testing environment. 2019-04-17 14:28:51 +00:00
dgp f720f4cad5 Isolate tests of [info frame] results from testing environment. 2019-04-17 14:25:59 +00:00
dkf 25fb160692 Implement TIP 342 2019-04-16 13:25:39 +00:00
dkf bcca980f06 Add [dict getdef] alias 2019-04-15 19:57:54 +00:00
dkf 564d3a1a7b Doc tweak 2019-04-14 15:14:50 +00:00
dkf a929d96cba Implement TIP 504 2019-04-14 14:37:12 +00:00
dkf 0640ff837f Implement TIP 367 2019-04-14 14:17:57 +00:00
dkf 8f940bfbb8 Implement TIP 312 2019-04-14 14:17:14 +00:00
dkf e539ce9a7e Implement TIP 160 2019-04-14 14:15:30 +00:00
dkf e2dcb52134 Removed TCL_LINK_ALLOC; it wasn't used. 2019-04-14 07:52:16 +00:00
dgp c307971f0e merge 8.7 2019-04-12 20:15:37 +00:00
dgp 6ae823b6b7 merge 8.7 2019-04-12 19:44:34 +00:00
dgp 3947892f31 merge 8.7 2019-04-12 19:21:08 +00:00
dkf 1dbc626f0f Suggested fix for [60559fd4a6]: put selected tests in child interps 2019-04-11 21:39:50 +00:00
jan.nijtmans 02225865e4 Merge 8.7, and fix build problem on Windows 2019-04-07 14:39:45 +00:00
dkf e0b6a53069 More efficient version (after feedback from KBK). Better test too. 2019-04-05 18:37:44 +00:00
dkf 52458f51bc Clean up and refactor a bit 2019-04-04 23:47:38 +00:00
dkf 52d83cb65d Now with fewer memory leaks 2019-04-04 23:08:05 +00:00
dkf 3c6834dbe3 Fix unsigned wide linking. 2019-04-04 22:48:15 +00:00
dkf c4cf1a4e2c Split up tests to get better focus on what is being tested 2019-04-04 08:52:43 +00:00
dkf cbb2ececd3 Docs 2019-04-03 12:22:07 +00:00
dkf 515da61c9d refactor; mark broken tests as broken 2019-04-03 09:36:33 +00:00
dkf ad137eb4b2 Some fixes. Still broken on 64-bit systems 2019-04-03 09:08:37 +00:00
dkf d1069c7b4f Import of TIP 312 implementation 2019-04-03 07:58:17 +00:00
dgp dab604e786 typos 2019-04-01 16:15:45 +00:00
dkf 325bbf5792 Document 2019-04-01 10:51:33 +00:00
dkf 8d4509eafc Add tests 2019-04-01 10:38:47 +00:00
dkf d2fb211d20 Implement [dict getwithdefault] 2019-04-01 08:48:16 +00:00
dkf 3471a570b6 Added documentation 2019-03-30 12:54:52 +00:00
dkf 83f6cc3841 Tests, and reduce number of copies. 2019-03-30 12:41:59 +00:00
dkf d78f576dc5 Implementation of [lremove]. 2019-03-30 10:36:58 +00:00
dkf 8ac5057a32 Support -winsize read-only option 2019-03-29 14:22:23 +00:00
dkf 5624496889 Oops 2019-03-29 11:57:23 +00:00
dkf 99c5fed89e Tests, but not working ones... 2019-03-28 13:11:58 +00:00
dkf ba13f3330a Documentation 2019-03-28 10:53:55 +00:00
dkf f787bc7152 Implement -closemode 2019-03-27 21:14:46 +00:00
dkf bc322bfae7 Partial implementation on Windows. UNTESTED 2019-03-27 13:54:18 +00:00
dkf 7ff500ca4d Add autoconf support 2019-03-27 08:29:13 +00:00
dkf 4701c749af Better handling, reset capabilty, and ensure that inherited channels are correct 2019-03-24 22:08:26 +00:00
dkf 8d4ff7c84a Start of implementation of TIP 160: better terminal control 2019-03-24 18:44:45 +00:00
127 changed files with 8298 additions and 24200 deletions
-185
View File
@@ -1,185 +0,0 @@
README: Tcl
This is the Tcl 8.7a2 source distribution.
http://sourceforge.net/projects/tcl/files/Tcl/
You can get any source release of Tcl from the URL above.
Contents
--------
1. Introduction
2. Documentation
3. Compiling and installing Tcl
4. Development tools
5. Tcl newsgroup
6. The Tcler's Wiki
7. Mailing lists
8. Support and Training
9. Tracking Development
10. Thank You
1. Introduction
---------------
Tcl provides a powerful platform for creating integration applications that
tie together diverse applications, protocols, devices, and frameworks.
When paired with the Tk toolkit, Tcl provides the fastest and most powerful
way to create GUI applications that run on PCs, Unix, and Mac OS X.
Tcl can also be used for a variety of web-related tasks and for creating
powerful command languages for applications.
Tcl is maintained, enhanced, and distributed freely by the Tcl community.
Source code development and tracking of bug reports and feature requests
takes place at:
http://core.tcl-lang.org/
Tcl/Tk release and mailing list services are hosted by SourceForge:
http://sourceforge.net/projects/tcl/
with the Tcl Developer Xchange hosted at:
http://www.tcl-lang.org/
Tcl is a freely available open source package. You can do virtually
anything you like with it, such as modifying it, redistributing it,
and selling it either in whole or in part. See the file
"license.terms" for complete information.
2. Documentation
----------------
Extensive documentation is available at our website.
The home page for this release, including new features, is
http://www.tcl-lang.org/software/tcltk/8.7.html
Detailed release notes can be found at the file distributions page
by clicking on the relevant version.
http://sourceforge.net/projects/tcl/files/Tcl/
Information about Tcl itself can be found at
http://www.tcl-lang.org/about/
There have been many Tcl books on the market. Many are mentioned in the Wiki:
http://wiki.tcl-lang.org/_/ref?N=25206
To view the complete set of reference manual entries for Tcl 8.7 online,
visit the URL:
http://www.tcl-lang.org/man/tcl8.7/
2a. Unix Documentation
----------------------
The "doc" subdirectory in this release contains a complete set of
reference manual entries for Tcl. Files with extension ".1" are for
programs (for example, tclsh.1); files with extension ".3" are for C
library procedures; and files with extension ".n" describe Tcl
commands. The file "doc/Tcl.n" gives a quick summary of the Tcl
language syntax. To print any of the man pages on Unix, cd to the
"doc" directory and invoke your favorite variant of troff using the
normal -man macros, for example
ditroff -man Tcl.n
to print Tcl.n. If Tcl has been installed correctly and your "man" program
supports it, you should be able to access the Tcl manual entries using the
normal "man" mechanisms, such as
man Tcl
2b. Windows Documentation
-------------------------
The "doc" subdirectory in this release contains a complete set of Windows
help files for Tcl. Once you install this Tcl release, a shortcut to the
Windows help Tcl documentation will appear in the "Start" menu:
Start | Programs | Tcl | Tcl Help
3. Compiling and installing Tcl
-------------------------------
There are brief notes in the unix/README, win/README, and macosx/README about
compiling on these different platforms. There is additional information
about building Tcl from sources at
http://www.tcl-lang.org/doc/howto/compile.html
4. Development tools
---------------------------
ActiveState produces a high quality set of commercial quality development
tools that is available to accelerate your Tcl application development.
Tcl Dev Kit builds on the earlier TclPro toolset and provides a debugger,
static code checker, single-file wrapping utility, bytecode compiler and
more. More information can be found at
http://www.ActiveState.com/Tcl
5. Tcl newsgroup
----------------
There is a USENET news group, "comp.lang.tcl", intended for the exchange of
information about Tcl, Tk, and related applications. The newsgroup is a
great place to ask general information questions. For bug reports, please
see the "Support and bug fixes" section below.
6. Tcl'ers Wiki
---------------
A Wiki-based open community site covering all aspects of Tcl/Tk is at:
http://wiki.tcl-lang.org/
It is dedicated to the Tcl programming language and its extensions. A
wealth of useful information can be found there. It contains code
snippets, references to papers, books, and FAQs, as well as pointers to
development tools, extensions, and applications. You can also recommend
additional URLs by editing the wiki yourself.
7. Mailing lists
----------------
Several mailing lists are hosted at SourceForge to discuss development or
use issues (like Macintosh and Windows topics). For more information and
to subscribe, visit:
http://sourceforge.net/projects/tcl/
and go to the Mailing Lists page.
8. Support and Training
------------------------
We are very interested in receiving bug reports, patches, and suggestions
for improvements. We prefer that you send this information to us as
tickets entered into our tracker at:
http://core.tcl-lang.org/tcl/reportlist
We will log and follow-up on each bug, although we cannot promise a
specific turn-around time. Enhancements may take longer and may not happen
at all unless there is widespread support for them (we're trying to
slow the rate at which Tcl/Tk turns into a kitchen sink). It's very
difficult to make incompatible changes to Tcl/Tk at this point, due to
the size of the installed base.
The Tcl community is too large for us to provide much individual support
for users. If you need help we suggest that you post questions to
comp.lang.tcl. We read the newsgroup and will attempt to answer esoteric
questions for which no one else is likely to know the answer. In addition,
see the following Web site for links to other organizations that offer
Tcl/Tk training:
http://wiki.tcl-lang.org/training
9. Tracking Development
-----------------------
Tcl is developed in public. To keep an eye on how Tcl is changing, see
http://core.tcl-lang.org/
10. Thank You
-------------
We'd like to express our thanks to the Tcl community for all the
helpful suggestions, bug reports, and patches we have received.
Tcl/Tk has improved vastly and will continue to do so with your help.
+148
View File
@@ -0,0 +1,148 @@
# README: Tcl
This is the **Tcl 8.7a2** source distribution.
You can get any source release of Tcl from [our distribution
site](https://sourceforge.net/projects/tcl/files/Tcl/).
[![Build Status](https://travis-ci.org/tcltk/tcl.svg?branch=core-8-branch)](https://travis-ci.org/tcltk/tcl)
## Contents
1. [Introduction](#intro)
2. [Documentation](#doc)
3. [Compiling and installing Tcl](#build)
4. [Development tools](#devtools)
5. [Tcl newsgroup](#complangtcl)
6. [The Tcler's Wiki](#wiki)
7. [Mailing lists](#email)
8. [Support and Training](#support)
9. [Tracking Development](#watch)
10. [Thank You](#thanks)
## <a id="intro">1.</a> Introduction
Tcl provides a powerful platform for creating integration applications that
tie together diverse applications, protocols, devices, and frameworks.
When paired with the Tk toolkit, Tcl provides the fastest and most powerful
way to create GUI applications that run on PCs, Unix, and Mac OS X.
Tcl can also be used for a variety of web-related tasks and for creating
powerful command languages for applications.
Tcl is maintained, enhanced, and distributed freely by the Tcl community.
Source code development and tracking of bug reports and feature requests
takes place at [core.tcl-lang.org](https://core.tcl-lang.org/).
Tcl/Tk release and mailing list services are [hosted by
SourceForge](https://sourceforge.net/projects/tcl/)
with the Tcl Developer Xchange hosted at
[www.tcl-lang.org](https://www.tcl-lang.org).
Tcl is a freely available open source package. You can do virtually
anything you like with it, such as modifying it, redistributing it,
and selling it either in whole or in part. See the file
`license.terms` for complete information.
## <a id="doc">2.</a> Documentation
Extensive documentation is available at our website.
The home page for this release, including new features, is
[here](https://www.tcl.tk/software/tcltk/8.7.html).
Detailed release notes can be found at the
[file distributions page](https://sourceforge.net/projects/tcl/files/Tcl/)
by clicking on the relevant version.
Information about Tcl itself can be found at the [Developer
Xchange](https://www.tcl-lang.org/about/).
There have been many Tcl books on the market. Many are mentioned in
[the Wiki](https://wiki.tcl-lang.org/_/ref?N=25206).
The complete set of reference manual entries for Tcl 8.7 is [online,
here](https://www.tcl-lang.org/man/tcl8.7/).
### <a id="doc.unix">2a.</a> Unix Documentation
The `doc` subdirectory in this release contains a complete set of
reference manual entries for Tcl. Files with extension "`.1`" are for
programs (for example, `tclsh.1`); files with extension "`.3`" are for C
library procedures; and files with extension "`.n`" describe Tcl
commands. The file "`doc/Tcl.n`" gives a quick summary of the Tcl
language syntax. To print any of the man pages on Unix, cd to the
"doc" directory and invoke your favorite variant of troff using the
normal -man macros, for example
groff -man -Tpdf Tcl.n >output.pdf
to print Tcl.n to PDF. If Tcl has been installed correctly and your "man" program
supports it, you should be able to access the Tcl manual entries using the
normal "man" mechanisms, such as
man Tcl
### <a id="doc.win">2b.</a> Windows Documentation
The "doc" subdirectory in this release contains a complete set of Windows
help files for Tcl. Once you install this Tcl release, a shortcut to the
Windows help Tcl documentation will appear in the "Start" menu:
Start | Programs | Tcl | Tcl Help
## <a id="build">3.</a> Compiling and installing Tcl
There are brief notes in the `unix/README`, `win/README`, and `macosx/README`
about compiling on these different platforms. There is additional information
about building Tcl from sources
[online](https://www.tcl-lang.org/doc/howto/compile.html).
## <a id="devtools">4.</a> Development tools
ActiveState produces a high quality set of commercial quality development
tools that is available to accelerate your Tcl application development.
Tcl Dev Kit builds on the earlier TclPro toolset and provides a debugger,
static code checker, single-file wrapping utility, bytecode compiler and
more. More information can be found at
http://www.ActiveState.com/Tcl
## <a id="complangtcl">5.</a> Tcl newsgroup
There is a USENET news group, "`comp.lang.tcl`", intended for the exchange of
information about Tcl, Tk, and related applications. The newsgroup is a
great place to ask general information questions. For bug reports, please
see the "Support and bug fixes" section below.
## <a id="wiki">6.</a> Tcl'ers Wiki
There is a [wiki-based open community site](https://wiki.tcl-lang.org/)
covering all aspects of Tcl/Tk.
It is dedicated to the Tcl programming language and its extensions. A
wealth of useful information can be found there. It contains code
snippets, references to papers, books, and FAQs, as well as pointers to
development tools, extensions, and applications. You can also recommend
additional URLs by editing the wiki yourself.
## <a id="email">7.</a> Mailing lists
Several mailing lists are hosted at SourceForge to discuss development or use
issues (like Macintosh and Windows topics). For more information and to
subscribe, visit [here](https://sourceforge.net/projects/tcl/) and go to the
Mailing Lists page.
## <a id="support">8.</a> Support and Training
We are very interested in receiving bug reports, patches, and suggestions for
improvements. We prefer that you send this information to us as tickets
entered into [our issue tracker](https://core.tcl-lang.org/tcl/reportlist).
We will log and follow-up on each bug, although we cannot promise a
specific turn-around time. Enhancements may take longer and may not happen
at all unless there is widespread support for them (we're trying to
slow the rate at which Tcl/Tk turns into a kitchen sink). It's very
difficult to make incompatible changes to Tcl/Tk at this point, due to
the size of the installed base.
The Tcl community is too large for us to provide much individual support for
users. If you need help we suggest that you post questions to `comp.lang.tcl`
or ask a question on [Stack
Overflow](https://stackoverflow.com/questions/tagged/tcl). We read the
newsgroup and will attempt to answer esoteric questions for which no one else
is likely to know the answer. In addition, see the wiki for [links to other
organizations](https://wiki.tcl-lang.org/training) that offer Tcl/Tk training.
## <a id="watch">9.</a> Tracking Development
Tcl is developed in public. You can keep an eye on how Tcl is changing at
[core.tcl-lang.org](https://core.tcl-lang.org/).
## <a id="thanks">10.</a> Thank You
We'd like to express our thanks to the Tcl community for all the
helpful suggestions, bug reports, and patches we have received.
Tcl/Tk has improved vastly and will continue to do so with your help.
+16 -1
View File
@@ -8,7 +8,7 @@
.so man.macros
.BS
.SH NAME
Tcl_NewIntObj, Tcl_NewLongObj, Tcl_NewWideIntObj, Tcl_SetIntObj, Tcl_SetLongObj, Tcl_SetWideIntObj, Tcl_GetIntFromObj, Tcl_GetLongFromObj, Tcl_GetWideIntFromObj, Tcl_NewBignumObj, Tcl_SetBignumObj, Tcl_GetBignumFromObj, Tcl_TakeBignumFromObj \- manipulate Tcl values as integers
Tcl_NewIntObj, Tcl_NewLongObj, Tcl_NewWideIntObj, Tcl_SetIntObj, Tcl_SetLongObj, Tcl_SetWideIntObj, Tcl_GetIntFromObj, Tcl_GetIntForIndex, Tcl_GetLongFromObj, Tcl_GetWideIntFromObj, Tcl_NewBignumObj, Tcl_SetBignumObj, Tcl_GetBignumFromObj, Tcl_TakeBignumFromObj \- manipulate Tcl values as integers
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
@@ -32,6 +32,9 @@ int
\fBTcl_GetIntFromObj\fR(\fIinterp, objPtr, intPtr\fR)
.sp
int
\fBTcl_GetIntForIndex\fR(\fIinterp, objPtr, endValue, intPtr\fR)
.sp
int
\fBTcl_GetLongFromObj\fR(\fIinterp, objPtr, longPtr\fR)
.sp
int
@@ -55,6 +58,8 @@ int
\fBTcl_InitBignumFromDouble\fR(\fIinterp, doubleValue, bigValue\fR)
.SH ARGUMENTS
.AS Tcl_WideInt doubleValue in/out
.AP int endValue in
\fBTcl_GetIntForIndex\fR will return this when the input value is "end".
.AP int intValue in
Integer value used to initialize or set a Tcl value.
.AP long longValue in
@@ -115,6 +120,16 @@ violates Tcl's copy-on-write policy. Any existing string representation
or internal representation in the unshared Tcl value will be freed
as a consequence of setting the new value.
.PP
The \fBTcl_GetIntForIndex\fR routine attempts to retrieve an index
value from the Tcl value \fIobjPtr\fR. If the attempt succeeds,
then \fBTCL_OK\fR is returned, and the value is written to the
storage provided by the caller. The attempt might fail if
\fIobjPtr\fR does not hold an index value. If the attempt fails,
then \fBTCL_ERROR\fR is returned, and if \fIinterp\fR is non-NULL,
an error message is left in \fIinterp\fR. The \fBTcl_ObjType\fR
of \fIobjPtr\fR may be changed to make subsequent calls to the
same routine more efficient.
.PP
The \fBTcl_GetIntFromObj\fR, \fBTcl_GetLongFromObj\fR,
\fBTcl_GetWideIntFromObj\fR, \fBTcl_GetBignumFromObj\fR, and
\fBTcl_TakeBignumFromObj\fR routines attempt to retrieve an integral
+99 -23
View File
@@ -9,7 +9,7 @@
.so man.macros
.BS
.SH NAME
Tcl_LinkVar, Tcl_UnlinkVar, Tcl_UpdateLinkedVar \- link Tcl variable to C variable
Tcl_LinkArray, Tcl_LinkVar, Tcl_UnlinkVar, Tcl_UpdateLinkedVar \- link Tcl variable to C variable
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
@@ -17,27 +17,52 @@ Tcl_LinkVar, Tcl_UnlinkVar, Tcl_UpdateLinkedVar \- link Tcl variable to C variab
int
\fBTcl_LinkVar\fR(\fIinterp, varName, addr, type\fR)
.sp
.VS "TIP 312"
int
\fBTcl_LinkArray\fR(\fIinterp, varName, addr, type, size\fR)
.VE "TIP 312"
.sp
\fBTcl_UnlinkVar\fR(\fIinterp, varName\fR)
.sp
\fBTcl_UpdateLinkedVar\fR(\fIinterp, varName\fR)
.SH ARGUMENTS
.AS Tcl_Interp writable
.AS Tcl_Interp varName in
.AP Tcl_Interp *interp in
Interpreter that contains \fIvarName\fR.
Also used by \fBTcl_LinkVar\fR to return error messages.
.AP "const char" *varName in
Name of global variable.
.AP char *addr in
.AP void *addr in
Address of C variable that is to be linked to \fIvarName\fR.
.sp
.VS "TIP 312"
In \fBTcl_LinkArray\fR, may be NULL to tell Tcl to create the storage
for the array in the variable.
.VE "TIP 312"
.AP int type in
Type of C variable. Must be one of \fBTCL_LINK_INT\fR,
Type of C variable for \fBTcl_LinkVar\fR or type of array element for
\fBTcl_LinkArray\fR. Must be one of \fBTCL_LINK_INT\fR,
\fBTCL_LINK_UINT\fR, \fBTCL_LINK_CHAR\fR, \fBTCL_LINK_UCHAR\fR,
\fBTCL_LINK_SHORT\fR, \fBTCL_LINK_USHORT\fR, \fBTCL_LINK_LONG\fR,
\fBTCL_LINK_ULONG\fR, \fBTCL_LINK_WIDE_INT\fR,
\fBTCL_LINK_WIDE_UINT\fR, \fBTCL_LINK_FLOAT\fR,
\fBTCL_LINK_DOUBLE\fR, \fBTCL_LINK_BOOLEAN\fR, or
\fBTCL_LINK_STRING\fR, optionally OR'ed with \fBTCL_LINK_READ_ONLY\fR
to make Tcl variable read-only.
\fBTCL_LINK_WIDE_UINT\fR, \fBTCL_LINK_FLOAT\fR, \fBTCL_LINK_DOUBLE\fR,
\fBTCL_LINK_BOOLEAN\fR, or one of the extra ones listed below.
.sp
In \fBTcl_LinkVar\fR, the additional linked type \fBTCL_LINK_STRING\fR may be
used.
.sp
.VS "TIP 312"
In \fBTcl_LinkArray\fR, the additional linked types \fBTCL_LINK_CHARS\fR and
\fBTCL_LINK_BYTES\fR may be used.
.VE "TIP 312"
.sp
All the above for both functions may be
optionally OR'ed with \fBTCL_LINK_READ_ONLY\fR to make the Tcl
variable read-only.
.AP int size in
.VS "TIP 312"
The number of elements in the C array. Must be greater than zero.
.VE "TIP 312"
.BE
.SH DESCRIPTION
.PP
@@ -52,12 +77,21 @@ while setting up the link (e.g. because \fIvarName\fR is the
name of array) then \fBTCL_ERROR\fR is returned and the interpreter's result
contains an error message.
.PP
.VS "TIP 312"
\fBTcl_LinkArray\fR is similar, but for arrays of fixed size (given by
the \fIsize\fR argument). When asked to allocate the backing C array
storage (via the \fIaddr\fR argument being NULL), it writes the
address that it allocated to the Tcl interpreter result.
.VE "TIP 312"
.PP
The \fItype\fR argument specifies the type of the C variable,
or the type of the elements of the C array,
and must have one of the following values, optionally OR'ed with
\fBTCL_LINK_READ_ONLY\fR:
.TP
\fBTCL_LINK_INT\fR
The C variable is of type \fBint\fR.
.
The C variable, or each element of the C array, is of type \fBint\fR.
Any value written into the Tcl variable must have a proper integer
form acceptable to \fBTcl_GetIntFromObj\fR; attempts to write
non-integer values into \fIvarName\fR will be rejected with
@@ -66,7 +100,8 @@ string, '+', '-' or the hex/octal/binary prefix) are accepted
as if they are valid too.
.TP
\fBTCL_LINK_UINT\fR
The C variable is of type \fBunsigned int\fR.
.
The C variable, or each element of the C array, is of type \fBunsigned int\fR.
Any value written into the Tcl variable must have a proper unsigned
integer form acceptable to \fBTcl_GetWideIntFromObj\fR and in the
platform's defined range for the \fBunsigned int\fR type; attempts to
@@ -76,16 +111,31 @@ representations (like the empty string, '+', '-' or the hex/octal/binary
prefix) are accepted as if they are valid too.
.TP
\fBTCL_LINK_CHAR\fR
The C variable is of type \fBchar\fR.
.
The C variable, or each element of the C array, is of type \fBchar\fR.
Any value written into the Tcl variable must have a proper integer
form acceptable to \fBTcl_GetIntFromObj\fR and be in the range of the
\fBchar\fR datatype; attempts to write non-integer or out-of-range
values into \fIvarName\fR will be rejected with Tcl errors. Incomplete
integer representations (like the empty string, '+', '-' or the
hex/octal/binary prefix) are accepted as if they are valid too.
.RS
.PP
.VS "TIP 312"
If using an array of these, consider using \fBTCL_LINK_CHARS\fR instead.
.VE "TIP 312"
.RE
.TP
\fBTCL_LINK_CHARS\fR
.VS "TIP 312"
The C array is of type \fBchar *\fR and is mapped into Tcl as a string.
Any value written into the Tcl variable must have the same length as
the underlying storage. Only supported with \fBTcl_LinkArray\fR.
.VE "TIP 312"
.TP
\fBTCL_LINK_UCHAR\fR
The C variable is of type \fBunsigned char\fR.
.
The C variable, or each element of the C array, is of type \fBunsigned char\fR.
Any value written into the Tcl variable must have a proper unsigned
integer form acceptable to \fBTcl_GetIntFromObj\fR and in the
platform's defined range for the \fBunsigned char\fR type; attempts to
@@ -93,9 +143,24 @@ write non-integer values (or values outside the range) into
\fIvarName\fR will be rejected with Tcl errors. Incomplete integer
representations (like the empty string, '+', '-' or the hex/octal/binary
prefix) are accepted as if they are valid too.
.RS
.PP
.VS "TIP 312"
If using an array of these, consider using \fBTCL_LINK_BYTES\fR instead.
.VE "TIP 312"
.RE
.TP
\fBTCL_LINK_BYTES\fR
.VS "TIP 312"
The C array is of type \fBunsigned char *\fR and is mapped into Tcl
as a bytearray.
Any value written into the Tcl variable must have the same length as
the underlying storage. Only supported with \fBTcl_LinkArray\fR.
.VE "TIP 312"
.TP
\fBTCL_LINK_SHORT\fR
The C variable is of type \fBshort\fR.
.
The C variable, or each element of the C array, is of type \fBshort\fR.
Any value written into the Tcl variable must have a proper integer
form acceptable to \fBTcl_GetIntFromObj\fR and be in the range of the
\fBshort\fR datatype; attempts to write non-integer or out-of-range
@@ -104,7 +169,8 @@ integer representations (like the empty string, '+', '-' or the
hex/octal/binary prefix) are accepted as if they are valid too.
.TP
\fBTCL_LINK_USHORT\fR
The C variable is of type \fBunsigned short\fR.
.
The C variable, or each element of the C array, is of type \fBunsigned short\fR.
Any value written into the Tcl variable must have a proper unsigned
integer form acceptable to \fBTcl_GetIntFromObj\fR and in the
platform's defined range for the \fBunsigned short\fR type; attempts to
@@ -114,7 +180,8 @@ representations (like the empty string, '+', '-' or the hex/octal/binary
prefix) are accepted as if they are valid too.
.TP
\fBTCL_LINK_LONG\fR
The C variable is of type \fBlong\fR.
.
The C variable, or each element of the C array, is of type \fBlong\fR.
Any value written into the Tcl variable must have a proper integer
form acceptable to \fBTcl_GetLongFromObj\fR; attempts to write
non-integer or out-of-range
@@ -123,7 +190,8 @@ integer representations (like the empty string, '+', '-' or the
hex/octal/binary prefix) are accepted as if they are valid too.
.TP
\fBTCL_LINK_ULONG\fR
The C variable is of type \fBunsigned long\fR.
.
The C variable, or each element of the C array, is of type \fBunsigned long\fR.
Any value written into the Tcl variable must have a proper unsigned
integer form acceptable to \fBTcl_GetWideIntFromObj\fR and in the
platform's defined range for the \fBunsigned long\fR type; attempts to
@@ -133,7 +201,8 @@ representations (like the empty string, '+', '-' or the hex/octal/binary
prefix) are accepted as if they are valid too.
.TP
\fBTCL_LINK_DOUBLE\fR
The C variable is of type \fBdouble\fR.
.
The C variable, or each element of the C array, is of type \fBdouble\fR.
Any value written into the Tcl variable must have a proper real
form acceptable to \fBTcl_GetDoubleFromObj\fR; attempts to write
non-real values into \fIvarName\fR will be rejected with
@@ -142,7 +211,8 @@ empty string, '.', '+', '-' or the hex/octal/binary prefix) are
accepted as if they are valid too.
.TP
\fBTCL_LINK_FLOAT\fR
The C variable is of type \fBfloat\fR.
.
The C variable, or each element of the C array, is of type \fBfloat\fR.
Any value written into the Tcl variable must have a proper real
form acceptable to \fBTcl_GetDoubleFromObj\fR and must be within the
range acceptable for a \fBfloat\fR; attempts to
@@ -152,7 +222,9 @@ or real representations (like the empty string, '.', '+', '-' or
the hex/octal/binary prefix) are accepted as if they are valid too.
.TP
\fBTCL_LINK_WIDE_INT\fR
The C variable is of type \fBTcl_WideInt\fR (which is an integer type
.
The C variable, or each element of the C array, is of type \fBTcl_WideInt\fR
(which is an integer type
at least 64-bits wide on all platforms that can support it.)
Any value written into the Tcl variable must have a proper integer
form acceptable to \fBTcl_GetWideIntFromObj\fR; attempts to write
@@ -162,9 +234,10 @@ string, '+', '-' or the hex/octal/binary prefix) are accepted
as if they are valid too.
.TP
\fBTCL_LINK_WIDE_UINT\fR
The C variable is of type \fBTcl_WideUInt\fR (which is an unsigned
integer type at least 64-bits wide on all platforms that can support
it.)
.
The C variable, or each element of the C array, is of type \fBTcl_WideUInt\fR
(which is an unsigned integer type at least 64-bits wide on all platforms that
can support it.)
Any value written into the Tcl variable must have a proper unsigned
integer form acceptable to \fBTcl_GetWideIntFromObj\fR (it will be
cast to unsigned);
@@ -175,7 +248,8 @@ the empty string, '+', '-' or the hex/octal/binary prefix) are accepted
as if they are valid too.
.TP
\fBTCL_LINK_BOOLEAN\fR
The C variable is of type \fBint\fR.
.
The C variable, or each element of the C array, is of type \fBint\fR.
If its value is zero then it will read from Tcl as
.QW 0 ;
otherwise it will read from Tcl as
@@ -188,6 +262,7 @@ non-boolean values into \fIvarName\fR will be rejected with
Tcl errors.
.TP
\fBTCL_LINK_STRING\fR
.
The C variable is of type \fBchar *\fR.
If its value is not NULL then it must be a pointer to a string
allocated with \fBTcl_Alloc\fR or \fBckalloc\fR.
@@ -197,6 +272,7 @@ new value.
If the C variable contains a NULL pointer then the Tcl variable
will read as
.QW NULL .
This is only supported by \fBTcl_LinkVar\fR.
.PP
If the \fBTCL_LINK_READ_ONLY\fR flag is present in \fItype\fR then the
variable will be read-only from Tcl, so that its value can only be
+4 -4
View File
@@ -331,11 +331,11 @@ trace procedures will always be invoked.
.SH "RESTRICTIONS"
.PP
A trace procedure can be called at any time, even when there
is a partially formed result in the interpreter's result area. If
are partially formed results stored in the interpreter. If
the trace procedure does anything that could damage this result (such
as calling \fBTcl_Eval\fR) then it must save the original values of
the interpreter's \fBresult\fR and \fBfreeProc\fR fields and restore
them before it returns.
as calling \fBTcl_Eval\fR) then it must use the \fBTcl_SaveInterpState\fR
and related routines to save and restore the original state of
the interpreter before it returns.
.SH "UNDEFINED VARIABLES"
.PP
It is legal to set a trace on an undefined variable.
+97 -9
View File
@@ -14,10 +14,13 @@ coroutine, yield, yieldto \- Create and produce values from coroutines
.nf
\fBcoroutine \fIname command\fR ?\fIarg...\fR?
\fByield\fR ?\fIvalue\fR?
.VS TIP396
\fByieldto\fR \fIcommand\fR ?\fIarg...\fR?
\fIname\fR ?\fIvalue...\fR?
.VE TIP396
.sp
.VS "8.7, TIP383"
\fBcoroinject \fIcoroName command\fR ?\fIarg...\fR?
\fBcoroprobe \fIcoroName command\fR ?\fIarg...\fR?
.VE "8.7, TIP383"
.fi
.BE
.SH DESCRIPTION
@@ -39,7 +42,6 @@ the context to be suspended. If the coroutine context never yields and instead
returns conventionally, the result of the \fBcoroutine\fR command will be the
result of the evaluation of the context.
.PP
.VS TIP396
The coroutine may also suspend its execution by use of the \fByieldto\fR
command, which instead of returning, cedes execution to some command called
\fIcommand\fR (resolved in the context of the coroutine) and to which \fIany
@@ -58,11 +60,10 @@ with multiple arguments is by using \fByieldto\fR and the \fBreturn\fR
command, like this:
.PP
.CS
proc yieldm {value} {
\fByieldto\fR return -level 0 $value
proc yieldMultiple {value} {
tailcall \fByieldto\fR string cat $value
}
.CE
.VE TIP396
.PP
The coroutine can also be deleted by destroying the command \fIname\fR, and
the name of the current coroutine can be retrieved by using
@@ -75,6 +76,51 @@ At the point when \fIcommand\fR is called, the current namespace will be the
global namespace and there will be no stack frames above it (in the sense of
\fBupvar\fR and \fBuplevel\fR). However, which command to call will be
determined in the namespace that the \fBcoroutine\fR command was called from.
.PP
.VS "8.7, TIP383"
A suspended coroutine (i.e., one that has \fByield\fRed or \fByieldto\fR-d)
may have its state inspected (or modified) at that point by using
\fBcoroprobe\fR to run a command at the point where the coroutine is at. The
command takes the name of the coroutine to run the command in, \fIcoroName\fR,
and the name of a command (any any arguments it requires) to immediately run
at that point. The result of that command is the result of the \fBcoroprobe\fR
command, and the gross state of the coroutine remains the same afterwards
(i.e., the coroutine is still expecting the results of a \fByield\fR or
\fByieldto\fR as before) though variables may have been changed.
.PP
Similarly, the \fBcoroinject\fR command may be used to place a command to be
run inside a suspended coroutine (when it is resumed) to process arguments,
with quite a bit of similarity to \fBcoroprobe\fR. However, with
\fBcoroinject\fR there are several key differences:
.VE "8.7, TIP383"
.IP \(bu
.VS "8.7, TIP383"
The coroutine is not immediately resumed after the injection has been done. A
consequence of this is that multiple injections may be done before the
coroutine is resumed. There injected commands are performed in \fIreverse
order of definition\fR (that is, they are internally stored on a stack).
.VE "8.7, TIP383"
.IP \(bu
.VS "8.7, TIP383"
An additional two arguments are appended to the list of arguments to be run
(that is, the \fIcommand\fR and its \fIargs\fR are extended by two elements).
The first is the name of the command that suspended the coroutine (\fByield\fR
or \fByieldto\fR), and the second is the argument (or list of arguments, in
the case of \fByieldto\fR) that is the current resumption value.
.VE "8.7, TIP383"
.IP \(bu
.VS "8.7, TIP383"
The result of the injected command is used as the result of the \fByield\fR or
\fByieldto\fR that caused the coroutine to become suspended. Where there are
multiple injected commands, the result of one becomes the resumption value
processed by the next.
.PP
The injection is a one-off. It is not retained once it has been executed. It
may \fByield\fR or \fByieldto\fR as part of its execution.
.PP
Note that running coroutines may be neither probed nor injected; the
operations may only be applied to
.VE "8.7, TIP383"
.SH EXAMPLES
.PP
This example shows a coroutine that will produce an infinite sequence of
@@ -138,7 +184,6 @@ for {set i 1} {$i <= 20} {incr i} {
}
.CE
.PP
.VS TIP396
This example shows how a value can be passed around a group of three
coroutines that yield to each other:
.PP
@@ -150,14 +195,57 @@ proc juggler {name target {value ""}} {
while {$value ne ""} {
puts "$name : $value"
set value [string range $value 0 end-1]
lassign [\fByieldto\fR $target $value] value
lassign [\fByieldto\fR \fI$target\fR $value] value
}
}
\fBcoroutine\fR j1 juggler Larry [
\fBcoroutine\fR j2 juggler Curly [
\fBcoroutine\fR j3 juggler Moe j1]] "Nyuck!Nyuck!Nyuck!"
.CE
.VE TIP396
.PP
.VS "8.7, TIP383"
This example shows a simple coroutine that collects non-empty values and
returns a list of them when not given an argument. It also shows how we can
look inside the coroutine to find out what it is doing, and how we can modify
the input on a one-off basis.
.PP
.CS
proc collectorImpl {} {
set me [info coroutine]
set accumulator {}
for {set val [\fByield\fR $me]} {$val ne ""} {set val [\fByield\fR]} {
lappend accumulator $val
}
return $accumulator
}
\fBcoroutine\fR collect collectorImpl
\fIcollect\fR 123
\fIcollect\fR "abc def"
\fIcollect\fR 456
puts [\fBcoroprobe \fIcollect\fR set accumulator]
# ==> 123 {abc def} 456
\fIcollect\fR "pqr"
\fBcoroinject \fIcollect\fR apply {{type value} {
puts "Received '$value' at a $type in [info coroutine]"
return [string toupper $value]
}}
\fIcollect\fR rst
# ==> Received 'rst' at a yield in ::collect
\fIcollect\fR xyz
puts [\fIcollect\fR]
# ==> 123 {abc def} 456 pqr RST xyz
.CE
.PP
This example shows a simple coroutine that collects non-empty values and
returns a list of them when not given an argument. It also shows how we can
look inside the coroutine to find out what it is doing.
.VE "8.7, TIP383"
.SS "DETAILED SEMANTICS"
.PP
This example demonstrates that coroutines start from the global namespace, and
+16
View File
@@ -120,6 +120,22 @@ It is an error to attempt to retrieve a value for a key that is not
present in the dictionary.
.RE
.TP
\fBdict getdef \fIdictionaryValue \fR?\fIkey ...\fR? \fIkey default\fR
.TP
\fBdict getwithdefault \fIdictionaryValue \fR?\fIkey ...\fR? \fIkey default\fR
.VS "8.7, TIP342"
This behaves the same as \fBdict get\fR (with at least one \fIkey\fR
argument), returning the value that the key path maps to in the
dictionary \fIdictionaryValue\fR, except that instead of producing an
error because the \fIkey\fR (or one of the \fIkey\fRs on the key path)
is absent, it returns the \fIdefault\fR argument instead.
.RS
.PP
Note that there must always be at least one \fIkey\fR provided, and that
\fBdict getdef\fR and \fBdict getwithdefault\fR are aliases for each other.
.RE
.VE "8.7, TIP342"
.TP
\fBdict incr \fIdictionaryVariable key \fR?\fIincrement\fR?
.
This adds the given increment value (an integer that defaults to 1 if
+61 -9
View File
@@ -97,7 +97,7 @@ and the value of \fBb\fR is 6. The command on the left side of each line
produces the value on the right side.
.PP
.CS
.ta 6c
.ta 9c
\fBexpr\fR 3.1 + $a \fI6.1\fR
\fBexpr\fR 2 + "$a.$b" \fI5.6\fR
\fBexpr\fR 4*[llength "6 2"] \fI8\fR
@@ -159,7 +159,18 @@ A right shift always propagates the sign bit.
.TP 20
\fB<\0\0>\0\0<=\0\0>=\fR
.
Boolean less than, greater than, less than or equal, and greater than or equal.
Boolean numeric-preferring comparisons: less than, greater than, less than or
equal, and greater than or equal. If either argument is not numeric, the
comparison is done using UNICODE string comparison, as with the string
comparison operators below, which have the same precedence.
.TP 20
\fBlt\0\0gt\0\0le\0\0ge\fR
.VS "8.7, TIP461"
Boolean string comparisons: less than, greater than, less than or equal, and
greater than or equal. These always compare values using their UNICODE strings
(also see \fBstring compare\fR), unlike with the numeric-preferring
comparisons abov, which have the same precedence.
.VE "8.7, TIP461"
.TP 20
\fB==\0\0!=\fR
.
@@ -190,16 +201,22 @@ Bit-wise OR. Valid for integer operands.
\fB&&\fR
.
Logical AND. If both operands are true, the result is 1, or 0 otherwise.
This operator evaluates lazily; it only evaluates its second operand if it
must in order to determine its result.
This operator evaluates lazily; it only evaluates its second operand if it
must in order to determine its result.
.TP 20
\fB||\fR
.
Logical OR. If both operands are false, the result is 0, or 1 otherwise.
This operator evaluates lazily; it only evaluates its second operand if it
must in order to determine its result.
.TP 20
\fIx\fB?\fIy\fB:\fIz\fR
\fIx \fB?\fI y \fB:\fI z\fR
.
If-then-else, as in C. If \fIx\fR is false , the result is the value of
\fIy\fR. Otherwise the result is the value of \fIz\fR.
This operator evaluates lazily; it evaluates only one of \fIy\fR or \fIz\fR.
.PP
The exponentiation operator promotes types in the same way that the multiply
and divide operators do, and the result is is the same as the result of
@@ -207,6 +224,7 @@ and divide operators do, and the result is is the same as the result of
Exponentiation groups right-to-left within a precedence level. Other binary
operators group left-to-right. For example, the value of
.PP
.PP
.CS
\fBexpr\fR {4*2 < 7}
.CE
@@ -337,39 +355,73 @@ This also avoids issues that can arise if Tcl is allowed to perform
substitution on the value before \fBexpr\fR is called.
.PP
In the following example, the value of the expression is 11 because the Tcl parser first
substitutes \fB$b\fR and \fBexpr\fR then substitutes \fB$a\fR. Enclosing the
expression in braces would result in a syntax error.
substitutes \fB$b\fR and \fBexpr\fR then substitutes \fB$a\fR as part
of evaluating the expression
.QW "$a + 2*4" .
Enclosing the
expression in braces would result in a syntax error as \fB$b\fR does
not evaluate to a numeric value.
.PP
.CS
set a 3
set b {$a + 2}
\fBexpr\fR $b*4
.CE
.PP
When an expression is generated at runtime, like the one above is, the bytcode
When an expression is generated at runtime, like the one above is, the bytecode
compiler must ensure that new code is generated each time the expression
is evaluated. This is the most costly kind of expression from a performance
perspective. In such cases, consider directly using the commands described in
the \fBmathfunc\fR(n) or \fBmathop\fR(n) documentation instead of \fBexpr\fR.
.PP
Most expressions are not formed at runtime, but are literal strings or contain
substitutions that don't introduce other substitutions. To allow the bytecode
compiler to work with an expression as a string literal at compilation time,
ensure that it contains no substitutions or that it is enclosed in braces or
otherwise quoted to prevent Tcl from performing substitutions, allowing
\fBexpr\fR to perform them instead.
.PP
If it is necessary to include a non-constant expression string within the
wider context of an otherwise-constant expression, the most efficient
technique is to put the varying part inside a recursive \fBexpr\fR, as this at
least allows for the compilation of the outer part, though it does mean that
the varying part must itself be evaluated as a separate expression. Thus, in
this example the result is 20 and the outer expression benefits from fully
cached bytecode compilation.
.PP
.CS
set a 3
set b {$a + 2}
\fBexpr\fR {[\fBexpr\fR $b] * 4}
.CE
.PP
In general, you should enclose your expression in braces wherever possible,
and where not possible, the argument to \fBexpr\fR should be an expression
defined elsewhere as simply as possible. It is usually more efficient and
safer to use other techniques (e.g., the commands in the \fBtcl::mathop\fR
namespace) than it is to do complex expression generation.
.SH EXAMPLES
.PP
A numeric comparison whose result is 1:
.PP
.CS
\fBexpr\fR {"0x03" > "2"}
.CE
.PP
A string comparison whose result is 1:
.PP
.CS
\fBexpr\fR {"0y" > "0x12"}
.CE
.PP
.VS "8.7, TIP461"
A forced string comparison whose result is 0:
.PP
.CS
\fBexpr\fR {"0x03" gt "2"}
.CE
.VE "8.7, TIP461"
.PP
Define a procedure that computes an
.QW interesting
mathematical function:
+30
View File
@@ -433,6 +433,36 @@ If \fIname\fR contains no separators then returns \fIname\fR. So,
\fBfile tail a/b\fR, \fBfile tail a/b/\fR and \fBfile tail b\fR all
return \fBb\fR.
.TP
\fBfile tempdir\fR ?\fItemplate\fR?
.VS "8.7, TIP 431"
Creates a temporary directory (guaranteed to be newly created and writable by
the current script) and returns its name. If \fItemplate\fR is given, it
specifies one of or both of the existing directory (on a filesystem controlled
by the operating system) to contain the temporary directory, and the base part
of the directory name; it is considered to have the location of the directory
if there is a directory separator in the name, and the base part is everything
after the last directory separator (if non-empty). The default containing
directory is determined by system-specific operations, and the default base
name prefix is
.QW \fBtcl\fR .
.RS
.PP
The following output is typical and illustrative; the actual output will vary
between platforms:
.PP
.CS
% \fBfile tempdir\fR
/var/tmp/tcl_u0kuy5
% \fBfile tempdir\fR /tmp/myapp
/tmp/myapp_8o7r9L
% \fBfile tempdir\fR /tmp/
/tmp/tcl_1mOJHD
% \fBfile tempdir\fR myapp
/var/tmp/myapp_0ihS0n
.CE
.RE
.VE "8.7, TIP 431"
.TP
\fBfile tempfile\fR ?\fInameVar\fR? ?\fItemplate\fR?
'\" TIP #210
.VS 8.6
+1 -1
View File
@@ -72,7 +72,7 @@ elements to
.CE
.SH "SEE ALSO"
list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n),
lset(n), lreplace(n), lsort(n),
lset(n), lremove(n), lreplace(n), lsort(n),
string(n)
.SH KEYWORDS
element, list, range, sublist
+55
View File
@@ -0,0 +1,55 @@
'\"
'\" Copyright (c) 2019 Donal K. Fellows.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH lremove n 8.7 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
lremove \- Remove elements from a list by index
.SH SYNOPSIS
\fBlremove \fIlist\fR ?\fIindex ...\fR?
.BE
.SH DESCRIPTION
.PP
\fBlremove\fR returns a new list formed by simultaneously removing zero or
more elements of \fIlist\fR at each of the indices given by an arbirary number
of \fIindex\fR arguments. The indices may be in any order and may be repeated;
the element at index will only be removed once. The index values are
interpreted the same as index values for the command \fBstring index\fR,
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.
.SH EXAMPLES
.PP
Removing the third element of a list:
.PP
.CS
% \fBlremove\fR {a b c d e} 2
a b d e
.CE
.PP
Removing two elements from a list:
.PP
.CS
% \fBlremove\fR {a b c d e} end-1 1
a c e
.CE
.PP
Removing the same element indicated in two different ways:
.PP
.CS
% \fBlremove\fR {a b c d e} 2 end-2
a b d e
.CE
.SH "SEE ALSO"
list(n), lrange(n), lsearch(n), lsearch(n)
.SH KEYWORDS
element, list, remove
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+1 -1
View File
@@ -96,7 +96,7 @@ a b c d e f g h i
.VE TIP505
.SH "SEE ALSO"
list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n),
lset(n), lrange(n), lsort(n),
lset(n), lrange(n), lremove(n), lsort(n),
string(n)
.SH KEYWORDS
element, list, replace
+57 -10
View File
@@ -55,6 +55,16 @@ package require \fBTcl 8.5\fR
.br
\fB::tcl::mathop::ne\fR \fIarg arg\fR
.br
.VS "8.7, TIP461"
\fB::tcl::mathop::lt\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::le\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::gt\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::ge\fR ?\fIarg\fR ...?
.VE "8.7, TIP461"
.br
\fB::tcl::mathop::in\fR \fIarg list\fR
.br
\fB::tcl::mathop::ni\fR \fIarg list\fR
@@ -76,7 +86,8 @@ The following operator commands are supported:
\fB/\fR \fB%\fR \fB**\fR \fB&\fR \fB|\fR
\fB^\fR \fB>>\fR \fB<<\fR \fB==\fR \fBeq\fR
\fB!=\fR \fBne\fR \fB<\fR \fB<=\fR \fB>\fR
\fB>=\fR \fBin\fR \fBni\fR
\fB>=\fR \fBin\fR \fBni\fR \fBlt\fR \fBle\fR
\fBgt\fR \fBge\fR
.DE
.SS "MATHEMATICAL OPERATORS"
.PP
@@ -192,8 +203,8 @@ after the first having to be strictly more than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBstring
compare\fR command should be used instead.
arguments are numeric but should be compared as strings, the \fBlt\fR
operator or the \fBstring compare\fR command should be used instead.
.TP
\fB<=\fR ?\fIarg\fR ...?
.
@@ -202,8 +213,8 @@ after the first having to be equal to or more than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBstring
compare\fR command should be used instead.
arguments are numeric but should be compared as strings, the \fBle\fR
operator or the \fBstring compare\fR command should be used instead.
.TP
\fB>\fR ?\fIarg\fR ...?
.
@@ -212,8 +223,8 @@ after the first having to be strictly less than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBstring
compare\fR command should be used instead.
arguments are numeric but should be compared as strings, the \fBgt\fR
operator or the \fBstring compare\fR command should be used instead.
.TP
\fB>=\fR ?\fIarg\fR ...?
.
@@ -222,8 +233,40 @@ after the first having to be equal to or less than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBstring
compare\fR command should be used instead.
arguments are numeric but should be compared as strings, the \fBge\fR
operator or the \fBstring compare\fR command should be used instead.
.TP
\fBlt\fR ?\fIarg\fR ...?
.VS "8.7, TIP461"
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be strictly more than the one preceding it.
Comparisons are performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value.
.VE "8.7, TIP461"
.TP
\fBle\fR ?\fIarg\fR ...?
.VS "8.7, TIP461"
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be equal to or strictly more than the one preceding it.
Comparisons are performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value.
.VE "8.7, TIP461"
.TP
\fBgt\fR ?\fIarg\fR ...?
.VS "8.7, TIP461"
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be strictly less than the one preceding it.
Comparisons are performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value.
.VE "8.7, TIP461"
.TP
\fBge\fR ?\fIarg\fR ...?
.VS "8.7, TIP461"
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be equal to or strictly less than the one preceding it.
Comparisons are performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value.
.VE "8.7, TIP461"
.SS "BIT-WISE OPERATORS"
.PP
The behaviors of the bit-wise operator commands (all of which only operate on
@@ -299,8 +342,12 @@ set gotIt [\fBin\fR 3 $list]
\fI# Test to see if a value is within some defined range\fR
set inRange [\fB<=\fR 1 $x 5]
\fI# Test to see if a list is sorted\fR
\fI# Test to see if a list is numerically sorted\fR
set sorted [\fB<=\fR {*}$list]
\fI# Test to see if a list is lexically sorted\fR
set alphaList {a b c d e f}
set sorted [\fBle\fR {*}$alphaList]
.CE
.SH "SEE ALSO"
expr(n), mathfunc(n), namespace(n)
+140 -6
View File
@@ -166,8 +166,9 @@ is opened and initialized in a platform-dependent manner. Acceptable
values for the \fIfileName\fR to use to open a serial port are described in
the PORTABILITY ISSUES section.
.PP
The \fBfconfigure\fR command can be used to query and set additional
configuration options specific to serial ports (where supported):
The \fBchan configure\fR and \fBfconfigure\fR commands can be used to query
and set additional configuration options specific to serial ports (where
supported):
.TP
\fB\-mode\fR \fIbaud\fB,\fIparity\fB,\fIdata\fB,\fIstop\fR
.
@@ -249,6 +250,75 @@ handshake characters. Normally the operating system default should be
DC1 (0x11) and DC3 (0x13) representing the ASCII standard
XON and XOFF characters.
.TP
\fB\-closemode\fR \fIcloseMode\fR
.VS "8.7, TIP 160"
(Windows and Unix). This option is used to query or change the close mode of
the serial channel, which defines how pending output in operating system
buffers is handled when the channel is closed. The following values for
\fIcloseMode\fR are supported:
.RS
.TP
\fBdefault\fR
.
indicates that a system default operation should be used; all serial channels
default to this.
.TP
\fBdiscard\fR
.
indicates that the contents of the OS buffers should be discarded. Note that
this is \fInot recommended\fR when writing to a POSIX terminal, as it can
interact unexpectedly with handling of \fBstderr\fR.
.TP
\fBdrain\fR
.
indicates that Tcl should wait when closing the channel until all output has
been consumed. This may slow down \fBclose\fR noticeably.
.RE
.VE "8.7, TIP 160"
.TP
\fB\-inputmode\fR \fIinputMode\fR
.VS "8.7, TIP 160"
(Unix only; Windows has the equivalent option on console channels). This
option is used to query or change the input mode of the serial channel under
the assumption that it is talking to a terminal, which controls how interactive
input from users is handled. The following values for \fIinputMode\fR are
supported:
.RS
.TP
\fBnormal\fR
.
indicates that normal line-oriented input should be used, with standard
terminal editing capabilities enabled.
.TP
\fBpassword\fR
.
indicates that non-echoing input should be used, with standard terminal
editing capabilities enabled but no writing of typed characters to the
terminal (except for newlines). Some terminals may indicate this specially.
.TP
\fBraw\fR
.
indicates that all keyboard input should be given directly to Tcl with the
terminal doing no processing at all. It does not echo the keys, leaving it up
to the Tcl script to interpret what to do.
.TP
\fBreset\fR (set only)
.
indicates that the terminal should be reset to what state it was in when the
terminal was opened.
.PP
Note that setting this option (technically, anything that changes the terminal
state from its initial value \fIvia this option\fR) will cause the channel to
turn on an automatic reset of the terminal when the channel is closed.
.RE
.TP
\fB\-winsize\fR
.
(Unix only; Windows has the equivalent option on console channels). This
option is query only. It retrieves a two-element list with the the current
width and height of the terminal.
.VE "8.7, TIP 160"
.TP
\fB\-pollinterval\fR \fImsec\fR
.
(Windows only). This option is used to set the maximum time between
@@ -275,7 +345,7 @@ In case of a serial communication error, \fBread\fR or \fBputs\fR
returns a general Tcl file I/O error.
\fBfconfigure\fR \fB\-lasterror\fR can be called to get a list of error details.
See below for an explanation of the various error codes.
.SH "SERIAL PORT SIGNALS"
.SS "SERIAL PORT SIGNALS"
.PP
RS-232 is the most commonly used standard electrical interface for serial
communications. A negative voltage (-3V..-12V) define a mark (on=1) bit and
@@ -316,7 +386,7 @@ milliseconds. Normally a receive or transmit data signal stays at the mark
(on=1) voltage until the next character is transferred. A BREAK is sometimes
used to reset the communications line or change the operating mode of
communications hardware.
.SH "ERROR CODES (Windows only)"
.SS "ERROR CODES (Windows only)"
.PP
A lot of different errors may occur during serial read operations or during
event polling in background. The external device may have been switched
@@ -359,7 +429,7 @@ may cause this error.
\fBBREAK\fR
.
A BREAK condition has been detected by your UART (see above).
.SH "PORTABILITY ISSUES"
.SS "PORTABILITY ISSUES"
.TP
\fBWindows \fR
.
@@ -408,7 +478,55 @@ input, but is redirected from a file, then the above problem does not occur.
See the \fBPORTABILITY ISSUES\fR section of the \fBexec\fR command for
additional information not specific to command pipelines about executing
applications on the various platforms
.SH "EXAMPLE"
.SH "CONSOLE CHANNELS"
.VS "8.7, TIP 160"
On Windows only, console channels (usually \fBstdin\fR or \fBstdout\fR)
support the following options:
.TP
\fB\-inputmode\fR \fIinputMode\fR
.
This option is used to query or change the input mode of the console channel,
which controls how interactive input from users is handled. The following
values for \fIinputMode\fR are supported:
.RS
.TP
\fBnormal\fR
.
indicates that normal line-oriented input should be used, with standard
console editing capabilities enabled.
.TP
\fBpassword\fR
.
indicates that non-echoing input should be used, with standard console
editing capabilitied enabled but no writing of typed characters to the
terminal (except for newlines).
.TP
\fBraw\fR
.
indicates that all keyboard input should be given directly to Tcl with the
console doing no processing at all. It does not echo the keys, leaving it up
to the Tcl script to interpret what to do.
.TP
\fBreset\fR (set only)
.
indicates that the console should be reset to what state it was in when the
console channel was opened.
.PP
Note that setting this option (technically, anything that changes the console
state from its default \fIvia this option\fR) will cause the channel to turn
on an automatic reset of the console when the channel is closed.
.RE
.TP
\fB\-winsize\fR
.
This option is query only.
It retrieves a two-element list with the the current width and height of the
console that this channel is talking to.
.PP
Note that the equivalent options exist on Unix, but are on the serial channel
type.
.VE "8.7, TIP 160"
.SH "EXAMPLES"
.PP
Open a command pipeline and catch any errors:
.PP
@@ -419,6 +537,22 @@ if {[catch {close $fl} err]} {
puts "ls command failed: $err"
}
.CE
.PP
.VS "8.7, TIP 160"
Read a password securely from the user (assuming that the script is being run
interactively):
.PP
.CS
chan configure stdin \fB-inputmode password\fR
try {
chan puts -nonewline "Password: "
chan flush stdout
set thePassword [chan gets stdin]
} finally {
chan configure stdin \fB-inputmode reset\fR
}
.CE
.VE "8.7, TIP 160"
.SH "SEE ALSO"
file(n), close(n), filename(n), fconfigure(n), gets(n), read(n),
puts(n), exec(n), pid(n), fopen(3)
+11 -5
View File
@@ -89,9 +89,9 @@ length of the string then this command returns an empty string.
.RE
.TP
\fBstring insert \fIstring index insertString\fR
.
.VS "TIP 504"
Returns a copy of \fIstring\fR with \fIinsertString\fR inserted at the
\fIindex\fR'th character. \fIindex\fR may be specified as described in the
\fIindex\fR'th character. The \fIindex\fR may be specified as described in the
\fBSTRING INDICES\fR section.
.RS
.PP
@@ -104,6 +104,7 @@ If \fIindex\fR is at or before the start of \fIstring\fR (e.g., \fIindex\fR is
or after the end of \fIstring\fR (e.g., \fIindex\fR is \fBend\fR),
\fIinsertString\fR is appended to \fIstring\fR.
.RE
.VE "TIP 504"
.TP
\fBstring is \fIclass\fR ?\fB\-strict\fR? ?\fB\-failindex \fIvarname\fR? \fIstring\fR
.
@@ -291,7 +292,9 @@ the special interpretation of the characters \fB*?[]\e\fR in
.
Returns a range of consecutive characters from \fIstring\fR, starting
with the character whose index is \fIfirst\fR and ending with the
character whose index is \fIlast\fR. An index of 0 refers to the first
character whose index is \fIlast\fR (using the forms described in
\fBSTRING INDICES\fR). An index of \fB0\fR refers to the first
character of the string; an index of \fBend\fR refers to last
character of the string. \fIfirst\fR and \fIlast\fR may be specified
as for the \fBindex\fR method. If \fIfirst\fR is less than zero then
it is treated as if it were zero, and if \fIlast\fR is greater than or
@@ -301,13 +304,16 @@ string is returned.
.TP
\fBstring repeat \fIstring count\fR
.
Returns \fIstring\fR repeated \fIcount\fR number of times.
Returns a string consisting of \fIstring\fR concatenated with itself
\fIcount\fR times. If \fIcount\fR is 0, the empty string will be
returned.
.TP
\fBstring replace \fIstring first last\fR ?\fInewstring\fR?
.
Removes a range of consecutive characters from \fIstring\fR, starting
with the character whose index is \fIfirst\fR and ending with the
character whose index is \fIlast\fR. An index of 0 refers to the
character whose index is \fIlast\fR (using the forms described in
\fBSTRING INDICES\fR). An index of 0 refers to the
first character of the string. \fIFirst\fR and \fIlast\fR may be
specified as for the \fBindex\fR method. If \fInewstring\fR is
specified, then it is placed in the removed character range. If
+65 -48
View File
@@ -9,16 +9,26 @@
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
timerate \- Time-related execution resp. performance measurement of a script
timerate \- Calibrated performance measurements of script execution time
.SH SYNOPSIS
\fBtimerate \fIscript\fR \fI?time ?max-count??\fR
\fBtimerate \fIscript\fR ?\fItime\fR? ?\fImax-count\fR?
.sp
\fBtimerate \fI?-direct?\fR \fI?-overhead double?\fR \fIscript\fR \fI?time ?max-count??\fR
\fBtimerate \fR?\fB\-direct\fR? ?\fB\-overhead\fI double\fR? \fIscript\fR ?\fItime\fR? ?\fImax-count\fR?
.sp
\fBtimerate \fI?-calibrate?\fR \fI?-direct?\fR \fIscript\fR \fI?time ?max-count??\fR
\fBtimerate \fR?\fB\-calibrate\fR? ?\fB\-direct\fR? \fIscript\fR ?\fItime\fR? ?\fImax-count\fR?
.BE
.SH DESCRIPTION
.PP
The \fBtimerate\fR command does calibrated performance measurement of a Tcl
command or script, \fIscript\fR. The \fIscript\fR should be written so that it
can be executed multiple times during the performance measurement process.
Time is measured in elapsed time using the finest timer resolution as possible,
not CPU time; if \fIscript\fR interacts with the OS, the cost of that
interaction is included.
This command may be used to provide information as to how well a script or
Tcl command is performing, and can help determine bottlenecks and fine-tune
application performance.
.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.
@@ -28,47 +38,48 @@ by the maximal number of iterations to evaluate the script.
If \fImax-count\fR is specified, the evalution will stop either this count of
iterations is reached or the time is exceeded.
.sp
It will then return a canonical tcl-list of the form
It will then return a canonical tcl-list of the form:
.PP
.CS
\fB0.095977 \(mcs/# 52095836 # 10419167 #/sec 5000.000 nett-ms\fR
\fB0.095977 \(mcs/# 52095836 # 10419167 #/sec 5000.000 net-ms\fR
.CE
.PP
which indicates:
.IP \(bu
.IP \(bu 3
the average amount of time required per iteration, in microseconds ([\fBlindex\fR $result 0])
.IP \(bu
.IP \(bu 3
the count how many times it was executed ([\fBlindex\fR $result 2])
.IP \(bu
.IP \(bu 3
the estimated rate per second ([\fBlindex\fR $result 4])
.IP \(bu
.IP \(bu 3
the estimated real execution time without measurement overhead ([\fBlindex\fR $result 6])
.PP
Time is measured in elapsed time using the finest 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.
The following options may be supplied to the \fBtimerate\fR command:
.TP
\fI-calibrate\fR
\fB\-calibrate\fR
.
To measure very fast scripts as exact as posible the calibration process
To measure very fast scripts as exactly as possible, a calibration process
may be required.
The \fI-calibrate\fR option is used to calibrate timerate, calculating the
estimated overhead of the given script as the default overhead for future
invocations of the \fBtimerate\fR command. If the \fItime\fR parameter is not
specified, the calibrate procedure runs for up to 10 seconds.
The \fB\-calibrate\fR option is used to calibrate \fBtimerate\fR itself,
calculating the estimated overhead of the given script as the default overhead
for future invocations of the \fBtimerate\fR command. If the \fItime\fR
parameter is not specified, the calibrate procedure runs for up to 10 seconds.
.RS
.PP
Note that calibration is not thread safe in the current implementation.
.RE
.TP
\fI-overhead double\fR
\fB\-overhead \fIdouble\fR
.
The \fI-overhead\fR parameter supplies an estimate (in microseconds) of the
The \fB\-overhead\fR parameter supplies an estimate (in microseconds) of the
measurement overhead of each iteration of the tested script. This quantity
will be subtracted from the measured time prior to reporting results.
will be subtracted from the measured time prior to reporting results. This can
be useful for removing the cost of interpreter state reset commands from the
script being measured.
.TP
\fI-direct\fR
\fB\-direct\fR
.
The \fI-direct\fR option causes direct execution of the supplied script,
The \fB-direct\fR option causes direct execution of the supplied script,
without compilation, in a manner similar to the \fBtime\fR command. It can be
used to measure the cost of \fBTcl_EvalObjEx\fR, of the invocation of canonical
lists, and of the uncompiled versions of bytecoded commands.
@@ -76,31 +87,33 @@ lists, and of the uncompiled versions of bytecoded commands.
As opposed to the \fBtime\fR commmand, which runs the tested script for a fixed
number of iterations, the timerate command runs it for a fixed time.
Additionally, the compiled variant of the script will be used during the entire
measurement, as if the script were part of a compiled procedure, if the \fI-direct\fR
measurement, as if the script were part of a compiled procedure, if the \fB\-direct\fR
option is not specified. The fixed time period and possibility of compilation allow
for more precise results and prevent very long execution times by slow scripts, making
it practical for measuring scripts with highly uncertain execution times.
.SH EXAMPLE
.SH EXAMPLES
Estimate how fast it takes for a simple Tcl \fBfor\fR loop (including
operations on variable \fIi\fR) to count to a ten:
operations on variable \fIi\fR) to count to ten:
.PP
.CS
# calibrate:
timerate -calibrate {}
# measure:
timerate { for {set i 0} {$i<10} {incr i} {} } 5000
\fI# calibrate\fR
\fBtimerate\fR -calibrate {}
\fI# measure\fR
\fBtimerate\fR { for {set i 0} {$i<10} {incr i} {} } 5000
.CE
.PP
Estimate how fast it takes for a simple Tcl \fBfor\fR loop, ignoring the
overhead for to perform ten iterations, ignoring the overhead of the management
of the variable that controls the loop:
overhead of the management of the variable that controls the loop:
.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
\fI# calibrate for overhead of variable operations\fR
set i 0; \fBtimerate\fR -calibrate {expr {$i<10}; incr i} 1000
\fI# measure\fR
\fBtimerate\fR {
for {set i 0} {$i<10} {incr i} {}
} 5000
.CE
.PP
Estimate the speed of calculating the hour of the day using \fBclock format\fR only,
@@ -108,14 +121,18 @@ ignoring overhead of the portion of the script that prepares the time for it to
calculate:
.PP
.CS
# calibrate:
timerate -calibrate {}
# estimate overhead:
\fI# calibrate\fR
\fBtimerate\fR -calibrate {}
\fI# estimate overhead\fR
set tm 0
set ovh [lindex [timerate { incr tm [expr {24*60*60}] }] 0]
# measure using esimated overhead:
set ovh [lindex [\fBtimerate\fR {
incr tm [expr {24*60*60}]
}] 0]
\fI# measure using estimated overhead\fR
set tm 0
timerate -overhead $ovh {
\fBtimerate\fR -overhead $ovh {
clock format $tm -format %H
incr tm [expr {24*60*60}]; # overhead for this is ignored
} 5000
@@ -123,7 +140,7 @@ timerate -overhead $ovh {
.SH "SEE ALSO"
time(n)
.SH KEYWORDS
script, timerate, time
performance measurement, script, time
.\" Local Variables:
.\" mode: nroff
.\" End:
+1 -1
View File
@@ -889,7 +889,7 @@ cbrdissect(
MDEBUG(("cbackref n%d %d{%d-%d}\n", t->id, n, min, max));
/* get the backreferenced string */
if (v->pmatch[n].rm_so == -1) {
if (v->pmatch[n].rm_so == TCL_INDEX_NONE) {
return REG_NOMATCH;
}
brstring = v->start + v->pmatch[n].rm_so;
+12 -1
View File
@@ -667,7 +667,7 @@ declare 186 {
Tcl_DString *resultPtr)
}
declare 187 {
int Tcl_LinkVar(Tcl_Interp *interp, const char *varName, char *addr,
int Tcl_LinkVar(Tcl_Interp *interp, const char *varName, void *addr,
int type)
}
@@ -2379,6 +2379,17 @@ declare 643 {
int Tcl_IsShared(Tcl_Obj *objPtr)
}
# TIP#312 New Tcl_LinkArray() function
declare 644 {
int Tcl_LinkArray(Tcl_Interp *interp, const char *varName, void *addr,
int type, int size)
}
declare 645 {
int Tcl_GetIntForIndex(Tcl_Interp *interp, Tcl_Obj *objPtr,
int endValue, int *indexPtr)
}
# ----- BASELINE -- FOR -- 8.7.0 ----- #
##############################################################################
+3
View File
@@ -1093,6 +1093,8 @@ typedef struct Tcl_DString {
#endif
#define TCL_LINK_FLOAT 13
#define TCL_LINK_WIDE_UINT 14
#define TCL_LINK_CHARS 15
#define TCL_LINK_BINARY 16
#define TCL_LINK_READ_ONLY 0x80
/*
@@ -2327,6 +2329,7 @@ typedef int (Tcl_ArgvGenFuncProc)(ClientData clientData, Tcl_Interp *interp,
#define TCL_IO_FAILURE (-1)
#define TCL_AUTO_LENGTH (-1)
#define TCL_INDEX_NONE (-1)
/*
*----------------------------------------------------------------------------
+16 -2
View File
@@ -145,6 +145,8 @@ typedef enum TalInstType {
* 1 */
ASSEM_DICT_GET, /* 'dict get' and related - consumes N+1
* operands, produces 1, N > 0 */
ASSEM_DICT_GET_DEF, /* 'dict getwithdefault' - consumes N+2
* operands, produces 1, N > 0 */
ASSEM_DICT_SET, /* specifies key count and LVT index, consumes
* N+1 operands, produces 1, N > 0 */
ASSEM_DICT_UNSET, /* specifies key count and LVT index, consumes
@@ -362,6 +364,7 @@ static const TalInstDesc TalInstructionTable[] = {
{"dictExists", ASSEM_DICT_GET, INST_DICT_EXISTS, INT_MIN,1},
{"dictExpand", ASSEM_1BYTE, INST_DICT_EXPAND, 3, 1},
{"dictGet", ASSEM_DICT_GET, INST_DICT_GET, INT_MIN,1},
{"dictGetDef", ASSEM_DICT_GET_DEF, INST_DICT_GET_DEF, INT_MIN,1},
{"dictIncrImm", ASSEM_SINT4_LVT4,
INST_DICT_INCR_IMM, 1, 1},
{"dictLappend", ASSEM_LVT4, INST_DICT_LAPPEND, 2, 1},
@@ -471,8 +474,12 @@ static const TalInstDesc TalInstructionTable[] = {
{"strcat", ASSEM_CONCAT1, INST_STR_CONCAT1, INT_MIN,1},
{"streq", ASSEM_1BYTE, INST_STR_EQ, 2, 1},
{"strfind", ASSEM_1BYTE, INST_STR_FIND, 2, 1},
{"strge", ASSEM_1BYTE, INST_STR_GE, 2, 1},
{"strgt", ASSEM_1BYTE, INST_STR_GT, 2, 1},
{"strindex", ASSEM_1BYTE, INST_STR_INDEX, 2, 1},
{"strle", ASSEM_1BYTE, INST_STR_LE, 2, 1},
{"strlen", ASSEM_1BYTE, INST_STR_LEN, 1, 1},
{"strlt", ASSEM_1BYTE, INST_STR_LT, 2, 1},
{"strmap", ASSEM_1BYTE, INST_STR_MAP, 3, 1},
{"strmatch", ASSEM_BOOL, INST_STR_MATCH, 2, 1},
{"strneq", ASSEM_1BYTE, INST_STR_NEQ, 2, 1},
@@ -514,6 +521,7 @@ static const unsigned char NonThrowingByteCodes[] = {
INST_PUSH1, INST_PUSH4, INST_POP, INST_DUP, /* 1-4 */
INST_JUMP1, INST_JUMP4, /* 34-35 */
INST_END_CATCH, INST_PUSH_RESULT, INST_PUSH_RETURN_CODE, /* 70-72 */
INST_STR_EQ, INST_STR_NEQ, INST_STR_CMP, INST_STR_LEN, /* 73-76 */
INST_LIST, /* 79 */
INST_OVER, /* 95 */
INST_PUSH_RETURN_OPTIONS, /* 108 */
@@ -528,7 +536,8 @@ static const unsigned char NonThrowingByteCodes[] = {
INST_STR_TRIM, INST_STR_TRIM_LEFT, INST_STR_TRIM_RIGHT, /* 166-168 */
INST_CONCAT_STK, /* 169 */
INST_STR_UPPER, INST_STR_LOWER, INST_STR_TITLE, /* 170-172 */
INST_NUM_TYPE /* 180 */
INST_NUM_TYPE, /* 180 */
INST_STR_LT, INST_STR_GT, INST_STR_LE, INST_STR_GE /* 191-194 */
};
/*
@@ -619,10 +628,14 @@ BBUpdateStackReqs(
if (consumed == INT_MIN) {
/*
* The instruction is variadic; it consumes 'count' operands.
* The instruction is variadic; it consumes 'count' operands, or
* 'count+1' for ASSEM_DICT_GET_DEF.
*/
consumed = count;
if (TalInstructionTable[tblIdx].instType == ASSEM_DICT_GET_DEF) {
consumed++;
}
}
if (produced < 0) {
/*
@@ -1396,6 +1409,7 @@ AssembleOneLine(
break;
case ASSEM_DICT_GET:
case ASSEM_DICT_GET_DEF:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "count");
goto cleanup;
+425 -61
View File
@@ -171,8 +171,13 @@ static Tcl_NRPostProc TEOV_RunLeaveTraces;
static Tcl_NRPostProc EvalObjvCore;
static Tcl_NRPostProc Dispatch;
static Tcl_ObjCmdProc NRCoroInjectObjCmd;
static Tcl_ObjCmdProc NRInjectObjCmd;
static Tcl_NRPostProc NRPostInvoke;
static Tcl_ObjCmdProc CoroTypeObjCmd;
static Tcl_ObjCmdProc TclNRCoroInjectObjCmd;
static Tcl_ObjCmdProc TclNRCoroProbeObjCmd;
static Tcl_NRPostProc InjectHandler;
static Tcl_NRPostProc InjectHandlerPostCall;
MODULE_SCOPE const TclStubs tclStubs;
@@ -242,6 +247,8 @@ static const CmdInfo builtInCmds[] = {
{"catch", Tcl_CatchObjCmd, TclCompileCatchCmd, TclNRCatchObjCmd, CMD_IS_SAFE},
{"concat", Tcl_ConcatObjCmd, TclCompileConcatCmd, NULL, CMD_IS_SAFE},
{"continue", Tcl_ContinueObjCmd, TclCompileContinueCmd, NULL, CMD_IS_SAFE},
{"coroinject", NULL, NULL, TclNRCoroInjectObjCmd, CMD_IS_SAFE},
{"coroprobe", NULL, NULL, TclNRCoroProbeObjCmd, CMD_IS_SAFE},
{"coroutine", NULL, NULL, TclNRCoroutineObjCmd, CMD_IS_SAFE},
{"error", Tcl_ErrorObjCmd, TclCompileErrorCmd, NULL, CMD_IS_SAFE},
{"eval", Tcl_EvalObjCmd, NULL, TclNREvalObjCmd, CMD_IS_SAFE},
@@ -262,6 +269,7 @@ static const CmdInfo builtInCmds[] = {
{"lmap", Tcl_LmapObjCmd, TclCompileLmapCmd, TclNRLmapCmd, CMD_IS_SAFE},
{"lpop", Tcl_LpopObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lrange", Tcl_LrangeObjCmd, TclCompileLrangeCmd, NULL, CMD_IS_SAFE},
{"lremove", Tcl_LremoveObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lrepeat", Tcl_LrepeatObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lreplace", Tcl_LreplaceObjCmd, TclCompileLreplaceCmd, NULL, CMD_IS_SAFE},
{"lreverse", Tcl_LreverseObjCmd, NULL, NULL, CMD_IS_SAFE},
@@ -364,6 +372,7 @@ static const UnsafeEnsembleInfo unsafeEnsembleCommands[] = {
{"file", "size"},
{"file", "stat"},
{"file", "tail"},
{"file", "tempdir"},
{"file", "tempfile"},
{"file", "type"},
{"file", "volumes"},
@@ -495,6 +504,14 @@ static const OpCmdInfo mathOpCmds[] = {
/* unused */ {0}, NULL},
{ "eq", TclSortingOpCmd, TclCompileStreqOpCmd,
/* unused */ {0}, NULL},
{ "lt", TclSortingOpCmd, TclCompileStrLtOpCmd,
/* unused */ {0}, NULL},
{ "le", TclSortingOpCmd, TclCompileStrLeOpCmd,
/* unused */ {0}, NULL},
{ "gt", TclSortingOpCmd, TclCompileStrGtOpCmd,
/* unused */ {0}, NULL},
{ "ge", TclSortingOpCmd, TclCompileStrGeOpCmd,
/* unused */ {0}, NULL},
{ NULL, NULL, NULL,
{0}, NULL}
};
@@ -972,8 +989,11 @@ Tcl_CreateInterp(void)
TclNRAssembleObjCmd, NULL, NULL);
cmdPtr->compileProc = &TclCompileAssembleCmd;
/* Coroutine monkeybusiness */
Tcl_NRCreateCommand(interp, "::tcl::unsupported::inject", NULL,
NRCoroInjectObjCmd, NULL, NULL);
NRInjectObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "::tcl::unsupported::corotype",
CoroTypeObjCmd, NULL, NULL);
/* Export unsupported commands */
nsPtr = Tcl_FindNamespace(interp, "::tcl::unsupported", NULL, 0);
@@ -2376,14 +2396,16 @@ Tcl_CreateCommand(
break;
}
/* An existing command conflicts. Try to delete it.. */
/*
* An existing command conflicts. Try to delete it...
*/
cmdPtr = Tcl_GetHashValue(hPtr);
/*
* 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.
* 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->refCount++;
@@ -2403,16 +2425,15 @@ Tcl_CreateCommand(
if (!isNew) {
/*
* If the deletion callback recreated the command, just throw away
* the new command (if we try to delete it again, we could get
* stuck in an infinite loop).
* If the deletion callback recreated the command, just throw away the
* new command (if we try to delete it again, we could get stuck in an
* infinite loop).
*/
ckfree(Tcl_GetHashValue(hPtr));
}
if (!deleted) {
/*
* Command resolvers (per-interp, per-namespace) might have resolved
* to a command for the given namespace scope with this command not
@@ -2595,17 +2616,17 @@ TclCreateObjCommandInNs(
}
/*
* An existing command conflicts. Try to delete it.
* An existing command conflicts. Try to delete it...
*/
cmdPtr = Tcl_GetHashValue(hPtr);
/*
* [***] This is wrong. See Tcl Bug a16752c252. However, this buggy
* behavior is kept under particular circumstances to accommodate
* deployed binaries of the "tclcompiler" program
* http://sourceforge.net/projects/tclpro/
* that crash if the bug is fixed.
* [***] This is wrong. See Tcl Bug a16752c252.
* However, this buggy behavior is kept under particular circumstances
* to accommodate deployed binaries of the "tclcompiler" program
* <http://sourceforge.net/projects/tclpro/> that crash if the bug is
* fixed.
*/
if (cmdPtr->objProc == TclInvokeStringCommand
@@ -4605,15 +4626,22 @@ EvalObjvCore(
reresolve:
assert(cmdPtr == NULL);
if (preCmdPtr) {
/* Caller gave it to us */
/*
* Caller gave it to us.
*/
if (!(preCmdPtr->flags & CMD_IS_DELETED)) {
/* So long as it exists, use it. */
/*
* So long as it exists, use it.
*/
cmdPtr = preCmdPtr;
} else if (flags & TCL_EVAL_NORESOLVE) {
/*
* When it's been deleted, and we're told not to attempt
* resolving it ourselves, all we can do is raise an error.
* When it's been deleted, and we're told not to attempt resolving
* it ourselves, all we can do is raise an error.
*/
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"attempt to invoke a deleted command"));
Tcl_SetErrorCode(interp, "TCL", "EVAL", "DELETEDCOMMAND", NULL);
@@ -4629,14 +4657,12 @@ EvalObjvCore(
if (enterTracesDone || iPtr->tracePtr
|| (cmdPtr->flags & CMD_HAS_EXEC_TRACES)) {
Tcl_Obj *commandPtr = TclGetSourceFromFrame(
flags & TCL_EVAL_SOURCE_IN_FRAME ? iPtr->cmdFramePtr : NULL,
objc, objv);
Tcl_IncrRefCount(commandPtr);
if (!enterTracesDone) {
int code = TEOV_RunEnterTraces(interp, &cmdPtr, commandPtr,
objc, objv);
@@ -4644,10 +4670,10 @@ EvalObjvCore(
* Send any exception from enter traces back as an exception
* raised by the traced command.
* TODO: Is this a bug? Letting an execution trace BREAK or
* CONTINUE or RETURN in the place of the traced command?
* Would either converting all exceptions to TCL_ERROR, or
* just swallowing them be better? (Swallowing them has the
* problem of permanently hiding program errors.)
* CONTINUE or RETURN in the place of the traced command? Would
* either converting all exceptions to TCL_ERROR, or just
* swallowing them be better? (Swallowing them has the problem of
* permanently hiding program errors.)
*/
if (code != TCL_OK) {
@@ -4656,9 +4682,8 @@ EvalObjvCore(
}
/*
* If the enter traces made the resolved cmdPtr unusable, go
* back and resolve again, but next time don't run enter
* traces again.
* If the enter traces made the resolved cmdPtr unusable, go back
* and resolve again, but next time don't run enter traces again.
*/
if (cmdPtr == NULL) {
@@ -4669,9 +4694,9 @@ EvalObjvCore(
}
/*
* Schedule leave traces. Raise the refCount on the resolved
* cmdPtr, so that when it passes to the leave traces we know
* it's still valid.
* Schedule leave traces. Raise the refCount on the resolved cmdPtr,
* so that when it passes to the leave traces we know it's still
* valid.
*/
cmdPtr->refCount++;
@@ -4741,8 +4766,6 @@ TclNRRunCallbacks(
#if !defined(TCL_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9
Interp *iPtr = (Interp *) interp;
#endif /* !defined(TCL_NO_DEPRECATED) */
NRE_callback *callbackPtr;
Tcl_NRPostProc *procPtr;
/*
* If the interpreter has a non-empty string result, the result object is
@@ -4760,11 +4783,14 @@ TclNRRunCallbacks(
}
#endif /* !defined(TCL_NO_DEPRECATED) */
/* This is the trampoline. */
/*
* This is the trampoline.
*/
while (TOP_CB(interp) != rootPtr) {
callbackPtr = TOP_CB(interp);
procPtr = callbackPtr->procPtr;
NRE_callback *callbackPtr = TOP_CB(interp);
Tcl_NRPostProc *procPtr = callbackPtr->procPtr;
TOP_CB(interp) = callbackPtr->nextPtr;
result = procPtr(callbackPtr->data, interp, result);
TCLNR_FREE(interp, callbackPtr);
@@ -4924,7 +4950,7 @@ TEOV_Error(
int objc = PTR2INT(data[0]);
Tcl_Obj **objv = data[1];
if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)){
if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
/*
* If there was an error, a command string will be needed for the
* error log: get it out of the itemPtr. The details depend on the
@@ -5133,7 +5159,7 @@ TEOV_RunLeaveTraces(
const char *command = TclGetStringFromObj(commandPtr, &length);
if (!(cmdPtr->flags & CMD_IS_DELETED)) {
if (cmdPtr->flags & CMD_HAS_EXEC_TRACES){
if (cmdPtr->flags & CMD_HAS_EXEC_TRACES) {
traceCode = TclCheckExecutionTraces(interp, command, length,
cmdPtr, result, TCL_TRACE_LEAVE_EXEC, objc, objv);
}
@@ -6972,14 +6998,17 @@ TclNRInvoke(
}
cmdPtr = Tcl_GetHashValue(hPtr);
/* Avoid the exception-handling brain damage when numLevels == 0 . */
/*
* Avoid the exception-handling brain damage when numLevels == 0
*/
iPtr->numLevels++;
Tcl_NRAddCallback(interp, NRPostInvoke, NULL, NULL, NULL, NULL);
/*
* Normal command resolution of objv[0] isn't going to find cmdPtr.
* That's the whole point of **hidden** commands. So tell the
* Eval core machinery not to even try (and risk finding something wrong).
* That's the whole point of **hidden** commands. So tell the Eval core
* machinery not to even try (and risk finding something wrong).
*/
return TclNREvalObjv(interp, objc, objv, TCL_EVAL_NORESOLVE, cmdPtr);
@@ -8373,13 +8402,21 @@ TclDTraceInfo(
Tcl_DictObjGet(NULL, info, *k++, &val);
args[i] = val ? TclGetString(val) : NULL;
}
/* no "proc" -> use "lambda" */
/*
* no "proc" -> use "lambda"
*/
if (!args[2]) {
Tcl_DictObjGet(NULL, info, *k, &val);
args[2] = val ? TclGetString(val) : NULL;
}
k++;
/* no "class" -> use "object" */
/*
* no "class" -> use "object"
*/
if (!args[5]) {
Tcl_DictObjGet(NULL, info, *k, &val);
args[5] = val ? TclGetString(val) : NULL;
@@ -8733,8 +8770,10 @@ TclNRTailcallObjCmd(
Tcl_Obj *listPtr, *nsObjPtr;
Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
/* The tailcall data is in a Tcl list: the first element is the
* namespace, the rest the command to be tailcalled. */
/*
* The tailcall data is in a Tcl list: the first element is the
* namespace, the rest the command to be tailcalled.
*/
nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1);
listPtr = Tcl_NewListObj(objc, objv);
@@ -9185,7 +9224,335 @@ TclNREvalList(
/*
*----------------------------------------------------------------------
*
* NRCoroInjectObjCmd --
* CoroTypeObjCmd --
*
* Implementation of [::tcl::unsupported::corotype] command.
*
*----------------------------------------------------------------------
*/
static int
CoroTypeObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Command *cmdPtr;
CoroutineData *corPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "coroName");
return TCL_ERROR;
}
/*
* Look up the coroutine.
*/
cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[1]);
if ((!cmdPtr) || (cmdPtr->nreProc != TclNRInterpCoroutine)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"can only get coroutine type of a coroutine", -1));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COROUTINE",
TclGetString(objv[1]), NULL);
return TCL_ERROR;
}
/*
* An active coroutine is "active". Can't tell what it might do in the
* future.
*/
corPtr = cmdPtr->objClientData;
if (!COR_IS_SUSPENDED(corPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("active", -1));
return TCL_OK;
}
/*
* Inactive coroutines are classified by the (effective) command used to
* suspend them, which matters when you're injecting a probe.
*/
switch (corPtr->nargs) {
case COROUTINE_ARGUMENTS_SINGLE_OPTIONAL:
Tcl_SetObjResult(interp, Tcl_NewStringObj("yield", -1));
return TCL_OK;
case COROUTINE_ARGUMENTS_ARBITRARY:
Tcl_SetObjResult(interp, Tcl_NewStringObj("yieldto", -1));
return TCL_OK;
default:
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"unknown coroutine type", -1));
Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "BAD_TYPE", NULL);
return TCL_ERROR;
}
}
/*
*----------------------------------------------------------------------
*
* TclNRCoroInjectObjCmd, TclNRCoroProbeObjCmd --
*
* Implementation of [coroinject] and [coroprobe] commands.
*
*----------------------------------------------------------------------
*/
static inline CoroutineData *
GetCoroutineFromObj(
Tcl_Interp *interp,
Tcl_Obj *objPtr,
const char *errMsg)
{
/*
* How to get a coroutine from its handle.
*/
Command *cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objPtr);
if ((!cmdPtr) || (cmdPtr->nreProc != TclNRInterpCoroutine)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(errMsg, -1));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COROUTINE",
TclGetString(objPtr), NULL);
return NULL;
}
return cmdPtr->objClientData;
}
static int
TclNRCoroInjectObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
CoroutineData *corPtr;
ExecEnv *savedEEPtr = iPtr->execEnvPtr;
/*
* Usage more or less like tailcall:
* coroinject coroName cmd ?arg1 arg2 ...?
*/
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "coroName cmd ?arg1 arg2 ...?");
return TCL_ERROR;
}
corPtr = GetCoroutineFromObj(interp, objv[1],
"can only inject a command into a coroutine");
if (!corPtr) {
return TCL_ERROR;
}
if (!COR_IS_SUSPENDED(corPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"can only inject a command into a suspended coroutine", -1));
Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ACTIVE", NULL);
return TCL_ERROR;
}
/*
* Add the callback to the coro's execEnv, so that it is the first thing
* to happen when the coro is resumed.
*/
iPtr->execEnvPtr = corPtr->eePtr;
TclNRAddCallback(interp, InjectHandler, corPtr,
Tcl_NewListObj(objc - 2, objv + 2), INT2PTR(corPtr->nargs), NULL);
iPtr->execEnvPtr = savedEEPtr;
return TCL_OK;
}
static int
TclNRCoroProbeObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
CoroutineData *corPtr;
ExecEnv *savedEEPtr = iPtr->execEnvPtr;
int numLevels, unused;
int *stackLevel = &unused;
/*
* Usage more or less like tailcall:
* coroprobe coroName cmd ?arg1 arg2 ...?
*/
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "coroName cmd ?arg1 arg2 ...?");
return TCL_ERROR;
}
corPtr = GetCoroutineFromObj(interp, objv[1],
"can only inject a probe command into a coroutine");
if (!corPtr) {
return TCL_ERROR;
}
if (!COR_IS_SUSPENDED(corPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"can only inject a probe command into a suspended coroutine",
-1));
Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ACTIVE", NULL);
return TCL_ERROR;
}
/*
* Add the callback to the coro's execEnv, so that it is the first thing
* to happen when the coro is resumed.
*/
iPtr->execEnvPtr = corPtr->eePtr;
TclNRAddCallback(interp, InjectHandler, corPtr,
Tcl_NewListObj(objc - 2, objv + 2), INT2PTR(corPtr->nargs), corPtr);
iPtr->execEnvPtr = savedEEPtr;
/*
* Now we immediately transfer control to the coroutine to run our probe.
* TRICKY STUFF copied from the [yield] implementation.
*
* Push the callback to restore the caller's context on yield back.
*/
TclNRAddCallback(interp, NRCoroutineCallerCallback, corPtr,
NULL, NULL, NULL);
/*
* Record the stackLevel at which the resume is happening, then swap
* the interp's environment to make it suitable to run this coroutine.
*/
corPtr->stackLevel = stackLevel;
numLevels = corPtr->auxNumLevels;
corPtr->auxNumLevels = iPtr->numLevels;
/*
* Do the actual stack swap.
*/
SAVE_CONTEXT(corPtr->caller);
corPtr->callerEEPtr = iPtr->execEnvPtr;
RESTORE_CONTEXT(corPtr->running);
iPtr->execEnvPtr = corPtr->eePtr;
iPtr->numLevels += numLevels;
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* InjectHandler, InjectHandlerPostProc --
*
* Part of the implementation of [coroinject] and [coroprobe]. These are
* run inside the context of the coroutine being injected/probed into.
*
* InjectHandler runs a script (possibly adding arguments) in the context
* of the coroutine. The script is specified as a one-shot list (with
* reference count equal to 1) in data[1]. This function also arranges
* for InjectHandlerPostProc to be the part that runs after the script
* completes.
*
* InjectHandlerPostProc cleans up after InjectHandler (deleting the
* list) and, for the [coroprobe] command *only*, yields back to the
* caller context (i.e., where [coroprobe] was run).
*s
*----------------------------------------------------------------------
*/
static int
InjectHandler(
ClientData data[],
Tcl_Interp *interp,
int result)
{
CoroutineData *corPtr = data[0];
Tcl_Obj *listPtr = data[1];
int nargs = PTR2INT(data[2]);
ClientData isProbe = data[3];
int objc;
Tcl_Obj **objv;
if (!isProbe) {
/*
* If this is [coroinject], add the extra arguments now.
*/
if (nargs == COROUTINE_ARGUMENTS_SINGLE_OPTIONAL) {
Tcl_ListObjAppendElement(NULL, listPtr,
Tcl_NewStringObj("yield", -1));
} else if (nargs == COROUTINE_ARGUMENTS_ARBITRARY) {
Tcl_ListObjAppendElement(NULL, listPtr,
Tcl_NewStringObj("yieldto", -1));
} else {
/*
* I don't think this is reachable...
*/
Tcl_ListObjAppendElement(NULL, listPtr, Tcl_NewIntObj(nargs));
}
Tcl_ListObjAppendElement(NULL, listPtr, Tcl_GetObjResult(interp));
}
/*
* Call the user's script; we're in the right place.
*/
Tcl_IncrRefCount(listPtr);
TclMarkTailcall(interp);
TclNRAddCallback(interp, InjectHandlerPostCall, corPtr, listPtr,
INT2PTR(nargs), isProbe);
TclListObjGetElements(NULL, listPtr, &objc, &objv);
return TclNREvalObjv(interp, objc, objv, 0, NULL);
}
static int
InjectHandlerPostCall(
ClientData data[],
Tcl_Interp *interp,
int result)
{
CoroutineData *corPtr = data[0];
Tcl_Obj *listPtr = data[1];
int nargs = PTR2INT(data[2]);
ClientData isProbe = data[3];
int numLevels;
/*
* Delete the command words for what we just executed.
*/
Tcl_DecrRefCount(listPtr);
/*
* If we were doing a probe, splice ourselves back out of the stack
* cleanly here. General injection should instead just look after itself.
*
* Code from guts of [yield] implementation.
*/
if (isProbe) {
if (result == TCL_ERROR) {
Tcl_AddErrorInfo(interp,
"\n (injected coroutine probe command)");
}
corPtr->nargs = nargs;
corPtr->stackLevel = NULL;
numLevels = iPtr->numLevels;
iPtr->numLevels = corPtr->auxNumLevels;
corPtr->auxNumLevels = numLevels - corPtr->auxNumLevels;
iPtr->execEnvPtr = corPtr->callerEEPtr;
}
return result;
}
/*
*----------------------------------------------------------------------
*
* NRInjectObjCmd --
*
* Implementation of [::tcl::unsupported::inject] command.
*
@@ -9193,13 +9560,12 @@ TclNREvalList(
*/
static int
NRCoroInjectObjCmd(
NRInjectObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Command *cmdPtr;
CoroutineData *corPtr;
ExecEnv *savedEEPtr = iPtr->execEnvPtr;
@@ -9213,16 +9579,11 @@ NRCoroInjectObjCmd(
return TCL_ERROR;
}
cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[1]);
if ((!cmdPtr) || (cmdPtr->nreProc != TclNRInterpCoroutine)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"can only inject a command into a coroutine", -1));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COROUTINE",
TclGetString(objv[1]), NULL);
corPtr = GetCoroutineFromObj(interp, objv[1],
"can only inject a command into a coroutine");
if (!corPtr) {
return TCL_ERROR;
}
corPtr = cmdPtr->objClientData;
if (!COR_IS_SUSPENDED(corPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"can only inject a command into a suspended coroutine", -1));
@@ -9415,9 +9776,12 @@ TclNRCoroutineObjCmd(
TclNRAddCallback(interp, NRCoroutineExitCallback, corPtr,
NULL, NULL, NULL);
/* ensure 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);
Tcl_NREvalObj(interp, Tcl_NewListObj(objc - 2, objv + 2), 0);
iPtr->numLevels--;
SAVE_CONTEXT(corPtr->running);
+156 -138
View File
@@ -159,93 +159,88 @@ static const EnsembleImplMap decodeMap[] = {
};
/*
* The following object types represent an array of bytes. The intent is
* to allow arbitrary binary data to pass through Tcl as a Tcl value
* without loss or damage. Such values are useful for things like
* encoded strings or Tk images to name just two.
* The following object types represent an array of bytes. The intent is to
* allow arbitrary binary data to pass through Tcl as a Tcl value without loss
* or damage. Such values are useful for things like encoded strings or Tk
* images to name just two.
*
* It's strange to have two Tcl_ObjTypes in place for this task when
* one would do, so a bit of detail and history how we got to this point
* and where we might go from here.
* It's strange to have two Tcl_ObjTypes in place for this task when one would
* do, so a bit of detail and history how we got to this point and where we
* might go from here.
*
* A bytearray is an ordered sequence of bytes. Each byte is an integer
* value in the range [0-255]. To be a Tcl value type, we need a way to
* encode each value in the value set as a Tcl string. The simplest
* encoding is to represent each byte value as the same codepoint value.
* A bytearray of N bytes is encoded into a Tcl string of N characters
* where the codepoint of each character is the value of corresponding byte.
* This approach creates a one-to-one map between all bytearray values
* and a subset of Tcl string values.
* A bytearray is an ordered sequence of bytes. Each byte is an integer value
* in the range [0-255]. To be a Tcl value type, we need a way to encode each
* value in the value set as a Tcl string. The simplest encoding is to
* represent each byte value as the same codepoint value. A bytearray of N
* bytes is encoded into a Tcl string of N characters where the codepoint of
* each character is the value of corresponding byte. This approach creates a
* one-to-one map between all bytearray values and a subset of Tcl string
* values.
*
* When converting a Tcl string value to the bytearray internal rep, the
* question arises what to do with strings outside that subset? That is,
* those Tcl strings containing at least one codepoint greater than 255?
* The obviously correct answer is to raise an error! That string value
* does not represent any valid bytearray value. Full Stop. The
* setFromAnyProc signature has a completion code return value for just
* this reason, to reject invalid inputs.
* those Tcl strings containing at least one codepoint greater than 255? The
* obviously correct answer is to raise an error! That string value does not
* represent any valid bytearray value. Full Stop. The setFromAnyProc
* signature has a completion code return value for just this reason, to
* reject invalid inputs.
*
* Unfortunately this was not the path taken by the authors of the
* original tclByteArrayType. They chose to accept all Tcl string values
* as acceptable string encodings of the bytearray values that result
* from masking away the high bits of any codepoint value at all. This
* meant that every bytearray value had multiple accepted string
* representations.
* Unfortunately this was not the path taken by the authors of the original
* tclByteArrayType. They chose to accept all Tcl string values as acceptable
* string encodings of the bytearray values that result from masking away the
* high bits of any codepoint value at all. This meant that every bytearray
* value had multiple accepted string representations.
*
* The implications of this choice are truly ugly. When a Tcl value has
* a string representation, we are required to accept that as the true
* value. Bytearray values that possess a string representation cannot
* be processed as bytearrays because we cannot know which true value
* that bytearray represents. The consequence is that we drag around
* an internal rep that we cannot make any use of. This painful price
* is extracted at any point after a string rep happens to be generated
* for the value. This happens even when the troublesome codepoints
* outside the byte range never show up. This happens rather routinely
* in normal Tcl operations unless we burden the script writer with the
* cognitive burden of avoiding it. The price is also paid by callers
* of the C interface. The routine
* The implications of this choice are truly ugly. When a Tcl value has a
* string representation, we are required to accept that as the true value.
* Bytearray values that possess a string representation cannot be processed
* as bytearrays because we cannot know which true value that bytearray
* represents. The consequence is that we drag around an internal rep that we
* cannot make any use of. This painful price is extracted at any point after
* a string rep happens to be generated for the value. This happens even when
* the troublesome codepoints outside the byte range never show up. This
* happens rather routinely in normal Tcl operations unless we burden the
* script writer with the cognitive burden of avoiding it. The price is also
* paid by callers of the C interface. The routine
*
* unsigned char *Tcl_GetByteArrayFromObj(objPtr, lenPtr)
*
* has a guarantee to always return a non-NULL value, but that value
* points to a byte sequence that cannot be used by the caller to
* process the Tcl value absent some sideband testing that objPtr
* is "pure". Tcl offers no public interface to perform this test,
* so callers either break encapsulation or are unavoidably buggy. Tcl
* has defined a public interface that cannot be used correctly. The
* Tcl source code itself suffers the same problem, and has been buggy,
* but progressively less so as more and more portions of the code have
* been retrofitted with the required "purity testing". The set of values
* able to pass the purity test can be increased via the introduction of
* a "canonical" flag marker, but the only way the broken interface itself
* has a guarantee to always return a non-NULL value, but that value points to
* a byte sequence that cannot be used by the caller to process the Tcl value
* absent some sideband testing that objPtr is "pure". Tcl offers no public
* interface to perform this test, so callers either break encapsulation or
* are unavoidably buggy. Tcl has defined a public interface that cannot be
* used correctly. The Tcl source code itself suffers the same problem, and
* has been buggy, but progressively less so as more and more portions of the
* code have been retrofitted with the required "purity testing". The set of
* values able to pass the purity test can be increased via the introduction
* of a "canonical" flag marker, but the only way the broken interface itself
* can be discarded is to start over and define the Tcl_ObjType properly.
* Bytearrays should simply be usable as bytearrays without a kabuki
* dance of testing.
* Bytearrays should simply be usable as bytearrays without a kabuki dance of
* testing.
*
* The Tcl_ObjType "properByteArrayType" is (nearly) a correct
* implementation of bytearrays. Any Tcl value with the type
* properByteArrayType can have its bytearray value fetched and
* used with confidence that acting on that value is equivalent to
* acting on the true Tcl string value. This still implies a side
* testing burden -- past mistakes will not let us avoid that
* immediately, but it is at least a conventional test of type, and
* can be implemented entirely by examining the objPtr fields, with
* no need to query the intrep, as a canonical flag would require.
* The Tcl_ObjType "properByteArrayType" is (nearly) a correct implementation
* of bytearrays. Any Tcl value with the type properByteArrayType can have
* its bytearray value fetched and used with confidence that acting on that
* value is equivalent to acting on the true Tcl string value. This still
* implies a side testing burden -- past mistakes will not let us avoid that
* immediately, but it is at least a conventional test of type, and can be
* implemented entirely by examining the objPtr fields, with no need to query
* the intrep, as a canonical flag would require.
*
* Until Tcl_GetByteArrayFromObj() and Tcl_SetByteArrayLength() can
* be revised to admit the possibility of returning NULL when the true
* value is not a valid bytearray, we need a mechanism to retain
* compatibility with the deployed callers of the broken interface.
* That's what the retained "tclByteArrayType" provides. In those
* unusual circumstances where we convert an invalid bytearray value
* to a bytearray type, it is to this legacy type. Essentially any
* time this legacy type gets used, it's a signal of a bug being ignored.
* A TIP should be drafted to remove this connection to the broken past
* so that Tcl 9 will no longer have any trace of it. Prescribing a
* migration path will be the key element of that work. The internal
* changes now in place are the limit of what can be done short of
* interface repair. They provide a great expansion of the histories
* over which bytearray values can be useful in the meanwhile.
* Until Tcl_GetByteArrayFromObj() and Tcl_SetByteArrayLength() can be revised
* to admit the possibility of returning NULL when the true value is not a
* valid bytearray, we need a mechanism to retain compatibility with the
* deployed callers of the broken interface. That's what the retained
* "tclByteArrayType" provides. In those unusual circumstances where we
* convert an invalid bytearray value to a bytearray type, it is to this
* legacy type. Essentially any time this legacy type gets used, it's a
* signal of a bug being ignored. A TIP should be drafted to remove this
* connection to the broken past so that Tcl 9 will no longer have any trace
* of it. Prescribing a migration path will be the key element of that work.
* The internal changes now in place are the limit of what can be done short
* of interface repair. They provide a great expansion of the histories over
* which bytearray values can be useful in the meanwhile.
*/
static const Tcl_ObjType properByteArrayType = {
@@ -400,10 +395,10 @@ Tcl_DbNewByteArrayObj(
void
Tcl_SetByteArrayObj(
Tcl_Obj *objPtr, /* Object to initialize as a ByteArray. */
const unsigned char *bytes, /* The array of bytes to use as the new
value. May be NULL even if length > 0. */
const unsigned char *bytes, /* The array of bytes to use as the new value.
* May be NULL even if length > 0. */
int length) /* Length of the array of bytes, which must
be >= 0. */
* be >= 0. */
{
ByteArray *byteArrayPtr;
Tcl_ObjIntRep ir;
@@ -723,14 +718,16 @@ UpdateStringOfByteArray(
if (size == length) {
char *dst = Tcl_InitStringRep(objPtr, (char *)src, size);
TclOOM(dst, size);
} else {
char *dst = Tcl_InitStringRep(objPtr, NULL, size);
TclOOM(dst, size);
for (i = 0; i < length; i++) {
dst += Tcl_UniCharToUtf(src[i], dst);
}
(void)Tcl_InitStringRep(objPtr, NULL, size);
(void) Tcl_InitStringRep(objPtr, NULL, size);
}
}
@@ -771,11 +768,14 @@ TclAppendBytesToByteArray(
"TclAppendBytesToByteArray");
}
if (len == 0) {
/* Append zero bytes is a no-op. */
/*
* Append zero bytes is a no-op.
*/
return;
}
length = (unsigned int)len;
length = (unsigned int) len;
irPtr = TclFetchIntRep(objPtr, &properByteArrayType);
if (irPtr == NULL) {
@@ -804,12 +804,18 @@ TclAppendBytesToByteArray(
unsigned int attempt;
if (needed <= INT_MAX/2) {
/* Try to allocate double the total space that is needed. */
/*
* Try to allocate double the total space that is needed.
*/
attempt = 2 * needed;
ptr = attemptckrealloc(byteArrayPtr, BYTEARRAY_SIZE(attempt));
}
if (ptr == NULL) {
/* Try to allocate double the increment that is needed (plus). */
/*
* Try to allocate double the increment that is needed (plus).
*/
unsigned int limit = INT_MAX - needed;
unsigned int extra = length + TCL_MIN_GROWTH;
int growth = (int) ((extra > limit) ? limit : extra);
@@ -818,7 +824,10 @@ TclAppendBytesToByteArray(
ptr = attemptckrealloc(byteArrayPtr, BYTEARRAY_SIZE(attempt));
}
if (ptr == NULL) {
/* Last chance: Try to allocate exactly what is needed. */
/*
* Last chance: Try to allocate exactly what is needed.
*/
attempt = needed;
ptr = ckrealloc(byteArrayPtr, BYTEARRAY_SIZE(attempt));
}
@@ -893,7 +902,7 @@ BinaryFormatCmd(
int count; /* Count associated with current format
* character. */
int flags; /* Format field flags */
const char *format; /* Pointer to current position in format
const char *format; /* Pointer to current position in format
* string. */
Tcl_Obj *resultPtr = NULL; /* Object holding result buffer. */
unsigned char *buffer; /* Start of result buffer. */
@@ -1079,9 +1088,9 @@ BinaryFormatCmd(
memset(buffer, 0, length);
/*
* Pack the data into the result object. Note that we can skip the
* error checking during this pass, since we have already parsed the
* string once.
* Pack the data into the result object. Note that we can skip the error
* checking during this pass, since we have already parsed the string
* once.
*/
arg = 2;
@@ -1294,7 +1303,7 @@ BinaryFormatCmd(
}
arg++;
for (i = 0; i < count; i++) {
if (FormatNumber(interp, cmd, listv[i], &cursor)!=TCL_OK) {
if (FormatNumber(interp, cmd, listv[i], &cursor) != TCL_OK) {
Tcl_DecrRefCount(resultPtr);
return TCL_ERROR;
}
@@ -1398,7 +1407,7 @@ BinaryScanCmd(
int count; /* Count associated with current format
* character. */
int flags; /* Format field flags */
const char *format; /* Pointer to current position in format
const char *format; /* Pointer to current position in format
* string. */
Tcl_Obj *resultPtr = NULL; /* Object holding result buffer. */
unsigned char *buffer; /* Start of result buffer. */
@@ -1457,7 +1466,7 @@ BinaryScanCmd(
if (cmd == 'A') {
while (size > 0) {
if (src[size-1] != '\0' && src[size-1] != ' ') {
if (src[size - 1] != '\0' && src[size - 1] != ' ') {
break;
}
size--;
@@ -2052,6 +2061,7 @@ FormatNumber(
if (Tcl_GetDoubleFromObj(interp, src, &dvalue) != TCL_OK) {
const Tcl_ObjIntRep *irPtr = TclFetchIntRep(src, &tclDoubleType);
if (irPtr == NULL) {
return TCL_ERROR;
}
@@ -2064,7 +2074,7 @@ FormatNumber(
* valid range for float.
*/
if (fabs(dvalue) > (double)FLT_MAX) {
if (fabs(dvalue) > (double) FLT_MAX) {
fvalue = (dvalue >= 0.0) ? FLT_MAX : -FLT_MAX;
} else {
fvalue = (float) dvalue;
@@ -2185,9 +2195,9 @@ ScanNumber(
int type, /* Format character from "binary scan" */
int flags, /* Format field flags */
Tcl_HashTable **numberCachePtrPtr)
/* Place to look for cache of scanned
* value objects, or NULL if too many
* different numbers have been scanned. */
/* Place to look for cache of scanned value
* objects, or NULL if too many different
* numbers have been scanned. */
{
long value;
float fvalue;
@@ -2261,6 +2271,7 @@ ScanNumber(
/*
* Check to see if the value was sign extended properly on systems
* where an int is more than 32-bits.
*
* We avoid caching unsigned integers as we cannot distinguish between
* 32bit signed and unsigned in the hash (short and char are ok).
*/
@@ -2268,9 +2279,9 @@ ScanNumber(
if (flags & BINARY_UNSIGNED) {
return Tcl_NewWideIntObj((Tcl_WideInt)(unsigned long)value);
}
if ((value & (((unsigned) 1)<<31)) && (value > 0)) {
value -= (((unsigned) 1)<<31);
value -= (((unsigned) 1)<<31);
if ((value & (((unsigned) 1) << 31)) && (value > 0)) {
value -= (((unsigned) 1) << 31);
value -= (((unsigned) 1) << 31);
}
returnNumericObject:
@@ -2470,8 +2481,8 @@ BinaryEncodeHex(
data = Tcl_GetByteArrayFromObj(objv[1], &count);
cursor = Tcl_SetByteArrayLength(resultObj, count * 2);
for (offset = 0; offset < count; ++offset) {
*cursor++ = HexDigits[((data[offset] >> 4) & 0x0f)];
*cursor++ = HexDigits[(data[offset] & 0x0f)];
*cursor++ = HexDigits[(data[offset] >> 4) & 0x0f];
*cursor++ = HexDigits[data[offset] & 0x0f];
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
@@ -2511,7 +2522,7 @@ BinaryDecodeHex(
Tcl_WrongNumArgs(interp, 1, objv, "?options? data");
return TCL_ERROR;
}
for (i = 1; i < objc-1; ++i) {
for (i = 1; i < objc - 1; ++i) {
if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option",
TCL_EXACT, &index) != TCL_OK) {
return TCL_ERROR;
@@ -2525,13 +2536,13 @@ BinaryDecodeHex(
TclNewObj(resultObj);
datastart = data = (unsigned char *)
TclGetStringFromObj(objv[objc-1], &count);
TclGetStringFromObj(objv[objc - 1], &count);
dataend = data + count;
size = (count + 1) / 2;
begin = cursor = Tcl_SetByteArrayLength(resultObj, size);
while (data < dataend) {
value = 0;
for (i=0 ; i<2 ; i++) {
for (i = 0 ; i < 2 ; i++) {
if (data >= dataend) {
value <<= 4;
break;
@@ -2554,7 +2565,7 @@ BinaryDecodeHex(
if (c > 16) {
c += ('A' - 'a');
}
value |= (c & 0xf);
value |= c & 0xf;
}
if (i < 2) {
cut++;
@@ -2625,22 +2636,22 @@ BinaryEncode64(
const char *wrapchar = "\n";
int wrapcharlen = 1;
int offset, i, index, size, outindex = 0, count = 0;
enum {OPT_MAXLEN, OPT_WRAPCHAR };
enum { OPT_MAXLEN, OPT_WRAPCHAR };
static const char *const optStrings[] = { "-maxlen", "-wrapchar", NULL };
if (objc < 2 || objc%2 != 0) {
if (objc < 2 || objc % 2 != 0) {
Tcl_WrongNumArgs(interp, 1, objv,
"?-maxlen len? ?-wrapchar char? data");
return TCL_ERROR;
}
for (i = 1; i < objc-1; i += 2) {
for (i = 1; i < objc - 1; i += 2) {
if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option",
TCL_EXACT, &index) != TCL_OK) {
return TCL_ERROR;
}
switch (index) {
case OPT_MAXLEN:
if (Tcl_GetIntFromObj(interp, objv[i+1], &maxlen) != TCL_OK) {
if (Tcl_GetIntFromObj(interp, objv[i + 1], &maxlen) != TCL_OK) {
return TCL_ERROR;
}
if (maxlen < 0) {
@@ -2652,7 +2663,7 @@ BinaryEncode64(
}
break;
case OPT_WRAPCHAR:
wrapchar = TclGetStringFromObj(objv[i+1], &wrapcharlen);
wrapchar = TclGetStringFromObj(objv[i + 1], &wrapcharlen);
if (wrapcharlen == 0) {
maxlen = 0;
}
@@ -2661,9 +2672,9 @@ BinaryEncode64(
}
resultObj = Tcl_NewObj();
data = Tcl_GetByteArrayFromObj(objv[objc-1], &count);
data = Tcl_GetByteArrayFromObj(objv[objc - 1], &count);
if (count > 0) {
size = (((count * 4) / 3) + 3) & ~3; /* ensure 4 byte chunks */
size = (((count * 4) / 3) + 3) & ~3; /* ensure 4 byte chunks */
if (maxlen > 0 && size > maxlen) {
int adjusted = size + (wrapcharlen * (size / maxlen));
@@ -2674,15 +2685,15 @@ BinaryEncode64(
}
cursor = Tcl_SetByteArrayLength(resultObj, size);
limit = cursor + size;
for (offset = 0; offset < count; offset+=3) {
for (offset = 0; offset < count; offset += 3) {
unsigned char d[3] = {0, 0, 0};
for (i = 0; i < 3 && offset+i < count; ++i) {
for (i = 0; i < 3 && offset + i < count; ++i) {
d[i] = data[offset + i];
}
OUTPUT(B64Digits[d[0] >> 2]);
OUTPUT(B64Digits[((d[0] & 0x03) << 4) | (d[1] >> 4)]);
if (offset+1 < count) {
if (offset + 1 < count) {
OUTPUT(B64Digits[((d[1] & 0x0f) << 2) | (d[2] >> 6)]);
} else {
OUTPUT(B64Digits[64]);
@@ -2735,19 +2746,20 @@ BinaryEncodeUu(
enum { OPT_MAXLEN, OPT_WRAPCHAR };
static const char *const optStrings[] = { "-maxlen", "-wrapchar", NULL };
if (objc < 2 || objc%2 != 0) {
if (objc < 2 || objc % 2 != 0) {
Tcl_WrongNumArgs(interp, 1, objv,
"?-maxlen len? ?-wrapchar char? data");
return TCL_ERROR;
}
for (i = 1; i < objc-1; i += 2) {
for (i = 1; i < objc - 1; i += 2) {
if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option",
TCL_EXACT, &index) != TCL_OK) {
return TCL_ERROR;
}
switch (index) {
case OPT_MAXLEN:
if (Tcl_GetIntFromObj(interp, objv[i+1], &lineLength) != TCL_OK) {
if (Tcl_GetIntFromObj(interp, objv[i + 1],
&lineLength) != TCL_OK) {
return TCL_ERROR;
}
if (lineLength < 3 || lineLength > 85) {
@@ -2759,7 +2771,7 @@ BinaryEncodeUu(
}
break;
case OPT_WRAPCHAR:
wrapchar = Tcl_GetByteArrayFromObj(objv[i+1], &wrapcharlen);
wrapchar = Tcl_GetByteArrayFromObj(objv[i + 1], &wrapcharlen);
break;
}
}
@@ -2771,7 +2783,7 @@ BinaryEncodeUu(
resultObj = Tcl_NewObj();
offset = 0;
data = Tcl_GetByteArrayFromObj(objv[objc-1], &count);
data = Tcl_GetByteArrayFromObj(objv[objc - 1], &count);
rawLength = (lineLength - 1) * 3 / 4;
start = cursor = Tcl_SetByteArrayLength(resultObj,
(lineLength + wrapcharlen) *
@@ -2792,11 +2804,11 @@ BinaryEncodeUu(
lineLen = rawLength;
}
*cursor++ = UueDigits[lineLen];
for (i=0 ; i<lineLen ; i++) {
for (i = 0 ; i < lineLen ; i++) {
n <<= 8;
n |= data[offset++];
for (bits += 8; bits > 6 ; bits -= 6) {
*cursor++ = UueDigits[(n >> (bits-6)) & 0x3f];
*cursor++ = UueDigits[(n >> (bits - 6)) & 0x3f];
}
}
if (bits > 0) {
@@ -2804,7 +2816,7 @@ BinaryEncodeUu(
*cursor++ = UueDigits[(n >> (bits + 2)) & 0x3f];
bits = 0;
}
for (j=0 ; j<wrapcharlen ; ++j) {
for (j = 0 ; j < wrapcharlen ; ++j) {
*cursor++ = wrapchar[j];
}
}
@@ -2813,7 +2825,7 @@ BinaryEncodeUu(
* Fix the length of the output bytearray.
*/
Tcl_SetByteArrayLength(resultObj, cursor-start);
Tcl_SetByteArrayLength(resultObj, cursor - start);
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
}
@@ -2846,14 +2858,14 @@ BinaryDecodeUu(
unsigned char *begin, *cursor;
int i, index, size, count = 0, strict = 0, lineLen;
unsigned char c;
enum {OPT_STRICT };
enum { OPT_STRICT };
static const char *const optStrings[] = { "-strict", NULL };
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "?options? data");
return TCL_ERROR;
}
for (i = 1; i < objc-1; ++i) {
for (i = 1; i < objc - 1; ++i) {
if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option",
TCL_EXACT, &index) != TCL_OK) {
return TCL_ERROR;
@@ -2867,7 +2879,7 @@ BinaryDecodeUu(
TclNewObj(resultObj);
datastart = data = (unsigned char *)
TclGetStringFromObj(objv[objc-1], &count);
TclGetStringFromObj(objv[objc - 1], &count);
dataend = data + count;
size = ((count + 3) & ~3) * 3 / 4;
begin = cursor = Tcl_SetByteArrayLength(resultObj, size);
@@ -2899,7 +2911,7 @@ BinaryDecodeUu(
* Now we read a four-character grouping.
*/
for (i=0 ; i<4 ; i++) {
for (i = 0 ; i < 4 ; i++) {
if (data < dataend) {
d[i] = c = *data++;
if (c < 32 || c > 96) {
@@ -3017,7 +3029,7 @@ BinaryDecode64(
Tcl_WrongNumArgs(interp, 1, objv, "?options? data");
return TCL_ERROR;
}
for (i = 1; i < objc-1; ++i) {
for (i = 1; i < objc - 1; ++i) {
if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option",
TCL_EXACT, &index) != TCL_OK) {
return TCL_ERROR;
@@ -3031,7 +3043,7 @@ BinaryDecode64(
TclNewObj(resultObj);
datastart = data = (unsigned char *)
TclGetStringFromObj(objv[objc-1], &count);
TclGetStringFromObj(objv[objc - 1], &count);
dataend = data + count;
size = ((count + 3) & ~3) * 3 / 4;
begin = cursor = Tcl_SetByteArrayLength(resultObj, size);
@@ -3059,8 +3071,11 @@ BinaryDecode64(
c = '=';
} else {
if (strict && i <= 1) {
/* single resp. unfulfilled char (each 4th next single char)
* is rather bad64 error case in strict mode */
/*
* Single resp. unfulfilled char (each 4th next single
* char) is rather bad64 error case in strict mode.
*/
goto bad64;
}
cut += 3;
@@ -3076,10 +3091,10 @@ BinaryDecode64(
if (cut) {
if (c == '=' && i > 1) {
value <<= 6;
cut++;
value <<= 6;
cut++;
} else if (!strict && TclIsSpaceProc(c)) {
i--;
i--;
} else {
goto bad64;
}
@@ -3093,11 +3108,15 @@ BinaryDecode64(
value = (value << 6) | 0x3e;
} else if (c == '/') {
value = (value << 6) | 0x3f;
} else if (c == '=' && (
!strict || i > 1) /* "=" and "a=" is rather bad64 error case in strict mode */
) {
} else if (c == '=' && (!strict || i > 1)) {
/*
* "=" and "a=" is rather bad64 error case in strict mode.
*/
value <<= 6;
if (i) cut++;
if (i) {
cut++;
}
} else if (strict || !TclIsSpaceProc(c)) {
goto bad64;
} else {
@@ -3144,4 +3163,3 @@ BinaryDecode64(
* fill-column: 78
* End:
*/
+1
View File
@@ -1093,6 +1093,7 @@ TclInitFileCmd(
{"stat", FileAttrStatCmd, TclCompileBasic2ArgCmd, NULL, NULL, 1},
{"system", PathFilesystemCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
{"tail", PathTailCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"tempdir", TclFileTempDirCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 1},
{"tempfile", TclFileTemporaryCmd, TclCompileBasic0To2ArgCmd, NULL, NULL, 1},
{"type", FileAttrTypeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"volumes", FilesystemVolumesCmd, TclCompileBasic0ArgCmd, NULL, NULL, 1},
+154 -17
View File
@@ -56,7 +56,7 @@ typedef int (*SortMemCmpFn_t) (const void *, const void *, size_t);
* The following structure is used to pass this information.
*/
typedef struct SortInfo {
typedef struct {
int isIncreasing; /* Nonzero means sort in increasing order. */
int sortMode; /* The sort mode. One of SORTMODE_* values
* defined below. */
@@ -566,7 +566,7 @@ InfoBodyCmd(
* the object do not invalidate the internal rep.
*/
bytes = Tcl_GetStringFromObj(procPtr->bodyPtr, &numBytes);
bytes = TclGetStringFromObj(procPtr->bodyPtr, &numBytes);
Tcl_SetObjResult(interp, Tcl_NewStringObj(bytes, numBytes));
return TCL_OK;
}
@@ -1047,7 +1047,7 @@ InfoErrorStackCmd(
target = interp;
if (objc == 2) {
target = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
target = Tcl_GetSlave(interp, TclGetString(objv[1]));
if (target == NULL) {
return TCL_ERROR;
}
@@ -2155,7 +2155,7 @@ InfoCmdTypeCmd(
Tcl_WrongNumArgs(interp, 1, objv, "commandName");
return TCL_ERROR;
}
command = Tcl_FindCommand(interp, Tcl_GetString(objv[1]), NULL,
command = Tcl_FindCommand(interp, TclGetString(objv[1]), NULL,
TCL_LEAVE_ERR_MSG);
if (command == NULL) {
return TCL_ERROR;
@@ -2231,7 +2231,7 @@ Tcl_JoinObjCmd(
joinObjPtr = (objc == 2) ? Tcl_NewStringObj(" ", 1) : objv[2];
Tcl_IncrRefCount(joinObjPtr);
(void) Tcl_GetStringFromObj(joinObjPtr, &length);
(void) TclGetStringFromObj(joinObjPtr, &length);
if (length == 0) {
resObjPtr = TclStringCat(interp, listLen, elemPtrs, 0);
} else {
@@ -2584,7 +2584,7 @@ Tcl_LpopObjCmd(
/* Argument objects. */
{
int listLen, result;
Tcl_Obj *elemPtr;
Tcl_Obj *elemPtr, *stored;
Tcl_Obj *listPtr, **elemPtrs;
if (objc < 2) {
@@ -2622,6 +2622,7 @@ Tcl_LpopObjCmd(
/*
* Second, remove the element.
* TclLsetFlat adds a ref count which is handled.
*/
if (objc == 2) {
@@ -2632,6 +2633,7 @@ Tcl_LpopObjCmd(
if (result != TCL_OK) {
return result;
}
Tcl_IncrRefCount(listPtr);
} else {
listPtr = TclLsetFlat(interp, listPtr, objc-2, objv+2, NULL);
@@ -2640,8 +2642,9 @@ Tcl_LpopObjCmd(
}
}
listPtr = Tcl_ObjSetVar2(interp, objv[1], NULL, listPtr, TCL_LEAVE_ERR_MSG);
if (listPtr == NULL) {
stored = Tcl_ObjSetVar2(interp, objv[1], NULL, listPtr, TCL_LEAVE_ERR_MSG);
Tcl_DecrRefCount(listPtr);
if (stored == NULL) {
return TCL_ERROR;
}
@@ -2701,6 +2704,140 @@ Tcl_LrangeObjCmd(
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_LremoveObjCmd --
*
* This procedure is invoked to process the "lremove" Tcl command. See the
* user documentation for details on what it does.
*
* Results:
* A standard Tcl object result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
static int
LremoveIndexCompare(
const void *el1Ptr,
const void *el2Ptr)
{
int idx1 = *((const int *) el1Ptr);
int idx2 = *((const int *) el2Ptr);
/*
* This will put the larger element first.
*/
return (idx1 < idx2) ? 1 : (idx1 > idx2) ? -1 : 0;
}
int
Tcl_LremoveObjCmd(
ClientData notUsed, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int i, idxc;
int listLen, *idxv, prevIdx, first, num;
Tcl_Obj *listObj;
/*
* Parse the arguments.
*/
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "list ?index ...?");
return TCL_ERROR;
}
listObj = objv[1];
if (TclListObjLength(interp, listObj, &listLen) != TCL_OK) {
return TCL_ERROR;
}
idxc = objc - 2;
if (idxc == 0) {
Tcl_SetObjResult(interp, listObj);
return TCL_OK;
}
idxv = ckalloc((objc - 2) * sizeof(int));
for (i = 2; i < objc; i++) {
if (TclGetIntForIndexM(interp, objv[i], /*endValue*/ listLen - 1,
&idxv[i - 2]) != TCL_OK) {
ckfree(idxv);
return TCL_ERROR;
}
}
/*
* Sort the indices, large to small so that when we remove an index we
* don't change the indices still to be processed.
*/
if (idxc > 1) {
qsort(idxv, idxc, sizeof(int), LremoveIndexCompare);
}
/*
* Make our working copy, then do the actual removes piecemeal.
*/
if (Tcl_IsShared(listObj)) {
listObj = TclListObjCopy(NULL, listObj);
}
num = 0;
first = listLen;
for (i = 0, prevIdx = -1 ; i < idxc ; i++) {
int idx = idxv[i];
/*
* Repeated index and sanity check.
*/
if (idx == prevIdx) {
continue;
}
prevIdx = idx;
if (idx < 0 || idx >= listLen) {
continue;
}
/*
* Coalesce adjacent removes to reduce the number of copies.
*/
if (num == 0) {
num = 1;
first = idx;
} else if (idx + 1 == first) {
num++;
first = idx;
} else {
/*
* Note that this operation can't fail now; we know we have a list
* and we're only ever contracting that list.
*/
(void) Tcl_ListObjReplace(interp, listObj, first, num, 0, NULL);
listLen -= num;
num = 1;
first = idx;
}
}
if (num != 0) {
(void) Tcl_ListObjReplace(interp, listObj, first, num, 0, NULL);
}
ckfree(idxv);
Tcl_SetObjResult(interp, listObj);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
@@ -2864,7 +3001,7 @@ Tcl_LreplaceObjCmd(
return result;
}
if (first < 0) {
if (first == TCL_INDEX_NONE) {
first = 0;
}
if (first > listLen) {
@@ -3243,10 +3380,10 @@ Tcl_LsearchObjCmd(
TCL_INDEX_NONE, &encoded) != TCL_OK) {
result = TCL_ERROR;
}
if (encoded == TCL_INDEX_NONE) {
if (encoded == (int)TCL_INDEX_NONE) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"index \"%s\" cannot select an element "
"from any list", Tcl_GetString(indices[j])));
"from any list", TclGetString(indices[j])));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX"
"OUTOFRANGE", NULL);
result = TCL_ERROR;
@@ -3376,8 +3513,8 @@ Tcl_LsearchObjCmd(
if (result != TCL_OK) {
goto done;
}
if (start < 0) {
start = 0;
if (start == TCL_INDEX_NONE) {
start = TCL_INDEX_START;
}
/*
@@ -3960,10 +4097,10 @@ Tcl_LsortObjCmd(
int result = TclIndexEncode(interp, indexv[j],
TCL_INDEX_NONE, TCL_INDEX_NONE, &encoded);
if ((result == TCL_OK) && (encoded == TCL_INDEX_NONE)) {
if ((result == TCL_OK) && (encoded == (int)TCL_INDEX_NONE)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"index \"%s\" cannot select an element "
"from any list", Tcl_GetString(indexv[j])));
"from any list", TclGetString(indexv[j])));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX"
"OUTOFRANGE", NULL);
result = TCL_ERROR;
@@ -4182,7 +4319,7 @@ Tcl_LsortObjCmd(
elementArray = ckalloc(length * sizeof(SortElement));
for (i=0; i < length; i++){
for (i=0; i < length; i++) {
idx = groupSize * i + groupOffset;
if (indexc) {
/*
@@ -4720,7 +4857,7 @@ SelectObjFromSublist(
return NULL;
}
if (currentObj == NULL) {
if (index == TCL_INDEX_NONE) {
if (index == (int)TCL_INDEX_NONE) {
index = TCL_INDEX_END - infoPtr->indexv[i];
Tcl_SetObjResult(infoPtr->interp, Tcl_ObjPrintf(
"element end-%d missing from sublist \"%s\"",
+328 -162
View File
@@ -2010,7 +2010,7 @@ StringMapCmd(
*/
if (!TclHasStringRep(objv[objc-2])
&& TclHasIntRep(objv[objc-2], &tclDictType)){
&& TclHasIntRep(objv[objc-2], &tclDictType)) {
int i, done;
Tcl_DictSearch search;
@@ -2424,15 +2424,16 @@ StringRplcCmd(
end = length - 1;
if (TclGetIntForIndexM(interp, objv[2], end, &first) != TCL_OK ||
TclGetIntForIndexM(interp, objv[3], end, &last) != TCL_OK){
TclGetIntForIndexM(interp, objv[3], end, &last) != TCL_OK) {
return TCL_ERROR;
}
/*
* 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,
* 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 */
@@ -2442,6 +2443,7 @@ StringRplcCmd(
* have (first <= end < 0 <= last) and an empty string is permitted
* to be replaced.
*/
Tcl_SetObjResult(interp, objv[1]);
} else {
Tcl_Obj *resultPtr;
@@ -3623,7 +3625,7 @@ TclNRSwitchObjCmd(
Tcl_Obj **listv;
blist = objv[0];
if (TclListObjGetElements(interp, objv[0], &objc, &listv) != TCL_OK){
if (TclListObjGetElements(interp, objv[0], &objc, &listv) != TCL_OK) {
return TCL_ERROR;
}
@@ -4133,11 +4135,12 @@ Tcl_TimeObjCmd(
*
* This object-based procedure is invoked to process the "timerate" Tcl
* command.
*
* This is similar to command "time", except the execution limited by
* given time (in milliseconds) instead of repetition count.
*
* Example:
* timerate {after 5} 1000 ; # equivalent for `time {after 5} [expr 1000/5]`
* timerate {after 5} 1000; # equivalent to: time {after 5} [expr 1000/5]
*
* Results:
* A standard Tcl object result.
@@ -4155,39 +4158,41 @@ Tcl_TimeRateObjCmd(
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static double measureOverhead = 0; /* global measure-overhead */
static double measureOverhead = 0;
/* global measure-overhead */
double overhead = -1; /* given measure-overhead */
register Tcl_Obj *objPtr;
register int result, i;
Tcl_Obj *calibrate = NULL, *direct = NULL;
Tcl_WideUInt count = 0; /* Holds repetition count */
Tcl_WideInt maxms = WIDE_MIN;
Tcl_WideInt maxms = WIDE_MIN;
/* Maximal running time (in milliseconds) */
Tcl_WideUInt maxcnt = WIDE_MAX;
/* Maximal count of iterations. */
Tcl_WideUInt threshold = 1; /* Current threshold for check time (faster
* repeat count without time check) */
Tcl_WideUInt maxIterTm = 1; /* Max time of some iteration as max threshold
* additionally avoid divide to zero (never < 1) */
Tcl_WideUInt maxIterTm = 1; /* Max time of some iteration as max
* threshold, additionally avoiding divide to
* zero (i.e., never < 1) */
unsigned short factor = 50; /* Factor (4..50) limiting threshold to avoid
* growth of execution time. */
register Tcl_WideInt start, middle, stop;
#ifndef TCL_WIDE_CLICKS
Tcl_Time now;
#endif
#endif /* !TCL_WIDE_CLICKS */
static const char *const options[] = {
"-direct", "-overhead", "-calibrate", "--", NULL
};
enum options {
TMRT_EV_DIRECT, TMRT_OVERHEAD, TMRT_CALIBRATE, TMRT_LAST
};
NRE_callback *rootPtr;
ByteCode *codePtr = NULL;
ByteCode *codePtr = NULL;
int codeOptimized = 0;
for (i = 1; i < objc - 1; i++) {
int index;
int index;
if (Tcl_GetIndexFromObj(NULL, objv[i], options, "option", TCL_EXACT,
&index) != TCL_OK) {
break;
@@ -4214,9 +4219,11 @@ Tcl_TimeRateObjCmd(
}
}
if (i >= objc || i < objc-3) {
usage:
Tcl_WrongNumArgs(interp, 1, objv, "?-direct? ?-calibrate? ?-overhead double? command ?time ?max-count??");
if (i >= objc || i < objc - 3) {
usage:
Tcl_WrongNumArgs(interp, 1, objv,
"?-direct? ?-calibrate? ?-overhead double? "
"command ?time ?max-count??");
return TCL_ERROR;
}
objPtr = objv[i++];
@@ -4227,6 +4234,7 @@ usage:
}
if (i < objc) { /* max-count*/
Tcl_WideInt v;
result = Tcl_GetWideIntFromObj(interp, objv[i], &v);
if (result != TCL_OK) {
return result;
@@ -4235,10 +4243,15 @@ usage:
}
}
/* if calibrate */
/*
* If we are doing calibration.
*/
if (calibrate) {
/*
* If no time specified for the calibration.
*/
/* if no time specified for the calibration */
if (maxms == WIDE_MIN) {
Tcl_Obj *clobjv[6];
Tcl_WideInt maxCalTime = 5000;
@@ -4247,18 +4260,24 @@ usage:
clobjv[0] = objv[0];
i = 1;
if (direct) {
clobjv[i++] = direct;
clobjv[i++] = direct;
}
clobjv[i++] = objPtr;
/* reset last measurement overhead */
measureOverhead = (double)0;
/*
* Reset last measurement overhead.
*/
measureOverhead = (double) 0;
/*
* Self-call with 100 milliseconds to warm-up, before entering the
* calibration cycle.
*/
/* self-call with 100 milliseconds to warm-up,
* before entering the calibration cycle */
TclNewIntObj(clobjv[i], 100);
Tcl_IncrRefCount(clobjv[i]);
result = Tcl_TimeRateObjCmd(dummy, interp, i+1, clobjv);
result = Tcl_TimeRateObjCmd(NULL, interp, i + 1, clobjv);
Tcl_DecrRefCount(clobjv[i]);
if (result != TCL_OK) {
return result;
@@ -4268,241 +4287,385 @@ usage:
clobjv[i++] = calibrate;
clobjv[i++] = objPtr;
/* set last measurement overhead to max */
measureOverhead = (double)UWIDE_MAX;
/*
* Set last measurement overhead to max.
*/
measureOverhead = (double) UWIDE_MAX;
/*
* Run the calibration cycle until it is more precise.
*/
/* calibration cycle until it'll be preciser */
maxms = -1000;
do {
lastMeasureOverhead = measureOverhead;
TclNewIntObj(clobjv[i], (int)maxms);
TclNewIntObj(clobjv[i], (int) maxms);
Tcl_IncrRefCount(clobjv[i]);
result = Tcl_TimeRateObjCmd(dummy, interp, i+1, clobjv);
result = Tcl_TimeRateObjCmd(NULL, interp, i + 1, clobjv);
Tcl_DecrRefCount(clobjv[i]);
if (result != TCL_OK) {
return result;
}
maxCalTime += maxms;
/* increase maxms for preciser calibration */
maxms -= (-maxms / 4);
/* as long as new value more as 0.05% better */
} while ( (measureOverhead >= lastMeasureOverhead
/*
* Increase maxms for more precise calibration.
*/
maxms -= -maxms / 4;
/*
* As long as new value more as 0.05% better
*/
} while ((measureOverhead >= lastMeasureOverhead
|| measureOverhead / lastMeasureOverhead <= 0.9995)
&& maxCalTime > 0
);
&& maxCalTime > 0);
return result;
}
if (maxms == 0) {
/* reset last measurement overhead */
/*
* Reset last measurement overhead
*/
measureOverhead = 0;
Tcl_SetObjResult(interp, Tcl_NewLongObj(0));
return TCL_OK;
}
/* if time is negative - make current overhead more precise */
/*
* If time is negative, make current overhead more precise.
*/
if (maxms > 0) {
/* set last measurement overhead to max */
measureOverhead = (double)UWIDE_MAX;
/*
* Set last measurement overhead to max.
*/
measureOverhead = (double) UWIDE_MAX;
} else {
maxms = -maxms;
}
}
if (maxms == WIDE_MIN) {
maxms = 1000;
maxms = 1000;
}
if (overhead == -1) {
overhead = measureOverhead;
}
/* be sure that resetting of result will not smudge the further measurement */
/*
* Ensure that resetting of result will not smudge the further
* measurement.
*/
Tcl_ResetResult(interp);
/* compile object */
/*
* Compile object if needed.
*/
if (!direct) {
if (TclInterpReady(interp) != TCL_OK) {
return TCL_ERROR;
}
codePtr = TclCompileObj(interp, objPtr, NULL, 0);
TclPreserveByteCode(codePtr);
/*
* Replace last compiled done instruction with continue: it's a part of
* iteration, this way evaluation will be more similar to a cycle (also
* avoids extra overhead to set result to interp, etc.)
*/
if (codePtr->codeStart[codePtr->numCodeBytes-1] == INST_DONE) {
codePtr->codeStart[codePtr->numCodeBytes-1] = INST_CONTINUE;
codeOptimized = 1;
}
}
/* get start and stop time */
/*
* Get start and stop time.
*/
#ifdef TCL_WIDE_CLICKS
start = middle = TclpGetWideClicks();
/* time to stop execution (in wide clicks) */
/*
* Time to stop execution (in wide clicks).
*/
stop = start + (maxms * 1000 / TclpWideClickInMicrosec());
#else
Tcl_GetTime(&now);
start = now.sec; start *= 1000000; start += now.usec;
start = now.sec;
start *= 1000000;
start += now.usec;
middle = start;
/* time to stop execution (in microsecs) */
/*
* Time to stop execution (in microsecs).
*/
stop = start + maxms * 1000;
#endif
#endif /* TCL_WIDE_CLICKS */
/* start measurement */
if (maxcnt > 0)
while (1) {
/* eval single iteration */
count++;
/*
* Start measurement.
*/
if (!direct) {
/* precompiled */
rootPtr = TOP_CB(interp);
result = TclNRExecuteByteCode(interp, codePtr);
result = TclNRRunCallbacks(interp, result, rootPtr);
} else {
/* eval */
result = TclEvalObjEx(interp, objPtr, 0, NULL, 0);
}
if (result != TCL_OK) {
/* allow break from measurement cycle (used for conditional stop) */
if (result != TCL_BREAK) {
goto done;
if (maxcnt > 0) {
while (1) {
/*
* Evaluate a single iteration.
*/
count++;
if (!direct) { /* precompiled */
rootPtr = TOP_CB(interp);
result = TclNRExecuteByteCode(interp, codePtr);
result = TclNRRunCallbacks(interp, result, rootPtr);
} else { /* eval */
result = TclEvalObjEx(interp, objPtr, 0, NULL, 0);
}
/* force stop immediately */
threshold = 1;
maxcnt = 0;
result = TCL_OK;
}
/*
* Allow break and continue from measurement cycle (used for
* conditional stop and flow control of iterations).
*/
/* don't check time up to threshold */
if (--threshold > 0) continue;
/* check stop time reached, estimate new threshold */
#ifdef TCL_WIDE_CLICKS
middle = TclpGetWideClicks();
#else
Tcl_GetTime(&now);
middle = now.sec; middle *= 1000000; middle += now.usec;
#endif
if (middle >= stop || count >= maxcnt) {
break;
}
/* don't calculate threshold by few iterations, because sometimes first
* iteration(s) can be too fast or slow (cached, delayed clean up, etc) */
if (count < 10) {
threshold = 1; continue;
}
/* average iteration time in microsecs */
threshold = (middle - start) / count;
if (threshold > maxIterTm) {
maxIterTm = threshold;
/* interations seems to be longer */
if (threshold > (maxIterTm * 2)) {
if ((factor *= 2) > 50) factor = 50;
} else {
if (factor < 50) factor++;
switch (result) {
case TCL_OK:
break;
case TCL_BREAK:
/*
* Force stop immediately.
*/
threshold = 1;
maxcnt = 0;
case TCL_CONTINUE:
result = TCL_OK;
break;
default:
goto done;
}
} else if (factor > 4) {
/* interations seems to be shorter */
if (threshold < (maxIterTm / 2)) {
if ((factor /= 2) < 4) factor = 4;
} else {
factor--;
/*
* Don't check time up to threshold.
*/
if (--threshold > 0) {
continue;
}
/*
* Check stop time reached, estimate new threshold.
*/
#ifdef TCL_WIDE_CLICKS
middle = TclpGetWideClicks();
#else
Tcl_GetTime(&now);
middle = now.sec;
middle *= 1000000;
middle += now.usec;
#endif /* TCL_WIDE_CLICKS */
if (middle >= stop || count >= maxcnt) {
break;
}
/*
* Don't calculate threshold by few iterations, because sometimes
* first iteration(s) can be too fast or slow (cached, delayed
* clean up, etc).
*/
if (count < 10) {
threshold = 1;
continue;
}
/*
* Average iteration time in microsecs.
*/
threshold = (middle - start) / count;
if (threshold > maxIterTm) {
maxIterTm = threshold;
/*
* Iterations seem to be longer.
*/
if (threshold > maxIterTm * 2) {
factor *= 2;
if (factor > 50) {
factor = 50;
}
} else {
if (factor < 50) {
factor++;
}
}
} else if (factor > 4) {
/*
* Iterations seem to be shorter.
*/
if (threshold < (maxIterTm / 2)) {
factor /= 2;
if (factor < 4) {
factor = 4;
}
} else {
factor--;
}
}
/*
* As relation between remaining time and time since last check,
* maximal some % of time (by factor), so avoid growing of the
* execution time if iterations are not consistent, e.g. was
* continuously on time).
*/
threshold = ((stop - middle) / maxIterTm) / factor + 1;
if (threshold > 100000) { /* fix for too large threshold */
threshold = 100000;
}
/*
* Consider max-count
*/
if (threshold > maxcnt - count) {
threshold = maxcnt - count;
}
}
/* as relation between remaining time and time since last check,
* maximal some % of time (by factor), so avoid growing of the execution time
* if iterations are not consistent, e. g. wax continuously on time) */
threshold = ((stop - middle) / maxIterTm) / factor + 1;
if (threshold > 100000) { /* fix for too large threshold */
threshold = 100000;
}
/* consider max-count */
if (threshold > maxcnt - count) {
threshold = maxcnt - count;
}
}
{
Tcl_Obj *objarr[8], **objs = objarr;
Tcl_WideInt val;
const char *fmt;
Tcl_WideUInt usec, val;
int digits;
middle -= start; /* execution time in microsecs */
/*
* Absolute execution time in microseconds or in wide clicks.
*/
usec = (Tcl_WideUInt)(middle - start);
#ifdef TCL_WIDE_CLICKS
/* convert execution time in wide clicks to microsecs */
middle *= TclpWideClickInMicrosec();
#endif
#ifdef TCL_WIDE_CLICKS
/*
* convert execution time (in wide clicks) to microsecs.
*/
if (!count) { /* no iterations - avoid divide by zero */
usec *= TclpWideClickInMicrosec();
#endif /* TCL_WIDE_CLICKS */
if (!count) { /* no iterations - avoid divide by zero */
objs[0] = objs[2] = objs[4] = Tcl_NewWideIntObj(0);
goto retRes;
}
/* if not calibrate */
/*
* If not calibrating...
*/
if (!calibrate) {
/* minimize influence of measurement overhead */
/*
* Minimize influence of measurement overhead.
*/
if (overhead > 0) {
/* estimate the time of overhead (microsecs) */
/*
* Estimate the time of overhead (microsecs).
*/
Tcl_WideUInt curOverhead = overhead * count;
if (middle > (Tcl_WideInt)curOverhead) {
middle -= curOverhead;
if (usec > curOverhead) {
usec -= curOverhead;
} else {
middle = 0;
usec = 0;
}
}
} else {
/* calibration - obtaining new measurement overhead */
if (measureOverhead > (double)middle / count) {
measureOverhead = (double)middle / count;
/*
* Calibration: obtaining new measurement overhead.
*/
if (measureOverhead > ((double) usec) / count) {
measureOverhead = ((double) usec) / count;
}
objs[0] = Tcl_NewDoubleObj(measureOverhead);
TclNewLiteralStringObj(objs[1], "\xC2\xB5s/#-overhead"); /* mics */
objs += 2;
}
val = middle / count; /* microsecs per iteration */
val = usec / count; /* microsecs per iteration */
if (val >= 1000000) {
objs[0] = Tcl_NewWideIntObj(val);
} else {
if (val < 10) { fmt = "%.6f"; } else
if (val < 100) { fmt = "%.4f"; } else
if (val < 1000) { fmt = "%.3f"; } else
if (val < 10000) { fmt = "%.2f"; } else
{ fmt = "%.1f"; };
objs[0] = Tcl_ObjPrintf(fmt, ((double)middle)/count);
if (val < 10) {
digits = 6;
} else if (val < 100) {
digits = 4;
} else if (val < 1000) {
digits = 3;
} else if (val < 10000) {
digits = 2;
} else {
digits = 1;
}
objs[0] = Tcl_ObjPrintf("%.*f", digits, ((double) usec)/count);
}
objs[2] = Tcl_NewWideIntObj(count); /* iterations */
/* calculate speed as rate (count) per sec */
if (!middle) middle++; /* +1 ms, just to avoid divide by zero */
/*
* Calculate speed as rate (count) per sec
*/
if (!usec) {
usec++; /* Avoid divide by zero. */
}
if (count < (WIDE_MAX / 1000000)) {
val = (count * 1000000) / middle;
val = (count * 1000000) / usec;
if (val < 100000) {
if (val < 100) { fmt = "%.3f"; } else
if (val < 1000) { fmt = "%.2f"; } else
{ fmt = "%.1f"; };
objs[4] = Tcl_ObjPrintf(fmt, ((double)(count * 1000000)) / middle);
if (val < 100) {
digits = 3;
} else if (val < 1000) {
digits = 2;
} else {
digits = 1;
}
objs[4] = Tcl_ObjPrintf("%.*f",
digits, ((double) (count * 1000000)) / usec);
} else {
objs[4] = Tcl_NewWideIntObj(val);
}
} else {
objs[4] = Tcl_NewWideIntObj((count / middle) * 1000000);
objs[4] = Tcl_NewWideIntObj((count / usec) * 1000000);
}
retRes:
/* estimated net execution time (in millisecs) */
/*
* Estimated net execution time (in millisecs).
*/
if (!calibrate) {
if (middle >= 1) {
objs[6] = Tcl_ObjPrintf("%.3f", (double)middle / 1000);
if (usec >= 1) {
objs[6] = Tcl_ObjPrintf("%.3f", (double)usec / 1000);
} else {
objs[6] = Tcl_NewWideIntObj(0);
}
TclNewLiteralStringObj(objs[7], "nett-ms");
TclNewLiteralStringObj(objs[7], "net-ms");
}
/*
* Construct the result as a list because many programs have always parsed
* as such (extracting the first element, typically).
*/
* Construct the result as a list because many programs have always
* parsed as such (extracting the first element, typically).
*/
TclNewLiteralStringObj(objs[1], "\xC2\xB5s/#"); /* mics/# */
TclNewLiteralStringObj(objs[3], "#");
@@ -4510,12 +4673,15 @@ usage:
Tcl_SetObjResult(interp, Tcl_NewListObj(8, objarr));
}
done:
done:
if (codePtr != NULL) {
if ( codeOptimized
&& codePtr->codeStart[codePtr->numCodeBytes-1] == INST_CONTINUE
) {
codePtr->codeStart[codePtr->numCodeBytes-1] = INST_DONE;
}
TclReleaseByteCode(codePtr);
}
return result;
}
+32
View File
@@ -1176,6 +1176,38 @@ TclCompileDictGetCmd(
return TCL_OK;
}
int
TclCompileDictGetWithDefaultCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
Tcl_Token *tokenPtr;
int i;
DefineLineInformation; /* TIP #280 */
/*
* There must be at least three arguments after the command.
*/
/* TODO: Consider support for compiling expanded args. */
if (parsePtr->numWords < 4) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
for (i=1 ; i<parsePtr->numWords ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt4(INST_DICT_GET_DEF, parsePtr->numWords-3, envPtr);
TclAdjustStackDepth(-2, envPtr);
return TCL_OK;
}
int
TclCompileDictExistsCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
+24 -24
View File
@@ -433,7 +433,7 @@ TclCompileIfCmd(
jumpFalseDist += 3;
TclStoreInt4AtPtr(jumpFalseDist, (ifFalsePc + 1));
} else {
Tcl_Panic("TclCompileIfCmd: unexpected opcode \"%d\" updating ifFalse jump", (int) opCode);
Tcl_Panic("TclCompileIfCmd: unexpected opcode \"%d\" updating ifFalse jump", opCode);
}
}
}
@@ -606,7 +606,7 @@ TclCompileInfoCommandsCmd(
if (!TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
goto notCompilable;
}
bytes = Tcl_GetString(objPtr);
bytes = TclGetString(objPtr);
/*
* We require that the argument start with "::" and not have any of "*\[?"
@@ -1038,7 +1038,7 @@ TclCompileLassignCmd(
*/
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
TclEmitInt4( TCL_INDEX_END, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
return TCL_OK;
}
@@ -1243,7 +1243,7 @@ TclCompileListCmd(
if (concat && numWords == 2) {
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( TCL_INDEX_END, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
}
return TCL_OK;
}
@@ -1319,7 +1319,7 @@ TclCompileLrangeCmd(
tokenPtr = TokenAfter(listTokenPtr);
if ((TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_NONE,
&idx1) != TCL_OK) || (idx1 == TCL_INDEX_NONE)) {
&idx1) != TCL_OK) || (idx1 == (int)TCL_INDEX_NONE)) {
return TCL_ERROR;
}
/*
@@ -1408,7 +1408,7 @@ TclCompileLinsertCmd(
CompileWord(envPtr, listTokenPtr, interp, 1);
if (parsePtr->numWords == 3) {
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( TCL_INDEX_END, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
return TCL_OK;
}
@@ -1418,10 +1418,10 @@ TclCompileLinsertCmd(
}
TclEmitInstInt4( INST_LIST, i - 3, envPtr);
if (idx == TCL_INDEX_START) {
if (idx == (int)TCL_INDEX_START) {
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
} else if (idx == TCL_INDEX_END) {
} else if (idx == (int)TCL_INDEX_END) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
} else {
/*
@@ -1436,7 +1436,7 @@ TclCompileLinsertCmd(
* differ in their interpretation of the "end" index.
*/
if (idx < TCL_INDEX_END) {
if (idx < (int)TCL_INDEX_END) {
idx++;
}
TclEmitInstInt4( INST_OVER, 1, envPtr);
@@ -1444,7 +1444,7 @@ TclCompileLinsertCmd(
TclEmitInt4( idx - 1, envPtr);
TclEmitInstInt4( INST_REVERSE, 3, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
TclEmitInt4( TCL_INDEX_END, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
}
@@ -1505,14 +1505,14 @@ TclCompileLreplaceCmd(
* we must defer to direct evaluation.
*/
if (idx1 == TCL_INDEX_NONE) {
suffixStart = TCL_INDEX_NONE;
} else if (idx2 == TCL_INDEX_NONE) {
if (idx1 == (int)TCL_INDEX_NONE) {
suffixStart = (int)TCL_INDEX_NONE;
} else if (idx2 == (int)TCL_INDEX_NONE) {
suffixStart = idx1;
} else if (idx2 == TCL_INDEX_END) {
suffixStart = TCL_INDEX_NONE;
} else if (((idx2 < TCL_INDEX_END) && (idx1 <= TCL_INDEX_END))
|| ((idx2 >= TCL_INDEX_START) && (idx1 >= TCL_INDEX_START))) {
} else if (idx2 == (int)TCL_INDEX_END) {
suffixStart = (int)TCL_INDEX_NONE;
} else if (((idx2 < (int)TCL_INDEX_END) && (idx1 <= (int)TCL_INDEX_END))
|| ((idx2 >= (int)TCL_INDEX_START) && (idx1 >= (int)TCL_INDEX_START))) {
suffixStart = (idx1 > idx2 + 1) ? idx1 : idx2 + 1;
} else {
return TCL_ERROR;
@@ -1546,11 +1546,11 @@ TclCompileLreplaceCmd(
* and canonicalization side effects.
*/
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( TCL_INDEX_END, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
return TCL_OK;
}
if (idx1 != TCL_INDEX_START) {
if (idx1 != (int)TCL_INDEX_START) {
/* Prefix may not be empty; generate bytecode to push it */
if (emptyPrefix) {
TclEmitOpcode( INST_DUP, envPtr);
@@ -1570,7 +1570,7 @@ TclCompileLreplaceCmd(
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
}
if (suffixStart == TCL_INDEX_NONE) {
if (suffixStart == (int)TCL_INDEX_NONE) {
TclEmitOpcode( INST_POP, envPtr);
if (emptyPrefix) {
PushStringLiteral(envPtr, "");
@@ -1578,7 +1578,7 @@ TclCompileLreplaceCmd(
} else {
/* Suffix may not be empty; generate bytecode to push it */
TclEmitInstInt4( INST_LIST_RANGE_IMM, suffixStart, envPtr);
TclEmitInt4( TCL_INDEX_END, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
if (!emptyPrefix) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
}
@@ -2295,8 +2295,8 @@ TclCompileRegsubCmd(
if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) {
goto done;
}
if (Tcl_GetString(patternObj)[0] == '-') {
if (strcmp(Tcl_GetString(patternObj), "--") != 0
if (TclGetString(patternObj)[0] == '-') {
if (strcmp(TclGetString(patternObj), "--") != 0
|| parsePtr->numWords == 5) {
goto done;
}
@@ -2361,7 +2361,7 @@ TclCompileRegsubCmd(
bytes++;
}
isSimpleGlob:
for (bytes = Tcl_GetString(replacementObj); *bytes; bytes++) {
for (bytes = TclGetString(replacementObj); *bytes; bytes++) {
switch (*bytes) {
case '\\': case '&':
goto done;
+62 -18
View File
@@ -482,16 +482,16 @@ TclCompileStringInsertCmd(
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 3);
if (idx == TCL_INDEX_START) {
if (idx == (int)TCL_INDEX_START) {
/* Prepend the insertion string */
OP4( REVERSE, 2);
OP1( STR_CONCAT1, 2);
} else if (idx == TCL_INDEX_END) {
} else if (idx == (int)TCL_INDEX_END) {
/* Append the insertion string */
OP1( STR_CONCAT1, 2);
} else {
/* Prefix + insertion + suffix */
if (idx < TCL_INDEX_END) {
if (idx < (int)TCL_INDEX_END) {
/* See comments in compiler for [linsert]. */
idx++;
}
@@ -821,7 +821,7 @@ TclCompileStringMatchCmd(
}
str = tokenPtr[1].start;
length = tokenPtr[1].size;
if ((length <= 1) || strncmp(str, "-nocase", (size_t) length)) {
if ((length <= 1) || strncmp(str, "-nocase", length)) {
/*
* Fail at run time, not in compilation.
*/
@@ -1012,7 +1012,7 @@ TclCompileStringRangeCmd(
* the string the same as the start of the string.
*/
if (idx1 == TCL_INDEX_NONE) {
if (idx1 == (int)TCL_INDEX_NONE) {
/* [string range $s end+1 $last] must be empty string */
OP( POP);
PUSH( "");
@@ -1027,7 +1027,7 @@ TclCompileStringRangeCmd(
* 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_NONE) {
if (idx2 == (int)TCL_INDEX_NONE) {
/* [string range $s $first -1] must be empty string */
OP( POP);
PUSH( "");
@@ -1105,8 +1105,8 @@ TclCompileStringReplaceCmd(
* compile direct to bytecode implementing the no-op.
*/
if ((last == TCL_INDEX_NONE) /* Know (last < 0) */
|| (first == TCL_INDEX_NONE) /* Know (first > end) */
if ((last == (int)TCL_INDEX_NONE) /* Know (last < 0) */
|| (first == (int)TCL_INDEX_NONE) /* Know (first > end) */
/*
* Tricky to determine when runtime (last < first) can be
@@ -1117,7 +1117,7 @@ TclCompileStringReplaceCmd(
* (last <= TCL_INDEX END) && (last < first) => ACCEPT
* else => cannot tell REJECT
*/
|| ((first <= TCL_INDEX_END) && (last <= TCL_INDEX_END)
|| ((first <= (int)TCL_INDEX_END) && (last <= (int)TCL_INDEX_END)
&& (last < first)) /* Know (last < first) */
/*
* (first == TCL_INDEX_NONE) &&
@@ -1128,7 +1128,7 @@ TclCompileStringReplaceCmd(
* (last <= TCL_INDEX_END) => cannot tell REJECT
* else [[last >= TCL_INDEX START]] && (last < first) => ACCEPT
*/
|| ((first >= TCL_INDEX_START) && (last >= TCL_INDEX_START)
|| ((first >= (int)TCL_INDEX_START) && (last >= (int)TCL_INDEX_START)
&& (last < first))) { /* Know (last < first) */
if (parsePtr->numWords == 5) {
tokenPtr = TokenAfter(tokenPtr);
@@ -1179,7 +1179,7 @@ TclCompileStringReplaceCmd(
* getting a guarantee that first <= last.
*/
if ((first == TCL_INDEX_START) && (last >= TCL_INDEX_START)) {
if ((first == (int)TCL_INDEX_START) && (last >= (int)TCL_INDEX_START)) {
/* empty prefix */
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
@@ -1187,13 +1187,13 @@ TclCompileStringReplaceCmd(
if (last == INT_MAX) {
OP( POP); /* Pop original */
} else {
OP44( STR_RANGE_IMM, last + 1, TCL_INDEX_END);
OP44( STR_RANGE_IMM, last + 1, (int)TCL_INDEX_END);
OP1( STR_CONCAT1, 2);
}
return TCL_OK;
}
if ((last == TCL_INDEX_NONE) && (first <= TCL_INDEX_END)) {
if ((last == (int)TCL_INDEX_NONE) && (first <= (int)TCL_INDEX_END)) {
OP44( STR_RANGE_IMM, 0, first-1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
@@ -1210,19 +1210,19 @@ TclCompileStringReplaceCmd(
* are harmless when they are replaced by another empty string.
*/
if (first == TCL_INDEX_START) {
if (first == (int)TCL_INDEX_START) {
/* empty prefix - build suffix only */
if (last == TCL_INDEX_END) {
if (last == (int)TCL_INDEX_END) {
/* empty suffix too => empty result */
OP( POP); /* Pop original */
PUSH ( "");
return TCL_OK;
}
OP44( STR_RANGE_IMM, last + 1, TCL_INDEX_END);
OP44( STR_RANGE_IMM, last + 1, (int)TCL_INDEX_END);
return TCL_OK;
} else {
if (last == TCL_INDEX_END) {
if (last == (int)TCL_INDEX_END) {
/* empty suffix - build prefix only */
OP44( STR_RANGE_IMM, 0, first-1);
return TCL_OK;
@@ -1230,7 +1230,7 @@ TclCompileStringReplaceCmd(
OP( DUP);
OP44( STR_RANGE_IMM, 0, first-1);
OP4( REVERSE, 2);
OP44( STR_RANGE_IMM, last + 1, TCL_INDEX_END);
OP44( STR_RANGE_IMM, last + 1, (int)TCL_INDEX_END);
OP1( STR_CONCAT1, 2);
return TCL_OK;
}
@@ -4493,6 +4493,50 @@ TclCompileStreqOpCmd(
{
return CompileComparisonOpCmd(interp, parsePtr, INST_STR_EQ, envPtr);
}
int
TclCompileStrLtOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr)
{
return CompileComparisonOpCmd(interp, parsePtr, INST_STR_LT, envPtr);
}
int
TclCompileStrLeOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr)
{
return CompileComparisonOpCmd(interp, parsePtr, INST_STR_LE, envPtr);
}
int
TclCompileStrGtOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr)
{
return CompileComparisonOpCmd(interp, parsePtr, INST_STR_GT, envPtr);
}
int
TclCompileStrGeOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr)
{
return CompileComparisonOpCmd(interp, parsePtr, INST_STR_GE, envPtr);
}
int
TclCompileMinusOpCmd(
+43 -6
View File
@@ -281,7 +281,11 @@ enum Marks {
* parse tree. The sub-expression between
* parens becomes the single argument of the
* matching OPEN_PAREN unary operator. */
#define END (BINARY | 28)
#define STR_LT (BINARY | 28)
#define STR_GT (BINARY | 29)
#define STR_LEQ (BINARY | 30)
#define STR_GEQ (BINARY | 31)
#define END (BINARY | 32)
/* This lexeme represents the end of the
* string being parsed. Treating it as a
* binary operator follows the same logic as
@@ -360,12 +364,14 @@ static const unsigned char prec[] = {
PREC_EQUAL, /* IN_LIST */
PREC_EQUAL, /* NOT_IN_LIST */
PREC_CLOSE_PAREN, /* CLOSE_PAREN */
PREC_COMPARE, /* STR_LT */
PREC_COMPARE, /* STR_GT */
PREC_COMPARE, /* STR_LEQ */
PREC_COMPARE, /* STR_GEQ */
PREC_END, /* END */
/* Expansion room for more binary operators */
0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
/* Unary operator lexemes */
PREC_UNARY, /* UNARY_PLUS */
PREC_UNARY, /* UNARY_MINUS */
@@ -415,12 +421,14 @@ static const unsigned char instruction[] = {
INST_LIST_IN, /* IN_LIST */
INST_LIST_NOT_IN, /* NOT_IN_LIST */
0, /* CLOSE_PAREN */
INST_STR_LT, /* STR_LT */
INST_STR_GT, /* STR_GT */
INST_STR_LE, /* STR_LEQ */
INST_STR_GE, /* STR_GEQ */
0, /* END */
/* Expansion room for more binary operators */
0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
/* Unary operator lexemes */
INST_UPLUS, /* UNARY_PLUS */
INST_UMINUS, /* UNARY_MINUS */
@@ -2001,6 +2009,35 @@ ParseLexeme(
return 2;
}
}
break;
case 'l':
if ((numBytes > 1)
&& ((numBytes == 2) || start[2] & 0x80 || !isalpha(UCHAR(start[2])))) {
switch (start[1]) {
case 't':
*lexemePtr = STR_LT;
return 2;
case 'e':
*lexemePtr = STR_LEQ;
return 2;
}
}
break;
case 'g':
if ((numBytes > 1)
&& ((numBytes == 2) || start[2] & 0x80 || !isalpha(UCHAR(start[2])))) {
switch (start[1]) {
case 't':
*lexemePtr = STR_GT;
return 2;
case 'e':
*lexemePtr = STR_GEQ;
return 2;
}
}
break;
}
literal = Tcl_NewObj();
@@ -2568,7 +2605,7 @@ TclSingleOpCmd(
*
* TclSortingOpCmd --
* Implements the commands:
* <, <=, >, >=, ==, eq
* <, <=, >, >=, ==, eq, lt, le, gt, ge
* in the ::tcl::mathop namespace. These commands are defined for
* arbitrary number of arguments by computing the AND of the base
* operator applied to all neighbor argument pairs.
+17
View File
@@ -659,6 +659,23 @@ InstructionDesc const tclInstructionTable[] = {
* 0=clicks, 1=microseconds, 2=milliseconds, 3=seconds.
* Stack: ... => ... time */
{"dictGetDef", 5, INT_MIN, 1, {OPERAND_UINT4}},
/* The top word is the default, the next op4 words (min 1) are a key
* path into the dictionary just below the keys on the stack, and all
* those values are replaced by the value read out of that key-path
* (like [dict get]) except if there is no such key, when instead the
* default is pushed instead.
* Stack: ... dict key1 ... keyN default => ... value */
{"strlt", 1, -1, 0, {OPERAND_NONE}},
/* String Less: push (stknext < stktop) */
{"strgt", 1, -1, 0, {OPERAND_NONE}},
/* String Greater: push (stknext > stktop) */
{"strle", 1, -1, 0, {OPERAND_NONE}},
/* String Less or equal: push (stknext <= stktop) */
{"strge", 1, -1, 0, {OPERAND_NONE}},
/* String Greater or equal: push (stknext >= stktop) */
{NULL, 0, 0, 0, {OPERAND_NONE}}
};
+9 -1
View File
@@ -840,8 +840,16 @@ typedef struct ByteCode {
#define INST_CLOCK_READ 189
#define INST_DICT_GET_DEF 190
/* TIP 461 */
#define INST_STR_LT 191
#define INST_STR_GT 192
#define INST_STR_LE 193
#define INST_STR_GE 194
/* The last opcode */
#define LAST_INST_OPCODE 189
#define LAST_INST_OPCODE 194
/*
* Table describing the Tcl bytecode instructions: their name (for displaying
+17 -2
View File
@@ -597,7 +597,7 @@ EXTERN char * Tcl_JoinPath(int argc, const char *const *argv,
Tcl_DString *resultPtr);
/* 187 */
EXTERN int Tcl_LinkVar(Tcl_Interp *interp, const char *varName,
char *addr, int type);
void *addr, int type);
/* Slot 188 is reserved */
/* 189 */
EXTERN Tcl_Channel Tcl_MakeFileChannel(ClientData handle, int mode);
@@ -1897,6 +1897,13 @@ EXTERN void Tcl_IncrRefCount(Tcl_Obj *objPtr);
EXTERN void Tcl_DecrRefCount(Tcl_Obj *objPtr);
/* 643 */
EXTERN int Tcl_IsShared(Tcl_Obj *objPtr);
/* 644 */
EXTERN int Tcl_LinkArray(Tcl_Interp *interp,
const char *varName, void *addr, int type,
int size);
/* 645 */
EXTERN int Tcl_GetIntForIndex(Tcl_Interp *interp,
Tcl_Obj *objPtr, int endValue, int *indexPtr);
typedef struct {
const struct TclPlatStubs *tclPlatStubs;
@@ -2119,7 +2126,7 @@ typedef struct TclStubs {
int (*tcl_InterpDeleted) (Tcl_Interp *interp); /* 184 */
int (*tcl_IsSafe) (Tcl_Interp *interp); /* 185 */
char * (*tcl_JoinPath) (int argc, const char *const *argv, Tcl_DString *resultPtr); /* 186 */
int (*tcl_LinkVar) (Tcl_Interp *interp, const char *varName, char *addr, int type); /* 187 */
int (*tcl_LinkVar) (Tcl_Interp *interp, const char *varName, void *addr, int type); /* 187 */
void (*reserved188)(void);
Tcl_Channel (*tcl_MakeFileChannel) (ClientData handle, int mode); /* 189 */
int (*tcl_MakeSafe) (Tcl_Interp *interp); /* 190 */
@@ -2576,6 +2583,8 @@ typedef struct TclStubs {
void (*tcl_IncrRefCount) (Tcl_Obj *objPtr); /* 641 */
void (*tcl_DecrRefCount) (Tcl_Obj *objPtr); /* 642 */
int (*tcl_IsShared) (Tcl_Obj *objPtr); /* 643 */
int (*tcl_LinkArray) (Tcl_Interp *interp, const char *varName, void *addr, int type, int size); /* 644 */
int (*tcl_GetIntForIndex) (Tcl_Interp *interp, Tcl_Obj *objPtr, int endValue, int *indexPtr); /* 645 */
} TclStubs;
extern const TclStubs *tclStubsPtr;
@@ -3894,6 +3903,10 @@ extern const TclStubs *tclStubsPtr;
(tclStubsPtr->tcl_DecrRefCount) /* 642 */
#define Tcl_IsShared \
(tclStubsPtr->tcl_IsShared) /* 643 */
#define Tcl_LinkArray \
(tclStubsPtr->tcl_LinkArray) /* 644 */
#define Tcl_GetIntForIndex \
(tclStubsPtr->tcl_GetIntForIndex) /* 645 */
#endif /* defined(USE_TCL_STUBS) */
@@ -3979,6 +3992,8 @@ extern const TclStubs *tclStubsPtr;
#define Tcl_AddObjErrorInfo(interp, message, length) \
Tcl_AppendObjToErrorInfo(interp, Tcl_NewStringObj(message, length))
#ifdef TCL_NO_DEPRECATED
#undef Tcl_GetStringResult
#define Tcl_GetStringResult(interp) Tcl_GetString(Tcl_GetObjResult(interp))
#undef Tcl_Eval
#define Tcl_Eval(interp, objPtr) \
Tcl_EvalEx(interp, objPtr, -1, 0)
+73 -5
View File
@@ -34,6 +34,8 @@ static int DictFilterCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const *objv);
static int DictGetCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const *objv);
static int DictGetDefCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const *objv);
static int DictIncrCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const *objv);
static int DictInfoCmd(ClientData dummy, Tcl_Interp *interp,
@@ -89,6 +91,9 @@ static const EnsembleImplMap implementationMap[] = {
{"filter", DictFilterCmd, NULL, NULL, NULL, 0 },
{"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL, 0 },
{"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL, 0 },
{"getdef", DictGetDefCmd, TclCompileDictGetWithDefaultCmd, NULL,NULL,0},
{"getwithdefault", DictGetDefCmd, TclCompileDictGetWithDefaultCmd,
NULL, NULL, 0 },
{"incr", DictIncrCmd, TclCompileDictIncrCmd, NULL, NULL, 0 },
{"info", DictInfoCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 },
{"keys", DictKeysCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 },
@@ -1624,6 +1629,71 @@ DictGetCmd(
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* DictGetDefCmd --
*
* This function implements the "dict getdef" and "dict getwithdefault"
* Tcl commands. See the user documentation for details on what it does,
* and TIP#342 for the formal specification.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
static int
DictGetDefCmd(
ClientData dummy,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictPtr, *keyPtr, *valuePtr, *defaultPtr;
Tcl_Obj *const *keyPath;
int numKeys;
if (objc < 4) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key ...? key default");
return TCL_ERROR;
}
/*
* Give the bits of arguments names for clarity.
*/
dictPtr = objv[1];
keyPath = &objv[2];
numKeys = objc - 4; /* Number of keys in keyPath; there's always
* one extra key afterwards too. */
keyPtr = objv[objc - 2];
defaultPtr = objv[objc - 1];
/*
* Implement the getting-with-default operation.
*/
dictPtr = TclTraceDictPath(interp, dictPtr, numKeys, keyPath,
DICT_PATH_EXISTS);
if (dictPtr == NULL) {
return TCL_ERROR;
} else if (dictPtr == DICT_PATH_NON_EXISTENT) {
Tcl_SetObjResult(interp, defaultPtr);
} else if (Tcl_DictObjGet(interp, dictPtr, keyPtr, &valuePtr) != TCL_OK) {
return TCL_ERROR;
} else if (valuePtr == NULL) {
Tcl_SetObjResult(interp, defaultPtr);
} else {
Tcl_SetObjResult(interp, valuePtr);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
@@ -2016,11 +2086,9 @@ DictExistsCmd(
return TCL_ERROR;
}
dictPtr = TclTraceDictPath(interp, objv[1], objc-3, objv+2,
DICT_PATH_EXISTS);
if (dictPtr == NULL || dictPtr == DICT_PATH_NON_EXISTENT
|| Tcl_DictObjGet(interp, dictPtr, objv[objc-1],
&valuePtr) != TCL_OK) {
dictPtr = TclTraceDictPath(NULL, objv[1], objc-3, objv+2,DICT_PATH_EXISTS);
if (dictPtr == NULL || dictPtr == DICT_PATH_NON_EXISTENT ||
Tcl_DictObjGet(NULL, dictPtr, objv[objc-1], &valuePtr) != TCL_OK) {
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
} else {
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL));
+1 -1
View File
@@ -837,7 +837,7 @@ UpdateStringOfInstName(
if (inst > LAST_INST_OPCODE) {
dst = Tcl_InitStringRep(objPtr, NULL, TCL_INTEGER_SPACE + 5);
TclOOM(dst, TCL_INTEGER_SPACE + 5);
sprintf(dst, "inst_%" TCL_Z_MODIFIER "d", inst);
sprintf(dst, "inst_%" TCL_Z_MODIFIER "u", inst);
(void) Tcl_InitStringRep(objPtr, NULL, strlen(dst));
} else {
const char *s = tclInstructionTable[inst].name;
+121 -82
View File
@@ -97,9 +97,9 @@ static const char *const resultStrings[] = {
*/
#ifdef TCL_COMPILE_STATS
long tclObjsAlloced = 0;
long tclObjsFreed = 0;
long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS] = { 0, 0, 0, 0, 0 };
size_t tclObjsAlloced = 0;
size_t tclObjsFreed = 0;
size_t tclObjsShared[TCL_MAX_SHARED_OBJ_STATS] = { 0, 0, 0, 0, 0 };
#endif /* TCL_COMPILE_STATS */
/*
@@ -5084,6 +5084,10 @@ TEBCresume(
case INST_STR_EQ:
case INST_STR_NEQ: /* String (in)equality check */
case INST_STR_CMP: /* String compare. */
case INST_STR_LT:
case INST_STR_GT:
case INST_STR_LE:
case INST_STR_GE:
stringCompare:
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
@@ -5114,15 +5118,19 @@ TEBCresume(
match = (match != 0);
break;
case INST_LT:
case INST_STR_LT:
match = (match < 0);
break;
case INST_GT:
case INST_STR_GT:
match = (match > 0);
break;
case INST_LE:
case INST_STR_LE:
match = (match <= 0);
break;
case INST_GE:
case INST_STR_GE:
match = (match >= 0);
break;
}
@@ -6471,7 +6479,7 @@ TEBCresume(
listTmpIndex++;
}
}
TRACE_APPEND(("%d lists, iter %" TCL_Z_MODIFIER "d, %s loop\n",
TRACE_APPEND(("%d lists, iter %" TCL_Z_MODIFIER "u, %s loop\n",
numLists, iterNum, (continueLoop? "continue" : "exit")));
/*
@@ -6769,55 +6777,23 @@ TEBCresume(
TRACE_APPEND(("OK\n"));
NEXT_INST_F(1, 1, 0);
case INST_DICT_GET:
case INST_DICT_EXISTS: {
register Tcl_Interp *interp2 = interp;
register int found;
opnd = TclGetUInt4AtPtr(pc+1);
TRACE(("%u => ", opnd));
dictPtr = OBJ_AT_DEPTH(opnd);
if (*pc == INST_DICT_EXISTS) {
interp2 = NULL;
}
if (opnd > 1) {
dictPtr = TclTraceDictPath(interp2, dictPtr, opnd-1,
&OBJ_AT_DEPTH(opnd-1), DICT_PATH_READ);
if (dictPtr == NULL) {
if (*pc == INST_DICT_EXISTS) {
found = 0;
goto afterDictExists;
}
TRACE_WITH_OBJ((
"ERROR tracing dictionary path into \"%.30s\": ",
O2S(OBJ_AT_DEPTH(opnd))),
Tcl_GetObjResult(interp));
goto gotError;
}
}
if (Tcl_DictObjGet(interp2, dictPtr, OBJ_AT_TOS,
&objResultPtr) == TCL_OK) {
if (*pc == INST_DICT_EXISTS) {
found = (objResultPtr ? 1 : 0);
dictPtr = TclTraceDictPath(NULL, dictPtr, opnd-1,
&OBJ_AT_DEPTH(opnd-1), DICT_PATH_EXISTS);
if (dictPtr == NULL || dictPtr == DICT_PATH_NON_EXISTENT) {
found = 0;
goto afterDictExists;
}
if (!objResultPtr) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"key \"%s\" not known in dictionary",
TclGetString(OBJ_AT_TOS)));
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT",
TclGetString(OBJ_AT_TOS), NULL);
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd+1, 1);
} else if (*pc != INST_DICT_EXISTS) {
TRACE_APPEND(("ERROR reading leaf dictionary key \"%.30s\": %s",
O2S(dictPtr), O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
if (Tcl_DictObjGet(NULL, dictPtr, OBJ_AT_TOS,
&objResultPtr) == TCL_OK) {
found = (objResultPtr ? 1 : 0);
} else {
found = 0;
}
@@ -6833,6 +6809,68 @@ TEBCresume(
JUMP_PEEPHOLE_V(found, 5, opnd+1);
}
case INST_DICT_GET:
opnd = TclGetUInt4AtPtr(pc+1);
TRACE(("%u => ", opnd));
dictPtr = OBJ_AT_DEPTH(opnd);
if (opnd > 1) {
dictPtr = TclTraceDictPath(interp, dictPtr, opnd-1,
&OBJ_AT_DEPTH(opnd-1), DICT_PATH_READ);
if (dictPtr == NULL) {
TRACE_WITH_OBJ((
"ERROR tracing dictionary path into \"%.30s\": ",
O2S(OBJ_AT_DEPTH(opnd))),
Tcl_GetObjResult(interp));
goto gotError;
}
}
if (Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS,
&objResultPtr) != TCL_OK) {
TRACE_APPEND(("ERROR reading leaf dictionary key \"%.30s\": %s",
O2S(dictPtr), O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
if (!objResultPtr) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"key \"%s\" not known in dictionary",
TclGetString(OBJ_AT_TOS)));
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT",
TclGetString(OBJ_AT_TOS), NULL);
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd+1, 1);
case INST_DICT_GET_DEF:
opnd = TclGetUInt4AtPtr(pc+1);
TRACE(("%u => ", opnd));
dictPtr = OBJ_AT_DEPTH(opnd+1);
if (opnd > 1) {
dictPtr = TclTraceDictPath(interp, dictPtr, opnd-1,
&OBJ_AT_DEPTH(opnd), DICT_PATH_EXISTS);
if (dictPtr == NULL) {
TRACE_WITH_OBJ((
"ERROR tracing dictionary path into \"%.30s\": ",
O2S(OBJ_AT_DEPTH(opnd+1))),
Tcl_GetObjResult(interp));
goto gotError;
} else if (dictPtr == DICT_PATH_NON_EXISTENT) {
goto dictGetDefUseDefault;
}
}
if (Tcl_DictObjGet(interp, dictPtr, OBJ_UNDER_TOS,
&objResultPtr) != TCL_OK) {
TRACE_APPEND(("ERROR reading leaf dictionary key \"%.30s\": %s",
O2S(dictPtr), O2S(Tcl_GetObjResult(interp))));
goto gotError;
} else if (!objResultPtr) {
dictGetDefUseDefault:
objResultPtr = OBJ_AT_TOS;
}
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd+2, 1);
case INST_DICT_SET:
case INST_DICT_UNSET:
@@ -8161,7 +8199,7 @@ ExecuteExtendedBinaryMathOp(
if (opcode == INST_LSHIFT) {
mp_mul_2d(&big1, shift, &bigResult);
} else {
mp_tc_div_2d(&big1, shift, &bigResult);
mp_signed_rsh(&big1, shift, &bigResult);
}
mp_clear(&big1);
BIG_RESULT(&bigResult);
@@ -8178,15 +8216,15 @@ ExecuteExtendedBinaryMathOp(
switch (opcode) {
case INST_BITAND:
mp_tc_and(&big1, &big2, &bigResult);
mp_and(&big1, &big2, &bigResult);
break;
case INST_BITOR:
mp_tc_or(&big1, &big2, &bigResult);
mp_or(&big1, &big2, &bigResult);
break;
case INST_BITXOR:
mp_tc_xor(&big1, &big2, &bigResult);
mp_xor(&big1, &big2, &bigResult);
break;
}
@@ -8348,7 +8386,7 @@ ExecuteExtendedBinaryMathOp(
* Reduce small powers of 2 to shifts.
*/
if ((Tcl_WideUInt)w2 < CHAR_BIT*sizeof(Tcl_WideInt) - 1){
if ((Tcl_WideUInt) w2 < CHAR_BIT * sizeof(Tcl_WideInt) - 1) {
WIDE_RESULT(signum * (((Tcl_WideInt) 1) << (int) w2));
}
goto overflowExpon;
@@ -8917,19 +8955,19 @@ ValidatePcAndStackTop(
{
int stackUpperBound = codePtr->maxStackDepth;
/* Greatest legal value for stackTop. */
unsigned relativePc = (unsigned) (pc - codePtr->codeStart);
unsigned long codeStart = (unsigned long) codePtr->codeStart;
unsigned long codeEnd = (unsigned long)
size_t relativePc = (size_t) (pc - codePtr->codeStart);
size_t codeStart = (size_t) codePtr->codeStart;
size_t codeEnd = (size_t)
(codePtr->codeStart + codePtr->numCodeBytes);
unsigned char opCode = *pc;
if (((unsigned long) pc < codeStart) || ((unsigned long) pc > codeEnd)) {
if (((size_t) pc < codeStart) || ((size_t) pc > codeEnd)) {
fprintf(stderr, "\nBad instruction pc 0x%p in TclNRExecuteByteCode\n",
pc);
Tcl_Panic("TclNRExecuteByteCode execution failure: bad pc");
}
if ((unsigned) opCode > LAST_INST_OPCODE) {
fprintf(stderr, "\nBad opcode %d at pc %u in TclNRExecuteByteCode\n",
fprintf(stderr, "\nBad opcode %d at pc %" TCL_Z_MODIFIER "u in TclNRExecuteByteCode\n",
(unsigned) opCode, relativePc);
Tcl_Panic("TclNRExecuteByteCode execution failure: bad opcode");
}
@@ -8938,7 +8976,7 @@ ValidatePcAndStackTop(
int numChars;
const char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars, NULL, NULL);
fprintf(stderr, "\nBad stack top %d at pc %u in TclNRExecuteByteCode (min 0, max %i)",
fprintf(stderr, "\nBad stack top %d at pc %" TCL_Z_MODIFIER "u in TclNRExecuteByteCode (min 0, max %i)",
stackTop, relativePc, stackUpperBound);
if (cmd != NULL) {
Tcl_Obj *message;
@@ -9480,10 +9518,10 @@ EvalStatsCmd(
double objBytesIfUnshared, strBytesIfUnshared, sharingBytesSaved;
double strBytesSharedMultX, strBytesSharedOnce;
double numInstructions, currentHeaderBytes;
long numCurrentByteCodes, numByteCodeLits;
long refCountSum, literalMgmtBytes, sum;
int numSharedMultX, numSharedOnce;
int decadeHigh, minSizeDecade, maxSizeDecade, length, i;
size_t numCurrentByteCodes, numByteCodeLits;
size_t refCountSum, literalMgmtBytes, sum;
size_t numSharedMultX, numSharedOnce, minSizeDecade, maxSizeDecade, i;
int decadeHigh, length;
char *litTableStats;
LiteralEntry *entryPtr;
Tcl_Obj *objPtr;
@@ -9525,12 +9563,12 @@ EvalStatsCmd(
Tcl_AppendPrintfToObj(objPtr, "\n----------------------------------------------------------------\n");
Tcl_AppendPrintfToObj(objPtr,
"Compilation and execution statistics for interpreter %#lx\n",
(long int)iPtr);
"Compilation and execution statistics for interpreter %#" TCL_Z_MODIFIER "x\n",
(size_t)iPtr);
Tcl_AppendPrintfToObj(objPtr, "\nNumber ByteCodes executed\t%ld\n",
Tcl_AppendPrintfToObj(objPtr, "\nNumber ByteCodes executed\t%" TCL_Z_MODIFIER "u\n",
statsPtr->numExecutions);
Tcl_AppendPrintfToObj(objPtr, "Number ByteCodes compiled\t%ld\n",
Tcl_AppendPrintfToObj(objPtr, "Number ByteCodes compiled\t%" TCL_Z_MODIFIER "u\n",
statsPtr->numCompilations);
Tcl_AppendPrintfToObj(objPtr, " Mean executions/compile\t%.1f\n",
statsPtr->numExecutions / (float)statsPtr->numCompilations);
@@ -9542,7 +9580,7 @@ EvalStatsCmd(
Tcl_AppendPrintfToObj(objPtr, " Mean inst/execution\t\t%.0f\n",
numInstructions / statsPtr->numExecutions);
Tcl_AppendPrintfToObj(objPtr, "\nTotal ByteCodes\t\t\t%ld\n",
Tcl_AppendPrintfToObj(objPtr, "\nTotal ByteCodes\t\t\t%" TCL_Z_MODIFIER "u\n",
statsPtr->numCompilations);
Tcl_AppendPrintfToObj(objPtr, " Source bytes\t\t\t%.6g\n",
statsPtr->totalSrcBytes);
@@ -9552,18 +9590,18 @@ EvalStatsCmd(
statsPtr->totalByteCodeBytes);
Tcl_AppendPrintfToObj(objPtr, " Literal bytes\t\t%.6g\n",
totalLiteralBytes);
Tcl_AppendPrintfToObj(objPtr, " table %lu + bkts %lu + entries %lu + objects %lu + strings %.6g\n",
(unsigned long) sizeof(LiteralTable),
(unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
(unsigned long) (statsPtr->numLiteralsCreated * sizeof(LiteralEntry)),
(unsigned long) (statsPtr->numLiteralsCreated * sizeof(Tcl_Obj)),
Tcl_AppendPrintfToObj(objPtr, " table %" TCL_Z_MODIFIER "u + bkts %" TCL_Z_MODIFIER "u + entries %" TCL_Z_MODIFIER "u + objects %" TCL_Z_MODIFIER "u + strings %.6g\n",
sizeof(LiteralTable),
iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
statsPtr->numLiteralsCreated * sizeof(LiteralEntry),
statsPtr->numLiteralsCreated * sizeof(Tcl_Obj),
statsPtr->totalLitStringBytes);
Tcl_AppendPrintfToObj(objPtr, " Mean code/compile\t\t%.1f\n",
totalCodeBytes / statsPtr->numCompilations);
Tcl_AppendPrintfToObj(objPtr, " Mean code/source\t\t%.1f\n",
totalCodeBytes / statsPtr->totalSrcBytes);
Tcl_AppendPrintfToObj(objPtr, "\nCurrent (active) ByteCodes\t%ld\n",
Tcl_AppendPrintfToObj(objPtr, "\nCurrent (active) ByteCodes\t%" TCL_Z_MODIFIER "u\n",
numCurrentByteCodes);
Tcl_AppendPrintfToObj(objPtr, " Source bytes\t\t\t%.6g\n",
statsPtr->currentSrcBytes);
@@ -9594,17 +9632,17 @@ EvalStatsCmd(
numSharedMultX = 0;
Tcl_AppendPrintfToObj(objPtr, "\nTcl_IsShared object check (all objects):\n");
Tcl_AppendPrintfToObj(objPtr, " Object had refcount <=1 (not shared)\t%ld\n",
Tcl_AppendPrintfToObj(objPtr, " Object had refcount <=1 (not shared)\t%" TCL_Z_MODIFIER "u\n",
tclObjsShared[1]);
for (i = 2; i < TCL_MAX_SHARED_OBJ_STATS; i++) {
Tcl_AppendPrintfToObj(objPtr, " refcount ==%d\t\t%ld\n",
Tcl_AppendPrintfToObj(objPtr, " refcount ==%" TCL_Z_MODIFIER "u\t\t%" TCL_Z_MODIFIER "u\n",
i, tclObjsShared[i]);
numSharedMultX += tclObjsShared[i];
}
Tcl_AppendPrintfToObj(objPtr, " refcount >=%d\t\t%ld\n",
Tcl_AppendPrintfToObj(objPtr, " refcount >=%" TCL_Z_MODIFIER "u\t\t%" TCL_Z_MODIFIER "u\n",
i, tclObjsShared[0]);
numSharedMultX += tclObjsShared[0];
Tcl_AppendPrintfToObj(objPtr, " Total shared objects\t\t\t%d\n",
Tcl_AppendPrintfToObj(objPtr, " Total shared objects\t\t\t%" TCL_Z_MODIFIER "u\n",
numSharedMultX);
/*
@@ -9641,20 +9679,20 @@ EvalStatsCmd(
sharingBytesSaved = (objBytesIfUnshared + strBytesIfUnshared)
- currentLiteralBytes;
Tcl_AppendPrintfToObj(objPtr, "\nTotal objects (all interps)\t%ld\n",
Tcl_AppendPrintfToObj(objPtr, "\nTotal objects (all interps)\t%" TCL_Z_MODIFIER "u\n",
tclObjsAlloced);
Tcl_AppendPrintfToObj(objPtr, "Current objects\t\t\t%ld\n",
Tcl_AppendPrintfToObj(objPtr, "Current objects\t\t\t%" TCL_Z_MODIFIER "u\n",
(tclObjsAlloced - tclObjsFreed));
Tcl_AppendPrintfToObj(objPtr, "Total literal objects\t\t%ld\n",
Tcl_AppendPrintfToObj(objPtr, "Total literal objects\t\t%" TCL_Z_MODIFIER "u\n",
statsPtr->numLiteralsCreated);
Tcl_AppendPrintfToObj(objPtr, "\nCurrent literal objects\t\t%d (%0.1f%% of current objects)\n",
globalTablePtr->numEntries,
Percent(globalTablePtr->numEntries, tclObjsAlloced-tclObjsFreed));
Tcl_AppendPrintfToObj(objPtr, " ByteCode literals\t\t%ld (%0.1f%% of current literals)\n",
Tcl_AppendPrintfToObj(objPtr, " ByteCode literals\t\t%" TCL_Z_MODIFIER "u (%0.1f%% of current literals)\n",
numByteCodeLits,
Percent(numByteCodeLits, globalTablePtr->numEntries));
Tcl_AppendPrintfToObj(objPtr, " Literals reused > 1x\t\t%d\n",
Tcl_AppendPrintfToObj(objPtr, " Literals reused > 1x\t\t%" TCL_Z_MODIFIER "u\n",
numSharedMultX);
Tcl_AppendPrintfToObj(objPtr, " Mean reference count\t\t%.2f\n",
((double) refCountSum) / globalTablePtr->numEntries);
@@ -9679,7 +9717,7 @@ EvalStatsCmd(
Tcl_AppendPrintfToObj(objPtr, " String sharing savings \t%.6g = unshared %.6g - shared %.6g\n",
(strBytesIfUnshared - statsPtr->currentLitStringBytes),
strBytesIfUnshared, statsPtr->currentLitStringBytes);
Tcl_AppendPrintfToObj(objPtr, " Literal mgmt overhead\t\t%ld (%0.1f%% of bytes with sharing)\n",
Tcl_AppendPrintfToObj(objPtr, " Literal mgmt overhead\t\t%" TCL_Z_MODIFIER "u (%0.1f%% of bytes with sharing)\n",
literalMgmtBytes,
Percent(literalMgmtBytes, currentLiteralBytes));
Tcl_AppendPrintfToObj(objPtr, " table %lu + buckets %lu + entries %lu\n",
@@ -9729,7 +9767,8 @@ EvalStatsCmd(
Tcl_AppendPrintfToObj(objPtr, "\nLiteral string sizes:\n");
Tcl_AppendPrintfToObj(objPtr, "\t Up to length\t\tPercentage\n");
maxSizeDecade = 0;
for (i = 31; i >= 0; i--) {
i = 32;
while (i-- > 0) {
if (statsPtr->literalCount[i] > 0) {
maxSizeDecade = i;
break;
@@ -9827,7 +9866,7 @@ EvalStatsCmd(
Tcl_AppendPrintfToObj(objPtr, "\nInstruction counts:\n");
for (i = 0; i <= LAST_INST_OPCODE; i++) {
Tcl_AppendPrintfToObj(objPtr, "%20s %8ld ",
Tcl_AppendPrintfToObj(objPtr, "%20s %8" TCL_Z_MODIFIER "u ",
tclInstructionTable[i].name, statsPtr->instructionCount[i]);
if (statsPtr->instructionCount[i]) {
Tcl_AppendPrintfToObj(objPtr, "%6.1f%%\n",
+146 -1
View File
@@ -1345,7 +1345,7 @@ TclFileReadLinkCmd(
/*
*---------------------------------------------------------------------------
*
* TclFileTemporaryCmd
* TclFileTemporaryCmd --
*
* This function implements the "tempfile" subcommand of the "file"
* command.
@@ -1504,6 +1504,151 @@ TclFileTemporaryCmd(
return TCL_OK;
}
/*
*---------------------------------------------------------------------------
*
* TclFileTempDirCmd --
*
* This function implements the "tempdir" subcommand of the "file"
* command.
*
* Results:
* Returns a standard Tcl result.
*
* Side effects:
* Creates a temporary directory.
*
*---------------------------------------------------------------------------
*/
int
TclFileTempDirCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *dirNameObj; /* Object that will contain the directory
* name. */
Tcl_Obj *baseDirObj = NULL, *nameBaseObj = NULL;
/* Pieces of template. Each piece is NULL if
* it is omitted. The platform temporary file
* engine might ignore some pieces. */
if (objc < 1 || objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?template?");
return TCL_ERROR;
}
if (objc > 1) {
int length;
Tcl_Obj *templateObj = objv[1];
const char *string = TclGetStringFromObj(templateObj, &length);
const int onWindows = (tclPlatform == TCL_PLATFORM_WINDOWS);
/*
* Treat an empty string as if it wasn't there.
*/
if (length == 0) {
goto makeTemporary;
}
/*
* The template only gives a directory if there is a directory
* separator in it, and only gives a base name if there's at least one
* character after the last directory separator.
*/
if (strchr(string, '/') == NULL
&& (!onWindows || strchr(string, '\\') == NULL)) {
/*
* No directory separator, so just assume we have a file name.
* This is a bit wrong on Windows where we could have problems
* with disk name prefixes... but those are much less common in
* naked form so we just pass through and let the OS figure it out
* instead.
*/
nameBaseObj = templateObj;
Tcl_IncrRefCount(nameBaseObj);
} else if (string[length-1] != '/'
&& (!onWindows || string[length-1] != '\\')) {
/*
* If the template has a non-terminal directory separator, split
* into dirname and tail.
*/
baseDirObj = TclPathPart(interp, templateObj, TCL_PATH_DIRNAME);
nameBaseObj = TclPathPart(interp, templateObj, TCL_PATH_TAIL);
} else {
/*
* Otherwise, there must be a terminal directory separator, so
* just the directory is given.
*/
baseDirObj = templateObj;
Tcl_IncrRefCount(baseDirObj);
}
/*
* Only allow creation of temporary directories in the native
* filesystem since they are frequently used for integration with
* external tools or system libraries.
*/
if (baseDirObj != NULL && Tcl_FSGetFileSystemForPath(baseDirObj)
!= &tclNativeFilesystem) {
TclDecrRefCount(baseDirObj);
baseDirObj = NULL;
}
}
/*
* Convert empty parts of the template into unspecified parts.
*/
if (baseDirObj && !TclGetString(baseDirObj)[0]) {
TclDecrRefCount(baseDirObj);
baseDirObj = NULL;
}
if (nameBaseObj && !TclGetString(nameBaseObj)[0]) {
TclDecrRefCount(nameBaseObj);
nameBaseObj = NULL;
}
/*
* Create and open the temporary file.
*/
makeTemporary:
dirNameObj = TclpCreateTemporaryDirectory(baseDirObj, nameBaseObj);
/*
* If we created pieces of template, get rid of them now.
*/
if (baseDirObj) {
TclDecrRefCount(baseDirObj);
}
if (nameBaseObj) {
TclDecrRefCount(nameBaseObj);
}
/*
* Deal with results.
*/
if (dirNameObj == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"can't create temporary directory: %s",
Tcl_PosixError(interp)));
return TCL_ERROR;
}
Tcl_SetObjResult(interp, dirNameObj);
return TCL_OK;
}
/*
* Local Variables:
* mode: c
+4 -1
View File
@@ -311,7 +311,10 @@ CreateHashEntry(
if (hash != PTR2UINT(hPtr->hash)) {
continue;
}
if (((void *) key == hPtr) || compareKeysProc((void *) key, hPtr)) {
/* if keys pointers or values are equal */
if ((key == hPtr->key.oneWordValue)
|| compareKeysProc((void *) key, hPtr)
) {
if (newPtr) {
*newPtr = 0;
}
+35 -5
View File
@@ -3462,6 +3462,11 @@ Tcl_Close(
Tcl_ClearChannelHandlers(chan);
/*
* Cancel any outstanding timer.
*/
Tcl_DeleteTimerHandler(statePtr->timer);
/*
* Invoke the registered close callbacks and delete their records.
*/
@@ -4447,6 +4452,8 @@ Write(
}
}
UpdateInterest(chanPtr);
return total;
}
@@ -8475,9 +8482,9 @@ UpdateInterest(
*
* - Tcl drops READABLE here, because it has data in its own
* buffers waiting to be read by the extension.
* - A READABLE event is syntesized via timer.
* - A READABLE event is synthesized via timer.
* - The OS still reports the EXCEPTION condition on the file.
* - And the extension gets the EXCPTION event first, and handles
* - And the extension gets the EXCEPTION event first, and handles
* this as EOF.
*
* End result ==> Premature end of reading from a file.
@@ -8503,6 +8510,16 @@ UpdateInterest(
}
}
}
if (!statePtr->timer
&& mask & TCL_WRITABLE
&& GotFlag(statePtr, CHANNEL_NONBLOCKING)) {
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
ChannelTimerProc,chanPtr);
}
ChanWatch(chanPtr, mask);
}
@@ -8531,6 +8548,21 @@ ChannelTimerProc(
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
Tcl_Preserve(statePtr);
statePtr->timer = NULL;
if (statePtr->interestMask & TCL_WRITABLE
&& GotFlag(statePtr, CHANNEL_NONBLOCKING)
&& !GotFlag(statePtr, BG_FLUSH_SCHEDULED)
) {
/*
* Restart the timer in case a channel handler reenters the event loop
* before UpdateInterest gets called by Tcl_NotifyChannel.
*/
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
ChannelTimerProc,chanPtr);
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_WRITABLE);
}
if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA)
&& (statePtr->interestMask & TCL_READABLE)
&& (statePtr->inQueueHead != NULL)
@@ -8542,13 +8574,11 @@ ChannelTimerProc(
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
ChannelTimerProc,chanPtr);
Tcl_Preserve(statePtr);
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
Tcl_Release(statePtr);
} else {
statePtr->timer = NULL;
UpdateInterest(chanPtr);
}
Tcl_Release(statePtr);
}
/*
+60 -6
View File
@@ -54,6 +54,8 @@ static int ReflectGetOption(ClientData clientData,
static int ReflectSetOption(ClientData clientData,
Tcl_Interp *interp, const char *optionName,
const char *newValue);
static void TimerRunRead(ClientData clientData);
static void TimerRunWrite(ClientData clientData);
/*
* The C layer channel type/driver definition used by the reflection. This is
@@ -112,6 +114,17 @@ typedef struct {
int dead; /* Boolean signal that some operations
* should no longer be attempted. */
Tcl_TimerToken readTimer; /*
A token for the timer that is scheduled in
order to call Tcl_NotifyChannel when the
channel is readable
*/
Tcl_TimerToken writeTimer; /*
A token for the timer that is scheduled in
order to call Tcl_NotifyChannel when the
channel is writable
*/
/*
* Note regarding the usage of timers.
*
@@ -121,11 +134,9 @@ typedef struct {
*
* See 'rechan', 'memchan', etc.
*
* Here this is _not_ required. Interest in events is posted to the Tcl
* level via 'watch'. And posting of events is possible from the Tcl level
* as well, via 'chan postevent'. This means that the generation of all
* events, fake or not, timer based or not, is completely in the hands of
* the Tcl level. Therefore no timer here.
* A timer is used here as well in order to ensure at least on pass through
* the event loop when a channel becomes ready. See issues 67a5eabbd3d1 and
* ef28eb1f1516.
*/
} ReflectedChannel;
@@ -920,7 +931,18 @@ TclChanPostEventObjCmd(
#if TCL_THREADS
if (rcPtr->owner == rcPtr->thread) {
#endif
Tcl_NotifyChannel(chan, events);
if (events & TCL_READABLE) {
if (rcPtr->readTimer == NULL) {
rcPtr->readTimer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
TimerRunRead, rcPtr);
}
}
if (events & TCL_WRITABLE) {
if (rcPtr->writeTimer == NULL) {
rcPtr->writeTimer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
TimerRunWrite, rcPtr);
}
}
#if TCL_THREADS
} else {
ReflectEvent *ev = ckalloc(sizeof(ReflectEvent));
@@ -968,6 +990,24 @@ TclChanPostEventObjCmd(
#undef EVENT
}
static void
TimerRunRead(
ClientData clientData)
{
ReflectedChannel *rcPtr = clientData;
rcPtr->readTimer = NULL;
Tcl_NotifyChannel(rcPtr->chan, TCL_READABLE);
}
static void
TimerRunWrite(
ClientData clientData)
{
ReflectedChannel *rcPtr = clientData;
rcPtr->writeTimer = NULL;
Tcl_NotifyChannel(rcPtr->chan, TCL_WRITABLE);
}
/*
* Channel error message marshalling utilities.
*/
@@ -1161,6 +1201,12 @@ ReflectClose(
ckfree(tctPtr);
((Channel *)rcPtr->chan)->typePtr = NULL;
}
if (rcPtr->readTimer != NULL) {
Tcl_DeleteTimerHandler(rcPtr->readTimer);
}
if (rcPtr->writeTimer != NULL) {
Tcl_DeleteTimerHandler(rcPtr->writeTimer);
}
Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
return EOK;
}
@@ -1230,6 +1276,12 @@ ReflectClose(
ckfree(tctPtr);
((Channel *)rcPtr->chan)->typePtr = NULL;
}
if (rcPtr->readTimer != NULL) {
Tcl_DeleteTimerHandler(rcPtr->readTimer);
}
if (rcPtr->writeTimer != NULL) {
Tcl_DeleteTimerHandler(rcPtr->writeTimer);
}
Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
return (result == TCL_OK) ? EOK : EINVAL;
}
@@ -2131,6 +2183,8 @@ NewReflectedChannel(
rcPtr->chan = NULL;
rcPtr->interp = interp;
rcPtr->dead = 0;
rcPtr->readTimer = 0;
rcPtr->writeTimer = 0;
#if TCL_THREADS
rcPtr->thread = Tcl_GetCurrentThread();
#endif
+7 -1
View File
@@ -151,7 +151,7 @@ declare 32 {
#declare 33 {
# TclCmdProcType TclGetInterpProc(void)
#}
declare 34 {
declare 34 {deprecated {Use Tcl_GetIntForIndex}} {
int TclGetIntForIndex(Tcl_Interp *interp, Tcl_Obj *objPtr,
int endValue, int *indexPtr)
}
@@ -1028,6 +1028,12 @@ declare 257 {
void TclStaticPackage(Tcl_Interp *interp, const char *pkgName,
Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc)
}
# TIP 431: temporary directory creation function
declare 258 {
Tcl_Obj *TclpCreateTemporaryDirectory(Tcl_Obj *dirObj,
Tcl_Obj *basenameObj)
}
##############################################################################
+66 -40
View File
@@ -569,7 +569,7 @@ typedef struct CommandTrace {
struct CommandTrace *nextPtr;
/* Next in list of traces associated with a
* particular command. */
size_t refCount; /* Used to ensure this structure is not
unsigned int refCount; /* Used to ensure this structure is not
* deleted too early. Keeps track of how many
* pieces of code have a pointer to this
* structure. */
@@ -1519,11 +1519,11 @@ typedef struct LiteralEntry {
* NULL if end of chain. */
Tcl_Obj *objPtr; /* Points to Tcl object that holds the
* literal's bytes and length. */
size_t refCount; /* If in an interpreter's global literal
unsigned int refCount; /* If in an interpreter's global literal
* table, the number of ByteCode structures
* that share the literal object; the literal
* entry can be freed when refCount drops to
* 0. If in a local literal table, (size_t)-1. */
* 0. If in a local literal table, (unsigned)-1. */
Namespace *nsPtr; /* Namespace in which this literal is used. We
* try to avoid sharing literal non-FQ command
* names among different namespaces to reduce
@@ -1537,11 +1537,11 @@ typedef struct LiteralTable {
LiteralEntry *staticBuckets[TCL_SMALL_HASH_TABLE];
/* Bucket array used for small tables to avoid
* mallocs and frees. */
int numBuckets; /* Total number of buckets allocated at
unsigned int numBuckets; /* Total number of buckets allocated at
* **buckets. */
int numEntries; /* Total number of entries present in
unsigned int numEntries; /* Total number of entries present in
* table. */
int rebuildSize; /* Enlarge table when numEntries gets to be
unsigned int rebuildSize; /* Enlarge table when numEntries gets to be
* this large. */
unsigned int mask; /* Mask value used in hashing function. */
} LiteralTable;
@@ -1554,10 +1554,10 @@ typedef struct LiteralTable {
#ifdef TCL_COMPILE_STATS
typedef struct ByteCodeStats {
long numExecutions; /* Number of ByteCodes executed. */
long numCompilations; /* Number of ByteCodes created. */
long numByteCodesFreed; /* Number of ByteCodes destroyed. */
long instructionCount[256]; /* Number of times each instruction was
size_t numExecutions; /* Number of ByteCodes executed. */
size_t numCompilations; /* Number of ByteCodes created. */
size_t numByteCodesFreed; /* Number of ByteCodes destroyed. */
size_t instructionCount[256]; /* Number of times each instruction was
* executed. */
double totalSrcBytes; /* Total source bytes ever compiled. */
@@ -1565,10 +1565,10 @@ typedef struct ByteCodeStats {
double currentSrcBytes; /* Src bytes for all current ByteCodes. */
double currentByteCodeBytes;/* Code bytes in all current ByteCodes. */
long srcCount[32]; /* Source size distribution: # of srcs of
size_t srcCount[32]; /* Source size distribution: # of srcs of
* size [2**(n-1)..2**n), n in [0..32). */
long byteCodeCount[32]; /* ByteCode size distribution. */
long lifetimeCount[32]; /* ByteCode lifetime distribution (ms). */
size_t byteCodeCount[32]; /* ByteCode size distribution. */
size_t lifetimeCount[32]; /* ByteCode lifetime distribution (ms). */
double currentInstBytes; /* Instruction bytes-current ByteCodes. */
double currentLitBytes; /* Current literal bytes. */
@@ -1576,11 +1576,11 @@ typedef struct ByteCodeStats {
double currentAuxBytes; /* Current auxiliary information bytes. */
double currentCmdMapBytes; /* Current src<->code map bytes. */
long numLiteralsCreated; /* Total literal objects ever compiled. */
size_t numLiteralsCreated; /* Total literal objects ever compiled. */
double totalLitStringBytes; /* Total string bytes in all literals. */
double currentLitStringBytes;
/* String bytes in current literals. */
long literalCount[32]; /* Distribution of literal string sizes. */
size_t literalCount[32]; /* Distribution of literal string sizes. */
} ByteCodeStats;
#endif /* TCL_COMPILE_STATS */
@@ -2477,7 +2477,7 @@ typedef struct List {
/*
* Macros providing a faster path to booleans and integers:
* Tcl_GetBooleanFromObj, Tcl_GetLongFromObj, Tcl_GetIntFromObj
* and TclGetIntForIndex.
* and Tcl_GetIntForIndex.
*
* WARNING: these macros eval their args more than once.
*/
@@ -2513,8 +2513,8 @@ typedef struct List {
(((objPtr)->typePtr == &tclIntType \
&& (objPtr)->internalRep.wideValue <= (Tcl_WideInt)(INT_MAX)) \
? ((*(idxPtr) = ((objPtr)->internalRep.wideValue >= 0) \
? (int)(objPtr)->internalRep.wideValue : -1), TCL_OK) \
: TclGetIntForIndex((interp), (objPtr), (endValue), (idxPtr)))
? (int)(objPtr)->internalRep.wideValue : TCL_INDEX_NONE), TCL_OK) \
: Tcl_GetIntForIndex((interp), (objPtr), (endValue), (idxPtr)))
/*
* Macro used to save a function call for common uses of
@@ -2776,10 +2776,10 @@ MODULE_SCOPE const Tcl_HashKeyType tclObjHashKeyType;
MODULE_SCOPE Tcl_Obj * tclFreeObjList;
#ifdef TCL_COMPILE_STATS
MODULE_SCOPE long tclObjsAlloced;
MODULE_SCOPE long tclObjsFreed;
MODULE_SCOPE size_t tclObjsAlloced;
MODULE_SCOPE size_t tclObjsFreed;
#define TCL_MAX_SHARED_OBJ_STATS 5
MODULE_SCOPE long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS];
MODULE_SCOPE size_t tclObjsShared[TCL_MAX_SHARED_OBJ_STATS];
#endif /* TCL_COMPILE_STATS */
/*
@@ -2967,6 +2967,7 @@ MODULE_SCOPE Tcl_ObjCmdProc TclFileLinkCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclFileMakeDirsCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclFileReadLinkCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclFileRenameCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclFileTempDirCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclFileTemporaryCmd;
MODULE_SCOPE void TclCreateLateExitHandler(Tcl_ExitProc *proc,
ClientData clientData);
@@ -3105,6 +3106,7 @@ MODULE_SCOPE int TclMergeReturnOptions(Tcl_Interp *interp, int objc,
MODULE_SCOPE Tcl_Obj * TclNoErrorStack(Tcl_Interp *interp, Tcl_Obj *options);
MODULE_SCOPE int TclNokia770Doubles(void);
MODULE_SCOPE void TclNsDecrRefCount(Namespace *nsPtr);
MODULE_SCOPE int TclNamespaceDeleted(Namespace *nsPtr);
MODULE_SCOPE void TclObjVarErrMsg(Tcl_Interp *interp, Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr, const char *operation,
const char *reason, int index);
@@ -3471,6 +3473,9 @@ MODULE_SCOPE int Tcl_LpopObjCmd(ClientData clientData,
MODULE_SCOPE int Tcl_LrangeObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE int Tcl_LremoveObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE int Tcl_LrepeatObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
@@ -3645,6 +3650,9 @@ MODULE_SCOPE int TclCompileDictForCmd(Tcl_Interp *interp,
MODULE_SCOPE int TclCompileDictGetCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileDictGetWithDefaultCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileDictIncrCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
@@ -4021,42 +4029,36 @@ MODULE_SCOPE int TclDivOpCmd(ClientData clientData,
MODULE_SCOPE int TclCompileDivOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclLessOpCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE int TclCompileLessOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclLeqOpCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE int TclCompileLeqOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclGreaterOpCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE int TclCompileGreaterOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclGeqOpCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE int TclCompileGeqOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclEqOpCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE int TclCompileEqOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclStreqOpCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE int TclCompileStreqOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStrLtOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStrLeOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStrGtOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStrGeOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileAssembleCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
@@ -4196,7 +4198,6 @@ MODULE_SCOPE int TclIndexDecode(int encoded, int endValue);
/* Constants used in index value encoding routines. */
#define TCL_INDEX_END (-2)
#define TCL_INDEX_NONE (-1) /* Index out of range or END+1 */
#define TCL_INDEX_START (0)
/*
@@ -4515,6 +4516,31 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file,
#define TclHasStringRep(objPtr) ((objPtr)->bytes != NULL)
/*
*----------------------------------------------------------------
* Macro used by the Tcl core to get the bignum out of the bignum
* representation of a Tcl_Obj.
* The ANSI C "prototype" for this macro is:
*
* MODULE_SCOPE void TclUnpackBignum(Tcl_Obj *objPtr, mp_int bignum);
*----------------------------------------------------------------
*/
#define TclUnpackBignum(objPtr, bignum) \
do { \
register Tcl_Obj *bignumObj = (objPtr); \
register int bignumPayload = \
PTR2INT(bignumObj->internalRep.twoPtrValue.ptr2); \
if (bignumPayload == -1) { \
(bignum) = *((mp_int *) bignumObj->internalRep.twoPtrValue.ptr1); \
} else { \
(bignum).dp = bignumObj->internalRep.twoPtrValue.ptr1; \
(bignum).sign = bignumPayload >> 30; \
(bignum).alloc = (bignumPayload >> 15) & 0x7fff; \
(bignum).used = bignumPayload & 0x7fff; \
} \
} while (0)
/*
*----------------------------------------------------------------
* Macros used by the Tcl core to grow Tcl_Token arrays. They use the same
+11 -2
View File
@@ -28,6 +28,7 @@
#endif
#if !defined(TCL_NO_DEPRECATED) && (TCL_MAJOR_VERSION < 9)
# define tclGetIntForIndex tcl_GetIntForIndex
/* Those macro's are especially for Itcl 3.4 compatibility */
# define tclCreateNamespace tcl_CreateNamespace
# define tclDeleteNamespace tcl_DeleteNamespace
@@ -129,7 +130,8 @@ EXTERN int TclGetFrame(Tcl_Interp *interp, const char *str,
CallFrame **framePtrPtr);
/* Slot 33 is reserved */
/* 34 */
EXTERN int TclGetIntForIndex(Tcl_Interp *interp,
TCL_DEPRECATED("Use Tcl_GetIntForIndex")
int TclGetIntForIndex(Tcl_Interp *interp,
Tcl_Obj *objPtr, int endValue, int *indexPtr);
/* Slot 35 is reserved */
/* Slot 36 is reserved */
@@ -653,6 +655,9 @@ EXTERN void TclStaticPackage(Tcl_Interp *interp,
const char *pkgName,
Tcl_PackageInitProc *initProc,
Tcl_PackageInitProc *safeInitProc);
/* 258 */
EXTERN Tcl_Obj * TclpCreateTemporaryDirectory(Tcl_Obj *dirObj,
Tcl_Obj *basenameObj);
typedef struct TclIntStubs {
int magic;
@@ -692,7 +697,7 @@ typedef struct TclIntStubs {
const char * (*tclGetExtension) (const char *name); /* 31 */
int (*tclGetFrame) (Tcl_Interp *interp, const char *str, CallFrame **framePtrPtr); /* 32 */
void (*reserved33)(void);
int (*tclGetIntForIndex) (Tcl_Interp *interp, Tcl_Obj *objPtr, int endValue, int *indexPtr); /* 34 */
TCL_DEPRECATED_API("Use Tcl_GetIntForIndex") int (*tclGetIntForIndex) (Tcl_Interp *interp, Tcl_Obj *objPtr, int endValue, int *indexPtr); /* 34 */
void (*reserved35)(void);
void (*reserved36)(void);
int (*tclGetLoadedPackages) (Tcl_Interp *interp, const char *targetName); /* 37 */
@@ -916,6 +921,7 @@ typedef struct TclIntStubs {
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 */
void (*tclStaticPackage) (Tcl_Interp *interp, const char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc); /* 257 */
Tcl_Obj * (*tclpCreateTemporaryDirectory) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj); /* 258 */
} TclIntStubs;
extern const TclIntStubs *tclIntStubsPtr;
@@ -1359,6 +1365,8 @@ extern const TclIntStubs *tclIntStubsPtr;
(tclIntStubsPtr->tclPtrUnsetVar) /* 256 */
#define TclStaticPackage \
(tclIntStubsPtr->tclStaticPackage) /* 257 */
#define TclpCreateTemporaryDirectory \
(tclIntStubsPtr->tclpCreateTemporaryDirectory) /* 258 */
#endif /* defined(USE_TCL_STUBS) */
@@ -1375,6 +1383,7 @@ extern const TclIntStubs *tclIntStubsPtr;
# undef TclBackgroundException
# undef TclSetStartupScript
# undef TclGetStartupScript
# undef TclGetIntForIndex
# undef TclCreateNamespace
# undef TclDeleteNamespace
# undef TclAppendExportList
+1076 -303
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1105,7 +1105,7 @@ Tcl_ListObjReplace(
Tcl_Obj **oldPtrs = elemPtrs;
int newMax;
if (needGrow){
if (needGrow) {
newMax = 2 * numRequired;
} else {
newMax = listRepPtr->maxElemCount;
+28 -22
View File
@@ -104,7 +104,7 @@ TclDeleteLiteralTable(
{
LiteralEntry *entryPtr, *nextPtr;
Tcl_Obj *objPtr;
int i;
size_t i;
/*
* Release remaining literals in the table. Note that releasing a literal
@@ -227,7 +227,9 @@ TclCreateLiteral(
if (flags & LITERAL_ON_HEAP) {
ckfree(bytes);
}
globalPtr->refCount++;
if (globalPtr->refCount != (unsigned) -1) {
globalPtr->refCount++;
}
return objPtr;
}
}
@@ -296,7 +298,8 @@ TclCreateLiteral(
TclVerifyGlobalLiteralTable(iPtr);
{
LiteralEntry *entryPtr;
int found, i;
int found;
size_t i;
found = 0;
for (i=0 ; i<globalTablePtr->numBuckets ; i++) {
@@ -464,7 +467,7 @@ TclRegisterLiteral(
objIndex = AddLocalLiteralEntry(envPtr, objPtr, localHash);
#ifdef TCL_COMPILE_DEBUG
if (globalPtr != NULL && globalPtr->refCount < 1) {
if (globalPtr != NULL && globalPtr->refCount + 1 < 2) {
Tcl_Panic("%s: global literal \"%.*s\" had bad refCount %d",
"TclRegisterLiteral", (length>60? 60 : length), bytes,
globalPtr->refCount);
@@ -625,7 +628,7 @@ TclAddLiteralObj(
lPtr = &envPtr->literalArrayPtr[objIndex];
lPtr->objPtr = objPtr;
Tcl_IncrRefCount(objPtr);
lPtr->refCount = (size_t)-1; /* i.e., unused */
lPtr->refCount = (unsigned) -1; /* i.e., unused */
lPtr->nextPtr = NULL;
if (litPtrPtr) {
@@ -687,7 +690,8 @@ AddLocalLiteralEntry(
TclVerifyLocalLiteralTable(envPtr);
{
char *bytes;
int length, found, i;
int length, found;
size_t i;
found = 0;
for (i=0 ; i<localTablePtr->numBuckets ; i++) {
@@ -741,15 +745,15 @@ ExpandLocalLiteralArray(
*/
LiteralTable *localTablePtr = &envPtr->localLitTable;
int currElems = envPtr->literalArrayNext;
size_t currElems = envPtr->literalArrayNext;
size_t currBytes = (currElems * sizeof(LiteralEntry));
LiteralEntry *currArrayPtr = envPtr->literalArrayPtr;
LiteralEntry *newArrayPtr;
int i;
unsigned int newSize = (currBytes <= UINT_MAX / 2) ? 2*currBytes : UINT_MAX;
size_t i;
size_t newSize = (currBytes <= UINT_MAX / 2) ? 2*currBytes : UINT_MAX;
if (currBytes == newSize) {
Tcl_Panic("max size of Tcl literal array (%d literals) exceeded",
Tcl_Panic("max size of Tcl literal array (%" TCL_Z_MODIFIER "u literals) exceeded",
currElems);
}
@@ -848,7 +852,7 @@ TclReleaseLiteral(
* literal table entry (decrement the ref count of the object).
*/
if (entryPtr->refCount-- <= 1) {
if ((entryPtr->refCount != (unsigned)-1) && (entryPtr->refCount-- <= 1)) {
if (prevPtr == NULL) {
globalTablePtr->buckets[index] = entryPtr->nextPtr;
} else {
@@ -1090,7 +1094,9 @@ TclLiteralStats(
LiteralTable *tablePtr) /* Table for which to produce stats. */
{
#define NUM_COUNTERS 10
int count[NUM_COUNTERS], overflow, i, j;
size_t count[NUM_COUNTERS];
int overflow;
size_t i, j;
double average, tmp;
register LiteralEntry *entryPtr;
char *result, *p;
@@ -1129,7 +1135,7 @@ TclLiteralStats(
tablePtr->numEntries, tablePtr->numBuckets);
p = result + strlen(result);
for (i=0 ; i<NUM_COUNTERS ; i++) {
sprintf(p, "number of buckets with %d entries: %d\n",
sprintf(p, "number of buckets with %" TCL_Z_MODIFIER "u entries: %" TCL_Z_MODIFIER "u\n",
i, count[i]);
p += strlen(p);
}
@@ -1166,17 +1172,17 @@ TclVerifyLocalLiteralTable(
register LiteralTable *localTablePtr = &envPtr->localLitTable;
register LiteralEntry *localPtr;
char *bytes;
register int i;
int length, count;
size_t i, count;
int length;
count = 0;
for (i=0 ; i<localTablePtr->numBuckets ; i++) {
for (localPtr=localTablePtr->buckets[i] ; localPtr!=NULL;
localPtr=localPtr->nextPtr) {
count++;
if (localPtr->refCount != -1) {
if (localPtr->refCount != (unsigned)-1) {
bytes = TclGetStringFromObj(localPtr->objPtr, &length);
Tcl_Panic("%s: local literal \"%.*s\" had bad refCount %d",
Tcl_Panic("%s: local literal \"%.*s\" had bad refCount %u",
"TclVerifyLocalLiteralTable",
(length>60? 60 : length), bytes, localPtr->refCount);
}
@@ -1187,7 +1193,7 @@ TclVerifyLocalLiteralTable(
}
}
if (count != localTablePtr->numEntries) {
Tcl_Panic("%s: local literal table had %d entries, should be %d",
Tcl_Panic("%s: local literal table had %" TCL_Z_MODIFIER "u entries, should be %u",
"TclVerifyLocalLiteralTable", count,
localTablePtr->numEntries);
}
@@ -1217,15 +1223,15 @@ TclVerifyGlobalLiteralTable(
register LiteralTable *globalTablePtr = &iPtr->literalTable;
register LiteralEntry *globalPtr;
char *bytes;
register int i;
int length, count;
size_t i, count;
int length;
count = 0;
for (i=0 ; i<globalTablePtr->numBuckets ; i++) {
for (globalPtr=globalTablePtr->buckets[i] ; globalPtr!=NULL;
globalPtr=globalPtr->nextPtr) {
count++;
if (globalPtr->refCount < 1) {
if (globalPtr->refCount + 1 < 2) {
bytes = TclGetStringFromObj(globalPtr->objPtr, &length);
Tcl_Panic("%s: global literal \"%.*s\" had bad refCount %d",
"TclVerifyGlobalLiteralTable",
@@ -1238,7 +1244,7 @@ TclVerifyGlobalLiteralTable(
}
}
if (count != globalTablePtr->numEntries) {
Tcl_Panic("%s: global literal table had %d entries, should be %d",
Tcl_Panic("%s: global literal table had %" TCL_Z_MODIFIER "u entries, should be %u",
"TclVerifyGlobalLiteralTable", count,
globalTablePtr->numEntries);
}
+7
View File
@@ -1086,6 +1086,13 @@ Tcl_DeleteNamespace(
}
TclNsDecrRefCount(nsPtr);
}
int
TclNamespaceDeleted(
Namespace *nsPtr)
{
return (nsPtr->flags & NS_DYING) ? 1 : 0;
}
/*
*----------------------------------------------------------------------
+46 -43
View File
@@ -346,14 +346,14 @@ InitFoundation(
*/
Tcl_DStringInit(&buffer);
for (i=0 ; defineCmds[i].name ; i++) {
for (i = 0 ; defineCmds[i].name ; i++) {
TclDStringAppendLiteral(&buffer, "::oo::define::");
Tcl_DStringAppend(&buffer, defineCmds[i].name, -1);
Tcl_CreateObjCommand(interp, Tcl_DStringValue(&buffer),
defineCmds[i].objProc, INT2PTR(defineCmds[i].flag), NULL);
Tcl_DStringFree(&buffer);
}
for (i=0 ; objdefCmds[i].name ; i++) {
for (i = 0 ; objdefCmds[i].name ; i++) {
TclDStringAppendLiteral(&buffer, "::oo::objdefine::");
Tcl_DStringAppend(&buffer, objdefCmds[i].name, -1);
Tcl_CreateObjCommand(interp, Tcl_DStringValue(&buffer),
@@ -373,10 +373,10 @@ InitFoundation(
* Basic method declarations for the core classes.
*/
for (i=0 ; objMethods[i].name ; i++) {
for (i = 0 ; objMethods[i].name ; i++) {
TclOONewBasicMethod(interp, fPtr->objectCls, &objMethods[i]);
}
for (i=0 ; clsMethods[i].name ; i++) {
for (i = 0 ; clsMethods[i].name ; i++) {
TclOONewBasicMethod(interp, fPtr->classCls, &clsMethods[i]);
}
@@ -388,7 +388,7 @@ InitFoundation(
TclNewLiteralStringObj(namePtr, "new");
Tcl_NewInstanceMethod(interp, (Tcl_Object) fPtr->classCls->thisPtr,
namePtr /* keeps ref */, 0 /* ==private */, NULL, NULL);
namePtr /* keeps ref */, 0 /* private */, NULL, NULL);
fPtr->classCls->constructorPtr = (Method *) Tcl_NewMethod(interp,
(Tcl_Class) fPtr->classCls, NULL, 0, &classConstructor, NULL);
@@ -667,10 +667,8 @@ AllocObject(
Tcl_ResetResult(interp);
}
configNamespace:
((Namespace *)oPtr->namespacePtr)->refCount++;
((Namespace *) oPtr->namespacePtr)->refCount++;
/*
* Make the namespace know about the helper commands. This grants access
@@ -874,10 +872,14 @@ TclOODeleteDescendants(
if (clsPtr->mixinSubs.num > 0) {
while (clsPtr->mixinSubs.num > 0) {
mixinSubclassPtr = clsPtr->mixinSubs.list[clsPtr->mixinSubs.num-1];
/* This condition also covers the case where mixinSubclassPtr ==
mixinSubclassPtr =
clsPtr->mixinSubs.list[clsPtr->mixinSubs.num - 1];
/*
* This condition also covers the case where mixinSubclassPtr ==
* clsPtr
*/
if (!Deleted(mixinSubclassPtr->thisPtr)
&& !(mixinSubclassPtr->thisPtr->flags & DONT_DELETE)) {
Tcl_DeleteCommandFromToken(interp,
@@ -897,7 +899,7 @@ TclOODeleteDescendants(
if (clsPtr->subclasses.num > 0) {
while (clsPtr->subclasses.num > 0) {
subclassPtr = clsPtr->subclasses.list[clsPtr->subclasses.num-1];
subclassPtr = clsPtr->subclasses.list[clsPtr->subclasses.num - 1];
if (!Deleted(subclassPtr->thisPtr) && !IsRoot(subclassPtr)
&& !(subclassPtr->thisPtr->flags & DONT_DELETE)) {
Tcl_DeleteCommandFromToken(interp,
@@ -918,7 +920,8 @@ TclOODeleteDescendants(
if (clsPtr->instances.num > 0) {
while (clsPtr->instances.num > 0) {
instancePtr = clsPtr->instances.list[clsPtr->instances.num-1];
instancePtr = clsPtr->instances.list[clsPtr->instances.num - 1];
/*
* This condition also covers the case where instancePtr == oPtr
*/
@@ -1119,8 +1122,8 @@ ObjectNamespaceDeleted(
if (Deleted(oPtr)) {
/*
* TODO: Can ObjectNamespaceDeleted ever be called twice? If not, this
* guard could be removed.
* TODO: Can ObjectNamespaceDeleted ever be called twice? If not,
* this guard could be removed.
*/
return;
@@ -1134,7 +1137,10 @@ ObjectNamespaceDeleted(
oPtr->flags |= OBJECT_DELETED;
/* Let the dominoes fall */
/*
* Let the dominoes fall!
*/
if (oPtr->classPtr) {
TclOODeleteDescendants(interp, oPtr);
}
@@ -1150,8 +1156,8 @@ ObjectNamespaceDeleted(
CallContext *contextPtr =
TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL, NULL, NULL);
int result;
Tcl_InterpState state;
oPtr->flags |= DESTRUCTOR_CALLED;
if (contextPtr != NULL) {
@@ -1170,12 +1176,12 @@ ObjectNamespaceDeleted(
/*
* Instruct everyone to no longer use any allocated fields of the object.
* Also delete the command that refers to the object at this point (if
* it still exists) because otherwise its pointer to the object
* points into freed memory.
* Also delete the command that refers to the object at this point (if it
* still exists) because otherwise its pointer to the object points into
* freed memory.
*/
if (((Command *)oPtr->command)->flags && CMD_IS_DELETED) {
if (((Command *) oPtr->command)->flags && CMD_IS_DELETED) {
/*
* Something has already started the command deletion process. We can
* go ahead and clean up the the namespace,
@@ -1201,10 +1207,7 @@ ObjectNamespaceDeleted(
* methods on the object.
*/
/*
* TODO: Should this be protected with a * !IsRoot() condition?
*/
/* TODO: Should this be protected with a !IsRoot() condition? */
TclOORemoveFromInstances(oPtr, oPtr->selfCls);
if (oPtr->mixins.num > 0) {
@@ -1765,7 +1768,6 @@ TclNRNewObjectInstance(
TclPushTailcallPoint(interp);
return TclOOInvokeContext(contextPtr, interp, objc, objv);
}
Object *
TclNewObjectInstanceCommon(
@@ -1780,7 +1782,6 @@ TclNewObjectInstanceCommon(
const char *simpleName = NULL;
Namespace *nsPtr = NULL, *dummy;
Namespace *inNsPtr = (Namespace *) TclGetCurrentNamespace(interp);
int isNew;
if (nameStr) {
TclGetNamespaceForQualName(interp, nameStr, inNsPtr,
@@ -1790,21 +1791,14 @@ TclNewObjectInstanceCommon(
* Disallow creation of an object over an existing command.
*/
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, simpleName, &isNew);
if (!isNew) {
hPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, simpleName);
if (hPtr) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"can't create object \"%s\": command already exists with"
" that name", nameStr));
Tcl_SetErrorCode(interp, "TCL", "OO", "OVERWRITE_OBJECT", NULL);
return NULL;
}
/*
* We could make a hash entry! Don't actually want to do that here so
* nuke it immediately because we'll create it properly soon.
*/
Tcl_DeleteHashEntry(hPtr);
}
/*
@@ -1837,8 +1831,6 @@ TclNewObjectInstanceCommon(
return oPtr;
}
static int
FinalizeAlloc(
ClientData data[],
@@ -1974,7 +1966,11 @@ Tcl_CopyObjectInstance(
if (mixinPtr && mixinPtr != o2Ptr->selfCls) {
TclOOAddToInstances(o2Ptr, mixinPtr);
}
/* For the reference just created in DUPLICATE */
/*
* For the reference just created in DUPLICATE.
*/
AddRef(mixinPtr->thisPtr);
}
@@ -2012,6 +2008,7 @@ Tcl_CopyObjectInstance(
o2Ptr->flags = oPtr->flags & ~(
OBJECT_DELETED | ROOT_OBJECT | ROOT_CLASS | FILTER_HANDLING);
/*
* Copy the object's metadata.
*/
@@ -2075,9 +2072,11 @@ Tcl_CopyObjectInstance(
FOREACH(superPtr, cls2Ptr->superclasses) {
TclOOAddToSubclasses(cls2Ptr, superPtr);
/* For the new item in cls2Ptr->superclasses that memcpy just
* created
/*
* For the new item in cls2Ptr->superclasses that memcpy just
* created.
*/
AddRef(superPtr->thisPtr);
}
@@ -2121,7 +2120,11 @@ Tcl_CopyObjectInstance(
DUPLICATE(cls2Ptr->mixins, clsPtr->mixins, Class *);
FOREACH(mixinPtr, cls2Ptr->mixins) {
TclOOAddToMixinSubs(cls2Ptr, mixinPtr);
/* For the copy just created in DUPLICATE */
/*
* For the copy just created in DUPLICATE.
*/
AddRef(mixinPtr->thisPtr);
}
@@ -2783,7 +2786,7 @@ Tcl_ObjectContextInvokeNext(
int savedSkip = contextPtr->skip;
int result;
if (contextPtr->index+1 >= contextPtr->callPtr->numChain) {
if (contextPtr->index + 1 >= contextPtr->callPtr->numChain) {
/*
* We're at the end of the chain; generate an error message unless the
* interpreter is being torn down, in which case we might be getting
@@ -2852,7 +2855,7 @@ TclNRObjectContextInvokeNext(
{
register CallContext *contextPtr = (CallContext *) context;
if (contextPtr->index+1 >= contextPtr->callPtr->numChain) {
if (contextPtr->index + 1 >= contextPtr->callPtr->numChain) {
/*
* We're at the end of the chain; generate an error message unless the
* interpreter is being torn down, in which case we might be getting
+10 -7
View File
@@ -328,7 +328,7 @@ TclOOInvokeContext(
if (contextPtr->index == 0) {
int i;
for (i=0 ; i<contextPtr->callPtr->numChain ; i++) {
for (i = 0 ; i < contextPtr->callPtr->numChain ; i++) {
AddRef(contextPtr->callPtr->chain[i].mPtr);
}
@@ -406,7 +406,7 @@ FinalizeMethodRefs(
CallContext *contextPtr = data[0];
int i;
for (i=0 ; i<contextPtr->callPtr->numChain ; i++) {
for (i = 0 ; i < contextPtr->callPtr->numChain ; i++) {
TclOODelMethodRef(contextPtr->callPtr->chain[i].mPtr);
}
return result;
@@ -641,7 +641,10 @@ SortMethodNames(
return i;
}
/* Comparator for SortMethodNames */
/*
* Comparator for SortMethodNames
*/
static int
CmpStr(
const void *ptr1,
@@ -1004,7 +1007,7 @@ AddMethodToCallChain(
* any leading filters.
*/
for (i=cbPtr->filterLength ; i<callPtr->numChain ; i++) {
for (i = cbPtr->filterLength ; i < callPtr->numChain ; i++) {
if (callPtr->chain[i].mPtr == mPtr &&
callPtr->chain[i].isFilter == (doneFilters != NULL)) {
/*
@@ -1016,8 +1019,8 @@ AddMethodToCallChain(
Class *declCls = callPtr->chain[i].filterDeclarer;
for (; i+1<callPtr->numChain ; i++) {
callPtr->chain[i] = callPtr->chain[i+1];
for (; i + 1 < callPtr->numChain ; i++) {
callPtr->chain[i] = callPtr->chain[i + 1];
}
callPtr->chain[i].mPtr = mPtr;
callPtr->chain[i].isFilter = (doneFilters != NULL);
@@ -1817,7 +1820,7 @@ TclOORenderCallChain(
*/
objv = TclStackAlloc(interp, callPtr->numChain * sizeof(Tcl_Obj *));
for (i=0 ; i<callPtr->numChain ; i++) {
for (i = 0 ; i < callPtr->numChain ; i++) {
struct MInvoke *miPtr = &callPtr->chain[i];
descObjs[0] =
+47 -29
View File
@@ -49,6 +49,12 @@ struct DeclaredSlot {
{TCL_OO_METHOD_VERSION_CURRENT, "core method: " name " Resolver", \
resolver, NULL, NULL}}
/*
* A [string match] pattern used to determine if a method should be exported.
*/
#define PUBLIC_PATTERN "[a-z]*"
/*
* Forward declarations.
*/
@@ -278,7 +284,7 @@ TclOOObjectSetFilters(
} else {
filtersList = ckrealloc(oPtr->filters.list, size);
}
for (i=0 ; i<numFilters ; i++) {
for (i = 0 ; i < numFilters ; i++) {
filtersList[i] = filters[i];
Tcl_IncrRefCount(filters[i]);
}
@@ -337,7 +343,7 @@ TclOOClassSetFilters(
} else {
filtersList = ckrealloc(classPtr->filters.list, size);
}
for (i=0 ; i<numFilters ; i++) {
for (i = 0 ; i < numFilters ; i++) {
filtersList[i] = filters[i];
Tcl_IncrRefCount(filters[i]);
}
@@ -400,7 +406,11 @@ TclOOObjectSetMixins(
FOREACH(mixinPtr, oPtr->mixins) {
if (mixinPtr != oPtr->selfCls) {
TclOOAddToInstances(oPtr, mixinPtr);
/* For the new copy created by memcpy */
/*
* For the new copy created by memcpy().
*/
AddRef(mixinPtr->thisPtr);
}
}
@@ -452,7 +462,11 @@ TclOOClassSetMixins(
memcpy(classPtr->mixins.list, mixins, sizeof(Class *) * numMixins);
FOREACH(mixinPtr, classPtr->mixins) {
TclOOAddToMixinSubs(classPtr, mixinPtr);
/* For the new copy created by memcpy */
/*
* For the new copy created by memcpy.
*/
AddRef(mixinPtr->thisPtr);
}
}
@@ -724,15 +738,16 @@ TclOOUnknownDefinition(
* Got one match, and only one match!
*/
Tcl_Obj **newObjv = TclStackAlloc(interp, sizeof(Tcl_Obj*)*(objc-1));
Tcl_Obj **newObjv =
TclStackAlloc(interp, sizeof(Tcl_Obj*) * (objc - 1));
int result;
newObjv[0] = Tcl_NewStringObj(matchedStr, -1);
Tcl_IncrRefCount(newObjv[0]);
if (objc > 2) {
memcpy(newObjv+1, objv+2, sizeof(Tcl_Obj *) * (objc-2));
memcpy(newObjv + 1, objv + 2, sizeof(Tcl_Obj *) * (objc - 2));
}
result = Tcl_EvalObjv(interp, objc-1, newObjv, 0);
result = Tcl_EvalObjv(interp, objc - 1, newObjv, 0);
Tcl_DecrRefCount(newObjv[0]);
TclStackFree(interp, newObjv);
return result;
@@ -1039,17 +1054,20 @@ MagicDefinitionInvoke(
obj2Ptr = Tcl_NewObj();
cmd = FindCommand(interp, objv[cmdIndex], nsPtr);
if (cmd == NULL) {
/* punt this case! */
/*
* 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_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);
result = Tcl_EvalObjv(interp, objc - cmdIndex, objs, TCL_EVAL_INVOKE);
if (isRoot) {
TclResetRewriteEnsemble(interp, 1);
}
@@ -1685,7 +1703,7 @@ TclOODefineDeleteMethodObjCmd(
return TCL_ERROR;
}
for (i=1 ; i<objc ; i++) {
for (i = 1; i < objc; i++) {
/*
* Delete the method structure from the appropriate hash table.
*/
@@ -1811,7 +1829,7 @@ TclOODefineExportObjCmd(
return TCL_ERROR;
}
for (i=1 ; i<objc ; i++) {
for (i = 1; i < objc; i++) {
/*
* Exporting is done by adding the PUBLIC_METHOD flag to the method
* record. If there is no such method in this object or class (i.e.
@@ -1904,7 +1922,7 @@ TclOODefineForwardObjCmd(
Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
return TCL_ERROR;
}
isPublic = Tcl_StringMatch(TclGetString(objv[1]), "[a-z]*")
isPublic = Tcl_StringMatch(TclGetString(objv[1]), PUBLIC_PATTERN)
? PUBLIC_METHOD : 0;
if (IsPrivateDefine(interp)) {
isPublic = TRUE_PRIVATE_METHOD;
@@ -1914,7 +1932,7 @@ TclOODefineForwardObjCmd(
* Create the method structure.
*/
prefixObj = Tcl_NewListObj(objc-2, objv+2);
prefixObj = Tcl_NewListObj(objc - 2, objv + 2);
if (isInstanceForward) {
mPtr = TclOONewForwardInstanceMethod(interp, oPtr, isPublic, objv[1],
prefixObj);
@@ -2002,7 +2020,7 @@ TclOODefineMethodObjCmd(
if (IsPrivateDefine(interp)) {
isPublic = TRUE_PRIVATE_METHOD;
} else {
isPublic = Tcl_StringMatch(TclGetString(objv[1]), "[a-z]*")
isPublic = Tcl_StringMatch(TclGetString(objv[1]), PUBLIC_PATTERN)
? PUBLIC_METHOD : 0;
}
}
@@ -2124,7 +2142,7 @@ TclOODefineUnexportObjCmd(
return TCL_ERROR;
}
for (i=1 ; i<objc ; i++) {
for (i = 1; i < objc; i++) {
/*
* Unexporting is done by removing the PUBLIC_METHOD flag from the
* method record. If there is no such method in this object or class
@@ -2340,7 +2358,7 @@ ClassFilterSet(
int filterc;
Tcl_Obj **filterv;
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
"filterList");
return TCL_ERROR;
@@ -2424,7 +2442,7 @@ ClassMixinSet(
Tcl_Obj **mixinv;
Class **mixins;
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
"mixinList");
return TCL_ERROR;
@@ -2445,7 +2463,7 @@ ClassMixinSet(
mixins = TclStackAlloc(interp, sizeof(Class *) * mixinc);
for (i=0 ; i<mixinc ; i++) {
for (i = 0; i < mixinc; i++) {
mixins[i] = GetClassInOuterContext(interp, mixinv[i],
"may only mix in classes");
if (mixins[i] == NULL) {
@@ -2529,7 +2547,7 @@ ClassSuperSet(
Tcl_Obj **superv;
Class **superclasses, *superPtr;
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
"superclassList");
return TCL_ERROR;
@@ -2576,14 +2594,14 @@ ClassSuperSet(
superc = 1;
AddRef(superclasses[0]->thisPtr);
} else {
for (i=0 ; i<superc ; i++) {
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++) {
for (j = 0; j < i; j++) {
if (superclasses[j] == superclasses[i]) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"class should only be a direct superclass once",
@@ -2705,7 +2723,7 @@ ClassVarsSet(
Tcl_Obj **varv;
int i;
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
"filterList");
return TCL_ERROR;
@@ -2724,7 +2742,7 @@ ClassVarsSet(
return TCL_ERROR;
}
for (i=0 ; i<varc ; i++) {
for (i = 0; i < varc; i++) {
const char *varName = TclGetString(varv[i]);
if (strstr(varName, "::") != NULL) {
@@ -2803,7 +2821,7 @@ ObjFilterSet(
int filterc;
Tcl_Obj **filterv;
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
"filterList");
return TCL_ERROR;
@@ -2877,7 +2895,7 @@ ObjMixinSet(
Class **mixins;
int i;
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
"mixinList");
return TCL_ERROR;
@@ -2892,7 +2910,7 @@ ObjMixinSet(
mixins = TclStackAlloc(interp, sizeof(Class *) * mixinc);
for (i=0 ; i<mixinc ; i++) {
for (i = 0; i < mixinc; i++) {
mixins[i] = GetClassInOuterContext(interp, mixinv[i],
"may only mix in classes");
if (mixins[i] == NULL) {
@@ -2967,7 +2985,7 @@ ObjVarsSet(
int varc, i;
Tcl_Obj **varv;
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
"variableList");
return TCL_ERROR;
@@ -2980,7 +2998,7 @@ ObjVarsSet(
return TCL_ERROR;
}
for (i=0 ; i<varc ; i++) {
for (i = 0; i < varc; i++) {
const char *varName = TclGetString(varv[i]);
if (strstr(varName, "::") != NULL) {
+9 -20
View File
@@ -191,17 +191,6 @@ static Tcl_ThreadDataKey pendingObjDataKey;
| ((bignum).alloc << 15) | ((bignum).used)); \
}
#define UNPACK_BIGNUM(objPtr, bignum) \
if ((objPtr)->internalRep.twoPtrValue.ptr2 == INT2PTR(-1)) { \
(bignum) = *((mp_int *) ((objPtr)->internalRep.twoPtrValue.ptr1)); \
} else { \
(bignum).dp = (objPtr)->internalRep.twoPtrValue.ptr1; \
(bignum).sign = PTR2INT((objPtr)->internalRep.twoPtrValue.ptr2) >> 30; \
(bignum).alloc = \
(PTR2INT((objPtr)->internalRep.twoPtrValue.ptr2) >> 15) & 0x7fff; \
(bignum).used = PTR2INT((objPtr)->internalRep.twoPtrValue.ptr2) & 0x7fff; \
}
/*
* Prototypes for functions defined later in this file:
*/
@@ -2517,7 +2506,7 @@ Tcl_GetDoubleFromObj(
if (objPtr->typePtr == &tclBignumType) {
mp_int big;
UNPACK_BIGNUM(objPtr, big);
TclUnpackBignum(objPtr, big);
*dblPtr = TclBignumToDouble(&big);
return TCL_OK;
}
@@ -3033,7 +3022,7 @@ Tcl_GetLongFromObj(
unsigned long scratch, value = 0, numBytes = sizeof(unsigned long);
unsigned char *bytes = (unsigned char *) &scratch;
UNPACK_BIGNUM(objPtr, big);
TclUnpackBignum(objPtr, big);
if (mp_to_unsigned_bin_n(&big, bytes, &numBytes) == MP_OKAY) {
while (numBytes-- > 0) {
value = (value << CHAR_BIT) | *bytes++;
@@ -3273,7 +3262,7 @@ Tcl_GetWideIntFromObj(
Tcl_WideInt scratch;
unsigned char *bytes = (unsigned char *) &scratch;
UNPACK_BIGNUM(objPtr, big);
TclUnpackBignum(objPtr, big);
if (mp_to_unsigned_bin_n(&big, bytes, &numBytes) == MP_OKAY) {
while (numBytes-- > 0) {
value = (value << CHAR_BIT) | *bytes++;
@@ -3387,7 +3376,7 @@ FreeBignum(
{
mp_int toFree; /* Bignum to free */
UNPACK_BIGNUM(objPtr, toFree);
TclUnpackBignum(objPtr, toFree);
mp_clear(&toFree);
if (PTR2INT(objPtr->internalRep.twoPtrValue.ptr2) < 0) {
ckfree(objPtr->internalRep.twoPtrValue.ptr1);
@@ -3420,7 +3409,7 @@ DupBignum(
mp_int bignumCopy;
copyPtr->typePtr = &tclBignumType;
UNPACK_BIGNUM(srcPtr, bignumVal);
TclUnpackBignum(srcPtr, bignumVal);
if (mp_init_copy(&bignumCopy, &bignumVal) != MP_OKAY) {
Tcl_Panic("initialization failure in DupBignum");
}
@@ -3455,7 +3444,7 @@ UpdateStringOfBignum(
int size;
char *stringVal;
UNPACK_BIGNUM(objPtr, bignumVal);
TclUnpackBignum(objPtr, bignumVal);
if (MP_OKAY != mp_radix_size(&bignumVal, 10, &size)) {
Tcl_Panic("radix size failure in UpdateStringOfBignum");
}
@@ -3594,10 +3583,10 @@ GetBignumFromObj(
if (copy || Tcl_IsShared(objPtr)) {
mp_int temp;
UNPACK_BIGNUM(objPtr, temp);
TclUnpackBignum(objPtr, temp);
mp_init_copy(bignumValue, &temp);
} else {
UNPACK_BIGNUM(objPtr, *bignumValue);
TclUnpackBignum(objPtr, *bignumValue);
/* Optimized TclFreeIntRep */
objPtr->internalRep.twoPtrValue.ptr1 = NULL;
objPtr->internalRep.twoPtrValue.ptr2 = NULL;
@@ -3838,7 +3827,7 @@ TclGetNumberFromObj(
mp_int *bigPtr = Tcl_GetThreadData(&bignumKey,
(int) sizeof(mp_int));
UNPACK_BIGNUM(objPtr, *bigPtr);
TclUnpackBignum(objPtr, *bigPtr);
*typePtr = TCL_NUMBER_BIG;
*clientDataPtr = bigPtr;
return TCL_OK;
+216 -100
View File
@@ -38,16 +38,18 @@ typedef struct PkgAvail {
} PkgAvail;
typedef struct PkgName {
struct PkgName *nextPtr; /* Next in list of package names being initialized. */
struct PkgName *nextPtr; /* Next in list of package names being
* initialized. */
char name[1];
} PkgName;
typedef struct PkgFiles {
PkgName *names; /* Package names being initialized. Must be first field*/
Tcl_HashTable table; /* Table which contains files for each package */
PkgName *names; /* Package names being initialized. Must be
* first field. */
Tcl_HashTable table; /* Table which contains files for each
* package. */
} PkgFiles;
/*
* For each package that is known in any way to an interpreter, there is one
* record of the following type. These records are stored in the
@@ -63,7 +65,7 @@ typedef struct Package {
} Package;
typedef struct Require {
void * clientDataPtr;
void *clientDataPtr;
const char *name;
Package *pkgPtr;
char *versionToProvide;
@@ -221,8 +223,10 @@ Tcl_PkgProvideEx(
*----------------------------------------------------------------------
*/
static void PkgFilesCleanupProc(ClientData clientData,
Tcl_Interp *interp)
static void
PkgFilesCleanupProc(
ClientData clientData,
Tcl_Interp *interp)
{
PkgFiles *pkgFiles = (PkgFiles *) clientData;
Tcl_HashSearch search;
@@ -230,12 +234,14 @@ static void PkgFilesCleanupProc(ClientData clientData,
while (pkgFiles->names) {
PkgName *name = pkgFiles->names;
pkgFiles->names = name->nextPtr;
ckfree(name);
}
entry = Tcl_FirstHashEntry(&pkgFiles->table, &search);
while (entry) {
Tcl_Obj *obj = (Tcl_Obj *)Tcl_GetHashValue(entry);
Tcl_DecrRefCount(obj);
entry = Tcl_NextHashEntry(&search);
}
@@ -244,10 +250,16 @@ static void PkgFilesCleanupProc(ClientData clientData,
return;
}
void *TclInitPkgFiles(Tcl_Interp *interp)
void *
TclInitPkgFiles(
Tcl_Interp *interp)
{
/* If assocdata "tclPkgFiles" doesn't exist yet, create it */
/*
* If assocdata "tclPkgFiles" doesn't exist yet, create it.
*/
PkgFiles *pkgFiles = Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
if (!pkgFiles) {
pkgFiles = ckalloc(sizeof(PkgFiles));
pkgFiles->names = NULL;
@@ -257,9 +269,14 @@ void *TclInitPkgFiles(Tcl_Interp *interp)
return pkgFiles;
}
void TclPkgFileSeen(Tcl_Interp *interp, const char *fileName)
void
TclPkgFileSeen(
Tcl_Interp *interp,
const char *fileName)
{
PkgFiles *pkgFiles = (PkgFiles *) Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
PkgFiles *pkgFiles = (PkgFiles *)
Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
if (pkgFiles && pkgFiles->names) {
const char *name = pkgFiles->names->name;
Tcl_HashTable *table = &pkgFiles->table;
@@ -347,12 +364,12 @@ Tcl_PkgRequireEx(
*
* Second, how does this work? If we reach this point, then the global
* variable tclEmptyStringRep has the value NULL. Compare that with
* the definition of tclEmptyStringRep near the top of this file.
* It clearly should not have the value NULL; it
* should point to the char tclEmptyString. If we see it having the
* value NULL, then somehow we are seeing a Tcl library that isn't
* completely initialized, and that's an indicator for the error
* condition described above. (Further explanation is welcome.)
* the definition of tclEmptyStringRep near the top of this file. It
* clearly should not have the value NULL; it should point to the char
* tclEmptyString. If we see it having the value NULL, then somehow we
* are seeing a Tcl library that isn't completely initialized, and
* that's an indicator for the error condition described above.
* (Further explanation is welcome.)
*
* Third, so what do we do about it? This situation indicates the
* package we just loaded wasn't properly compiled to be stub-enabled,
@@ -416,9 +433,11 @@ Tcl_PkgRequireProc(
void *clientDataPtr)
{
RequireProcArgs args;
args.name = name;
args.clientDataPtr = clientDataPtr;
return Tcl_NRCallObjProc(interp, TclNRPkgRequireProc, (void *)&args, reqc, reqv);
return Tcl_NRCallObjProc(interp,
TclNRPkgRequireProc, (void *) &args, reqc, reqv);
}
static int
@@ -426,20 +445,28 @@ TclNRPkgRequireProc(
ClientData clientData,
Tcl_Interp *interp,
int reqc,
Tcl_Obj *const reqv[]) {
Tcl_Obj *const reqv[])
{
RequireProcArgs *args = clientData;
Tcl_NRAddCallback(interp, PkgRequireCore, (void *)args->name, INT2PTR(reqc), (void *)reqv, args->clientDataPtr);
Tcl_NRAddCallback(interp,
PkgRequireCore, (void *) args->name, INT2PTR(reqc), (void *) reqv,
args->clientDataPtr);
return TCL_OK;
}
static int
PkgRequireCore(ClientData data[], Tcl_Interp *interp, int result)
PkgRequireCore(
ClientData data[],
Tcl_Interp *interp,
int result)
{
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;
}
@@ -449,56 +476,86 @@ PkgRequireCore(ClientData data[], Tcl_Interp *interp, int result)
reqPtr->name = name;
reqPtr->pkgPtr = FindPackage(interp, name);
if (reqPtr->pkgPtr->version == NULL) {
Tcl_NRAddCallback(interp, SelectPackage, reqPtr, INT2PTR(reqc), (void *)reqv, PkgRequireCoreStep1);
Tcl_NRAddCallback(interp,
SelectPackage, reqPtr, INT2PTR(reqc), (void *) reqv,
PkgRequireCoreStep1);
} else {
Tcl_NRAddCallback(interp, PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
Tcl_NRAddCallback(interp,
PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *) reqv,NULL);
}
return TCL_OK;
}
static int
PkgRequireCoreStep1(ClientData data[], Tcl_Interp *interp, int result) {
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.
*/
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);
/*
* If we've got the package in the DB already, go on to actually loading
* it.
*/
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);
if (reqPtr->pkgPtr->version != NULL) {
Tcl_NRAddCallback(interp,
PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
return TCL_OK;
}
/*
* The package is not in the database. If there is a "package unknown"
* command, invoke it.
*/
script = ((Interp *) interp)->packageUnknown;
if (script == NULL) {
/*
* No package unknown script. Move on to finalizing.
*/
Tcl_NRAddCallback(interp,
PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
return TCL_OK;
}
/*
* Invoke the "package unknown" script synchronously.
*/
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;
}
static int
PkgRequireCoreStep2(ClientData data[], Tcl_Interp *interp, int result) {
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. */;
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));
@@ -511,20 +568,31 @@ PkgRequireCoreStep2(ClientData data[], Tcl_Interp *interp, int result) {
return result;
}
Tcl_ResetResult(interp);
/* pkgPtr may now be invalid, so refresh it. */
/*
* pkgPtr may now be invalid, so refresh it.
*/
reqPtr->pkgPtr = FindPackage(interp, name);
Tcl_NRAddCallback(interp, SelectPackage, reqPtr, INT2PTR(reqc), (void *)reqv, PkgRequireCoreFinal);
Tcl_NRAddCallback(interp,
SelectPackage, reqPtr, INT2PTR(reqc), (void *) reqv,
PkgRequireCoreFinal);
return TCL_OK;
}
static int
PkgRequireCoreFinal(ClientData data[], Tcl_Interp *interp, int result) {
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. */;
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));
@@ -565,14 +633,21 @@ PkgRequireCoreFinal(ClientData data[], Tcl_Interp *interp, int result) {
}
static int
PkgRequireCoreCleanup(ClientData data[], Tcl_Interp *interp, int result) {
PkgRequireCoreCleanup(
ClientData data[],
Tcl_Interp *interp,
int result)
{
ckfree(data[0]);
return result;
}
static int
SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
SelectPackage(
ClientData data[],
Tcl_Interp *interp,
int result)
{
PkgAvail *availPtr, *bestPtr, *bestStablePtr;
char *availVersion, *bestVersion, *bestStableVersion;
/* Internal rep. of versions */
@@ -600,10 +675,10 @@ SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
}
/*
* 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.
* 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;
@@ -616,15 +691,19 @@ SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
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.
* 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. */
/*
* Check satisfaction of requirements before considering the current
* version further.
*/
if (reqc > 0) {
satisfies = SomeRequirementSatisfied(availVersion, reqc, reqv);
if (!satisfies) {
@@ -646,13 +725,16 @@ SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
* 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. */
/*
* We have found a version which is better than our max.
*/
bestPtr = availPtr;
CheckVersionAndConvert(interp, bestPtr->version, &bestVersion, NULL);
@@ -673,18 +755,24 @@ SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
if (res > 0) {
/*
* This stable version of the package sought is better
* than the currently selected stable version.
* 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. */
/*
* We have found a stable version which is better than our max
* stable.
*/
bestStablePtr = availPtr;
CheckVersionAndConvert(interp, bestStablePtr->version, &bestStableVersion, NULL);
CheckVersionAndConvert(interp, bestStablePtr->version,
&bestStableVersion, NULL);
}
ckfree(availVersion);
@@ -706,9 +794,9 @@ SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
}
/*
* 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.
* 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)
@@ -717,13 +805,14 @@ SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
}
if (bestPtr == NULL) {
Tcl_NRAddCallback(interp, data[3], reqPtr, INT2PTR(reqc), (void *)reqv, 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.
* script itself from deletion and (b) don't assume that bestPtr will
* still exist when the script completes.
*/
char *versionToProvide = bestPtr->version;
@@ -734,7 +823,11 @@ SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
pkgPtr->clientData = versionToProvide;
pkgFiles = TclInitPkgFiles(interp);
/* Push "ifneeded" package name in "tclPkgFiles" assocdata. */
/*
* Push "ifneeded" package name in "tclPkgFiles" assocdata.
*/
pkgName = ckalloc(sizeof(PkgName) + strlen(name));
pkgName->nextPtr = pkgFiles->names;
strcpy(pkgName->name, name);
@@ -743,21 +836,31 @@ SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
TclPkgFileSeen(interp, bestPtr->pkgIndex);
}
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);
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) {
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;
/* Pop the "ifneeded" package name from "tclPkgFiles" assocdata*/
/*
* Pop the "ifneeded" package name from "tclPkgFiles" assocdata
*/
PkgFiles *pkgFiles = Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
PkgName *pkgName = pkgFiles->names;
pkgFiles->names = pkgName->nextPtr;
@@ -822,14 +925,13 @@ SelectPackageFinal(ClientData data[], Tcl_Interp *interp, int result) {
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.
* 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.
* 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) {
@@ -840,7 +942,8 @@ SelectPackageFinal(ClientData data[], Tcl_Interp *interp, int result) {
return result;
}
Tcl_NRAddCallback(interp, data[3], reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
Tcl_NRAddCallback(interp,
data[3], reqPtr, INT2PTR(reqc), (void *) reqv, NULL);
return TCL_OK;
}
@@ -1006,7 +1109,8 @@ TclNRPackageObjCmd(
}
pkgFiles = (PkgFiles *) Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
if (pkgFiles) {
Tcl_HashEntry *entry = Tcl_FindHashEntry(&pkgFiles->table, Tcl_GetString(objv[2]));
Tcl_HashEntry *entry =
Tcl_FindHashEntry(&pkgFiles->table, Tcl_GetString(objv[2]));
if (entry) {
Tcl_SetObjResult(interp, (Tcl_Obj *)Tcl_GetHashValue(entry));
}
@@ -1015,7 +1119,8 @@ TclNRPackageObjCmd(
}
case PKG_FORGET: {
const char *keyString;
PkgFiles *pkgFiles = (PkgFiles *) Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
PkgFiles *pkgFiles = (PkgFiles *)
Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
for (i = 2; i < objc; i++) {
keyString = TclGetString(objv[i]);
@@ -1088,7 +1193,7 @@ TclNRPackageObjCmd(
res = CompareVersions(avi, argv3i, NULL);
ckfree(avi);
if (res == 0){
if (res == 0) {
if (objc == 4) {
ckfree(argv3i);
Tcl_SetObjResult(interp,
@@ -1256,12 +1361,16 @@ TclNRPackageObjCmd(
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);
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;
}
@@ -1269,17 +1378,20 @@ TclNRPackageObjCmd(
Tcl_IncrRefCount(objvListPtr);
Tcl_IncrRefCount(objv[2]);
for (i = 0; i < newobjc; i++) {
/*
* Tcl_Obj structures may have come from another interpreter,
* so duplicate them.
*/
Tcl_ListObjAppendElement(interp, objvListPtr, Tcl_DuplicateObj(newobjv[i]));
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);
Tcl_NRAddCallback(interp,
TclNRPackageObjCmdCleanup, objv[2], objvListPtr, NULL,NULL);
Tcl_NRAddCallback(interp,
PkgRequireCore, (void *) argv2, INT2PTR(newobjc),
newObjvPtr, NULL);
return TCL_OK;
}
break;
@@ -1422,9 +1534,13 @@ TclNRPackageObjCmd(
}
static int
TclNRPackageObjCmdCleanup(ClientData data[], Tcl_Interp *interp, int result) {
TclDecrRefCount((Tcl_Obj *)data[0]);
TclDecrRefCount((Tcl_Obj *)data[1]);
TclNRPackageObjCmdCleanup(
ClientData data[],
Tcl_Interp *interp,
int result)
{
TclDecrRefCount((Tcl_Obj *) data[0]);
TclDecrRefCount((Tcl_Obj *) data[1]);
return result;
}
+5 -5
View File
@@ -263,7 +263,7 @@ Tcl_RegExpRange(
if ((size_t) index > regexpPtr->re.re_nsub) {
*startPtr = *endPtr = NULL;
} else if (regexpPtr->matches[index].rm_so < 0) {
} else if (regexpPtr->matches[index].rm_so == TCL_INDEX_NONE) {
*startPtr = *endPtr = NULL;
} else {
if (regexpPtr->objPtr) {
@@ -364,7 +364,7 @@ TclRegExpRangeUniChar(
* passed to Tcl_RegExpExec. */
int index, /* 0 means give the range of the entire match,
* > 0 means give the range of a matching
* subrange, -1 means the range of the
* subrange, TCL_INDEX_NONE means the range of the
* rm_extend field. */
int *startPtr, /* Store address of first character in
* (sub-)range here. */
@@ -373,12 +373,12 @@ TclRegExpRangeUniChar(
{
TclRegexp *regexpPtr = (TclRegexp *) re;
if ((regexpPtr->flags&REG_EXPECT) && index == -1) {
if ((regexpPtr->flags&REG_EXPECT) && (index == TCL_INDEX_NONE)) {
*startPtr = regexpPtr->details.rm_extend.rm_so;
*endPtr = regexpPtr->details.rm_extend.rm_eo;
} else if ((size_t) index > regexpPtr->re.re_nsub) {
*startPtr = -1;
*endPtr = -1;
*startPtr = TCL_INDEX_NONE;
*endPtr = TCL_INDEX_NONE;
} else {
*startPtr = regexpPtr->matches[index].rm_so;
*endPtr = regexpPtr->matches[index].rm_eo;
+1 -5
View File
@@ -464,7 +464,6 @@ Tcl_SetResult(
ResetObjResult(iPtr);
}
#endif /* !TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------
@@ -488,9 +487,6 @@ Tcl_GetStringResult(
register Tcl_Interp *interp)/* Interpreter whose result to return. */
{
Interp *iPtr = (Interp *) interp;
#ifdef TCL_NO_DEPRECATED
return Tcl_GetString(iPtr->objResultPtr);
#else
/*
* If the string result is empty, move the object result to the string
* result, then reset the object result.
@@ -501,8 +497,8 @@ Tcl_GetStringResult(
TCL_VOLATILE);
}
return iPtr->result;
#endif
}
#endif /* !TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------
+16 -16
View File
@@ -1849,15 +1849,15 @@ RefineApproximation(
*/
msb = binExponent + M2; /* 1008 */
nDigits = msb / DIGIT_BIT + 1;
nDigits = msb / MP_DIGIT_BIT + 1;
mp_init_size(&twoMv, nDigits);
i = (msb % DIGIT_BIT + 1);
i = (msb % MP_DIGIT_BIT + 1);
twoMv.used = nDigits;
significand *= SafeLdExp(1.0, i);
while (--nDigits >= 0) {
twoMv.dp[nDigits] = (mp_digit) significand;
significand -= (mp_digit) significand;
significand = SafeLdExp(significand, DIGIT_BIT);
significand = SafeLdExp(significand, MP_DIGIT_BIT);
}
for (i = 0; i <= 8; ++i) {
if (M5 & (1 << i)) {
@@ -3145,7 +3145,7 @@ ShouldBankerRoundUpPowD(
int isodd) /* 1 if the digit is odd, 0 if even. */
{
int i;
static const mp_digit topbit = ((mp_digit)1) << (DIGIT_BIT - 1);
static const mp_digit topbit = ((mp_digit)1) << (MP_DIGIT_BIT - 1);
if (b->used < sd || (b->dp[sd-1] & topbit) == 0) {
return 0;
@@ -4214,8 +4214,8 @@ TclDoubleDigits(
* in the denominator' case.
*/
if (s2 % DIGIT_BIT != 0) {
int delta = DIGIT_BIT - (s2 % DIGIT_BIT);
if (s2 % MP_DIGIT_BIT != 0) {
int delta = MP_DIGIT_BIT - (s2 % MP_DIGIT_BIT);
b2 += delta;
m2plus += delta;
@@ -4223,7 +4223,7 @@ TclDoubleDigits(
s2 += delta;
}
return ShorteningBignumConversionPowD(&d, bw, b2, b5,
m2plus, m2minus, m5, s2/DIGIT_BIT, k, len, ilim, ilim1,
m2plus, m2minus, m5, s2/MP_DIGIT_BIT, k, len, ilim, ilim1,
decpt, endPtr);
} else {
/*
@@ -4270,14 +4270,14 @@ TclDoubleDigits(
* in the denominator' case.
*/
if (s2 % DIGIT_BIT != 0) {
int delta = DIGIT_BIT - (s2 % DIGIT_BIT);
if (s2 % MP_DIGIT_BIT != 0) {
int delta = MP_DIGIT_BIT - (s2 % MP_DIGIT_BIT);
b2 += delta;
s2 += delta;
}
return StrictBignumConversionPowD(&d, bw, b2, b5,
s2/DIGIT_BIT, k, len, ilim, ilim1, decpt, endPtr);
s2/MP_DIGIT_BIT, k, len, ilim, ilim1, decpt, endPtr);
} else {
/*
* There are no helpful special cases, but at least we know in
@@ -4402,7 +4402,7 @@ TclInitDoubleConversion(void)
+ 0.5 * log(10.)) / log(10.));
minDigits = (int) floor((DBL_MIN_EXP - DBL_MANT_DIG)
* log((double) FLT_RADIX) / log(10.));
log10_DIGIT_MAX = (int) floor(DIGIT_BIT * log(2.) / log(10.));
log10_DIGIT_MAX = (int) floor(MP_DIGIT_BIT * log(2.) / log(10.));
/*
* Nokia 770's software-emulated floating point is "middle endian": the
@@ -4577,7 +4577,7 @@ TclBignumToDouble(
*/
mp_div_2d(a, -shift, &b, NULL);
if (mp_get_bit(&b, 0)) {
if (mp_isodd(&b)) {
if (b.sign == MP_ZPOS) {
mp_add_d(&b, 1, &b);
} else {
@@ -4606,7 +4606,7 @@ TclBignumToDouble(
r = 0.0;
for (i=b.used-1 ; i>=0 ; --i) {
r = ldexp(r, DIGIT_BIT) + b.dp[i];
r = ldexp(r, MP_DIGIT_BIT) + b.dp[i];
}
mp_clear(&b);
@@ -4675,7 +4675,7 @@ TclCeil(
mp_add_d(&b, 1, &b);
}
for (i=b.used-1 ; i>=0 ; --i) {
r = ldexp(r, DIGIT_BIT) + b.dp[i];
r = ldexp(r, MP_DIGIT_BIT) + b.dp[i];
}
r = ldexp(r, bits - mantBits);
}
@@ -4725,7 +4725,7 @@ TclFloor(
mp_copy(a, &b);
}
for (i=b.used-1 ; i>=0 ; --i) {
r = ldexp(r, DIGIT_BIT) + b.dp[i];
r = ldexp(r, MP_DIGIT_BIT) + b.dp[i];
}
r = ldexp(r, bits - mantBits);
}
@@ -4787,7 +4787,7 @@ BignumToBiasedFrExp(
r = 0.0;
for (i=b.used-1; i>=0; --i) {
r = ldexp(r, DIGIT_BIT) + b.dp[i];
r = ldexp(r, MP_DIGIT_BIT) + b.dp[i];
}
mp_clear(&b);
+5 -5
View File
@@ -2270,11 +2270,11 @@ Tcl_AppendFormatToObj(
}
#endif
} else if (useBig && big.used) {
int leftover = (big.used * DIGIT_BIT) % numBits;
mp_digit mask = (~(mp_digit)0) << (DIGIT_BIT-leftover);
int leftover = (big.used * MP_DIGIT_BIT) % numBits;
mp_digit mask = (~(mp_digit)0) << (MP_DIGIT_BIT-leftover);
numDigits = 1 +
(((Tcl_WideInt) big.used * DIGIT_BIT) / numBits);
(((Tcl_WideInt) big.used * MP_DIGIT_BIT) / numBits);
while ((mask & big.dp[big.used-1]) == 0) {
numDigits--;
mask >>= numBits;
@@ -2310,9 +2310,9 @@ Tcl_AppendFormatToObj(
if (useBig && big.used) {
if (index < big.used && (size_t) shift <
CHAR_BIT*sizeof(Tcl_WideUInt) - DIGIT_BIT) {
CHAR_BIT*sizeof(Tcl_WideUInt) - MP_DIGIT_BIT) {
bits |= ((Tcl_WideUInt) big.dp[index++]) << shift;
shift += DIGIT_BIT;
shift += MP_DIGIT_BIT;
}
shift -= numBits;
}
+15 -1
View File
@@ -61,6 +61,13 @@
#undef Tcl_BackgroundError
#define TclStaticPackage Tcl_StaticPackage
#undef TclBN_mp_tc_and
#undef TclBN_mp_tc_or
#undef TclBN_mp_tc_xor
#define TclBN_mp_tc_and TclBN_mp_and
#define TclBN_mp_tc_or TclBN_mp_or
#define TclBN_mp_tc_xor TclBN_mp_xor
/* See bug 510001: TclSockMinimumBuffers needs plat imp */
#if defined(_WIN64) || defined(TCL_NO_DEPRECATED) || TCL_MAJOR_VERSION > 8
# define TclSockMinimumBuffersOld 0
@@ -368,6 +375,8 @@ static int uniCharNcasecmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsig
# define Tcl_Eval 0
# undef Tcl_GlobalEval
# define Tcl_GlobalEval 0
# undef Tcl_GetStringResult
# define Tcl_GetStringResult 0
# undef Tcl_SaveResult
# define Tcl_SaveResult 0
# undef Tcl_RestoreResult
@@ -385,6 +394,7 @@ static int uniCharNcasecmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsig
# define TclpReaddir 0
# define TclSetStartupScript 0
# define TclGetStartupScript 0
# define TclGetIntForIndex 0
# define TclCreateNamespace 0
# define TclDeleteNamespace 0
# define TclAppendExportList 0
@@ -435,6 +445,7 @@ static int uniCharNcasecmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsig
# define TclBackgroundException Tcl_BackgroundException
# define TclSetStartupScript Tcl_SetStartupScript
# define TclGetStartupScript Tcl_GetStartupScript
# define TclGetIntForIndex Tcl_GetIntForIndex
# define TclCreateNamespace Tcl_CreateNamespace
# define TclDeleteNamespace Tcl_DeleteNamespace
# define TclAppendExportList Tcl_AppendExportList
@@ -749,6 +760,7 @@ static const TclIntStubs tclIntStubs = {
TclPtrObjMakeUpvar, /* 255 */
TclPtrUnsetVar, /* 256 */
TclStaticPackage, /* 257 */
TclpCreateTemporaryDirectory, /* 258 */
};
static const TclIntPlatStubs tclIntPlatStubs = {
@@ -947,7 +959,7 @@ const TclTomMathStubs tclTomMathStubs = {
TclBN_mp_tc_and, /* 73 */
TclBN_mp_tc_or, /* 74 */
TclBN_mp_tc_xor, /* 75 */
TclBN_mp_tc_div_2d, /* 76 */
TclBN_mp_signed_rsh, /* 76 */
TclBN_mp_get_bit, /* 77 */
};
@@ -1628,6 +1640,8 @@ const TclStubs tclStubs = {
Tcl_IncrRefCount, /* 641 */
Tcl_DecrRefCount, /* 642 */
Tcl_IsShared, /* 643 */
Tcl_LinkArray, /* 644 */
Tcl_GetIntForIndex, /* 645 */
};
/* !END!: Do not edit above this line. */
+126 -3
View File
@@ -308,6 +308,8 @@ static int TestinterpdeleteCmd(void *dummy,
Tcl_Interp *interp, int argc, const char **argv);
static int TestlinkCmd(void *dummy,
Tcl_Interp *interp, int argc, const char **argv);
static int TestlinkarrayCmd(void *dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const *objv);
static int TestlocaleCmd(void *dummy,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
@@ -665,6 +667,7 @@ Tcltest_Init(
Tcl_CreateCommand(interp, "testinterpdelete", TestinterpdeleteCmd,
NULL, NULL);
Tcl_CreateCommand(interp, "testlink", TestlinkCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testlinkarray", TestlinkarrayCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testlocale", TestlocaleCmd, NULL,
NULL);
Tcl_CreateCommand(interp, "testpanic", TestpanicCmd, NULL, NULL);
@@ -968,8 +971,10 @@ AsyncHandlerProc(
Tcl_MutexLock(&asyncTestMutex);
for (asyncPtr = firstHandler; asyncPtr != NULL;
asyncPtr = asyncPtr->nextPtr) {
if (asyncPtr->id == id) break;
asyncPtr = asyncPtr->nextPtr) {
if (asyncPtr->id == id) {
break;
}
}
Tcl_MutexUnlock(&asyncTestMutex);
@@ -3280,6 +3285,124 @@ TestlinkCmd(
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TestlinkarrayCmd --
*
* This function is invoked to process the "testlinkarray" Tcl command.
* It is used to test the 'Tcl_LinkArray' function.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Creates, deletes, and invokes variable links.
*
*----------------------------------------------------------------------
*/
static int
TestlinkarrayCmd(
ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *LinkOption[] = {
"update", "remove", "create", NULL
};
enum LinkOption { LINK_UPDATE, LINK_REMOVE, LINK_CREATE };
static const char *LinkType[] = {
"char", "uchar", "short", "ushort", "int", "uint", "long", "ulong",
"wide", "uwide", "float", "double", "string", "char*", "binary", NULL
};
/* all values after TCL_LINK_CHARS_ARRAY are used as arrays (see below) */
static int LinkTypes[] = {
TCL_LINK_CHAR, TCL_LINK_UCHAR,
TCL_LINK_SHORT, TCL_LINK_USHORT, TCL_LINK_INT, TCL_LINK_UINT,
TCL_LINK_LONG, TCL_LINK_ULONG, TCL_LINK_WIDE_INT, TCL_LINK_WIDE_UINT,
TCL_LINK_FLOAT, TCL_LINK_DOUBLE, TCL_LINK_STRING, TCL_LINK_CHARS,
TCL_LINK_BINARY
};
int optionIndex, typeIndex, readonly, i, size, length;
char *name, *arg;
Tcl_WideInt addr;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option args");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[1], LinkOption, "option", 0,
&optionIndex) != TCL_OK) {
return TCL_ERROR;
}
switch ((enum LinkOption) optionIndex) {
case LINK_UPDATE:
for (i=2; i<objc; i++) {
Tcl_UpdateLinkedVar(interp, Tcl_GetString(objv[i]));
}
return TCL_OK;
case LINK_REMOVE:
for (i=2; i<objc; i++) {
Tcl_UnlinkVar(interp, Tcl_GetString(objv[i]));
}
return TCL_OK;
case LINK_CREATE:
if (objc < 4) {
goto wrongArgs;
}
readonly = 0;
i = 2;
/*
* test on switch -r...
*/
arg = Tcl_GetStringFromObj(objv[i], &length);
if (length < 2) {
goto wrongArgs;
}
if (arg[0] == '-') {
if (arg[1] != 'r') {
goto wrongArgs;
}
readonly = TCL_LINK_READ_ONLY;
i++;
}
if (Tcl_GetIndexFromObj(interp, objv[i++], LinkType, "type", 0,
&typeIndex) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[i++], &size) == TCL_ERROR) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong size value", -1));
return TCL_ERROR;
}
name = Tcl_GetString(objv[i++]);
/*
* If no address is given request one in the underlying function
*/
if (i < objc) {
if (Tcl_GetWideIntFromObj(interp, objv[i], &addr) == TCL_ERROR) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"wrong address value", -1));
return TCL_ERROR;
}
} else {
addr = 0;
}
return Tcl_LinkArray(interp, name, INT2PTR(addr),
LinkTypes[typeIndex] | readonly, size);
}
return TCL_OK;
wrongArgs:
Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? type size name ?address?");
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
@@ -4294,7 +4417,7 @@ TesttranslatefilenameCmd(
*
* TestupvarCmd --
*
* This procedure implements the "testupvar2" command. It is used
* This procedure implements the "testupvar" command. It is used
* to test Tcl_UpVar and Tcl_UpVar2.
*
* Results:
+2 -2
View File
@@ -290,9 +290,9 @@ TestbignumobjCmd(
return TCL_ERROR;
}
if (!Tcl_IsShared(varPtr[varIndex])) {
Tcl_SetIntObj(varPtr[varIndex], !mp_get_bit(&bignumValue, 0));
Tcl_SetIntObj(varPtr[varIndex], !mp_isodd(&bignumValue));
} else {
SetVarToObj(varPtr, varIndex, Tcl_NewIntObj(!mp_get_bit(&bignumValue, 0)));
SetVarToObj(varPtr, varIndex, Tcl_NewIntObj(!mp_isodd(&bignumValue)));
}
mp_clear(&bignumValue);
break;
+13 -13
View File
@@ -310,8 +310,8 @@ TclCreateAbsoluteTimerHandler(
timerHandlerPtr->token = (Tcl_TimerToken) INT2PTR(tsdPtr->lastTimerId);
/*
* Add the event to the queue in the correct position
* (ordered by event firing time).
* Add the event to the queue in the correct position (ordered by event
* firing time).
*/
for (tPtr2 = tsdPtr->firstTimerHandlerPtr, prevPtr = NULL; tPtr2 != NULL;
@@ -1013,8 +1013,8 @@ AfterDelay(
Tcl_GetTime(&now);
endTime = now;
endTime.sec += (long)(ms/1000);
endTime.usec += ((int)(ms%1000))*1000;
endTime.sec += (long)(ms / 1000);
endTime.usec += ((int)(ms % 1000)) * 1000;
if (endTime.usec >= 1000000) {
endTime.sec++;
endTime.usec -= 1000000;
@@ -1042,17 +1042,17 @@ AfterDelay(
if (diff > TCL_TIME_MAXIMUM_SLICE) {
diff = TCL_TIME_MAXIMUM_SLICE;
}
if (diff == 0 && TCL_TIME_BEFORE(now, endTime)) {
diff = 1;
}
if (diff == 0 && TCL_TIME_BEFORE(now, endTime)) {
diff = 1;
}
if (diff > 0) {
Tcl_Sleep((int) diff);
if (diff < SLEEP_OFFLOAD_GETTIMEOFDAY) {
break;
}
Tcl_Sleep((long) diff);
if (diff < SLEEP_OFFLOAD_GETTIMEOFDAY) {
break;
}
} else {
break;
}
break;
}
} else {
diff = TCL_TIME_DIFF_MS(iPtr->limit.time, now);
if (diff > TCL_TIME_MAXIMUM_SLICE) {
+1 -1
View File
@@ -265,7 +265,7 @@ declare 75 {
int TclBN_mp_tc_xor(const mp_int *a, const mp_int *b, mp_int *c)
}
declare 76 {
int TclBN_mp_tc_div_2d(const mp_int *a, int b, mp_int *c)
int TclBN_mp_signed_rsh(const mp_int *a, int b, mp_int *c)
}
declare 77 {
int TclBN_mp_get_bit(const mp_int *a, int b)
+65 -48
View File
@@ -1,14 +1,6 @@
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#ifndef BN_H_
#define BN_H_
@@ -115,29 +107,30 @@ typedef unsigned long long mp_word;
#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
#define MP_DIGIT_MAX MP_MASK
/* equalities */
typedef int mp_sign;
#define MP_ZPOS 0 /* positive integer */
#define MP_NEG 1 /* negative */
typedef int mp_ord;
#define MP_LT -1 /* less than */
#define MP_EQ 0 /* equal to */
#define MP_GT 1 /* greater than */
#define MP_ZPOS 0 /* positive integer */
#define MP_NEG 1 /* negative */
typedef int mp_bool;
#define MP_YES 1 /* yes response */
#define MP_NO 0 /* no response */
typedef int mp_err;
#define MP_OKAY 0 /* ok result */
#define MP_ERR -1 /* unknown error */
#define MP_MEM -2 /* out of mem */
#define MP_VAL -3 /* invalid input */
#define MP_RANGE MP_VAL
#define MP_ITER -4 /* Max. iterations reached */
#define MP_YES 1 /* yes response */
#define MP_NO 0 /* no response */
/* Primality generation flags */
#define LTM_PRIME_BBS 0x0001 /* BBS style prime */
#define LTM_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */
#define LTM_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */
typedef int mp_err;
/* tunable cutoffs */
/* define this to use lower memory usage routines (exptmods mostly) */
/* #define MP_LOW_MEM */
@@ -146,6 +139,8 @@ typedef int mp_err;
#ifndef MP_PREC
# ifndef MP_LOW_MEM
# define MP_PREC 32 /* default digits of precision */
# elif defined(MP_8BIT)
# define MP_PREC 16 /* default digits of precision */
# else
# define MP_PREC 8 /* default digits of precision */
# endif
@@ -154,6 +149,45 @@ typedef int mp_err;
/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
#define MP_WARRAY (1u << (((sizeof(mp_word) * CHAR_BIT) - (2 * DIGIT_BIT)) + 1))
/*
* MP_WUR - warn unused result
* ---------------------------
*
* The result of functions annotated with MP_WUR must be
* checked and cannot be ignored.
*
* Most functions in libtommath return an error code.
* This error code must be checked in order to prevent crashes or invalid
* results.
*
* If you still want to avoid the error checks for quick and dirty programs
* without robustness guarantees, you can `#define MP_WUR` before including
* tommath.h, disabling the warnings.
*/
#ifndef MP_WUR
# if defined(__GNUC__) && __GNUC__ >= 4
# define MP_WUR __attribute__((warn_unused_result))
# else
# define MP_WUR
# endif
#endif
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 301)
# define MP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x)))
# define PRIVATE_MP_DEPRECATED_PRAGMA(s) _Pragma(#s)
# define MP_DEPRECATED_PRAGMA(s) PRIVATE_MP_DEPRECATED_PRAGMA(GCC warning s)
#elif defined(_MSC_VER) && _MSC_VER >= 1500
# define MP_DEPRECATED(x) __declspec(deprecated("replaced by " #x))
# define MP_DEPRECATED_PRAGMA(s) __pragma(message(s))
#else
# define MP_DEPRECATED
# define MP_DEPRECATED_PRAGMA(s)
#endif
#define USED(m) ((m)->used)
#define DIGIT(m,k) ((m)->dp[(k)])
#define SIGN(m) ((m)->sign)
/* the infamous mp_int structure */
#ifndef MP_INT_DECLARED
#define MP_INT_DECLARED
@@ -168,17 +202,15 @@ struct mp_int {
typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat);
#define USED(m) ((m)->used)
#define DIGIT(m, k) ((m)->dp[(k)])
#define SIGN(m) ((m)->sign)
/* error code to char* string */
const char *mp_error_to_string(int code);
/*
const char *mp_error_to_string(mp_err code);
*/
/* ---> init and deinit bignum functions <--- */
/* init a bignum */
/*
int mp_init(mp_int *a);
mp_err mp_init(mp_int *a);
*/
/* free a bignum */
@@ -188,7 +220,7 @@ void mp_clear(mp_int *a);
/* init a null terminated series of arguments */
/*
int mp_init_multi(mp_int *mp, ...);
mp_err mp_init_multi(mp_int *mp, ...);
*/
/* clear a null terminated series of arguments */
@@ -203,23 +235,23 @@ void mp_exch(mp_int *a, mp_int *b);
/* shrink ram required for a bignum */
/*
int mp_shrink(mp_int *a);
mp_err mp_shrink(mp_int *a);
*/
/* grow an int to a given size */
/*
int mp_grow(mp_int *a, int size);
mp_err mp_grow(mp_int *a, int size);
*/
/* init to a given number of digits */
/*
int mp_init_size(mp_int *a, int size);
mp_err mp_init_size(mp_int *a, int size);
*/
/* ---> Basic Manipulations <--- */
#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
#define mp_iseven(a) (!mp_get_bit((a),0))
#define mp_isodd(a) mp_get_bit((a),0)
#define mp_iseven(a) (((a)->used == 0 || (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
#define mp_isneg(a) (((a)->sign != MP_ZPOS) ? MP_YES : MP_NO)
/* set to zero */
@@ -380,24 +412,9 @@ int mp_or(const mp_int *a, const mp_int *b, mp_int *c);
int mp_and(const mp_int *a, const mp_int *b, mp_int *c);
*/
/* c = a XOR b (two complement) */
/*
int mp_tc_xor(const mp_int *a, const mp_int *b, mp_int *c);
*/
/* c = a OR b (two complement) */
/*
int mp_tc_or(const mp_int *a, const mp_int *b, mp_int *c);
*/
/* c = a AND b (two complement) */
/*
int mp_tc_and(const mp_int *a, const mp_int *b, mp_int *c);
*/
/* right shift (two complement) */
/*
int mp_tc_div_2d(const mp_int *a, int b, mp_int *c);
int mp_signed_rsh(const mp_int *a, int b, mp_int *c);
*/
/* ---> Basic arithmetic <--- */
+19 -8
View File
@@ -45,8 +45,11 @@
/* Rename the global symbols in libtommath to avoid linkage conflicts */
#define bn_reverse TclBN_reverse
#define s_mp_reverse TclBN_reverse
#define fast_s_mp_mul_digs TclBN_fast_s_mp_mul_digs
#define s_mp_mul_digs_fast TclBN_fast_s_mp_mul_digs
#define fast_s_mp_sqr TclBN_fast_s_mp_sqr
#define s_mp_sqr_fast TclBN_fast_s_mp_sqr
#define mp_add TclBN_mp_add
#define mp_add_d TclBN_mp_add_d
#define mp_and TclBN_mp_and
@@ -72,6 +75,8 @@
#define mp_get_long TclBN_mp_get_long
#define mp_get_long_long TclBN_mp_get_long_long
#define mp_grow TclBN_mp_grow
#define s_mp_get_bit TclBN_mp_get_bit
#define mp_grow TclBN_mp_grow
#define mp_init TclBN_mp_init
#define mp_init_copy TclBN_mp_init_copy
#define mp_init_multi TclBN_mp_init_multi
@@ -79,7 +84,9 @@
#define mp_init_set_int TclBN_mp_init_set_int
#define mp_init_size TclBN_mp_init_size
#define mp_karatsuba_mul TclBN_mp_karatsuba_mul
#define s_mp_karatsuba_mul TclBN_mp_karatsuba_mul
#define mp_karatsuba_sqr TclBN_mp_karatsuba_sqr
#define s_mp_karatsuba_sqr TclBN_mp_karatsuba_sqr
#define mp_lshd TclBN_mp_lshd
#define mp_mod TclBN_mp_mod
#define mp_mod_2d TclBN_mp_mod_2d
@@ -101,14 +108,17 @@
#define mp_sqrt TclBN_mp_sqrt
#define mp_sub TclBN_mp_sub
#define mp_sub_d TclBN_mp_sub_d
#define mp_tc_and TclBN_mp_tc_and
#define mp_tc_div_2d TclBN_mp_tc_div_2d
#define mp_tc_or TclBN_mp_tc_or
#define mp_tc_xor TclBN_mp_tc_xor
#define mp_signed_rsh TclBN_mp_signed_rsh
#define mp_tc_and TclBN_mp_and
#define mp_tc_div_2d TclBN_mp_signed_rsh
#define mp_tc_or TclBN_mp_or
#define mp_tc_xor TclBN_mp_xor
#define mp_to_unsigned_bin TclBN_mp_to_unsigned_bin
#define mp_to_unsigned_bin_n TclBN_mp_to_unsigned_bin_n
#define mp_toom_mul TclBN_mp_toom_mul
#define s_mp_toom_mul TclBN_mp_toom_mul
#define mp_toom_sqr TclBN_mp_toom_sqr
#define s_mp_toom_sqr TclBN_mp_toom_sqr
#define mp_toradix_n TclBN_mp_toradix_n
#define mp_unsigned_bin_size TclBN_mp_unsigned_bin_size
#define mp_xor TclBN_mp_xor
@@ -344,7 +354,8 @@ EXTERN int TclBN_mp_tc_or(const mp_int *a, const mp_int *b,
EXTERN int TclBN_mp_tc_xor(const mp_int *a, const mp_int *b,
mp_int *c);
/* 76 */
EXTERN int TclBN_mp_tc_div_2d(const mp_int *a, int b, mp_int *c);
EXTERN int TclBN_mp_signed_rsh(const mp_int *a, int b,
mp_int *c);
/* 77 */
EXTERN int TclBN_mp_get_bit(const mp_int *a, int b);
@@ -428,7 +439,7 @@ typedef struct TclTomMathStubs {
int (*tclBN_mp_tc_and) (const mp_int *a, const mp_int *b, mp_int *c); /* 73 */
int (*tclBN_mp_tc_or) (const mp_int *a, const mp_int *b, mp_int *c); /* 74 */
int (*tclBN_mp_tc_xor) (const mp_int *a, const mp_int *b, mp_int *c); /* 75 */
int (*tclBN_mp_tc_div_2d) (const mp_int *a, int b, mp_int *c); /* 76 */
int (*tclBN_mp_signed_rsh) (const mp_int *a, int b, mp_int *c); /* 76 */
int (*tclBN_mp_get_bit) (const mp_int *a, int b); /* 77 */
} TclTomMathStubs;
@@ -596,8 +607,8 @@ extern const TclTomMathStubs *tclTomMathStubsPtr;
(tclTomMathStubsPtr->tclBN_mp_tc_or) /* 74 */
#define TclBN_mp_tc_xor \
(tclTomMathStubsPtr->tclBN_mp_tc_xor) /* 75 */
#define TclBN_mp_tc_div_2d \
(tclTomMathStubsPtr->tclBN_mp_tc_div_2d) /* 76 */
#define TclBN_mp_signed_rsh \
(tclTomMathStubsPtr->tclBN_mp_signed_rsh) /* 76 */
#define TclBN_mp_get_bit \
(tclTomMathStubsPtr->tclBN_mp_get_bit) /* 77 */
+2 -2
View File
@@ -55,9 +55,9 @@ TclTomMathInitializeStubs(
}
if (stubsPtr == NULL) {
errMsg = "missing stub table pointer";
} else if(stubsPtr->tclBN_epoch() != epoch) {
} else if (stubsPtr->tclBN_epoch() != epoch) {
errMsg = "epoch number mismatch";
} else if(stubsPtr->tclBN_revision() != revision) {
} else if (stubsPtr->tclBN_revision() != revision) {
errMsg = "requires a later revision";
} else {
tclTomMathStubsPtr = stubsPtr;
+4 -4
View File
@@ -1139,7 +1139,7 @@ Tcl_UtfToUpper(
*/
if ((len < TclUtfCount(upChar)) || ((upChar & 0xF800) == 0xD800)) {
memcpy(dst, src, len);
memmove(dst, src, len);
dst += len;
} else {
dst += Tcl_UniCharToUtf(upChar, dst);
@@ -1201,7 +1201,7 @@ Tcl_UtfToLower(
*/
if ((len < TclUtfCount(lowChar)) || ((lowChar & 0xF800) == 0xD800)) {
memcpy(dst, src, len);
memmove(dst, src, len);
dst += len;
} else {
dst += Tcl_UniCharToUtf(lowChar, dst);
@@ -1260,7 +1260,7 @@ Tcl_UtfToTitle(
titleChar = Tcl_UniCharToTitle(titleChar);
if ((len < TclUtfCount(titleChar)) || ((titleChar & 0xF800) == 0xD800)) {
memcpy(dst, src, len);
memmove(dst, src, len);
dst += len;
} else {
dst += Tcl_UniCharToUtf(titleChar, dst);
@@ -1283,7 +1283,7 @@ Tcl_UtfToTitle(
}
if ((len < TclUtfCount(lowChar)) || ((lowChar & 0xF800) == 0xD800)) {
memcpy(dst, src, len);
memmove(dst, src, len);
dst += len;
} else {
dst += Tcl_UniCharToUtf(lowChar, dst);
+3 -3
View File
@@ -121,7 +121,7 @@ static int FindElement(Tcl_Interp *interp, const char *string,
/*
* The following is the Tcl object type definition for an object that
* represents a list index in the form, "end-offset". It is used as a
* performance optimization in TclGetIntForIndex. The internal rep is
* performance optimization in Tcl_GetIntForIndex. The internal rep is
* stored directly in the wideValue, so no memory management is required
* for it. This is a caching intrep, keeping the result of a parse
* around. This type is only created from a pre-existing string, so an
@@ -3872,7 +3872,7 @@ GetWideForIndex(
/*
*----------------------------------------------------------------------
*
* TclGetIntForIndex --
* Tcl_GetIntForIndex --
*
* 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
@@ -3894,7 +3894,7 @@ GetWideForIndex(
*/
int
TclGetIntForIndex(
Tcl_GetIntForIndex(
Tcl_Interp *interp, /* Interpreter to use for error reporting. If
* NULL, then no error message is left after
* errors. */
+28 -3
View File
@@ -381,6 +381,7 @@ static int ZipFSFileAttrsSetProc(Tcl_Interp *interp, int index,
static int ZipFSLoadFile(Tcl_Interp *interp, Tcl_Obj *path,
Tcl_LoadHandle *loadHandle,
Tcl_FSUnloadFileProc **unloadProcPtr, int flags);
static void ZipfsExitHandler(ClientData clientData);
static void ZipfsSetup(void);
static int ZipChannelClose(void *instanceData,
Tcl_Interp *interp);
@@ -1286,6 +1287,7 @@ ZipFSCatalogFilesystem(
*zf = *zf0;
zf->mountPoint = Tcl_GetHashKey(&ZipFS.zipHash, hPtr);
Tcl_CreateExitHandler(ZipfsExitHandler, (ClientData)zf);
zf->mountPointLen = strlen(zf->mountPoint);
zf->nameLength = strlen(zipname);
zf->name = ckalloc(zf->nameLength + 1);
@@ -1679,9 +1681,16 @@ TclZipfs_Mount(
return TCL_ERROR;
}
if (ZipFSOpenArchive(interp, zipname, 1, zf) != TCL_OK) {
ckfree(zf);
return TCL_ERROR;
}
return ZipFSCatalogFilesystem(interp, zf, mountPoint, passwd, zipname);
if (ZipFSCatalogFilesystem(interp, zf, mountPoint, passwd, zipname)
!= TCL_OK) {
ckfree(zf);
return TCL_ERROR;
}
ckfree(zf);
return TCL_OK;
}
/*
@@ -1711,6 +1720,7 @@ TclZipfs_MountBuffer(
int copy)
{
ZipFile *zf;
int result;
ReadLock();
if (!ZipFS.initialized) {
@@ -1768,11 +1778,14 @@ TclZipfs_MountBuffer(
zf->data = data;
zf->ptrToFree = NULL;
}
zf->passBuf[0] = 0; /* stop valgrind cries */
if (ZipFSFindTOC(interp, 0, zf) != TCL_OK) {
return TCL_ERROR;
}
return ZipFSCatalogFilesystem(interp, zf, mountPoint, NULL,
result = ZipFSCatalogFilesystem(interp, zf, mountPoint, NULL,
"Memory Buffer");
ckfree(zf);
return result;
}
/*
@@ -1840,6 +1853,7 @@ TclZipfs_Unmount(
ckfree(z);
}
ZipFSCloseArchive(interp, zf);
Tcl_DeleteExitHandler(ZipfsExitHandler, (ClientData)zf);
ckfree(zf);
unmounted = 1;
done:
@@ -1911,7 +1925,7 @@ ZipFSMountBufferObjCmd(
unsigned char *data;
int length;
if (objc > 4) {
if (objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "?mountpoint? ?data?");
return TCL_ERROR;
}
@@ -4833,6 +4847,17 @@ ZipfsAppHookFindTclInit(
return TCL_ERROR;
}
static void
ZipfsExitHandler(
ClientData clientData)
{
ZipFile *zf = (ZipFile *)clientData;
if (TCL_OK != TclZipfs_Unmount(NULL, zf->mountPoint)) {
Tcl_Panic("tried to unmount busy filesystem");
}
}
/*
*-------------------------------------------------------------------------
*
+1 -1
View File
@@ -40,5 +40,5 @@ namespace eval ::tcl::clock {
::msgcat::mcset ja LOCALE_DATE_FORMAT "%EY年%m月%d日"
::msgcat::mcset ja LOCALE_TIME_FORMAT "%H時%M分%S秒"
::msgcat::mcset ja LOCALE_DATE_TIME_FORMAT "%EY年%m月%d日 (%a) %H時%M分%S秒 %z"
::msgcat::mcset ja LOCALE_ERAS "{-9223372036854775808 西暦 0} {-3061011600 明治 1867} {-1812186000 大正 1911} {-1357635600 昭和 1925} {600220800 平成 1988}"
::msgcat::mcset ja LOCALE_ERAS "{-9223372036854775808 西暦 0} {-3061011600 明治 1867} {-1812186000 大正 1911} {-1357635600 昭和 1925} {600220800 平成 1988} {1556668800 令和 2018}"
}
+44 -42
View File
@@ -1,54 +1,56 @@
#include "tommath_private.h"
#ifdef BN_MP_AND_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* AND two ints together */
int mp_and(const mp_int *a, const mp_int *b, mp_int *c)
/* two complement and */
mp_err mp_and(const mp_int *a, const mp_int *b, mp_int *c)
{
int res, ix, px;
mp_int t;
const mp_int *x;
int used = MAX(a->used, b->used) + 1, i;
mp_err err;
mp_digit ac = 1, bc = 1, cc = 1;
mp_sign csign = ((a->sign == MP_NEG) && (b->sign == MP_NEG)) ? MP_NEG : MP_ZPOS;
if (a->used > b->used) {
if ((res = mp_init_copy(&t, a)) != MP_OKAY) {
return res;
if (c->alloc < used) {
if ((err = mp_grow(c, used)) != MP_OKAY) {
return err;
}
px = b->used;
x = b;
} else {
if ((res = mp_init_copy(&t, b)) != MP_OKAY) {
return res;
}
for (i = 0; i < used; i++) {
mp_digit x, y;
/* convert to two complement if negative */
if (a->sign == MP_NEG) {
ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
x = ac & MP_MASK;
ac >>= MP_DIGIT_BIT;
} else {
x = (i >= a->used) ? 0uL : a->dp[i];
}
/* convert to two complement if negative */
if (b->sign == MP_NEG) {
bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
y = bc & MP_MASK;
bc >>= MP_DIGIT_BIT;
} else {
y = (i >= b->used) ? 0uL : b->dp[i];
}
c->dp[i] = x & y;
/* convert to to sign-magnitude if negative */
if (csign == MP_NEG) {
cc += ~c->dp[i] & MP_MASK;
c->dp[i] = cc & MP_MASK;
cc >>= MP_DIGIT_BIT;
}
px = a->used;
x = a;
}
for (ix = 0; ix < px; ix++) {
t.dp[ix] &= x->dp[ix];
}
/* zero digits above the last from the smallest mp_int */
for (; ix < t.used; ix++) {
t.dp[ix] = 0;
}
mp_clamp(&t);
mp_exch(c, &t);
mp_clear(&t);
c->used = used;
c->sign = csign;
mp_clamp(c);
return MP_OKAY;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
+3 -16
View File
@@ -1,19 +1,10 @@
#include "tommath_private.h"
#ifdef BN_MP_CMP_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* compare two ints (signed)*/
int mp_cmp(const mp_int *a, const mp_int *b)
mp_ord mp_cmp(const mp_int *a, const mp_int *b)
{
/* compare based on sign */
if (a->sign != b->sign) {
@@ -33,7 +24,3 @@ int mp_cmp(const mp_int *a, const mp_int *b)
}
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
+3 -16
View File
@@ -1,19 +1,10 @@
#include "tommath_private.h"
#ifdef BN_MP_CMP_D_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* compare a digit */
int mp_cmp_d(const mp_int *a, mp_digit b)
mp_ord mp_cmp_d(const mp_int *a, mp_digit b)
{
/* compare based on sign */
if (a->sign == MP_NEG) {
@@ -35,7 +26,3 @@ int mp_cmp_d(const mp_int *a, mp_digit b)
}
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
+4 -17
View File
@@ -1,22 +1,13 @@
#include "tommath_private.h"
#ifdef BN_MP_CMP_MAG_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* compare maginitude of two ints (unsigned) */
int mp_cmp_mag(const mp_int *a, const mp_int *b)
mp_ord mp_cmp_mag(const mp_int *a, const mp_int *b)
{
int n;
mp_digit *tmpa, *tmpb;
const mp_digit *tmpa, *tmpb;
/* compare based on # of non-zero digits */
if (a->used > b->used) {
@@ -46,7 +37,3 @@ int mp_cmp_mag(const mp_int *a, const mp_int *b)
return MP_EQ;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
-44
View File
@@ -1,44 +0,0 @@
#include "tommath_private.h"
#ifdef BN_MP_GET_BIT_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* Checks the bit at position b and returns MP_YES
if the bit is 1, MP_NO if it is 0 and MP_VAL
in case of error */
int mp_get_bit(const mp_int *a, int b)
{
int limb;
mp_digit bit, isset;
if (b < 0) {
return MP_VAL;
}
limb = b / DIGIT_BIT;
if (limb >= a->used) {
return MP_NO;
}
bit = (mp_digit)(1) << (b % DIGIT_BIT);
isset = a->dp[limb] & bit;
return (isset != 0u) ? MP_YES : MP_NO;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
+44 -36
View File
@@ -1,48 +1,56 @@
#include "tommath_private.h"
#ifdef BN_MP_OR_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* OR two ints together */
int mp_or(const mp_int *a, const mp_int *b, mp_int *c)
/* two complement or */
mp_err mp_or(const mp_int *a, const mp_int *b, mp_int *c)
{
int res, ix, px;
mp_int t;
const mp_int *x;
int used = MAX(a->used, b->used) + 1, i;
mp_err err;
mp_digit ac = 1, bc = 1, cc = 1;
mp_sign csign = ((a->sign == MP_NEG) || (b->sign == MP_NEG)) ? MP_NEG : MP_ZPOS;
if (a->used > b->used) {
if ((res = mp_init_copy(&t, a)) != MP_OKAY) {
return res;
if (c->alloc < used) {
if ((err = mp_grow(c, used)) != MP_OKAY) {
return err;
}
px = b->used;
x = b;
} else {
if ((res = mp_init_copy(&t, b)) != MP_OKAY) {
return res;
}
px = a->used;
x = a;
}
for (ix = 0; ix < px; ix++) {
t.dp[ix] |= x->dp[ix];
for (i = 0; i < used; i++) {
mp_digit x, y;
/* convert to two complement if negative */
if (a->sign == MP_NEG) {
ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
x = ac & MP_MASK;
ac >>= MP_DIGIT_BIT;
} else {
x = (i >= a->used) ? 0uL : a->dp[i];
}
/* convert to two complement if negative */
if (b->sign == MP_NEG) {
bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
y = bc & MP_MASK;
bc >>= MP_DIGIT_BIT;
} else {
y = (i >= b->used) ? 0uL : b->dp[i];
}
c->dp[i] = x | y;
/* convert to to sign-magnitude if negative */
if (csign == MP_NEG) {
cc += ~c->dp[i] & MP_MASK;
c->dp[i] = cc & MP_MASK;
cc >>= MP_DIGIT_BIT;
}
}
mp_clamp(&t);
mp_exch(c, &t);
mp_clear(&t);
c->used = used;
c->sign = csign;
mp_clamp(c);
return MP_OKAY;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
+22
View File
@@ -0,0 +1,22 @@
#include "tommath_private.h"
#ifdef BN_MP_SIGNED_RSH_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* shift right by a certain bit count with sign extension */
mp_err mp_signed_rsh(const mp_int *a, int b, mp_int *c)
{
mp_err res;
if (a->sign == MP_ZPOS) {
return mp_div_2d(a, b, c, NULL);
}
res = mp_add_d(a, 1uL, c);
if (res != MP_OKAY) {
return res;
}
res = mp_div_2d(c, b, c, NULL);
return (res == MP_OKAY) ? mp_sub_d(c, 1uL, c) : res;
}
#endif
-90
View File
@@ -1,90 +0,0 @@
#include "tommath_private.h"
#ifdef BN_MP_TC_AND_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* two complement and */
int mp_tc_and(const mp_int *a, const mp_int *b, mp_int *c)
{
int res = MP_OKAY, bits, abits, bbits;
int as = mp_isneg(a), bs = mp_isneg(b);
mp_int *mx = NULL, _mx, acpy, bcpy;
if ((as != MP_NO) || (bs != MP_NO)) {
abits = mp_count_bits(a);
bbits = mp_count_bits(b);
bits = MAX(abits, bbits);
res = mp_init_set_int(&_mx, 1uL);
if (res != MP_OKAY) {
goto end;
}
mx = &_mx;
res = mp_mul_2d(mx, bits + 1, mx);
if (res != MP_OKAY) {
goto end;
}
if (as != MP_NO) {
res = mp_init(&acpy);
if (res != MP_OKAY) {
goto end;
}
res = mp_add(mx, a, &acpy);
if (res != MP_OKAY) {
mp_clear(&acpy);
goto end;
}
a = &acpy;
}
if (bs != MP_NO) {
res = mp_init(&bcpy);
if (res != MP_OKAY) {
goto end;
}
res = mp_add(mx, b, &bcpy);
if (res != MP_OKAY) {
mp_clear(&bcpy);
goto end;
}
b = &bcpy;
}
}
res = mp_and(a, b, c);
if ((as != MP_NO) && (bs != MP_NO) && (res == MP_OKAY)) {
res = mp_sub(c, mx, c);
}
end:
if (a == &acpy) {
mp_clear(&acpy);
}
if (b == &bcpy) {
mp_clear(&bcpy);
}
if (mx == &_mx) {
mp_clear(mx);
}
return res;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
-35
View File
@@ -1,35 +0,0 @@
#include "tommath_private.h"
#ifdef BN_MP_TC_DIV_2D_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* two complement right shift */
int mp_tc_div_2d(const mp_int *a, int b, mp_int *c)
{
int res;
if (mp_isneg(a) == MP_NO) {
return mp_div_2d(a, b, c, NULL);
}
res = mp_add_d(a, 1uL, c);
if (res != MP_OKAY) {
return res;
}
res = mp_div_2d(c, b, c, NULL);
return (res == MP_OKAY) ? mp_sub_d(c, 1uL, c) : res;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
-90
View File
@@ -1,90 +0,0 @@
#include "tommath_private.h"
#ifdef BN_MP_TC_OR_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* two complement or */
int mp_tc_or(const mp_int *a, const mp_int *b, mp_int *c)
{
int res = MP_OKAY, bits, abits, bbits;
int as = mp_isneg(a), bs = mp_isneg(b);
mp_int *mx = NULL, _mx, acpy, bcpy;
if ((as != MP_NO) || (bs != MP_NO)) {
abits = mp_count_bits(a);
bbits = mp_count_bits(b);
bits = MAX(abits, bbits);
res = mp_init_set_int(&_mx, 1uL);
if (res != MP_OKAY) {
goto end;
}
mx = &_mx;
res = mp_mul_2d(mx, bits + 1, mx);
if (res != MP_OKAY) {
goto end;
}
if (as != MP_NO) {
res = mp_init(&acpy);
if (res != MP_OKAY) {
goto end;
}
res = mp_add(mx, a, &acpy);
if (res != MP_OKAY) {
mp_clear(&acpy);
goto end;
}
a = &acpy;
}
if (bs != MP_NO) {
res = mp_init(&bcpy);
if (res != MP_OKAY) {
goto end;
}
res = mp_add(mx, b, &bcpy);
if (res != MP_OKAY) {
mp_clear(&bcpy);
goto end;
}
b = &bcpy;
}
}
res = mp_or(a, b, c);
if (((as != MP_NO) || (bs != MP_NO)) && (res == MP_OKAY)) {
res = mp_sub(c, mx, c);
}
end:
if (a == &acpy) {
mp_clear(&acpy);
}
if (b == &bcpy) {
mp_clear(&bcpy);
}
if (mx == &_mx) {
mp_clear(mx);
}
return res;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
-90
View File
@@ -1,90 +0,0 @@
#include "tommath_private.h"
#ifdef BN_MP_TC_XOR_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* two complement xor */
int mp_tc_xor(const mp_int *a, const mp_int *b, mp_int *c)
{
int res = MP_OKAY, bits, abits, bbits;
int as = mp_isneg(a), bs = mp_isneg(b);
mp_int *mx = NULL, _mx, acpy, bcpy;
if ((as != MP_NO) || (bs != MP_NO)) {
abits = mp_count_bits(a);
bbits = mp_count_bits(b);
bits = MAX(abits, bbits);
res = mp_init_set_int(&_mx, 1uL);
if (res != MP_OKAY) {
goto end;
}
mx = &_mx;
res = mp_mul_2d(mx, bits + 1, mx);
if (res != MP_OKAY) {
goto end;
}
if (as != MP_NO) {
res = mp_init(&acpy);
if (res != MP_OKAY) {
goto end;
}
res = mp_add(mx, a, &acpy);
if (res != MP_OKAY) {
mp_clear(&acpy);
goto end;
}
a = &acpy;
}
if (bs != MP_NO) {
res = mp_init(&bcpy);
if (res != MP_OKAY) {
goto end;
}
res = mp_add(mx, b, &bcpy);
if (res != MP_OKAY) {
mp_clear(&bcpy);
goto end;
}
b = &bcpy;
}
}
res = mp_xor(a, b, c);
if ((as != bs) && (res == MP_OKAY)) {
res = mp_sub(c, mx, c);
}
end:
if (a == &acpy) {
mp_clear(&acpy);
}
if (b == &bcpy) {
mp_clear(&bcpy);
}
if (mx == &_mx) {
mp_clear(mx);
}
return res;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
+44 -36
View File
@@ -1,48 +1,56 @@
#include "tommath_private.h"
#ifdef BN_MP_XOR_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* XOR two ints together */
int mp_xor(const mp_int *a, const mp_int *b, mp_int *c)
/* two complement xor */
mp_err mp_xor(const mp_int *a, const mp_int *b, mp_int *c)
{
int res, ix, px;
mp_int t;
const mp_int *x;
int used = MAX(a->used, b->used) + 1, i;
mp_err err;
mp_digit ac = 1, bc = 1, cc = 1;
mp_sign csign = (a->sign != b->sign) ? MP_NEG : MP_ZPOS;
if (a->used > b->used) {
if ((res = mp_init_copy(&t, a)) != MP_OKAY) {
return res;
if (c->alloc < used) {
if ((err = mp_grow(c, used)) != MP_OKAY) {
return err;
}
px = b->used;
x = b;
} else {
if ((res = mp_init_copy(&t, b)) != MP_OKAY) {
return res;
}
px = a->used;
x = a;
}
for (ix = 0; ix < px; ix++) {
t.dp[ix] ^= x->dp[ix];
for (i = 0; i < used; i++) {
mp_digit x, y;
/* convert to two complement if negative */
if (a->sign == MP_NEG) {
ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
x = ac & MP_MASK;
ac >>= MP_DIGIT_BIT;
} else {
x = (i >= a->used) ? 0uL : a->dp[i];
}
/* convert to two complement if negative */
if (b->sign == MP_NEG) {
bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
y = bc & MP_MASK;
bc >>= MP_DIGIT_BIT;
} else {
y = (i >= b->used) ? 0uL : b->dp[i];
}
c->dp[i] = x ^ y;
/* convert to to sign-magnitude if negative */
if (csign == MP_NEG) {
cc += ~c->dp[i] & MP_MASK;
c->dp[i] = cc & MP_MASK;
cc >>= MP_DIGIT_BIT;
}
}
mp_clamp(&t);
mp_exch(c, &t);
mp_clear(&t);
c->used = used;
c->sign = csign;
mp_clamp(c);
return MP_OKAY;
}
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */
+21
View File
@@ -0,0 +1,21 @@
#include "tommath_private.h"
#ifdef BN_S_MP_GET_BIT_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* Get bit at position b and return MP_YES if the bit is 1, MP_NO if it is 0 */
mp_bool s_mp_get_bit(const mp_int *a, int b)
{
mp_digit bit;
int limb = (int)((unsigned)b / MP_DIGIT_BIT);
if (limb >= a->used) {
return MP_NO;
}
bit = (mp_digit)1 << ((unsigned)b % MP_DIGIT_BIT);
return ((a->dp[limb] & bit) != 0u) ? MP_YES : MP_NO;
}
#endif
File diff suppressed because it is too large Load Diff
+9 -17
View File
@@ -1,14 +1,6 @@
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* SPDX-License-Identifier: Unlicense
*/
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#ifndef BN_H_
#define BN_H_
@@ -159,18 +151,18 @@ void mp_clear_multi(mp_int *mp, ...);
void mp_exch(mp_int *a, mp_int *b);
/* shrink ram required for a bignum */
int mp_shrink(mp_int *a);
mp_err mp_shrink(mp_int *a);
/* grow an int to a given size */
int mp_grow(mp_int *a, int size);
mp_err mp_grow(mp_int *a, int size);
/* init to a given number of digits */
int mp_init_size(mp_int *a, int size);
mp_err mp_init_size(mp_int *a, int size);
/* ---> Basic Manipulations <--- */
#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
#define mp_iseven(a) (!mp_get_bit((a),0))
#define mp_isodd(a) mp_get_bit((a),0)
#define mp_iseven(a) (((a)->used == 0 || (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
#define mp_isneg(a) (((a)->sign != MP_ZPOS) ? MP_YES : MP_NO)
/* set to zero */
@@ -294,7 +286,7 @@ int mp_tc_or(const mp_int *a, const mp_int *b, mp_int *c);
int mp_tc_and(const mp_int *a, const mp_int *b, mp_int *c);
/* right shift (two complement) */
int mp_tc_div_2d(const mp_int *a, int b, mp_int *c);
int mp_signed_rsh(const mp_int *a, int b, mp_int *c);
/* ---> Basic arithmetic <--- */
+6 -6
View File
@@ -59,7 +59,7 @@
# define BN_MP_FREAD_C
# define BN_MP_FWRITE_C
# define BN_MP_GCD_C
# define BN_MP_GET_BIT_C
# define BN_S_MP_GET_BIT_C
# define BN_MP_GET_DOUBLE_C
# define BN_MP_GET_INT_C
# define BN_MP_GET_LONG_C
@@ -135,7 +135,7 @@
# define BN_MP_SUB_D_C
# define BN_MP_SUBMOD_C
# define BN_MP_TC_AND_C
# define BN_MP_TC_DIV_2D_C
# define BN_MP_SIGNED_RSH_C
# define BN_MP_TC_OR_C
# define BN_MP_TC_XOR_C
# define BN_MP_TO_SIGNED_BIN_C
@@ -442,7 +442,7 @@
# define BN_MP_CLEAR_C
#endif
#if defined(BN_MP_GET_BIT_C)
#if defined(BN_S_MP_GET_BIT_C)
# define BN_MP_ISZERO_C
#endif
@@ -715,7 +715,7 @@
# define BN_MP_MUL_C
# define BN_MP_SUB_C
# define BN_MP_MOD_C
# define BN_MP_GET_BIT_C
# define BN_S_MP_GET_BIT_C
# define BN_MP_EXCH_C
# define BN_MP_ISZERO_C
# define BN_MP_CMP_C
@@ -802,7 +802,7 @@
# define BN_MP_MOD_C
# define BN_MP_SQR_C
# define BN_MP_SUB_C
# define BN_MP_GET_BIT_C
# define BN_S_MP_GET_BIT_C
# define BN_MP_ADD_C
# define BN_MP_ISODD_C
# define BN_MP_DIV_2_C
@@ -1034,7 +1034,7 @@
# define BN_MP_SUB_C
#endif
#if defined(BN_MP_TC_DIV_2D_C)
#if defined(BN_MP_SIGNED_RSH_C)
# define BN_MP_ISNEG_C
# define BN_MP_DIV_2D_C
# define BN_MP_ADD_D_C
+68 -22
View File
@@ -51,13 +51,13 @@ proc _test_out_total {} {
set mintm 0x7fffffff
set maxtm 0
set nett 0
set nettm 0
set wtm 0
set wcnt 0
set i 0
foreach tm $_(itm) {
if {[llength $tm] > 6} {
set nett [expr {$nett + [lindex $tm 6]}]
set nettm [expr {$nettm + [lindex $tm 6]}]
}
set wtm [expr {$wtm + [lindex $tm 0]}]
set wcnt [expr {$wcnt + [lindex $tm 2]}]
@@ -69,15 +69,15 @@ proc _test_out_total {} {
puts [string repeat ** 40]
set s [format "%d cases in %.2f sec." $tcnt [expr {([clock milliseconds] - $_(starttime)) / 1000.0}]]
if {$nett > 0} {
append s [format " (%.2f nett-sec.)" [expr {$nett / 1000.0}]]
if {$nettm > 0} {
append s [format " (%.2f net-sec.)" [expr {$nettm / 1000.0}]]
}
puts "Total $s:"
lset _(m) 0 [format %.6f $wtm]
lset _(m) 2 $wcnt
lset _(m) 4 [format %.3f [expr {$wcnt / (($nett ? $nett : ($tcnt * [lindex $_(reptime) 0])) / 1000.0)}]]
lset _(m) 4 [format %.3f [expr {$wcnt / (($nettm ? $nettm : ($tcnt * [lindex $_(reptime) 0])) / 1000.0)}]]
if {[llength $_(m)] > 6} {
lset _(m) 6 [format %.3f $nett]
lset _(m) 6 [format %.3f $nettm]
}
puts $_(m)
puts "Average:"
@@ -94,51 +94,97 @@ proc _test_out_total {} {
puts [lindex $_(itm) $maxi]
puts [string repeat ** 40]
puts ""
unset -nocomplain _(itm) _(starttime)
}
proc _test_start {reptime} {
upvar _ _
array set _ [list itm {} reptime $reptime starttime [clock milliseconds] -from-run 0]
}
proc _test_iter {args} {
if {[llength $args] > 2} {
return -code error "wrong # args: should be \"[lindex [info level [info level]] 0] ?level? measure-result\""
}
set lvl 1
if {[llength $args] > 1} {
set args [lassign $args lvl]
}
upvar $lvl _ _
puts [set _(m) {*}$args]
lappend _(itm) $_(m)
puts ""
}
proc _adjust_maxcount {reptime maxcount} {
if {[llength $reptime] > 1} {
lreplace $reptime 1 1 [expr {min($maxcount,[lindex $reptime 1])}]
} else {
lappend reptime $maxcount
}
}
proc _test_run {args} {
upvar _ _
# parse args:
set _(out-result) 1
if {[lindex $args 0] eq "-no-result"} {
set _(out-result) 0
array set _ [set _opts {-no-result 0 -uplevel 0}]
while {[llength $args] > 2} {
if {[set o [lindex $args 0]] ni $_opts || $_($o)} {
break
}
set _($o) 1
set args [lrange $args 1 end]
}
unset -nocomplain _opts o
if {[llength $args] < 2 || [llength $args] > 3} {
return -code error "wrong # args: should be \"[lindex [info level [info level]] 0] ?-no-result? reptime lst ?outcmd?\""
}
set outcmd {puts $_(r)}
set _(outcmd) {puts}
set args [lassign $args reptime lst]
if {[llength $args]} {
set outcmd [lindex $args 0]
set _(outcmd) [lindex $args 0]
}
# avoid output if only once:
if {[lindex $reptime 0] <= 1 || ([llength $reptime] > 1 && [lindex $reptime 1] == 1)} {
set _(out-result) 0
set _(-no-result) 1
}
if {![info exists _(itm)]} {
array set _ [list itm {} reptime $reptime starttime [clock milliseconds] -from-run 1]
} else {
array set _ [list reptime $reptime]
}
array set _ [list itm {} reptime $reptime starttime [clock milliseconds]]
# process measurement:
foreach _(c) [_test_get_commands $lst] {
puts "% [regsub -all {\n[ \t]*} $_(c) {; }]"
{*}$_(outcmd) "% [regsub -all {\n[ \t]*} $_(c) {; }]"
if {[regexp {^\s*\#} $_(c)]} continue
if {[regexp {^\s*(?:setup|cleanup)\s+} $_(c)]} {
puts [if 1 [lindex $_(c) 1]]
set _(c) [lindex $_(c) 1]
if {$_(-uplevel)} {
set _(c) [list uplevel 1 $_(c)]
}
{*}$_(outcmd) [if 1 $_(c)]
continue
}
if {$_(-uplevel)} {
set _(c) [list uplevel 1 $_(c)]
}
set _(ittime) $_(reptime)
# if output result (and not once):
if {$_(out-result)} {
if {!$_(-no-result)} {
set _(r) [if 1 $_(c)]
if {$outcmd ne {}} $outcmd
if {[llength $_(reptime)] > 1} { # decrement max-count
lset _(reptime) 1 [expr {[lindex $_(reptime) 1] - 1}]
if {$_(outcmd) ne {}} {{*}$_(outcmd) $_(r)}
if {[llength $_(ittime)] > 1} { # decrement max-count
lset _(ittime) 1 [expr {[lindex $_(ittime) 1] - 1}]
}
}
puts [set _(m) [timerate $_(c) {*}$_(reptime)]]
{*}$_(outcmd) [set _(m) [timerate $_(c) {*}$_(ittime)]]
lappend _(itm) $_(m)
puts ""
{*}$_(outcmd) ""
}
if {$_(-from-run)} {
_test_out_total
}
_test_out_total
}
}; # end of namespace ::tclTestPerf
+12
View File
@@ -964,6 +964,18 @@ test basic-48.24.$noComp {expansion: empty not canonical list, regression test,
run {list [list {*}{ }] [list {*}[format %c 32]] [list {*}[set a { }]]}
} -result [lrepeat 3 {}] -cleanup {unset -nocomplain a}
test basic-48.25.$noComp {Bug cc191552c: expansion: empty non-canonical list} -setup {
unset -nocomplain ::CRLF
set ::CRLF "\r\n"
} -body {
# Force variant that turned up in Bug 2c154a40be as that's externally
# noticeable in an important downstream project.
run {scan [list {*}$::CRLF]x %c%c%c}
} -cleanup {
unset -nocomplain ::CRLF
} -result {120 {} {}}
} ;# End of noComp loop
test basic-49.1 {Tcl_EvalEx: verify TCL_EVAL_GLOBAL operation} testevalex {
+12 -10
View File
@@ -36707,16 +36707,18 @@ test clock-58.1 {clock l10n - Japanese localisation} {*}{
}
-body {
set trouble {}
foreach {date jdate} [list \
1872-12-31 \u897f\u66a61872\u5e7412\u670831\u65e5 \
1873-01-01 \u660e\u6cbb06\u5e7401\u670801\u65e5 \
1912-07-29 \u660e\u6cbb45\u5e7407\u670829\u65e5 \
1912-07-30 \u5927\u6b6301\u5e7407\u670830\u65e5 \
1926-12-24 \u5927\u6b6315\u5e7412\u670824\u65e5 \
1926-12-25 \u662d\u548c01\u5e7412\u670825\u65e5 \
1989-01-07 \u662d\u548c64\u5e7401\u670807\u65e5 \
1989-01-08 \u5e73\u621001\u5e7401\u670808\u65e5 \
] {
foreach {date jdate} {
1872-12-31 \u897f\u66a61872\u5e7412\u670831\u65e5
1873-01-01 \u660e\u6cbb06\u5e7401\u670801\u65e5
1912-07-29 \u660e\u6cbb45\u5e7407\u670829\u65e5
1912-07-30 \u5927\u6b6301\u5e7407\u670830\u65e5
1926-12-24 \u5927\u6b6315\u5e7412\u670824\u65e5
1926-12-25 \u662d\u548c01\u5e7412\u670825\u65e5
1989-01-07 \u662d\u548c64\u5e7401\u670807\u65e5
1989-01-08 \u5e73\u621001\u5e7401\u670808\u65e5
2019-04-30 \u5e73\u621031\u5e7404\u670830\u65e5
2019-05-01 \u4ee4\u548c01\u5e7405\u670801\u65e5
} {
set status [catch {
set secs [clock scan $date \
-timezone +0900 \
+58 -2
View File
@@ -235,7 +235,7 @@ test cmdAH-5.1 {Tcl_FileObjCmd} -returnCodes error -body {
} -result {wrong # args: should be "file subcommand ?arg ...?"}
test cmdAH-5.2 {Tcl_FileObjCmd} -returnCodes error -body {
file x
} -result {unknown or ambiguous subcommand "x": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempfile, type, volumes, or writable}
} -result {unknown or ambiguous subcommand "x": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempdir, tempfile, type, volumes, or writable}
test cmdAH-5.3 {Tcl_FileObjCmd} -returnCodes error -body {
file exists
} -result {wrong # args: should be "file exists name"}
@@ -1526,7 +1526,7 @@ test cmdAH-29.6.1 {
# Error conditions
test cmdAH-30.1 {Tcl_FileObjCmd: error conditions} -returnCodes error -body {
file gorp x
} -result {unknown or ambiguous subcommand "gorp": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempfile, type, volumes, or writable}
} -result {unknown or ambiguous subcommand "gorp": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempdir, tempfile, type, volumes, or writable}
test cmdAH-30.2 {Tcl_FileObjCmd: error conditions} -returnCodes error -body {
file ex x
} -match glob -result {unknown or ambiguous subcommand "ex": must be *}
@@ -1658,6 +1658,62 @@ test cmdAH-32.6 {file tempfile - templates} -body {
} -constraints {unix nonPortable} -cleanup {
catch {file delete $name}
} -result ok
test cmdAH-33.1 {file tempdir} -body {
file tempdir a b
} -returnCodes error -result {wrong # args: should be "file tempdir ?template?"}
test cmdAH-33.2 {file tempdir} -body {
set d [file tempdir]
list [file tail $d] [file exists $d] [file type $d] \
[glob -nocomplain -directory $d *]
} -match glob -result {tcl_* 1 directory {}} -cleanup {
catch {file delete $d}
}
test cmdAH-33.3 {file tempdir} -body {
set d [file tempdir gorp]
list [file tail $d] [file exists $d] [file type $d] \
[glob -nocomplain -directory $d *]
} -match glob -result {gorp_* 1 directory {}} -cleanup {
catch {file delete $d}
}
test cmdAH-33.4 {file tempdir} -setup {
set base [file join [temporaryDirectory] gorp]
file mkdir $base
} -body {
set pre [glob -nocomplain -directory $base *]
set d [file normalize [file tempdir $base/]]
list [string map [list $base GORP:] $d] [file exists $d] [file type $d] \
$pre [glob -nocomplain -directory $d *]
} -match glob -result {GORP:/tcl_* 1 directory {} {}} -cleanup {
catch {file delete -force $base}
}
test cmdAH-33.5 {file tempdir} -setup {
set base [file join [temporaryDirectory] gorp]
file mkdir $base
} -body {
set pre [glob -nocomplain -directory $base *]
set d [file normalize [file tempdir $base/gorp]]
list [string map [list $base GORP:] $d] [file exists $d] [file type $d] \
$pre [glob -nocomplain -directory $d *]
} -match glob -result {GORP:/gorp_* 1 directory {} {}} -cleanup {
catch {file delete -force $base}
}
test cmdAH-33.6 {file tempdir: missing parent dir} -setup {
set base [file join [temporaryDirectory] gorp]
file mkdir $base
} -returnCodes error -body {
file tempdir $base/quux/
} -cleanup {
catch {file delete -force $base}
} -result {can't create temporary directory: no such file or directory}
test cmdAH-33.7 {file tempdir: missing parent dir} -setup {
set base [file join [temporaryDirectory] gorp]
file mkdir $base
} -returnCodes error -body {
file tempdir $base/quux/foobar
} -cleanup {
catch {file delete -force $base}
} -result {can't create temporary directory: no such file or directory}
# This shouldn't work, but just in case a test above failed...
catch {close $newFileId}
+48 -3
View File
@@ -19,7 +19,7 @@ catch [list package require -exact Tcltest [info patchlevel]]
# Used for constraining memory leak tests
testConstraint memory [llength [info commands memory]]
testConstraint testobj [llength [info commands testobj]]
test cmdIL-1.1 {Tcl_LsortObjCmd procedure} -returnCodes error -body {
lsort
} -result {wrong # args: should be "lsort ?-option value ...? list"}
@@ -774,6 +774,52 @@ test cmdIL-7.8 {lreverse command - shared intrep [Bug 1675044]} -setup {
rename K {}
} -result 1
test cmdIL-8.1 {lremove command: error path} -returnCodes error -body {
lremove
} -result {wrong # args: should be "lremove list ?index ...?"}
test cmdIL-8.2 {lremove command: error path} -returnCodes error -body {
lremove {{}{}}
} -result {list element in braces followed by "{}" instead of space}
test cmdIL-8.3 {lremove command: error path} -returnCodes error -body {
lremove {a b c} gorp
} -result {bad index "gorp": must be integer?[+-]integer? or end?[+-]integer?}
test cmdIL-8.4 {lremove command: no indices} -body {
lremove {a b c}
} -result {a b c}
test cmdIL-8.5 {lremove command: before start} -body {
lremove {a b c} -1
} -result {a b c}
test cmdIL-8.6 {lremove command: after end} -body {
lremove {a b c} 3
} -result {a b c}
test cmdIL-8.7 {lremove command} -body {
lremove {a b c} 0
} -result {b c}
test cmdIL-8.8 {lremove command} -body {
lremove {a b c} 1
} -result {a c}
test cmdIL-8.9 {lremove command} -body {
lremove {a b c} end
} -result {a b}
test cmdIL-8.10 {lremove command} -body {
lremove {a b c} end-1
} -result {a c}
test cmdIL-8.11 {lremove command} -body {
lremove {a b c d e} 1 3
} -result {a c e}
test cmdIL-8.12 {lremove command} -body {
lremove {a b c d e} 3 1
} -result {a c e}
test cmdIL-8.13 {lremove command: same index twice} -body {
lremove {a b c d e} 2 2
} -result {a b d e}
test cmdIL-8.14 {lremove command: same index twice} -body {
lremove {a b c d e} 3 end-1
} -result {a b c e}
test cmdIL-8.15 {lremove command: many indices} -body {
lremove {a b c d e} 1 3 1 4 0
} -result {c}
# This belongs in info test, but adding tests there breaks tests
# that compute source file line numbers.
test info-20.6 {Bug 3587651} -setup {
@@ -782,8 +828,7 @@ test info-20.6 {Bug 3587651} -setup {
}}}} -body { namespace eval my {expr {"demo" in [info functions]}}} -cleanup {
namespace delete my
} -result 1
# cleanup
::tcltest::cleanupTests
return
+17 -3
View File
@@ -316,7 +316,7 @@ test cmdMZ-4.13 {Tcl_SplitObjCmd: basic split commands} {
# The tests for Tcl_SubstObjCmd are in subst.test
# The tests for Tcl_SwitchObjCmd are in switch.test
# todo: rewrite this if monotonic clock is provided resp. command "after"
# todo: rewrite this if monotonic clock is provided resp. command "after"
# gets microsecond accuracy (RFE [fdfbd5e10] gets merged):
proc _nrt_sleep {msec} {
set usec [expr {$msec * 1000}]
@@ -369,10 +369,10 @@ test cmdMZ-6.4 {Tcl_TimeRateObjCmd: compile of script happens even with negative
list [catch {timerate "foreach a {c d e} \{" -12456} msg] $msg
} {1 {missing close-brace}}
test cmdMZ-6.5a {Tcl_TimeRateObjCmd: result format and one iteration} {
regexp {^\d+(?:\.\d+)? \ws/# 1 # \d+(?:\.\d+)? #/sec \d+(?:\.\d+)? nett-ms$} [timerate {} 0]
regexp {^\d+(?:\.\d+)? \ws/# 1 # \d+(?:\.\d+)? #/sec \d+(?:\.\d+)? net-ms$} [timerate {} 0]
} 1
test cmdMZ-6.5b {Tcl_TimeRateObjCmd: result format without iterations} {
regexp {^0 \ws/# 0 # 0 #/sec 0 nett-ms$} [timerate {} 0 0]
regexp {^0 \ws/# 0 # 0 #/sec 0 net-ms$} [timerate {} 0 0]
} 1
test cmdMZ-6.6 {Tcl_TimeRateObjCmd: slower commands take longer, but it remains almost the same time of measument} {
set m1 [timerate {_nrt_sleep 0} 20]
@@ -403,6 +403,14 @@ test cmdMZ-6.8 {Tcl_TimeRateObjCmd: allow (conditional) break from timerate} {
[expr {[lindex $m1 4] > 1000}] \
[expr {[lindex $m1 6] < 10}]
} {1 1 1 1}
test cmdMZ-6.8.1 {Tcl_TimeRateObjCmd: allow (conditional) continue in timerate} {
set m1 [timerate {continue; return -code error "unexpected"} 1000 10]
list \
[expr {[lindex $m1 0] < 1000}] \
[expr {[lindex $m1 2] == 10}] \
[expr {[lindex $m1 4] > 1000}] \
[expr {[lindex $m1 6] < 100}]
} {1 1 1 1}
test cmdMZ-6.9 {Tcl_TimeRateObjCmd: max count of iterations} {
set m1 [timerate {} 1000 5]; # max-count wins
set m2 [timerate {_nrt_sleep 20} 1 5]; # max-time wins
@@ -416,6 +424,12 @@ test cmdMZ-6.10 {Tcl_TimeRateObjCmd: huge overhead cause 0us result} {
[expr {[lindex $m1 4] == 1000000}] \
[expr {[lindex $m1 6] <= 0.001}]
} {1 1 1 1}
test cmdMZ-6.11 {Tcl_TimeRateObjCmd: done/continue optimization rollback} {
set m1 {set m2 ok}
if 1 $m1
timerate $m1 1000 10
if 1 $m1; # if rollback is missing throws an error: invoked "continue" outside of a loop
} ok
test cmdMZ-try-1.0 {
+241 -11
View File
@@ -626,19 +626,31 @@ test coroutine-7.5 {return codes} {
}
set result
} {0 1 2 3 4 5}
test coroutine-7.6 {Early yield crashes} {
proc foo args {}
trace add execution foo enter {catch yield}
coroutine demo foo
rename foo {}
} {}
test coroutine-7.7 {Bug 2486550} -setup {
interp hide {} yield
test coroutine-7.6 {Early yield crashes} -setup {
set i [interp create]
} -body {
coroutine demo interp invokehidden {} yield ok
# Force into a child interpreter [bug 60559fd4a6]
$i eval {
proc foo args {}
trace add execution foo enter {catch yield}
coroutine demo foo
rename foo {}
return ok
}
} -cleanup {
demo
interp expose {} yield
interp delete $i
} -result ok
test coroutine-7.7 {Bug 2486550} -setup {
set i [interp create]
$i hide yield
} -body {
# Force into a child interpreter [bug 60559fd4a6]
$i eval {
coroutine demo interp invokehidden {} yield ok
}
} -cleanup {
$i eval demo
interp delete $i
} -result ok
test coroutine-7.8 {yieldto context nuke: Bug a90d9331bc} -setup {
namespace eval cotest {}
@@ -781,7 +793,225 @@ test coroutine-8.1.2 {coro inject with result, ticket 42202ba1e5ff566e} -body {
set result
} -result {inject-executed}
test coroutine-9.1 {coroprobe with yield} -body {
coroutine demo apply {{} { foreach i {1 2} yield }}
list [coroprobe demo set i] [demo] [coroprobe demo set i] [demo]
} -cleanup {
catch {rename demo {}}
} -result {1 {} 2 {}}
test coroutine-9.2 {coroprobe with yieldto} -body {
coroutine demo apply {{} { lmap i {1 2} {yieldto string cat} }}
list [coroprobe demo set i] [demo a b] [coroprobe demo set i] [demo c d]
} -cleanup {
catch {rename demo {}}
} -result {1 {} 2 {{a b} {c d}}}
test coroutine-9.3 {coroprobe errors} -setup {
catch {rename demo {}}
} -body {
coroprobe demo set i
} -returnCodes error -result {can only inject a probe command into a coroutine}
test coroutine-9.4 {coroprobe errors} -body {
proc demo {} { foreach i {1 2} yield }
coroprobe demo set i
} -returnCodes error -cleanup {
catch {rename demo {}}
} -result {can only inject a probe command into a coroutine}
test coroutine-9.5 {coroprobe errors} -body {
coroutine demo apply {{} { foreach i {1 2} yield }}
coroprobe
} -returnCodes error -cleanup {
catch {rename demo {}}
} -result {wrong # args: should be "coroprobe coroName cmd ?arg1 arg2 ...?"}
test coroutine-9.6 {coroprobe errors} -body {
coroutine demo apply {{} { foreach i {1 2} yield }}
coroprobe demo
} -returnCodes error -cleanup {
catch {rename demo {}}
} -result {wrong # args: should be "coroprobe coroName cmd ?arg1 arg2 ...?"}
test coroutine-9.7 {coroprobe errors in probe command} -body {
coroutine demo apply {{} { foreach i {1 2} yield }}
coroprobe demo set
} -returnCodes error -cleanup {
catch {rename demo {}}
} -result {wrong # args: should be "set varName ?newValue?"}
test coroutine-9.8 {coroprobe errors in probe command} -body {
coroutine demo apply {{} { foreach i {1 2} yield }}
list [catch {coroprobe demo set}] [demo] [coroprobe demo set i]
} -cleanup {
catch {rename demo {}}
} -result {1 {} 2}
test coroutine-9.9 {coroprobe: advanced features} -setup {
set i [interp create]
} -body {
$i eval {
coroutine demo apply {{} {
set f [info level],[info frame]
foreach i {1 2} yield
}}
coroprobe demo apply {{} {
upvar 1 f f
list [info coroutine] [info level] [info frame] $f
}}
}
} -cleanup {
interp delete $i
} -result {::demo 2 3 1,2}
test coroutine-10.1 {coroinject with yield} -setup {
set result {}
} -body {
coroutine demo apply {{} { lmap i {1 2} yield }}
coroinject demo apply {{op val} {lappend ::result $op $val}}
list $result [demo x] [demo y] $result
} -cleanup {
catch {rename demo {}}
} -result {{} {} {{yield x} y} {yield x}}
test coroutine-10.2 {coroinject stacking} -setup {
set result {}
} -body {
coroutine demo apply {{} { lmap i {1 2} yield }}
coroinject demo apply {{op val} {lappend ::result $op $val A;return $val}}
coroinject demo apply {{op val} {lappend ::result $op $val B;return $val}}
list $result [demo x] [demo y] $result
} -cleanup {
catch {rename demo {}}
} -result {{} {} {x y} {yield x B yield x A}}
test coroutine-10.3 {coroinject with yieldto} -setup {
set result {}
} -body {
coroutine demo apply {{} { lmap i {1 2} {yieldto string cat} }}
coroinject demo apply {{op val} {lappend ::result $op $val;return $val}}
list $result [demo x mp] [demo y le] $result
} -cleanup {
catch {rename demo {}}
} -result {{} {} {{x mp} {y le}} {yieldto {x mp}}}
test coroutine-10.4 {coroinject errors} -setup {
catch {rename demo {}}
} -body {
coroinject demo set i
} -returnCodes error -result {can only inject a command into a coroutine}
test coroutine-10.5 {coroinject errors} -body {
proc demo {} { foreach i {1 2} yield }
coroinject demo set i
} -returnCodes error -cleanup {
catch {rename demo {}}
} -result {can only inject a command into a coroutine}
test coroutine-10.6 {coroinject errors} -body {
coroutine demo apply {{} { foreach i {1 2} yield }}
coroinject
} -returnCodes error -cleanup {
catch {rename demo {}}
} -result {wrong # args: should be "coroinject coroName cmd ?arg1 arg2 ...?"}
test coroutine-10.7 {coroinject errors} -body {
coroutine demo apply {{} { foreach i {1 2} yield }}
coroinject demo
} -returnCodes error -cleanup {
catch {rename demo {}}
} -result {wrong # args: should be "coroinject coroName cmd ?arg1 arg2 ...?"}
test coroutine-10.8 {coroinject errors in injected command} -body {
coroutine demo apply {{} { foreach i {1 2} yield }}
coroinject demo apply {args {error "ERR: $args"}}
list [catch demo msg] $msg [catch demo msg] $msg
} -cleanup {
catch {rename demo {}}
} -result {1 {ERR: yield {}} 1 {invalid command name "demo"}}
test coroutine-10.9 {coroinject: advanced features} -setup {
set i [interp create]
} -body {
$i eval {
coroutine demo apply {{} {
set l [info level]
set f [info frame]
lmap i {1 2} yield
}}
coroinject demo apply {{arg op val} {
global result
upvar 1 f f l l
lappend result [info coroutine] $arg $op $val
lappend result [info level] $l [info frame] $f
lappend result [yield $arg]
return [string toupper $val]
}} grill
list [demo ABC] [demo pqr] [demo def] $result
}
} -cleanup {
interp delete $i
} -result {grill {} {ABC def} {::demo grill yield ABC 2 1 3 2 pqr}}
test coroutine-11.1 {coro type} {
coroutine demo eval {
yield
yield "PHASE 1"
yieldto string cat "PHASE 2"
::tcl::unsupported::corotype [info coroutine]
}
list [demo] [::tcl::unsupported::corotype demo] \
[demo] [::tcl::unsupported::corotype demo] [demo]
} {{PHASE 1} yield {PHASE 2} yieldto active}
test coroutine-11.2 {coro type} -setup {
catch {rename nosuchcommand ""}
} -returnCodes error -body {
::tcl::unsupported::corotype nosuchcommand
} -result {can only get coroutine type of a coroutine}
test coroutine-11.3 {coro type} -returnCodes error -body {
proc notacoroutine {} {}
::tcl::unsupported::corotype notacoroutine
} -returnCodes error -cleanup {
rename notacoroutine {}
} -result {can only get coroutine type of a coroutine}
test coroutine-12.1 {coroutine general introspection} -setup {
set i [interp create]
} -body {
$i eval {
# Make the introspection code
namespace path tcl::unsupported
proc probe {type var} {
upvar 1 $var v
set f [info frame]
incr f -1
set result [list $v [dict get [info frame $f] proc]]
if {$type eq "yield"} {
tailcall yield $result
} else {
tailcall yieldto string cat $result
}
}
proc pokecoro {c var} {
inject $c probe [corotype $c] $var
$c
}
# Coroutine implementations
proc cbody1 {} {
set val [info coroutine]
set accum {}
while {[set val [yield $val]] ne ""} {
lappend accum $val
set val ok
}
return $accum
}
proc cbody2 {} {
set val [info coroutine]
set accum {}
while {[llength [set val [yieldto string cat $val]]]} {
lappend accum {*}$val
set val ok
}
return $accum
}
# Make the coroutines
coroutine c1 cbody1
coroutine c2 cbody2
list [c1 abc] [c2 1 2 3] [pokecoro c1 accum] [pokecoro c2 accum] \
[c1 def] [c2 4 5 6] [pokecoro c1 accum] [pokecoro c2 accum] \
[c1] [c2]
}
} -cleanup {
interp delete $i
} -result {ok ok {abc ::cbody1} {{1 2 3} ::cbody2} ok ok {{abc def} ::cbody1} {{1 2 3 4 5 6} ::cbody2} {abc def} {1 2 3 4 5 6}}
# cleanup
unset lambda
+105
View File
@@ -2047,6 +2047,111 @@ test dict-25.1 {compiled dict update with low-refcount values [Bug d553228d9f]}
dict update item item item two two {}
}}
} {}
set dict dict; # Used to force interpretation, not compilation
test dict-26.1 {dict getdef command} -body {
dict getdef {a b} a c
} -result b
test dict-26.2 {dict getdef command} -body {
dict getdef {a b} b c
} -result c
test dict-26.3 {dict getdef command} -body {
dict getdef {a {b c}} a b d
} -result c
test dict-26.4 {dict getdef command} -body {
dict getdef {a {b c}} a c d
} -result d
test dict-26.5 {dict getdef command} -body {
dict getdef {a {b c}} b c d
} -result d
test dict-26.6 {dict getdef command} -returnCodes error -body {
dict getdef {a {b c d}} a b d
} -result {missing value to go with key}
test dict-26.7 {dict getdef command} -returnCodes error -body {
dict getdef
} -result {wrong # args: should be "dict getdef dictionary ?key ...? key default"}
test dict-26.8 {dict getdef command} -returnCodes error -body {
dict getdef {}
} -result {wrong # args: should be "dict getdef dictionary ?key ...? key default"}
test dict-26.9 {dict getdef command} -returnCodes error -body {
dict getdef {} {}
} -result {wrong # args: should be "dict getdef dictionary ?key ...? key default"}
test dict-26.10 {dict getdef command} -returnCodes error -body {
dict getdef {a b c} d e
} -result {missing value to go with key}
test dict-26.11 {dict getdef command} -body {
$dict getdef {a b} a c
} -result b
test dict-26.12 {dict getdef command} -body {
$dict getdef {a b} b c
} -result c
test dict-26.13 {dict getdef command} -body {
$dict getdef {a {b c}} a b d
} -result c
test dict-26.14 {dict getdef command} -body {
$dict getdef {a {b c}} a c d
} -result d
test dict-26.15 {dict getdef command} -body {
$dict getdef {a {b c}} b c d
} -result d
test dict-26.16 {dict getdef command} -returnCodes error -body {
$dict getdef {a {b c d}} a b d
} -result {missing value to go with key}
test dict-26.17 {dict getdef command} -returnCodes error -body {
$dict getdef {a b c} d e
} -result {missing value to go with key}
test dict-27.1 {dict getwithdefault command} -body {
dict getwithdefault {a b} a c
} -result b
test dict-27.2 {dict getwithdefault command} -body {
dict getwithdefault {a b} b c
} -result c
test dict-27.3 {dict getwithdefault command} -body {
dict getwithdefault {a {b c}} a b d
} -result c
test dict-27.4 {dict getwithdefault command} -body {
dict getwithdefault {a {b c}} a c d
} -result d
test dict-27.5 {dict getwithdefault command} -body {
dict getwithdefault {a {b c}} b c d
} -result d
test dict-27.6 {dict getwithdefault command} -returnCodes error -body {
dict getwithdefault {a {b c d}} a b d
} -result {missing value to go with key}
test dict-27.7 {dict getwithdefault command} -returnCodes error -body {
dict getwithdefault
} -result {wrong # args: should be "dict getwithdefault dictionary ?key ...? key default"}
test dict-27.8 {dict getwithdefault command} -returnCodes error -body {
dict getwithdefault {}
} -result {wrong # args: should be "dict getwithdefault dictionary ?key ...? key default"}
test dict-27.9 {dict getwithdefault command} -returnCodes error -body {
dict getwithdefault {} {}
} -result {wrong # args: should be "dict getwithdefault dictionary ?key ...? key default"}
test dict-27.10 {dict getdef command} -returnCodes error -body {
dict getwithdefault {a b c} d e
} -result {missing value to go with key}
test dict-27.11 {dict getwithdefault command} -body {
$dict getwithdefault {a b} a c
} -result b
test dict-27.12 {dict getwithdefault command} -body {
$dict getwithdefault {a b} b c
} -result c
test dict-27.13 {dict getwithdefault command} -body {
$dict getwithdefault {a {b c}} a b d
} -result c
test dict-27.14 {dict getwithdefault command} -body {
$dict getwithdefault {a {b c}} a c d
} -result d
test dict-27.15 {dict getwithdefault command} -body {
$dict getwithdefault {a {b c}} b c d
} -result d
test dict-27.16 {dict getwithdefault command} -returnCodes error -body {
$dict getwithdefault {a {b c d}} a b d
} -result {missing value to go with key}
test dict-27.17 {dict getdef command} -returnCodes error -body {
$dict getwithdefault {a b c} d e
} -result {missing value to go with key}
# cleanup
::tcltest::cleanupTests
+20
View File
@@ -411,6 +411,26 @@ test expr-8.34 {expr edge cases} -body {
test expr-8.35 {expr edge cases} -body {
expr {1ea}
} -returnCodes error -match glob -result *
test expr-8.36 {CompileEqualtyExpr: string comparison ops} {
set x 012
set y 0x0
list [expr {$x < $y}] [expr {$x lt $y}] [expr {$x lt $x}]
} {0 1 0}
test expr-8.37 {CompileEqualtyExpr: string comparison ops} {
set x 012
set y 0x0
list [expr {$x <= $y}] [expr {$x le $y}] [expr {$x le $x}]
} {0 1 1}
test expr-8.38 {CompileEqualtyExpr: string comparison ops} {
set x 012
set y 0x0
list [expr {$x > $y}] [expr {$x gt $y}] [expr {$x gt $x}]
} {1 0 0}
test expr-8.39 {CompileEqualtyExpr: string comparison ops} {
set x 012
set y 0x0
list [expr {$x >= $y}] [expr {$x ge $y}] [expr {$x ge $x}]
} {1 0 1}
test expr-9.1 {CompileRelationalExpr: just shift expr} {expr 3<<2} 12
test expr-9.2 {CompileRelationalExpr: just shift expr} {expr 0xff>>2} 63
+5 -1
View File
@@ -68,7 +68,11 @@ proc http::Log {args} {
}
return
}
# The http::Log routine above needs the variable ::httpTest::testOptions
# Set up to destroy it when that variable goes away.
trace add variable ::httpTest::testOptions unset {apply {args {
proc ::http::Log args {}
}}}
# Called by http::Log (the "testing" version) to record logs for later analysis.
+20 -20
View File
@@ -768,26 +768,26 @@ test info-22.8 {info frame, basic trace} -match glob -body {
* {type source line * file tcltest* cmd {uplevel 1 $script} proc ::tcltest::RunTest}}
unset -nocomplain msg
test info-23.0.0 {eval'd info frame} {!singleTestInterp} {
eval {info frame}
} 8
test info-23.0.1 {eval'd info frame} -constraints {singleTestInterp} -match glob -body {
eval {info frame}
} -result {1[12]} ;# SingleTestInterp results changes depending on running the whole suite, or info.test alone.
test info-23.1.0 {eval'd info frame, semi-dynamic} {!singleTestInterp} {
eval info frame
} 8
test info-23.1.1 {eval'd info frame, semi-dynamic} -constraints {singleTestInterp} -match glob -body {
eval info frame
} -result {1[12]}
test info-23.2.0 {eval'd info frame, dynamic} -constraints {!singleTestInterp} -body {
set script {info frame}
eval $script
} -cleanup {unset script} -result 8
test info-23.2.1 {eval'd info frame, dynamic} -constraints {singleTestInterp} -match glob -body {
set script {info frame}
eval $script
} -cleanup {unset script} -result {1[12]}
## The line 1967 is off by 5 from the true value of 1972. This is a knownBug, see testcase 30.0
test info-23.0 {eval'd info frame} -constraints {!singleTestInterp} -body {
list [i eval {info frame}] [i eval {eval {info frame}}]
} -setup {interp create i} -cleanup {interp delete i} -result {1 2}
test info-23.1 {eval'd info frame, semi-dynamic} -constraints {!singleTestInterp} -body {
i eval {eval info frame}
} -setup {interp create i} -cleanup {interp delete i} -result 2
test info-23.2 {eval'd info frame, dynamic} -constraints {!singleTestInterp} -body {
i eval { set script {info frame}
eval $script}
} -setup {interp create i} -cleanup {interp delete i} -result 2
test info-23.3 {eval'd info frame, literal} -match glob -body {
eval {
info frame 0
+1 -1
View File
@@ -20,7 +20,7 @@ catch [list package require -exact Tcltest [info patchlevel]]
testConstraint testinterpdelete [llength [info commands testinterpdelete]]
set hidden_cmds {cd encoding exec exit fconfigure file glob load open pwd socket source tcl:encoding:dirs tcl:encoding:system tcl:file:atime tcl:file:attributes tcl:file:copy tcl:file:delete tcl:file:dirname tcl:file:executable tcl:file:exists tcl:file:extension tcl:file:isdirectory tcl:file:isfile tcl:file:link tcl:file:lstat tcl:file:mkdir tcl:file:mtime tcl:file:nativename tcl:file:normalize tcl:file:owned tcl:file:readable tcl:file:readlink tcl:file:rename tcl:file:rootname tcl:file:size tcl:file:stat tcl:file:tail tcl:file:tempfile tcl:file:type tcl:file:volumes tcl:file:writable tcl:info:cmdtype tcl:info:nameofexecutable tcl:process:autopurge tcl:process:list tcl:process:purge tcl:process:status tcl:zipfs:lmkimg tcl:zipfs:lmkzip tcl:zipfs:mkimg tcl:zipfs:mkkey tcl:zipfs:mkzip tcl:zipfs:mount tcl:zipfs:mount_data tcl:zipfs:unmount unload}
set hidden_cmds {cd encoding exec exit fconfigure file glob load open pwd socket source tcl:encoding:dirs tcl:encoding:system tcl:file:atime tcl:file:attributes tcl:file:copy tcl:file:delete tcl:file:dirname tcl:file:executable tcl:file:exists tcl:file:extension tcl:file:isdirectory tcl:file:isfile tcl:file:link tcl:file:lstat tcl:file:mkdir tcl:file:mtime tcl:file:nativename tcl:file:normalize tcl:file:owned tcl:file:readable tcl:file:readlink tcl:file:rename tcl:file:rootname tcl:file:size tcl:file:stat tcl:file:tail tcl:file:tempdir tcl:file:tempfile tcl:file:type tcl:file:volumes tcl:file:writable tcl:info:cmdtype tcl:info:nameofexecutable tcl:process:autopurge tcl:process:list tcl:process:purge tcl:process:status tcl:zipfs:lmkimg tcl:zipfs:lmkzip tcl:zipfs:mkimg tcl:zipfs:mkkey tcl:zipfs:mkzip tcl:zipfs:mount tcl:zipfs:mount_data tcl:zipfs:unmount unload}
foreach i [interp slaves] {
interp delete $i
+63
View File
@@ -5963,6 +5963,69 @@ test io-44.5 {FileEventProc procedure: end of file} {stdio unixExecs openpipe fi
} {initial foo eof}
close $f
test chan-io-44.6 {FileEventProc procedure: write-only non-blocking channel} -setup {
} -constraints {stdio unixExecs fileevent openpipe} -body {
namespace eval refchan {
namespace ensemble create
namespace export *
proc finalize {chan args} {
namespace delete c_$chan
}
proc initialize {chan args} {
namespace eval c_$chan {}
namespace upvar c_$chan watching watching
set watching {}
list finalize initialize seek watch write
}
proc watch {chan args} {
namespace upvar c_$chan watching watching
foreach arg $args {
switch $arg {
write {
if {$arg ni $watching} {
lappend watching $arg
}
chan postevent $chan $arg
}
}
}
}
proc write {chan args} {
chan postevent $chan write
return 1
}
}
set f [chan create w [namespace which refchan]]
chan configure $f -blocking 0
set data "some data"
set x 0
chan event $f writable [namespace code {
puts $f $data
incr count [string length $data]
if {$count > 262144} {
chan event $f writable {}
set x done
}
}]
after 10000 [namespace code {
set x timeout
}]
vwait [namespace which -variable x]
return $x
} -cleanup {
catch {chan close $f}
} -result done
makeFile "foo bar" foo
test io-45.1 {DeleteFileEvent, cleanup on close} {fileevent} {
+118 -63
View File
@@ -206,78 +206,90 @@ test iocmd-7.5 {close command} -setup {
close $chan
} -returnCodes error -result "Half-close of write-side not possible, side not opened or already closed"
test iocmd-8.1 {fconfigure command} {
list [catch {fconfigure} msg] $msg
} {1 {wrong # args: should be "fconfigure channelId ?-option value ...?"}}
test iocmd-8.2 {fconfigure command} {
list [catch {fconfigure a b c d e f} msg] $msg
} {1 {wrong # args: should be "fconfigure channelId ?-option value ...?"}}
test iocmd-8.3 {fconfigure command} {
list [catch {fconfigure a b} msg] $msg
} {1 {can not find channel named "a"}}
test iocmd-8.4 {fconfigure command} {
proc expectedOpts {got extra} {
set basicOpts {
-blocking -buffering -buffersize -encoding -eofchar -translation
}
set opts [list {*}$basicOpts {*}$extra]
lset opts end [string cat "or " [lindex $opts end]]
return [format {bad option "%s": should be one of %s} $got [join $opts ", "]]
}
test iocmd-8.1 {fconfigure command} -returnCodes error -body {
fconfigure
} -result {wrong # args: should be "fconfigure channelId ?-option value ...?"}
test iocmd-8.2 {fconfigure command} -returnCodes error -body {
fconfigure a b c d e f
} -result {wrong # args: should be "fconfigure channelId ?-option value ...?"}
test iocmd-8.3 {fconfigure command} -returnCodes error -body {
fconfigure a b
} -result {can not find channel named "a"}
test iocmd-8.4 {fconfigure command} -setup {
file delete $path(test1)
set f1 [open $path(test1) w]
set x [list [catch {fconfigure $f1 froboz} msg] $msg]
} -body {
fconfigure $f1 froboz
} -returnCodes error -cleanup {
close $f1
set x
} {1 {bad option "froboz": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}}
test iocmd-8.5 {fconfigure command} {
list [catch {fconfigure stdin -buffering froboz} msg] $msg
} {1 {bad value for -buffering: must be one of full, line, or none}}
test iocmd-8.6 {fconfigure command} {
list [catch {fconfigure stdin -translation froboz} msg] $msg
} {1 {bad value for -translation: must be one of auto, binary, cr, lf, crlf, or platform}}
test iocmd-8.7 {fconfigure command} {
} -result [expectedOpts "froboz" {}]
test iocmd-8.5 {fconfigure command} -returnCodes error -body {
fconfigure stdin -buffering froboz
} -result {bad value for -buffering: must be one of full, line, or none}
test iocmd-8.6 {fconfigure command} -returnCodes error -body {
fconfigure stdin -translation froboz
} -result {bad value for -translation: must be one of auto, binary, cr, lf, crlf, or platform}
test iocmd-8.7 {fconfigure command} -setup {
file delete $path(test1)
} -body {
set f1 [open $path(test1) w]
fconfigure $f1 -translation lf -eofchar {} -encoding unicode
set x [fconfigure $f1]
close $f1
set x
} {-blocking 1 -buffering full -buffersize 4096 -encoding unicode -eofchar {} -translation lf}
test iocmd-8.8 {fconfigure command} {
fconfigure $f1
} -cleanup {
catch {close $f1}
} -result {-blocking 1 -buffering full -buffersize 4096 -encoding unicode -eofchar {} -translation lf}
test iocmd-8.8 {fconfigure command} -setup {
file delete $path(test1)
set x {}
} -body {
set f1 [open $path(test1) w]
fconfigure $f1 -translation lf -buffering line -buffersize 3030 \
-eofchar {} -encoding unicode
set x ""
lappend x [fconfigure $f1 -buffering]
lappend x [fconfigure $f1]
close $f1
set x
} {line {-blocking 1 -buffering line -buffersize 3030 -encoding unicode -eofchar {} -translation lf}}
test iocmd-8.9 {fconfigure command} {
} -cleanup {
catch {close $f1}
} -result {line {-blocking 1 -buffering line -buffersize 3030 -encoding unicode -eofchar {} -translation lf}}
test iocmd-8.9 {fconfigure command} -setup {
file delete $path(test1)
} -body {
set f1 [open $path(test1) w]
fconfigure $f1 -translation binary -buffering none -buffersize 4040 \
-eofchar {} -encoding binary
set x [fconfigure $f1]
close $f1
set x
} {-blocking 1 -buffering none -buffersize 4040 -encoding binary -eofchar {} -translation lf}
test iocmd-8.10 {fconfigure command} {
list [catch {fconfigure a b} msg] $msg
} {1 {can not find channel named "a"}}
fconfigure $f1
} -cleanup {
catch {close $f1}
} -result {-blocking 1 -buffering none -buffersize 4040 -encoding binary -eofchar {} -translation lf}
test iocmd-8.10 {fconfigure command} -returnCodes error -body {
fconfigure a b
} -result {can not find channel named "a"}
set path(fconfigure.dummy) [makeFile {} fconfigure.dummy]
test iocmd-8.11 {fconfigure command} {
test iocmd-8.11 {fconfigure command} -body {
set chan [open $path(fconfigure.dummy) r]
set res [list [catch {fconfigure $chan -froboz blarfo} msg] $msg]
close $chan
set res
} {1 {bad option "-froboz": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}}
test iocmd-8.12 {fconfigure command} {
fconfigure $chan -froboz blarfo
} -returnCodes error -cleanup {
catch {close $chan}
} -result [expectedOpts "-froboz" {}]
test iocmd-8.12 {fconfigure command} -body {
set chan [open $path(fconfigure.dummy) r]
set res [list [catch {fconfigure $chan -b blarfo} msg] $msg]
close $chan
set res
} {1 {bad option "-b": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}}
test iocmd-8.13 {fconfigure command} {
fconfigure $chan -b blarfo
} -returnCodes error -cleanup {
catch {close $chan}
} -result [expectedOpts "-b" {}]
test iocmd-8.13 {fconfigure command} -body {
set chan [open $path(fconfigure.dummy) r]
set res [list [catch {fconfigure $chan -buffer blarfo} msg] $msg]
close $chan
set res
} {1 {bad option "-buffer": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}}
fconfigure $chan -buffer blarfo
} -returnCodes error -cleanup {
catch {close $chan}
} -result [expectedOpts "-buffer" {}]
removeFile fconfigure.dummy
test iocmd-8.14 {fconfigure command} {
fconfigure stdin -buffers
@@ -294,7 +306,7 @@ test iocmd-8.15.1 {fconfigure command / tcp channel} -constraints {socket unixOr
close $srv
unset cli srv port
rename iocmdSRV {}
} -returnCodes error -result {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -connecting, -peername, or -sockname}
} -returnCodes error -result [expectedOpts "-blah" {-connecting -peername -sockname}]
test iocmd-8.16 {fconfigure command / tcp channel} -constraints socket -setup {
set srv [socket -server iocmdSRV -myaddr 127.0.0.1 0]
set port [lindex [fconfigure $srv -sockname] 2]
@@ -337,7 +349,7 @@ test iocmd-8.18 {fconfigure command / unix tty channel} -constraints {nonPortabl
if {$tty ne ""} {
close $tty
}
} -returnCodes error -result {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, or -mode}
} -returnCodes error -result [expectedOpts "-blah" {-closemode -inputmode -mode -queue -ttystatus -xchar}]
test iocmd-8.19 {fconfigure command / win tty channel} -constraints {nonPortable win} -setup {
set tty ""
} -body {
@@ -348,7 +360,13 @@ test iocmd-8.19 {fconfigure command / win tty channel} -constraints {nonPortable
if {$tty ne ""} {
close $tty
}
} -returnCodes error -result {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -mode, -handshake, -pollinterval, -sysbuffer, -timeout, -ttycontrol, or -xchar}
} -returnCodes error -result [expectedOpts "-blah" {-closemode -mode -handshake -pollinterval -sysbuffer -timeout -ttycontrol -xchar}]
test iocmd-8.20 {fconfigure command / win console channel} -constraints {nonPortable win} -setup {
# I don't know how else to open the console, but this is non-portable
set console stdin
} -body {
fconfigure $console -blah blih
} -returnCodes error -result [expectedOpts "-blah" {-inputmode}]
# TODO: Test parsing of serial channel options (nonPortable, since requires an
# open channel to work with).
@@ -912,6 +930,17 @@ proc onfinal {} {
if {[lindex $hargs 0] ne "finalize"} {return}
return -code return ""
}
proc onwatch {} {
upvar args hargs
lassign $hargs watch chan eventspec
if {$watch ne "watch"} return
foreach spec $eventspec {
chan postevent $chan $spec
}
return
}
}
# Set everything up in the main thread.
@@ -1984,28 +2013,29 @@ test iocmd-31.6 {chan postevent, posted events do happen} -match glob -body {
set res {}
proc foo {args} {oninit; onfinal; track; return}
set c [chan create {r w} foo]
note [fileevent $c readable {note TOCK}]
set stop [after 10000 {note TIMEOUT}]
set tock {}
note [fileevent $c readable {lappend res TOCK; set tock 1}]
set stop [after 10000 {lappend res TIMEOUT; set tock 1}]
after 1000 {note [chan postevent $c r]}
vwait ::res
vwait ::tock
catch {after cancel $stop}
close $c
rename foo {}
set res
} -result {{watch rc* read} {} TOCK {} {watch rc* {}}}
} -result {{watch rc* read} {} {} TOCK {watch rc* {}}}
test iocmd-31.7 {chan postevent, posted events do happen} -match glob -body {
set res {}
proc foo {args} {oninit; onfinal; track; return}
set c [chan create {r w} foo]
note [fileevent $c writable {note TOCK}]
set stop [after 10000 {note TIMEOUT}]
note [fileevent $c writable {lappend res TOCK; set tock 1}]
set stop [after 10000 {lappend res TIMEOUT; set tock 1}]
after 1000 {note [chan postevent $c w]}
vwait ::res
vwait ::tock
catch {after cancel $stop}
close $c
rename foo {}
set res
} -result {{watch rc* write} {} TOCK {} {watch rc* {}}}
} -result {{watch rc* write} {} {} TOCK {watch rc* {}}}
test iocmd-31.8 {chan postevent after close throws error} -match glob -setup {
proc foo {args} {oninit; onfinal; track; return}
proc dummy args { return }
@@ -2018,6 +2048,31 @@ test iocmd-31.8 {chan postevent after close throws error} -match glob -setup {
rename foo {}
rename dummy {}
} -returnCodes error -result {can not find reflected channel named "rc*"}
test iocmd-31.9 {
chan postevent
call to current coroutine
see 67a5eabbd3d1
} -match glob -body {
set res {}
proc foo {args} {oninit; onwatch; onfinal; track; return}
set c [chan create {r w} foo]
after 0 [list ::apply [list c {
coroutine c1 ::apply [list c {
chan event $c readable [list [info coroutine]]
yield
set ::done READING
} [namespace current]] $c
} [namespace current]] $c]
set stop [after 10000 {set done TIMEOUT}]
vwait ::done
catch {after cancel $stop}
lappend res $done
close $c
rename foo {}
set res
} -result {{watch rc* read} READING {watch rc* {}}}
# --- === *** ###########################
# 'Pull the rug' tests. Create channel in a interpreter A, move to
+484 -2
View File
@@ -20,11 +20,22 @@ if {"::tcltest" ni [namespace children]} {
catch [list package require -exact Tcltest [info patchlevel]]
testConstraint testlink [llength [info commands testlink]]
testConstraint testlinkarray [llength [info commands testlinkarray]]
foreach i {int real bool string} {
unset -nocomplain $i
}
test link-0.1 {leak test} {testlink} {
interp create i
load {} Tcltest i
i eval {
testlink create 1 0 0 0 0 0 0 0 0 0 0 0 0 0
namespace delete ::
}
interp delete i
} {}
test link-1.1 {reading C variables from Tcl} -constraints {testlink} -setup {
testlink delete
} -body {
@@ -88,7 +99,7 @@ test link-2.5 {writing bad values into variables} -setup {
testlink set 43 1.23 4 - 56785678 64 250 30000 60000 0xbeefbabe 12321 32123 3.25 1231231234
testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1
list [catch {set wide gorp} msg] $msg $bool
} -result {1 {can't set "wide": variable must have integer value} 1}
} -result {1 {can't set "wide": variable must have wide integer value} 1}
test link-2.6 {writing C variables from Tcl} -constraints {testlink} -setup {
testlink delete
} -body {
@@ -363,7 +374,7 @@ test link-7.7 {access to linked variables via upvar} -setup {
testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1
testlink set -4 16.3 1 {} 778899 {} {} {} {} {} {} {} {} {}
list [catch x msg] $msg $wide
} -result {1 {can't set "y": variable must have integer value} 778899}
} -result {1 {can't set "y": variable must have wide integer value} 778899}
test link-8.1 {Tcl_UpdateLinkedVar procedure} {testlink} {
proc x args {
@@ -398,6 +409,477 @@ test link-8.3 {Tcl_UpdateLinkedVar procedure, read-only variable} {testlink} {
testlink update 47 {} {} {} {} {} {} {} {} {} {} {} {} {}
} msg] $msg $int
} {0 {} 47}
test link-9.1 {linkarray usage messages} -returnCodes error -body {
testlinkarray
} -result {wrong # args: should be "testlinkarray option args"}
test link-9.2 {linkarray usage messages} -returnCodes error -body {
testlinkarray x
} -result {bad option "x": must be update, remove, or create}
test link-9.3 {linkarray usage messages} -body {
testlinkarray update
} -result {}
test link-9.4 {linkarray usage messages} -body {
testlinkarray remove
} -result {}
test link-9.5 {linkarray usage messages} -returnCodes error -body {
testlinkarray create
} -result {wrong # args: should be "testlinkarray create ?-readonly? type size name ?address?"}
test link-9.6 {linkarray usage messages} -returnCodes error -body {
testlinkarray create xx 1 my
} -result {bad type "xx": must be char, uchar, short, ushort, int, uint, long, ulong, wide, uwide, float, double, string, char*, or binary}
test link-9.7 {linkarray usage messages} -returnCodes error -body {
testlinkarray create char* 0 my
} -result {wrong array size given}
test link-10.1 {linkarray char*} -setup {
set mylist [list]
} -body {
testlinkarray create char* 1 ::my(var)
lappend mylist [set ::my(var) ""]
catch {set ::my(var) x} msg
lappend mylist $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{} {can't set "::my(var)": wrong size of char* value}}
test link-10.2 {linkarray char*} -body {
testlinkarray create char* 4 ::my(var)
set ::my(var) x
catch {set ::my(var) xyzz} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": wrong size of char* value}
test link-10.3 {linkarray char*} -body {
testlinkarray create -r char* 4 ::my(var)
catch {set ::my(var) x} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-11.1 {linkarray char} -setup {
set mylist [list]
} -body {
testlinkarray create char 1 ::my(var)
catch {set ::my(var) x} msg
lappend mylist $msg
lappend mylist [set ::my(var) 120]
catch {set ::my(var) 1234} msg
lappend mylist $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": variable must have char value} 120 {can't set "::my(var)": variable must have char value}}
test link-11.2 {linkarray char} -setup {
set mylist [list]
} -body {
testlinkarray create char 4 ::my(var)
catch {set ::my(var) {1 2 3}} msg
lappend mylist $msg
set ::my(var) {1 2 3 4}
lappend mylist $my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong dimension} {1 2 3 4}}
test link-11.3 {linkarray char} -body {
testlinkarray create -r char 2 ::my(var)
catch {set ::my(var) {1 2}} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-12.1 {linkarray unsigned char} -setup {
set mylist [list]
} -body {
testlinkarray create uchar 1 ::my(var)
catch {set ::my(var) x} msg
lappend mylist $msg
lappend mylist [set ::my(var) 120]
catch {set ::my(var) 1234} msg
lappend mylist $msg
catch {set ::my(var) -1} msg
lappend mylist $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": variable must have unsigned char value} 120 {can't set "::my(var)": variable must have unsigned char value} {can't set "::my(var)": variable must have unsigned char value}}
test link-12.2 {linkarray unsigned char} -setup {
set mylist [list]
} -body {
testlinkarray create uchar 4 ::my(var)
catch {set ::my(var) {1 2 3}} msg
lappend mylist $msg
set ::my(var) {1 2 3 4}
lappend mylist $my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong dimension} {1 2 3 4}}
test link-12.3 {linkarray unsigned char} -body {
testlinkarray create -r uchar 2 ::my(var)
catch {set ::my(var) {1 2}} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-13.1 {linkarray short} -setup {
set mylist [list]
} -body {
testlinkarray create short 1 ::my(var)
catch {set ::my(var) x} msg
lappend mylist $msg
lappend mylist [set ::my(var) 120]
catch {set ::my(var) 123456} msg
lappend mylist $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": variable must have short value} 120 {can't set "::my(var)": variable must have short value}}
test link-13.2 {linkarray short} -setup {
set mylist [list]
} -body {
testlinkarray create short 4 ::my(var)
catch {set ::my(var) {1 2 3}} msg
lappend mylist $msg
set ::my(var) {1 2 3 4}
lappend mylist $my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong dimension} {1 2 3 4}}
test link-13.3 {linkarray short} -body {
testlinkarray create -r short 2 ::my(var)
catch {set ::my(var) {1 2}} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-14.1 {linkarray unsigned short} -setup {
set mylist [list]
} -body {
testlinkarray create ushort 1 ::my(var)
catch {set ::my(var) x} msg
lappend mylist $msg
lappend mylist [set ::my(var) 120]
catch {set ::my(var) 123456} msg
lappend mylist $msg
catch {set ::my(var) -1} msg
lappend mylist $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": variable must have unsigned short value} 120 {can't set "::my(var)": variable must have unsigned short value} {can't set "::my(var)": variable must have unsigned short value}}
test link-14.2 {linkarray unsigned short} -setup {
set mylist [list]
} -body {
testlinkarray create ushort 4 ::my(var)
catch {set ::my(var) {1 2 3}} msg
lappend mylist $msg
set ::my(var) {1 2 3 4}
lappend mylist $my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong dimension} {1 2 3 4}}
test link-14.3 {linkarray unsigned short} -body {
testlinkarray create -r ushort 2 ::my(var)
catch {set ::my(var) {1 2}} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-15.1 {linkarray int} -setup {
set mylist [list]
} -body {
testlinkarray create int 1 ::my(var)
catch {set ::my(var) x} msg
lappend mylist $msg
lappend mylist [set ::my(var) 120]
catch {set ::my(var) 1e3} msg
lappend mylist $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": variable must have integer value} 120 {can't set "::my(var)": variable must have integer value}}
test link-15.2 {linkarray int} -setup {
set mylist [list]
} -body {
testlinkarray create int 4 ::my(var)
catch {set ::my(var) {1 2 3}} msg
lappend mylist $msg
set ::my(var) {1 2 3 4}
lappend mylist $my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong dimension} {1 2 3 4}}
test link-15.3 {linkarray int} -body {
testlinkarray create -r int 2 ::my(var)
catch {set ::my(var) {1 2}} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-16.1 {linkarray unsigned int} -setup {
set mylist [list]
} -body {
testlinkarray create uint 1 ::my(var)
catch {set ::my(var) x} msg
lappend mylist $msg
lappend mylist [set ::my(var) 120]
catch {set ::my(var) 1e33} msg
lappend mylist $msg
catch {set ::my(var) -1} msg
lappend mylist $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain ::my
} -result {{can't set "::my(var)": variable must have unsigned int value} 120 {can't set "::my(var)": variable must have unsigned int value} {can't set "::my(var)": variable must have unsigned int value}}
test link-16.2 {linkarray unsigned int} -setup {
set mylist [list]
} -body {
testlinkarray create uint 4 ::my(var)
catch {set ::my(var) {1 2 3}} msg
lappend mylist $msg
set ::my(var) {1 2 3 4}
lappend mylist $my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain ::my
} -result {{can't set "::my(var)": wrong dimension} {1 2 3 4}}
test link-16.3 {linkarray unsigned int} -body {
testlinkarray create -r uint 2 ::my(var)
catch {set ::my(var) {1 2}} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-17.1 {linkarray long} -setup {
set mylist [list]
} -body {
testlinkarray create long 1 ::my(var)
catch {set ::my(var) x} msg
lappend mylist $msg
lappend mylist [set ::my(var) 120]
catch {set ::my(var) 1e33} msg
lappend mylist $msg
} -match glob -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": variable must have * value} 120 {can't set "::my(var)": variable must have * value}}
test link-17.2 {linkarray long} -setup {
set mylist [list]
} -body {
testlinkarray create long 4 ::my(var)
catch {set ::my(var) {1 2 3}} msg
lappend mylist $msg
set ::my(var) {1 2 3 4}
lappend mylist $my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong dimension} {1 2 3 4}}
test link-17.3 {linkarray long} -body {
testlinkarray create -r long 2 ::my(var)
catch {set ::my(var) {1 2}} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-18.1 {linkarray unsigned long} -setup {
set mylist [list]
} -body {
testlinkarray create ulong 1 ::my(var)
catch {set ::my(var) x} msg
lappend mylist $msg
lappend mylist [set ::my(var) 120]
catch {set ::my(var) 1e33} msg
lappend mylist $msg
} -match glob -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": variable must have unsigned * value} 120 {can't set "::my(var)": variable must have unsigned * value}}
test link-18.2 {linkarray unsigned long} -body {
testlinkarray create ulong 1 ::my(var)
set ::my(var) 120
catch {set ::my(var) -1} msg
return $msg
} -match glob -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": variable must have unsigned * value}
test link-18.3 {linkarray unsigned long} -setup {
set mylist [list]
} -body {
testlinkarray create ulong 4 ::my(var)
catch {set ::my(var) {1 2 3}} msg
lappend mylist $msg
set ::my(var) {1 2 3 4}
lappend mylist $my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong dimension} {1 2 3 4}}
test link-18.4 {linkarray unsigned long} -body {
testlinkarray create -r ulong 2 ::my(var)
catch {set ::my(var) {1 2}} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-19.1 {linkarray wide} -setup {
set mylist [list]
} -body {
testlinkarray create wide 1 ::my(var)
catch {set ::my(var) x} msg
lappend mylist $msg
lappend mylist [set ::my(var) 120]
catch {set ::my(var) 1e33} msg
lappend mylist $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": variable must have wide integer value} 120 {can't set "::my(var)": variable must have wide integer value}}
test link-19.2 {linkarray wide} -setup {
set mylist [list]
} -body {
testlinkarray create wide 4 ::my(var)
catch {set ::my(var) {1 2 3}} msg
lappend mylist $msg
set ::my(var) {1 2 3 4}
lappend mylist $my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong dimension} {1 2 3 4}}
test link-19.3 {linkarray wide} -body {
testlinkarray create -r wide 2 ::my(var)
catch {set ::my(var) {1 2}} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-20.1 {linkarray unsigned wide} -setup {
set mylist [list]
} -body {
testlinkarray create uwide 1 ::my(var)
catch {set ::my(var) x} msg
lappend mylist $msg
lappend mylist [set ::my(var) 120]
catch {set ::my(var) 1e33} msg
lappend mylist $msg
lappend mylist [set ::my(var) 0xbabed00dbabed00d]
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": variable must have unsigned wide int value} 120 {can't set "::my(var)": variable must have unsigned wide int value} 0xbabed00dbabed00d}
test link-20.2 {linkarray unsigned wide} -body {
testlinkarray create uwide 1 ::my(var)
set ::my(var) 120
catch {set ::my(var) -1} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": variable must have unsigned wide int value}
test link-20.3 {linkarray unsigned wide} -setup {
set mylist [list]
} -body {
testlinkarray create uwide 4 ::my(var)
catch {set ::my(var) {1 2 3}} msg
lappend mylist $msg
set ::my(var) {1 2 3 4}
lappend mylist $my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong dimension} {1 2 3 4}}
test link-20.4 {linkarray unsigned wide} -body {
testlinkarray create -r uwide 2 ::my(var)
catch {set ::my(var) {1 2}} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-21.1 {linkarray string} -setup {
set mylist [list]
} -body {
testlinkarray create string 1 ::my(var)
lappend mylist [set ::my(var) ""]
lappend mylist [set ::my(var) "xyz"]
lappend mylist $::my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{} xyz xyz}
test link-21.2 {linkarray string} -body {
testlinkarray create -r string 4 ::my(var)
catch {set ::my(var) x} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
test link-22.1 {linkarray binary} -setup {
set mylist [list]
} -body {
testlinkarray create binary 1 ::my(var)
set ::my(var) x
catch {set ::my(var) xy} msg
lappend mylist $msg
lappend mylist $::my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong size of binary value} x}
test link-22.2 {linkarray binary} -setup {
set mylist [list]
} -body {
testlinkarray create binary 4 ::my(var)
catch {set ::my(var) abc} msg
lappend mylist $msg
catch {set ::my(var) abcde} msg
lappend mylist $msg
set ::my(var) abcd
lappend mylist $::my(var)
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {{can't set "::my(var)": wrong size of binary value} {can't set "::my(var)": wrong size of binary value} abcd}
test link-22.3 {linkarray binary} -body {
testlinkarray create -r binary 4 ::my(var)
catch {set ::my(var) xyzv} msg
return $msg
} -cleanup {
testlinkarray remove ::my(var)
unset -nocomplain my
} -result {can't set "::my(var)": linked variable is read-only}
catch {testlink set 0 0 0 - 0 0 0 0 0 0 0 0 0 0}
catch {testlink delete}
+42 -2
View File
@@ -95,7 +95,7 @@ proc TestOp {op args} {
}
return [lindex $results 0]
}
# start of tests
namespace eval ::testmathop {
@@ -1342,6 +1342,46 @@ test mathop-26.2 { misc ops, corner cases } {
set res
} [list 2147483648 9223372036854775808 9223372036854775808 4294967296 18446744073709551616]
test mathop-27.1 {lt operator} {::tcl::mathop::lt} 1
test mathop-27.2 {lt operator} {::tcl::mathop::lt a} 1
test mathop-27.3 {lt operator} {::tcl::mathop::lt a b} 1
test mathop-27.4 {lt operator} {::tcl::mathop::lt b a} 0
test mathop-27.5 {lt operator} {::tcl::mathop::lt a a} 0
test mathop-27.6 {lt operator} {::tcl::mathop::lt a b c} 1
test mathop-27.7 {lt operator} {::tcl::mathop::lt b a c} 0
test mathop-27.8 {lt operator} {::tcl::mathop::lt a c b} 0
test mathop-27.9 {lt operator} {::tcl::mathop::lt 012 0x0} 1
test mathop-28.1 {le operator} {::tcl::mathop::le} 1
test mathop-28.2 {le operator} {::tcl::mathop::le a} 1
test mathop-28.3 {le operator} {::tcl::mathop::le a b} 1
test mathop-28.4 {le operator} {::tcl::mathop::le b a} 0
test mathop-28.5 {le operator} {::tcl::mathop::le a a} 1
test mathop-28.6 {le operator} {::tcl::mathop::le a b c} 1
test mathop-28.7 {le operator} {::tcl::mathop::le b a c} 0
test mathop-28.8 {le operator} {::tcl::mathop::le a c b} 0
test mathop-28.9 {le operator} {::tcl::mathop::le 012 0x0} 1
test mathop-29.1 {gt operator} {::tcl::mathop::gt} 1
test mathop-29.2 {gt operator} {::tcl::mathop::gt a} 1
test mathop-29.3 {gt operator} {::tcl::mathop::gt a b} 0
test mathop-29.4 {gt operator} {::tcl::mathop::gt b a} 1
test mathop-29.5 {gt operator} {::tcl::mathop::gt a a} 0
test mathop-29.6 {gt operator} {::tcl::mathop::gt c b a} 1
test mathop-29.7 {gt operator} {::tcl::mathop::gt b a c} 0
test mathop-29.8 {gt operator} {::tcl::mathop::gt a c b} 0
test mathop-29.9 {gt operator} {::tcl::mathop::gt 0x0 012} 1
test mathop-30.1 {ge operator} {::tcl::mathop::ge} 1
test mathop-30.2 {ge operator} {::tcl::mathop::ge a} 1
test mathop-30.3 {ge operator} {::tcl::mathop::ge a b} 0
test mathop-30.4 {ge operator} {::tcl::mathop::ge b a} 1
test mathop-30.5 {ge operator} {::tcl::mathop::ge a a} 1
test mathop-30.6 {ge operator} {::tcl::mathop::ge c b a} 1
test mathop-30.7 {ge operator} {::tcl::mathop::ge b a c} 0
test mathop-30.8 {ge operator} {::tcl::mathop::ge a c b} 0
test mathop-30.9 {ge operator} {::tcl::mathop::ge 0x0 012} 1
if 0 {
# Compare ops to expr bytecodes
namespace import ::tcl::mathop::*
@@ -1354,7 +1394,7 @@ if 0 {
_X 3 4 5
set ::tcl_traceCompile 0
}
# cleanup
namespace delete ::testmathop
namespace delete ::testmathop2
+2 -2
View File
@@ -2549,7 +2549,7 @@ test oo-16.17 {OO: object introspection: creationid #500} -body {
test oo-16.18 {OO: object introspection: creationid #500} -body {
info object creationid
} -returnCodes error -result {wrong # args: should be "info object creationid objName"}
test oo-16.18 {OO: object introspection: creationid #500} -body {
test oo-16.18.1 {OO: object introspection: creationid #500} -body {
info object creationid oo::object gorp
} -returnCodes error -result {wrong # args: should be "info object creationid objName"}
test oo-16.19 {OO: object introspection: creationid #500} -setup {
@@ -4095,7 +4095,7 @@ test oo-32.6 {TIP 516: slots - class test} -setup [SampleSlotSetup {
} -cleanup [SampleSlotCleanup {
rename sampleSlot {}
}] -result {0 {} {g h i a b c} {1 Resolve g 1 Resolve h 1 Resolve i 1 Get 1 Set {g h i a b c}}}
test oo-32.6 {TIP 516: slots - class test} -setup [SampleSlotSetup {
test oo-32.7 {TIP 516: slots - class test} -setup [SampleSlotSetup {
SampleSlot create sampleSlot
}] -body {
list [info level] [sampleSlot -remove c a] \

Some files were not shown because too many files have changed in this diff Show More