Compare commits

...
779 Commits
Author SHA1 Message Date
jan.nijtmans 084fba1d17 \Merge 8.7 2018-09-28 19:59:40 +00:00
jan.nijtmans 3f2c2080cc Merge 8.6 2018-09-28 18:49:45 +00:00
jan.nijtmans 3d5f129cb0 Another patch contributed by Gustaf Neumann: shifting negative numbers is undefined behavior in the C standard
https://stackoverflow.com/questions/8415895/is-left-and-right-shifting-negative-integers-defined-behavior
2018-09-28 18:45:34 +00:00
jan.nijtmans 6d137e77a5 nmake build fixes for zipfs (ongoing, zip attachments not done yet) 2018-09-28 18:21:10 +00:00
dkf 4ee2aeb33d Small fixes to unix makefile 2018-09-28 13:59:19 +00:00
dkf fd03d49b6f Better phrasing from TIP 509 2018-09-28 09:54:24 +00:00
dkf 29fbee5784 Implement TIP 509: reentrant mutexes on all platforms 2018-09-28 09:50:58 +00:00
dkf eede8c60a1 Clean up code style and add key phrases to documentation. 2018-09-28 09:49:57 +00:00
dkf 9dabbdf40b merge core-8-branch 2018-09-28 09:18:49 +00:00
dkf 2f3fc1cfa2 Fix minor typo 2018-09-28 07:24:59 +00:00
jan.nijtmans 66dc9d1fbf Merge 8.7 2018-09-27 21:46:24 +00:00
dkf b1e6b58b6a Implementation of TIP 426: Determining the "Type" of Commands 2018-09-27 11:08:14 +00:00
dkf 6ec7c04557 Restricted the information made available to safe interpreters a bit. 2018-09-27 11:06:59 +00:00
dkf bfdc5233eb merge core-8-branch 2018-09-27 08:24:26 +00:00
dkf 1146932b9e Implementation of TIP 505: Make [lreplace] Accept All Out-of-Range Index Values 2018-09-27 08:22:07 +00:00
dkf 6cdb3193ec Implementation of TIP 505: Make [lreplace] Accept All Out-of-Range Index Values 2018-09-27 08:19:18 +00:00
dkf bf46b6a1da Updated documentation 2018-09-27 07:44:50 +00:00
dkf 00d5f9266b Implementation of TIP 516: More OO Slot Operations and TIP 515: Level Value Reform 2018-09-27 07:25:04 +00:00
dkf efa79f01e6 Implementation of TIP 516: More OO Slot Operations 2018-09-27 07:22:42 +00:00
jan.nijtmans 9f745ab1cd Implementatin of TIP #515: Level Value Reform 2018-09-26 23:43:00 +00:00
dkf f0ab769a7c Implementation of TIP 508: [array default] 2018-09-26 23:17:48 +00:00
jan.nijtmans 59f808eb7a Improvements for zipfs. Document that TclZipfs_AppHook only works on Windows in UNICODE mode. Also, remove this from the stub table because it should never be called this way.
Prevent a possible crash on win32 startup.
2018-09-26 19:38:08 +00:00
dkf 9aa47b2cfa Improved comment. 2018-09-26 13:09:20 +00:00
dkf 761a7867d5 Make defaults work even when [upvar]ed to just a non-existent element. 2018-09-26 13:08:46 +00:00
dkf 46c087f956 merge core-8-branch 2018-09-26 09:47:14 +00:00
dkf 3b77852126 Fix semantics of [lappend] with defaults in a procedure. 2018-09-26 08:12:34 +00:00
jan.nijtmans f0f3d8a55b merge 8.6 2018-09-25 21:18:03 +00:00
jan.nijtmans d5583552c0 Contributed patch from Gustaf Neumann, preventing problems where "localCachePtr" can be NULL 2018-09-25 21:16:32 +00:00
dgp 71e4ddb74f merge 8.7 2018-09-25 13:31:19 +00:00
dkf b1f92f4888 Added test cases for errors 2018-09-25 10:18:32 +00:00
dkf beac2287a9 Corrected the semantics of [append] with defaults 2018-09-25 07:36:09 +00:00
dkf 7b0e9cef60 More correct variable existence checks 2018-09-25 07:27:31 +00:00
dkf 76e2e078e3 Correct variable existence check in [array default exists] 2018-09-25 07:24:44 +00:00
dkf 036cd8c9be merge core-8-branch 2018-09-25 07:24:04 +00:00
jan.nijtmans ac61d77a41 More fixes in Tcl_WinTChar2Utf: Don't restart loop when output contains null-byte. 2018-09-24 23:24:00 +00:00
dgp d0fab95780 merge 8.6 2018-09-24 16:19:17 +00:00
dgp 338b9ec9d2 Silence debugging message in test suite. 2018-09-24 16:15:25 +00:00
dkf 4719e1f68d Add tests. Exposes quite a few bugs in the implementation... 2018-09-24 08:21:36 +00:00
dkf be629669a5 Added docs 2018-09-23 17:29:46 +00:00
dkf 8a6dda8529 merge core-8-branch 2018-09-23 16:42:11 +00:00
jan.nijtmans 243ea5f7a3 Merge 8.6 2018-09-23 13:29:42 +00:00
jan.nijtmans 6d3aeef45e Give lambda function a name "ReceiveChunked" for easier testing. New function quoteString and code cleanup 2018-09-23 13:27:14 +00:00
jan.nijtmans fbdc68b6a2 Handle the (unlikely) case that Tcl_DStringSetLength() results in a re-allocation of the buffer 2018-09-22 16:51:43 +00:00
jan.nijtmans d6a9a5d664 Merge 8.7 2018-09-22 13:24:33 +00:00
jan.nijtmans 9f9a9e291d Change ULLONG_MAX -> UWIDE_MAX, LLONG_MAX -> WIDE_MAX and LLONG_MIN -> WIDE_MIN everywhere, because not all platforms equal Tcl_WideInt type as equal to "long long". This should fix test-cases on platforms where Tcl_WideInt != long long, and have no effect on 'normal' platforms 2018-09-22 13:18:49 +00:00
jan.nijtmans 4ec357c743 merge 8.7 2018-09-22 12:45:29 +00:00
jan.nijtmans 31b9d1f712 Fix a couple of test-cases, since http1.0 is no longer there 2018-09-22 12:29:46 +00:00
jan.nijtmans 25ac7e62ba forgot one location for http version number 2018-09-22 12:05:14 +00:00
jan.nijtmans 854cf964d2 Merge 8.6 2018-09-22 10:21:36 +00:00
jan.nijtmans 63ef0e3d26 Update http version number, and fix some related test-cases 2018-09-22 10:20:28 +00:00
jan.nijtmans df89a7f211 Prevent possible build order problem, due to missing dde/registry dll's.
Make sure that Tcl_WinTChar2Utf() never produces intermediate null-bytes.
2018-09-22 10:09:23 +00:00
dkf d025ae5c08 merge core-8-branch 2018-09-21 09:29:24 +00:00
kjnash 39318d91b7 merge bug-46b6edad51-concurrent-http 2018-09-20 13:41:13 +00:00
kjnash d24a3eb2ba merge 8.6 2018-09-15 18:41:23 +00:00
jan.nijtmans bd42171094 missing type-cast 2018-09-13 20:37:44 +00:00
jan.nijtmans c5943ec574 Eliminate the use of macro's like LLONG_MAX|MIN, since they assume that Tcl_WideInt equals "long long". Also eliminate uses of Tcl_WideAsLong() and friends, as - often - simple type cases make things more clear. 2018-09-13 20:33:58 +00:00
jan.nijtmans f11320b6b0 Fix various test-cases, which started failing on Windows due to TIP #430 2018-09-13 20:31:45 +00:00
jan.nijtmans 1775284940 Fix test-case registry-6.20, which started failing starting with the TIP #389 commit. 2018-09-13 20:30:20 +00:00
jan.nijtmans 3200ec75ef Stub fix, safe interpreter fix, and use more size_t wherever possible 2018-09-12 19:32:31 +00:00
jan.nijtmans 9b45aaa5b0 TIP #430 implementation 2018-09-12 19:30:00 +00:00
jan.nijtmans 1a3cef4874 Make ready for TIP #494 compatibility 2018-09-11 22:41:00 +00:00
dkf 90e3bdc291 Simplify the slot resolution protocol 2018-09-11 07:44:04 +00:00
dgp cdce5491b3 Rebase TIP 505 implementation a patch for 8.6. 2018-09-10 15:28:23 +00:00
dkf 4f17861678 Tests and docs 2018-09-10 08:33:11 +00:00
jan.nijtmans 0babbf966b slightly better: Use GetFileSizeEx() on win64 and GetFileSize on win32 2018-09-09 17:05:38 +00:00
jan.nijtmans a35eba4ac2 Merge core-8-branch 2018-09-08 21:18:57 +00:00
dkf 0d73b8a7c0 Implementation of TIP 516 2018-09-08 12:52:06 +00:00
jan.nijtmans 945b10776d Merge 8.6 2018-09-07 22:23:00 +00:00
sebres 9a15a1b586 small code review (duplicate code removed) 2018-09-07 14:24:49 +00:00
dgp 4b7caf2e4a merge 8.6 2018-09-07 12:11:01 +00:00
dgp 95db69f27b Added test for [631b4c45df]. 2018-09-07 12:04:32 +00:00
sebres e94df65350 merge 8.6 (segfault fix) 2018-09-07 12:02:25 +00:00
jan.nijtmans b8d2426e1b Use GetFileSizeEx() in stead of GetFileSize(), to get the file size on Windows.
Minor improvement: attach empty .zip file to tclsh.exe (both for Windows and UNIX), zo "zip -A" can be used to modify its zip contents.
2018-09-07 11:56:40 +00:00
sebres e80eaec4d3 amend to [e8ab4d85fa], proc.test: extended with new test-case to cover situation like [631b4c45df] 2018-09-07 11:55:01 +00:00
sebres b9577c0641 closes [631b4c45df]: segfault by usage of wrong length (no string representation) 2018-09-07 10:45:30 +00:00
jan.nijtmans 833b02bc83 TIP #515 implementation: Level Value Reform 2018-09-07 09:53:17 +00:00
jan.nijtmans 6269e32c3b Bug-fix: Move TclZipfs_AppHook() from 0 -> 2 in the stub table, otherwise it overrides the entry for Tcl_MacOSXOpenBundleResources (since MacOSX is UNIX as well...). 2018-09-06 11:25:41 +00:00
jan.nijtmans 3e7ffcaf4b Code review 2018-09-06 09:47:30 +00:00
jan.nijtmans 5c9968a001 Minor code cleanup.
win/tclWinPipe.c: Eliminate some compiler warnings on mingw-w64
win/tclWinNotify.c: Eliminate tsdPtr->timeout variable, since it's only being written to.
other files: code cleanup, eliminate unnecessary type casts
2018-09-05 12:11:13 +00:00
dkf fbef9aa840 merge core-8-branch 2018-09-04 19:47:55 +00:00
jan.nijtmans fdf1df3b29 Fix [540bed4bde]: binary format can result in "integer value too large to represent".
Implemented a new utility function TclGetWideBitsFromObj(), which handles the overflowing of integers using bignums. 
This function can be used in a _LOT_ of other places, preventing code duplication. Done that as well.
Those changes have no effect on other commands, only two new "binary format" test-cases for this specific situation: binary-44.5 and binary-44.6
2018-09-04 14:37:01 +00:00
jan.nijtmans 2f2b7f6ac7 Eliminate use of wideBiggerThanInt test constraint, since it's the same as {longIs32bit wideIs64bit}. And ... it's name is actually wrong ...
Don't use int() any more in any test constraint, since it's semantics might change. We don't want the test constraints to change with it. (See: TIP# 514)
Simplify implementation of wideIs64bit test constraint, just testing for 64-bit sign bit is enough.
2018-09-03 12:53:15 +00:00
dkf 5f1bd2f2e3 Implement TIP 478: Add Expected Class Level Behaviors to oo::class 2018-09-02 13:48:22 +00:00
sebres 0787b1d152 merge 8.6 2018-08-30 11:14:15 +00:00
sebres cb9f3f9268 merge 8.5 2018-08-30 11:13:09 +00:00
sebres 6d88b01d1e test-cases to cover quoting of the newline character, and the documentation extended. 2018-08-30 11:08:51 +00:00
sebres 6dfe3f5de6 merge 8.6 2018-08-29 17:01:22 +00:00
sebres 77a26f5c95 merge 8.5 2018-08-29 16:59:10 +00:00
sebres 9cec6bac27 tcltest: forgotten built-in constraint "slowTest" 2018-08-29 16:58:06 +00:00
sebres 2f19b0f346 small amend to [cae24931ed] (no _CRT_glob in both cases __GNUC__ || TCL_BROKEN_MAINARGS). 2018-08-29 16:55:36 +00:00
sebres 265c9d416f partially cherry-picking of [5099a81b50], never reached 8.6, so for example build for MINGW breaks tests winpipe-8.1 etc, because "*" will be expanded. 2018-08-29 15:55:13 +00:00
sebres db610f91eb code review after merge with 8.5 (restore usage of some functions, after lost by conflict resolving) 2018-08-29 15:49:19 +00:00
sebres afb5bf5583 merge 8.5 ([21b0629c81] 0-day vulnerability - insufficient escape by exec of batch-files for windows) 2018-08-29 15:41:55 +00:00
sebres 9b7ce068fe closes [21b0629c81] 0-day vulnerability - insufficient escape by exec of batch-files for windows 2018-08-29 14:45:57 +00:00
dkf d4d1014e7d merge core-8-branch 2018-08-26 11:07:37 +00:00
sebres 820a737a2f code review, skip slow test winpipe-8.2 executed args from injectList particularly (normally winpipe-8.3 covers the same but jointly), to enable use parameter -constraints slowTest, added new test with randomly generated potentially dangerous args 2018-08-23 10:26:03 +00:00
sebres c2d61d8dbc code review, restored backwards compatibility of the simplest escape of quote-chars (so reverted several tests winpipe-7.x) 2018-08-23 08:00:32 +00:00
sebres fb0bf9d1b9 fixes escape for special cases (+ more test-cases):
- `%` char to be escaped (quoted) in any case (regardless pairing flag), otherwise `%username%` will be interpolated as username.
- escape of multiple backslashes before quote is different (as without following quote) in unpaired quote syntax (upaired flag set)
2018-08-21 18:52:21 +00:00
sebres 01dd016ad8 because executable (1st argument) always proper escaped now, don't need to replace long path name of batch-executable with short path name (reduced to 16-bit applications only). 2018-08-20 19:58:44 +00:00
sebres d660b325b5 small amend: avoid reset of unpaired quote flag between arguments (previous affects next) + test cases extended with several injection checks. 2018-08-20 16:15:37 +00:00
sebres 26b477b907 win: fixes [21b0629c81] - exec/open process pipe under windows (0-day vulnerability - insufficient escape) 2018-08-20 14:35:44 +00:00
jan.nijtmans 89ff80fbdd merge-mark 2018-08-19 09:16:30 +00:00
jan.nijtmans b3993adcfb Merge 8.6 2018-08-17 22:21:12 +00:00
jan.nijtmans 90afac281e Minor fix to entier(): Allow it to convert to "wideInt" as well when range is appropriate 2018-08-17 22:15:49 +00:00
sebres aed158b518 win: TclpCreateProcess or [exec process ...] - search for application extended with ".cmd" extension:
automatically tries appending ".com", ".exe", ".bat" and ".cmd", in that order, to the name, looking for an executable.
(partially cherry-picked from 8.6 branch)
2018-08-17 18:26:10 +00:00
hypnotoad 9b285dde85 Merging changes with 8.7 2018-08-14 08:46:22 +00:00
pooryorick e5270637c0 Reposition the MODULE_SCOPE definition so that packages like tbcload don't get
an error when they include tclPort.h.
2018-08-14 05:43:17 +00:00
dkf f5efc84600 Added a note about the genesis of the compiled header. 2018-08-11 12:01:06 +00:00
dkf 245151ad96 Improve script compilation. Prove that compilation works with safe interps. 2018-08-11 11:18:20 +00:00
pooryorick 65f3d0f56b Repair breakage in recent refactoring of env.test. 2018-08-10 18:57:53 +00:00
pooryorick 18c102aa70 minor changes to documentation 2018-08-10 18:44:41 +00:00
pooryorick e53f3cf9c6 Tighten up SaveResult.3, make installManPage more robust against newlines. 2018-08-10 15:03:14 +00:00
dgp 6c78bf0adc Repair breakage in recent refactoring of env.test 2018-08-08 20:48:06 +00:00
jan.nijtmans 12647cc4fb Merge 8.6 2018-08-08 06:46:31 +00:00
jan.nijtmans 8346cad0dd Fix harmless gcc warning 2018-08-08 06:45:29 +00:00
jan.nijtmans 620b4d531d merge 8.6 (test cases fix in ioTrans) 2018-08-07 08:22:28 +00:00
dkf ed3e9c60ba Combine the two bits of scripted code inside TclOO's definition into one. 2018-08-05 20:14:04 +00:00
dkf d87884d51b Make it much easier to maintain the TclOO initialisation script. 2018-08-05 15:01:30 +00:00
sebres de5637f853 ioTrans.test: fixed cleanup - avoids error deleting "tempchanfile": permission denied: file seems to be locked/opened inside interp $idb 2018-08-03 13:46:30 +00:00
jan.nijtmans 40947c7d3e Purge end-of-line spacing 2018-08-02 22:37:00 +00:00
jan.nijtmans cff4a9d980 merge 8.6 2018-07-31 20:22:18 +00:00
jan.nijtmans c1ae69114b Remove some actually dead code 2018-07-31 19:49:51 +00:00
sebres ad757b50dc merge 8.6: bug [d051b77fc1] fixed 2018-07-26 18:58:03 +00:00
sebres 5902889825 amend after merge: 8.6th provide additionally an error-code (so missing errCode = "OVERFLOW") 2018-07-26 18:56:41 +00:00
sebres 04c687936c merge 8.5 - bug [d051b77fc1] fixed 2018-07-26 18:51:03 +00:00
sebres 304b569170 merge test cases from 8.6 2018-07-26 18:15:17 +00:00
sebres 2133e40e58 amend to [d498578df4], still one test for [Bug ba921a8d98] with inplace by subst inside string (compiled as "strcat" instruction) 2018-07-26 18:07:34 +00:00
sebres c7cdc550c4 test cases added to cover width overflow by format (should cause limit exceeded) 2018-07-26 16:46:47 +00:00
dgp 7633450128 [ba921a8d98] Make sure [string cat] includes all data from all bytearrays. 2018-07-26 16:14:44 +00:00
sebres 7e727bed70 closes [d051b77fc18d7340]: fixed segfault by integer overflow (if width by format like "%4000000000g" overflows to negative values by scan of length) 2018-07-26 15:57:38 +00:00
dgp 164a7f04c0 New test for [Bug ba921a8d98]. 2018-07-26 15:51:28 +00:00
Kevin B Kenny 54fbd7dbcb Resolve inadvertent fork 2018-07-25 01:43:43 +00:00
pooryorick 772d2da10b Fix for [ba921a8d98e02a96] - concatenating binary array with empty string yields the empty string. 2018-07-22 20:44:16 +00:00
Kevin B Kenny 0ae1df9bfc Merge 8.6: Add a note in the 'clock' man page about the interpretation of impossible values on [clock scan] 2018-07-21 18:45:41 +00:00
Kevin B Kenny 814c867db4 Add a note in the 'clock' man page about the interpretation of impossible values on [clock scan] 2018-07-21 18:45:09 +00:00
sebres 6667ddcb54 merge 8.6 2018-07-20 16:05:48 +00:00
sebres d00a212e82 win: avoids warning by x64-build in function 'TclWinCPUID' - pointer targets in passing argument 1 of '__cpuid' differ in signedness [-Wpointer-sign] (int* vs unsigned int*) 2018-07-20 15:58:56 +00:00
sebres 7fb72851e8 win: fixes x64-build within gcc-compile runtime env for (mingw64, etc): "$do64bit" may be "amd64|x64|yes", so it could find & copy wrong zlib.dll. 2018-07-20 15:54:11 +00:00
sebres 4a3f32b84a win: fixed test-cases (see [525ccacaef]) running under windows outside of temp-folder 2018-07-16 13:59:29 +00:00
dkf 77aceb5c5f Added more tests and made [initialize] an alternate spelling for [initialise]. 2018-07-15 15:46:33 +00:00
sebres 8a7c004dbc merge 8.6 2018-07-12 15:31:27 +00:00
sebres a1790a1683 merge 8.5 2018-07-12 14:25:09 +00:00
sebres 885a163b3c win: closes [3f7af0e21e13f1f5] - avoid "permissions denied" by file delete, if file stat (TclpObjStat) used internally in other worker, for example by usage of file mkdir etc. 2018-07-12 14:17:57 +00:00
sebres 87e508c590 amend to [1830f9f520e2abdd], fixed package.test if built without test - avoids test file error: package "Tcltest" isn't loaded statically 2018-07-10 08:19:08 +00:00
sebres a76637248c merge 8.6 2018-07-09 19:03:38 +00:00
sebres 2a46a48670 merge 8.5 2018-07-09 18:15:34 +00:00
sebres 51aecf205d closes [270f78ca95b642fb]: fix the race condition for file mkdir if some worker deletes directory immediately after the succeded create inside 3rd worker. 2018-07-09 17:18:07 +00:00
dkf d0f8889c8f And another test 2018-07-07 08:57:49 +00:00
dkf 27110774bd Added direct tests for [myclass] 2018-07-07 08:45:00 +00:00
dkf 5a06fd4bcf Document the [myclass] command; someone might find it useful besides me. 2018-07-07 08:22:13 +00:00
dkf 969f9f571c Improving the singleton 2018-07-06 13:50:54 +00:00
jan.nijtmans 64cbe6e187 Merge 8.6. Also remove a useless #undef/#define which will be overrided later. 2018-07-05 19:46:24 +00:00
jan.nijtmans 367ce9ad48 tclDictObj.c:366: warning: dereferencing type-punned pointer will break strict-aliasing rules
Prevent this warning, which gcc 4.4 (a.o.) gives on this construct. void pointers work well already in whatever assignment.
2018-07-05 19:39:19 +00:00
jan.nijtmans 6982ae0ca7 Make Tcl_GetUnicode() a macro. Mark many other stub-entries which are no longer are in use (because they were converted to macros) as deprecated, since they will be removed in Tcl 9.0 2018-07-04 20:20:28 +00:00
jan.nijtmans da7eafc83b Micro-optimization in Tcl_GetString() and Tcl_GetStringFromObj() 2018-07-04 20:18:39 +00:00
dkf 414bcee273 Documentation for [classmethod] 2018-07-02 07:44:09 +00:00
dkf d11660acfe Create a special command, [ :my:class], (in each instance namespace) that allows objects to delegate methods to their class. 2018-07-01 16:39:11 +00:00
dkf 5c7ba37901 More docs 2018-06-30 21:36:01 +00:00
dkf 1d1e95e779 More docs 2018-06-30 18:30:53 +00:00
dkf bffb982059 More docs 2018-06-30 13:44:25 +00:00
dkf 0978bd50ce Started to write documentation 2018-06-30 05:13:39 +00:00
dkf 3f8c7d5d40 More test cases. More fixes. 2018-06-29 07:15:06 +00:00
dkf 4c24e60418 Split out TIP 478 tests into their own file. 2018-06-28 10:40:37 +00:00
dkf 8219fb2632 Tests for abstract and singleton 2018-06-28 08:12:07 +00:00
dkf 082e8c6d7a Add better error handling and make the delegation work with cloning. 2018-06-27 07:39:49 +00:00
jan.nijtmans 7a9d97826e Since Tcl is always compiled with -DUNICODE -D_UNICODE (on Windows) and we know TCL_UTF_MAX>=4, we can simplify things. No change in functionality. 2018-06-26 19:45:22 +00:00
dgp 9683822257 merge 8.6 2018-06-26 17:07:02 +00:00
dgp 9da2aebeae Use a thread exit handler, and not a custom exit proc for package cleanup. 2018-06-26 17:00:29 +00:00
dgp bf884c9bc9 merge 8.6 2018-06-26 14:23:22 +00:00
dgp ed5ed756bc Restore lost tests. 2018-06-26 14:22:08 +00:00
jan.nijtmans fdee46ab16 merge 8.6 2018-06-25 20:38:16 +00:00
jan.nijtmans 0839047d8b Simplify ToUtf(), expecially for TCL_UTF_MAX>3 (with correct surrogate handling).
Fix various typo's
2018-06-25 07:22:19 +00:00
jan.nijtmans 94f9cf81ed Fix "string tolower" and friends for handling unpaired surrogates correctly. Also add test-cases for those situations.
Various typo's in comments.
2018-06-24 20:26:27 +00:00
pooryorick e2a79c2604 Fix for [3592747]: Let TclNRTailcallEval handle namespace problems. 2018-06-24 07:17:46 +00:00
dkf 05209c57d3 Make the delegates work by moving their creation into C. 2018-06-23 15:03:26 +00:00
pooryorick 6cbfdcc4a3 Add a test for no generation of a string representation when comparing with the
empty string.
2018-06-23 14:18:06 +00:00
pooryorick 94ec3d9431 Add another suppress rule for valgrind, factor test code into
tests/tcltests.tcl, and constrained a some tests in the valgrind case.
2018-06-22 15:10:04 +00:00
pooryorick 6c1e9f2b0c merge pyk-tcltest-exit 2018-06-21 22:44:04 +00:00
pooryorick 563bd6e4dd Fix function signature of TclThreadTestFinalize. 2018-06-21 22:43:18 +00:00
pooryorick b418ff1759 merge pyk-tcltest-exit 2018-06-21 22:23:04 +00:00
pooryorick 56ca35e8a9 Add custom exit procedure for tcltests executable. 2018-06-21 22:21:31 +00:00
pooryorick 107fb1eb33 Suppress more valgrind "still reachable" reports and ensure that threads are
fully finalized in thread tests.
2018-06-21 22:16:29 +00:00
pooryorick c911dc937f Add valgrind suppression for dlopen and ensure that processes are reaped in
http11.test.
2018-06-20 19:06:40 +00:00
pooryorick 645241afc1 Remove recent auto_path modification in tests/all.tcl and suppress more
valgrind reports.
2018-06-20 08:03:22 +00:00
pooryorick 03a3c09b1f new file: tools/valgrind_suppress. num-callers bumped from 8 to 24. Valgrind
now issues no "still reachable" reports for cmdAH.test.
2018-06-19 11:47:08 +00:00
jan.nijtmans 5c87050dd8 Merge 8.6. And add more documentation and test-cases regarding the behavior of Tcl_UniCharToUtf() 2018-06-18 15:59:19 +00:00
jan.nijtmans 3c57d80efe Fix [53cad613d8]: TIP 389 implementation makes Tk tests font-4.12 and font-4.15 fail. One more situation in which high surrogate causes problem 2018-06-18 15:54:38 +00:00
jan.nijtmans 04004f3abc Unbreak build on Windows (and - most likely - some other platforms too) 2018-06-18 15:51:43 +00:00
pooryorick 155e8a1ad5 Avoid valgrind "still reachable" reports stemming from early termination of
threads.
2018-06-18 08:09:32 +00:00
pooryorick 625aca976a Full cleanup of env cache when in a PURIFY build. 2018-06-18 07:06:04 +00:00
pooryorick e9c0ec1219 Plug leak in TclSetEnv. 2018-06-18 05:59:22 +00:00
dkf 8e696a5e5d Leaving out the weird delegates stops the test failures. 2018-06-17 17:27:41 +00:00
dkf 9e511d7874 Most of the implementation ported over. [classmethod] is trickier... 2018-06-17 16:47:45 +00:00
jan.nijtmans 5af99f55b2 merge 8.6 2018-06-17 16:11:50 +00:00
jan.nijtmans 8047a470ef Fix [53cad613d8a4de166e680f09a6c6399ebddbc17c|53cad613d8]: TIP 389 implementation makes Tk tests font-4.12 and font-4.15 fail. (Fix it in 8.6 too, for benefit of androwish) 2018-06-17 16:07:09 +00:00
dkf 1f91c778bb Split scripted parts of TclOO into their own file. 2018-06-17 15:42:58 +00:00
pooryorick 2b739c838a Remove dependencies between tests in env.test. 2018-06-17 08:47:29 +00:00
pooryorick dd713ee96e Add tests/tcltests.tcl as a place to store common code for tests. 2018-06-16 22:57:36 +00:00
pooryorick 983854ad7b Add tests/tcltests.tcl as a place to store common code for tests. 2018-06-16 22:56:07 +00:00
dkf 7bf68c2335 Add in basic github meta-files to reduce problems with issues being filed where we don't see them. 2018-06-16 18:07:30 +00:00
pooryorick 41a6159754 new package
tcltests
exclude some exec.test tests when running under valgrind
2018-06-16 17:55:31 +00:00
jan.nijtmans c9802b0230 merge 8.6 2018-06-15 18:37:45 +00:00
jan.nijtmans df97278634 merge 8.5 2018-06-15 18:35:56 +00:00
jan.nijtmans 06fc5fb636 Align common install locations in SC_PATH_TCLCONFIG and SC_PATH_TKCONFIG. Add FreeBSD (closes [d6d60efd35]) and OpenBSD 8.5 paths 2018-06-15 18:31:24 +00:00
pooryorick 15f804e04e new package
tcltests
exclude some exec.test tests when running under valgrind
2018-06-15 13:17:17 +00:00
dgp e5de25734f merge 8.6 2018-06-13 16:12:54 +00:00
dgp e393000b1d merge 8.5 2018-06-13 16:06:38 +00:00
dgp 83d92bd747 Stop creating a stray child process. 2018-06-13 15:59:15 +00:00
pooryorick 33b8401436 Avoid valgrind "still reachable" reports stemming from early termination of
threads.
2018-06-13 10:49:25 +00:00
hypnotoad d62033b7e2 Adding typecasts in tclZipfs.c to eliminate a compiler warning 2018-06-12 19:32:03 +00:00
dgp 1b3a0a73ae Remove AbsolutePath(), no longer used. 2018-06-12 19:16:38 +00:00
dgp 9e3e0498e7 merge 8.7 2018-06-12 19:14:47 +00:00
dgp 0d36d5f3d8 merge 8.7 2018-06-12 18:03:09 +00:00
dgp a54459bed6 close fork 2018-06-12 18:02:24 +00:00
dgp b5e61d9f54 merge 8.6 2018-06-12 17:53:43 +00:00
dgp 5a05e0d782 merge 8.5 2018-06-12 17:53:19 +00:00
dgp 9c8f784329 [860a9f1945] Remove test safe-8.8; Mac OS 9 tests are no longer useful. 2018-06-12 17:10:03 +00:00
fbonnet 7fe9e1b90c Removed thread-specific mutex lock counter and replaced by shared counter + thread ID for systems without PTHREAD_MUTEX_RECURSIVE 2018-06-09 17:20:15 +00:00
jan.nijtmans bae4992913 merge-mark (Unicode 11.0 beta was already here, and there were not changed in the final version) 2018-06-09 07:45:45 +00:00
jan.nijtmans 1efbaebb6a Merge 8.5 (= update Unicode data to Unicode version 11.0) 2018-06-09 07:44:33 +00:00
jan.nijtmans ac47e6953d Update all Unicode tables to Unicode version 11.0 2018-06-09 07:42:42 +00:00
jan.nijtmans 400feb302b Update to latest tzdata (backported from 8.6) 2018-06-09 07:41:47 +00:00
sebres 9c9b3d93f9 merge 8.5 (empty merge point, no functional changes, because does not affect 8.6) 2018-06-08 13:02:59 +00:00
sebres 04d1270786 resolves some warnings by compiling with new gcc-versions (>= 7.x):
- '*' in boolean context, suggest '&&' instead [-Wint-in-bool-context]
  - passing argument 1 of 'Tcl_CreateExitHandler' from incompatible pointer type [-Wincompatible-pointer-types]
2018-06-08 12:50:43 +00:00
jan.nijtmans f8b9cb869d re-generate configure script (where does --runstatedir come from? 2018-06-08 06:56:33 +00:00
pooryorick 4755be8f41 Give tests more time to finish since valgrind slows things down considerably. 2018-06-07 20:59:27 +00:00
sebres c2e16d9b1f amend to [eeefdb44cf]: fixes missing install path (closes [593aa7c421]) for mingw/*nix 2018-06-05 21:59:09 +00:00
sebres 3b14a4b0ed re-autoconfigure with v.2.69 2018-06-05 09:10:56 +00:00
sebres a3fdad2b4f merge 8.6 2018-06-05 09:04:08 +00:00
sebres b89a3efc56 merge 8.5 2018-06-04 13:52:19 +00:00
sebres 240e6b50d2 fixes [92564326a9] if compiled on some x86 systems (with dirent64 but without DIR64, partially cherry-picked from https://www.androwish.org/index.html/info/6119b8ac2aee8411). 2018-06-04 13:49:38 +00:00
dgp 38be8d3de6 merge 8.7 2018-06-04 13:17:58 +00:00
dgp 29bbdb74d3 merge 8.7 2018-06-04 13:07:15 +00:00
dkf ddd37fb237 TIP 500: Private Methods and Variables in TclOO 2018-06-03 11:44:19 +00:00
dkf 63be474164 merge core-8-branch 2018-06-02 14:19:33 +00:00
kjnash 754bb107b4 Bugfix - always cleanup persistent socket. 2018-06-01 18:34:07 +00:00
dgp fa47c96ac2 merge 8.7 2018-05-31 19:23:15 +00:00
jan.nijtmans 5e3ca11761 Neither use --disable-threads on MacOS builds, and don't mention it any more in the README 2018-05-31 07:17:23 +00:00
dkf 6ab540f5ff Tweaking the documentation 2018-05-30 09:38:48 +00:00
jan.nijtmans 63b0fef31a No longer pass "--enable-threads" to battery-included sub-packages, since it's the default, even when Tcl is built without threads, now. This opens the way (in the future) to remove this option from the sub-packages 2018-05-30 07:15:13 +00:00
jan.nijtmans bb503004b6 merge 8.6 2018-05-29 07:23:51 +00:00
jan.nijtmans 267cdaec03 One TCL_NORETURN -> TCL_NORETURN1 minor mistake. Make it build when Tcl_SetPanicProc is a macro (normally it isn't) 2018-05-29 07:23:05 +00:00
sebres a2ce3dab9b merge 8.5 2018-05-28 13:17:18 +00:00
sebres 6a4d06759e win: searching for FQDN in user-name should be utf-8 safe (user-name could contain non-ascii utf-8 chars) 2018-05-28 13:13:39 +00:00
sebres 6966f0a2b1 merge 8.5 (conflicts resolved, rewritten without winapi-stubs) 2018-05-28 12:26:20 +00:00
sebres 89a84af271 merge-integrate sebres-bug-9e6b569963-8-5-branch to 8.5 2018-05-28 12:05:15 +00:00
jan.nijtmans f2ec60553a merge 8.7 2018-05-27 16:32:05 +00:00
jan.nijtmans bb5d24622f don't bother to use constraint "threaded", because that's the way we want to build anyway 2018-05-27 14:17:08 +00:00
dkf 813979693c Add sensible behaviour with export and unexport of private methods. 2018-05-27 12:04:39 +00:00
dgp c8da3bbfaf close fork 2018-05-26 13:14:33 +00:00
fbonnet 35f5b82868 Fixed test process-7.3 2018-05-26 11:13:34 +00:00
fbonnet b91a2765ae TIP #509: Implement reentrant mutexes on all platforms 2018-05-25 19:43:23 +00:00
sebres 5e7a1545a6 minor indentation fix (no functional changes) 2018-05-25 15:51:23 +00:00
sebres f4651a5660 avoid dual init of stubs (possible race condition, 8.5th only) 2018-05-25 15:48:50 +00:00
sebres a0290b85c5 optimized winapi-stubs loading (8.5th only); if user name specified without domain and equals the current user - try safest and fastest way to get current user-home path (without usage of netapi) 2018-05-25 15:04:27 +00:00
sebres 8145564d30 merge/reintegrate test-cases from bug-9e6b569963 2018-05-25 10:04:01 +00:00
jan.nijtmans 66ef201ad7 merge 8.6 2018-05-25 06:51:55 +00:00
fvogel 6d943ef7b5 Remove test filesystem-1.30.3, this is unstestable 2018-05-24 20:51:45 +00:00
sebres 1c13d543f4 [9e6b569963] win: if user specified without domain (and local user was not found), try to resolve user-home using current domain, so following code's are similar:
file normalize ~$::tcl_platform(user)@$::env(USERDOMAIN)
  file normalize ~$::tcl_platform(user)
2018-05-24 20:49:12 +00:00
sebres 263de53394 merge 8.5, conflicts resolved (rewritten without winapi-stubs) 2018-05-24 20:36:32 +00:00
sebres a410c0d8d5 fixed typo in winFCmd-12.6.2: unneeded extra-bracket removed 2018-05-24 20:20:26 +00:00
sebres ecec1703aa win: TclpGetUserHome should return normalized path (also in case we find domain and NetUserGetInfo returns path), PoC:
file normalize ~$::tcl_platform(user)@$::env(USERDOMAIN)
2018-05-24 20:12:43 +00:00
fbonnet fae1c11488 Create new branch named "tip-509" 2018-05-24 16:26:16 +00:00
dgp 1ab67324ca merge 8.7 2018-05-24 13:27:12 +00:00
dgp 202eeb707c merge 8.7 2018-05-24 12:24:54 +00:00
fvogel 36a1a69178 Add support for ~domain\user style user names, with new test test filesystem-1.30.3. Warning: does not yet work. 2018-05-23 21:08:01 +00:00
jan.nijtmans edb38932e8 Unbreak build with other CFLAGS, such as TCL_MEM_DEBUG=1 or TCL_THREADS=0 on Linux 2018-05-23 19:31:15 +00:00
dgp 46aab3eb09 unbreak the build 2018-05-23 13:34:53 +00:00
jan.nijtmans ce025f259b Simplify usage of TCL_THREAD, along the lines of [eeddb0693a950be980a66de3811630a00c7bab54|eeddb0693a]. Suggested by DKF 2018-05-22 20:53:24 +00:00
jan.nijtmans f6af18a947 More removals of TCL_THREADS usage (configure scripts/win makefiles) 2018-05-22 20:12:03 +00:00
jan.nijtmans b729965a3c Fix build with TCL_THREADS=0 on Linux/other without epoll or kqueu support. In that case, fallback to select notifier 2018-05-22 20:10:21 +00:00
dkf 0cab7d260b More docs 2018-05-22 08:26:55 +00:00
jan.nijtmans 708eadd19e Demonstrate how Tcl can build without TCL_THREADS defined at all (assuming TCL_THREADS=1 as default). Activated by -DTCL_NO_DEPRECATED=1. See also [eeddb0693a950be980a66de3811630a00c7bab54|eeddb0693a] 2018-05-21 08:12:51 +00:00
dkf 7bbadfe0e0 merge core-8-branch 2018-05-20 15:09:43 +00:00
dkf 4523d8df2c Disable many warnings that are pointless in the stub library. Yes, it accesses deprecated fields, we know because we deprecated them. 2018-05-19 11:26:13 +00:00
dkf 791f1c2741 Minor updates to C API to handle private methods. 2018-05-19 11:18:51 +00:00
dkf d431841a06 Corrections for a number of small things to align with TIP 2018-05-19 08:38:42 +00:00
fvogel dffe6bc7f1 Add test filesystem-1.30.2 {normalisation of nonexistent user specified as user@domain} 2018-05-19 07:10:43 +00:00
fvogel 423f761169 Fix [9e6b569963]: file normalize ~user fails on Windows 2018-05-18 19:54:56 +00:00
fvogel ba42e43e97 Add test filesystem-1.30.1 checking file normalize ~$::tcl_platform(user). This test should currently fail when the computer is connected to a Windows domain controller, due to [9e6b569963]: file normalize ~user fails on Windows 2018-05-18 06:18:56 +00:00
jan.nijtmans 4f1ea4779b TIP #491 implementation: Threading Support: phasing out non-threaded builds 2018-05-17 18:53:29 +00:00
dkf e6fdfbe93b Make [info object methods] and [info class methods] work right. 2018-05-15 13:04:10 +00:00
dkf bd706be303 Make sure that [self call] reports useful info. 2018-05-14 20:55:40 +00:00
jan.nijtmans 4e12ee1bc4 merge 8.6 2018-05-14 19:16:53 +00:00
jan.nijtmans 7672af7212 merge 8.5 2018-05-14 19:16:24 +00:00
jan.nijtmans eae621b175 Unbreak build when HAVE_FTS is not set.
Move definitions of Tcl_DirEntry and TclDIR to tclWinPort.h, where it actually belongs
2018-05-14 19:14:40 +00:00
fbonnet c2fceada6c Initial implementation of TIP #508: [array default] 2018-05-13 22:15:36 +00:00
fbonnet 6ba27f887c Create new branch named "tip-508" 2018-05-13 21:56:54 +00:00
dkf 5eef06ea24 Correct results from unknown method handler. 2018-05-13 19:20:52 +00:00
dkf 9333525d11 Make [info vars] aware of private variable resolution. 2018-05-13 16:10:44 +00:00
dkf 911c1c6237 Merge core-8-branch 2018-05-13 10:08:32 +00:00
dkf 49a9e59311 General code style cleanup. 2018-05-13 07:17:00 +00:00
dgp 242d4d7095 Missing test file boilerplate. 2018-05-11 17:26:13 +00:00
dgp c744824995 merge 8.7 2018-05-11 11:51:18 +00:00
dgp ae6192f9cb merge 8.7 2018-05-11 11:26:20 +00:00
jan.nijtmans 9cb3b15616 TIP #425 implementation: Correct use of UTF-8 in Panic Callback (Windows only) 2018-05-11 09:42:08 +00:00
jan.nijtmans 6d0cc0c589 Merge 8.5. This adds Emoji 11.0 support, when Tcl is compiled with TCL_UTF_MAX>3. Useful for Androwish, for example. 2018-05-11 09:20:59 +00:00
jan.nijtmans d9bc6cbae2 Add emoji 11.0 to the set. Only active when compiled with TCL_UTF_MAX>3. Also prepare tooling for Unicode 11.0 (while being on it) 2018-05-11 09:14:42 +00:00
jan.nijtmans 388266030b merge 8.6 2018-05-11 08:12:04 +00:00
jan.nijtmans ede72e80ac merge 8.5 2018-05-11 08:10:17 +00:00
jan.nijtmans 7bf3f83abd Rename Tcl_Dir to TclDIR, making it clear that this macro is not part of the public API 2018-05-11 07:53:20 +00:00
fbonnet d3fd405e6b Added tcl::process test suite 2018-05-10 17:37:10 +00:00
fbonnet eed54b6281 Fixed makefile.vc: install will create missing dir "tcl8/8.7" for msgcat 2018-05-10 13:47:37 +00:00
fbonnet 6dbdfc31d2 Added man page for tcl::process 2018-05-10 13:44:43 +00:00
dgp 35d6c2453e merge 8.6 2018-05-09 15:49:27 +00:00
sebres f7f4cbb151 merge 8.5 2018-05-09 10:34:44 +00:00
sebres f5e8751307 amend to [85bcf84100]: replaces DIR with Tcl_Dir (DIR/DIR64 regarding HAVE_STRUCT_DIRENT64) 2018-05-09 10:29:33 +00:00
pooryorick 7855612da6 Fix epoll notifier memory leak in initialization/finalization routines, 2018-05-08 20:03:14 +00:00
dgp 7f26fedbcc merge 8.6 2018-05-08 15:00:40 +00:00
sebres 47e9dbdc37 prevents UB/segfault by unexpected return-code (not -1/0/1) and avoid warnings like:
tclCmdMZ.c:2815:15: warning: `s1` may be used uninitialized in this function [-Wmaybe-uninitialized]
  s1len = Tcl_NumUtfChars(s1, s1len);
          ^~~~~~~~~~~~~~~~~~~~~~~~~~
2018-05-08 10:16:26 +00:00
sebres 8fd1568405 merge fix for [92564326a98b5510] from 8.5 2018-05-08 09:56:35 +00:00
sebres 78ee8c697e fixes [92564326a98b5510]: wrong x64-aligned handle from readdir64 by opendir/rewinddir/closedir, if HAVE_STRUCT_DIRENT64 used. 2018-05-08 09:49:16 +00:00
dkf 08f43a1ff4 More efficient way of getting array element names; why search when direct lookup is possible? 2018-05-07 15:42:08 +00:00
pooryorick 1f71d7079b merge core-8-6-branch 2018-05-07 14:33:15 +00:00
dkf 5cef8b0f8e Make the 'varname' method know about private variables. 2018-05-07 12:43:40 +00:00
pooryorick 5f0cf291f5 Deduplicate code in INST_STR_CMP, StringCmpCmd, and StringEqualCmd. 2018-05-07 07:43:00 +00:00
jan.nijtmans 5500074eff Remove some tip389 restrictions in test-cases, which are no longer necessary.
Eliminate gcc compiler warnings when compiling with -DTCL_UTF_MAX=6
Other code clean-up and comment improvements. No change in functionality.
2018-05-07 07:40:58 +00:00
pooryorick db133f0144 Factor options handling out of StringCmpCmd. 2018-05-06 18:13:54 +00:00
dkf 66525c95ee Documentation. 2018-05-06 14:20:29 +00:00
pooryorick 86c6a11cdb Preparation to deduplicate code between byte-compiled and legacy
implementations of [string compare].
2018-05-06 13:45:21 +00:00
dkf 13bdb0305c Corrections to test names. 2018-05-06 07:17:27 +00:00
dkf 2a19591dc7 Fix up instance privates. 2018-05-06 07:13:30 +00:00
dkf 411bfad9f4 merge 8.7 2018-05-05 17:30:52 +00:00
dkf f58e9ed842 Private methods seem to be working... 2018-05-05 17:23:17 +00:00
pooryorick e383cd7b26 Avoid generating string representation when comparing the empty string. 2018-05-05 17:04:08 +00:00
pooryorick 3a3fd2954f Avoid generating string representation when comparing the empty string. 2018-05-05 16:38:27 +00:00
dgp 5238a999d5 merge 8.7 2018-04-27 13:21:27 +00:00
hypnotoad ab49bdfd12 Added an initialization of 0 for the namelen field for new ZipFile data structures. In memory
debugging mode, that value will be something random, not zero on alloc.
2018-04-27 03:06:36 +00:00
dgp 351c77bca3 silence compiler warning 2018-04-24 14:02:49 +00:00
dgp c1555b7cfd merge 8.7 2018-04-24 13:59:43 +00:00
kjnash 227db01958 Restore production test settings: set tests/httpPipeline.test to non-verbose, and comment out most Log calls in library/http/http.tcl 2018-04-21 14:22:35 +00:00
kjnash 41954059c4 merge 8.6 2018-04-21 13:47:09 +00:00
kjnash b169c964e6 Amend httpPipeline.test tests to use stdout not stderr, and thus avoid the report {Test files exiting with errors} even when all tests pass. 2018-04-21 13:31:16 +00:00
kjnash 3771e638b0 Document the new proc http::registerError in http.n 2018-04-20 20:06:30 +00:00
jan.nijtmans f44e7c1795 Merge 8.7
Move stuff from SC_ENABLE_THREADS to SC_TCL_LINK_LIBS in tcl.m4, so SC_ENABLE_THREADS is no longer needed in configure.ac
2018-04-17 22:48:00 +00:00
dgp 04604552b2 ran autoconf on the unix directory. This breaks the build. 2018-04-16 14:51:19 +00:00
dgp b5d6b4f138 merge 8.7 2018-04-16 14:46:58 +00:00
dkf ad02c0b532 Added basic tests of the 'private' definition command. 2018-04-15 15:11:38 +00:00
dkf 28e500cbf9 Testing the private variables. 2018-04-15 14:47:26 +00:00
dkf 637c7dbc7e Added tests for [info object creationid] 2018-04-15 10:29:48 +00:00
kjnash 4588d7300e Restore Tcl 8+4 tab convention 2018-04-13 15:48:13 +00:00
kjnash d690b84738 Improve detection and reporting of TLS errors. New command http::registerError to assist the latter. Ensure that http::cleanup cancels any timeout event if not already done. Add comments on non-blocking read/gets. 2018-04-13 15:41:00 +00:00
dkf 49879791f4 Duplicate the private variable config when cloning objects. 2018-04-13 07:23:37 +00:00
dkf 8262e514d0 Added introspectors mentioned in TIP. 2018-04-12 23:54:58 +00:00
dgp 48ed067359 merge 8.7 2018-04-07 17:12:14 +00:00
dkf 5a8d06b076 Start of private method dispatch machinery. 2018-04-05 07:26:27 +00:00
kjnash 6bc8c27b7f Restore most lines to 80 columns 2018-04-04 13:37:37 +00:00
kjnash 6a58a0cab2 Use coroutines to remove blocking on HTTP connections 2018-04-04 12:00:03 +00:00
kjnash 1357172367 Increase test timeout to 10s. Remove commenting from Log calls that report long delay for [socket]. 2018-04-01 01:09:57 +00:00
kjnash 466fd1d930 Chasing timeout bug: reduce client timeout to 4s in tests; more sanity checking in non-keep-alive tests; tidying; more logging in http.tcl. 2018-03-31 15:27:52 +00:00
dgp 008f1c98d0 merge 8.7 2018-03-30 19:53:14 +00:00
dgp 3fe69cba13 merge 8.7 2018-03-30 19:51:05 +00:00
dgp 42a2b87f32 merge 8.7 2018-03-30 19:42:35 +00:00
dgp a3204f806c Rebase TIP 502 draft implementation. 2018-03-30 12:32:22 +00:00
kjnash 441e4f6796 For thorough testing, set test file to verbose, and uncomment Log calls in http.tcl. 2018-03-30 10:13:57 +00:00
kjnash 3117af219f Bugfixes. Details in ticket 46b6edad51. 2018-03-30 10:02:44 +00:00
kjnash a0e1b18138 Adapt tests/httpPipeline.test for test without installation. Comment out some Log calls from tests/httpTestScript.tcl 2018-03-29 18:20:56 +00:00
kjnash 70af5c2b82 Implement queuing and pipelining for HTTP requests over a persistent connection. 2018-03-27 14:20:23 +00:00
kjnash d38ae8f974 Adapt fconfigure -translation for two-way pipelined operation. 2018-03-27 08:56:16 +00:00
kjnash 0d887fa465 Define variable tk used in Log calls for testing. 2018-03-27 08:55:21 +00:00
kjnash e9bb0992b0 First step for implementing concurrent requests using the same connection. Define namespace variables socket* and http where they will (eventually) be used. Leave them unused except in http::init where they are initialised. 2018-03-27 08:52:40 +00:00
kjnash f35c0dc2ed Revise tests/http11.test for use with commits from 78b23edb6b onwards. Adjust proc "handler" to conform to http(n) 2018-03-27 08:49:13 +00:00
kjnash e80e214673 BUGFIX. Send "Connection: keep-alive" even if HTTP/1.1. Some servers (including Apache 2.2 on RHEL6) use the discretion granted by RFCs and will close the connection unless this header is sent. 2018-03-27 08:37:06 +00:00
kjnash 731f40c6d9 New http::config option -zip to control whether to send an "Accept-Encoding" request-header for a zipped response. Default true for backward compatibility. 2018-03-27 08:32:37 +00:00
kjnash 767cf6314a Workaround for bug with https and unchunked response. A [read] does not deliver until the server closes the socket. The workaround is to specify the buffer size as the precise length required. 2018-03-27 08:29:43 +00:00
kjnash b00317d174 Changes to response handling in Finish, Eot and Event. Carefully distinguish expected and premature eof. Stricter handling of errors, minor bugfixes. Details in ticket 46b6edad51. 2018-03-27 08:25:14 +00:00
kjnash a8408767a4 Add "array unset socketMapping" in http::init. The sockets are closed and therefore do not belong in socketMapping, which should be unset. 2018-03-27 08:20:14 +00:00
kjnash 4f8b177250 Tidying - add empty else clauses, omit :: at start of command name http::CloseSocket in proc definition, use two lines instead of "return [Finish ...]" because there is no return value! 2018-03-27 08:17:38 +00:00
kjnash 25aad1ab18 Update some Log calls, mainly to specify token. 2018-03-27 08:15:26 +00:00
kjnash 3b48db4a90 Update some comments and a Log. 2018-03-27 08:12:47 +00:00
kjnash 58eff8f224 Rename some variables and commands. Details in ticket 46b6edad51. 2018-03-27 08:10:50 +00:00
kjnash 97721e9675 Add parentheses to some "if" tests; transform one test without changing its outcome. 2018-03-27 08:08:19 +00:00
kjnash d88d33f74d Give all procs an explicit return, except where commented as "Implicit Return". 2018-03-27 08:07:05 +00:00
kjnash 0a9706f48f Adjust to 80 columns except one 82-column line which would be less intelligible. 2018-03-27 08:05:42 +00:00
kjnash 45f91441a5 Adjust whitespace to Tcl 8+4 tab convention. 2018-03-27 08:03:58 +00:00
kjnash 38781266d3 Create new branch named "bug-46b6edad51-concurrent-http" 2018-03-27 07:48:33 +00:00
dgp 843d29b448 Rest of TIP 505 implementation -- mostly undoing dumb things. 2018-03-26 18:59:00 +00:00
dgp 1a73baff09 Work in progress implementing TIP 505. 2018-03-26 16:27:40 +00:00
dkf 383c53f80e This should be the implementation of private variables. 2018-03-18 18:04:50 +00:00
jan.nijtmans ba9cf35aa3 In case of redirecting stderr to a file on Windows, append CRLF after Panic output. 2018-03-15 23:01:00 +00:00
jan.nijtmans db41a49d9c merge 8.7 2018-03-15 21:53:00 +00:00
jan.nijtmans cbbab84b71 Merge 8.7 (convert makefile.vc to CRLF line-endings only) 2018-03-15 21:13:00 +00:00
dgp 55a65632d0 Merge 8.7; Updated the package manifest by hand; was broken until then.
If there's a maintenance knob to turn, that needs to be better known.
2018-03-15 19:09:42 +00:00
dgp 47152d94c1 merge 8.7 2018-03-15 14:06:52 +00:00
dgp f52d25e68a merge 8.7 2018-03-11 23:08:20 +00:00
dgp 6de6ee8aa9 merge 8.7 2018-03-07 15:13:07 +00:00
dgp 3616fc519b merge 8.7 2018-03-06 13:50:45 +00:00
dgp 5fd49d1907 Merge 8.7; avoid checkin converting TclGetNumberFromObj to TclParseNumber. 2018-03-05 16:09:08 +00:00
dgp 7024801722 merge 8.7 2018-03-01 20:20:55 +00:00
dgp 40dfdbd929 Avoid full list conversion when we can cheaply discover a multi-element list
is not possible.
2018-03-01 19:30:15 +00:00
dgp 0cb6effe14 Continue consistent use of LLONG_MIN and LLONG_MAX. 2018-03-01 04:19:37 +00:00
dgp a0c07fcf28 merge 8.7 2018-03-01 04:13:47 +00:00
dgp 221f1bc18e Use mp_isneg() as appropriate. 2018-02-28 13:40:36 +00:00
dgp c0c1cce296 merge 8.7 2018-02-28 13:38:01 +00:00
dgp a628ce605f merge 8.7 2018-02-27 23:17:17 +00:00
dgp 3607c177d9 Don't save indices with values outside the int range in bytecode. 2018-02-27 22:35:24 +00:00
dgp e1efe253d2 Much more progress expanding the vocabulary of index values, and getting
results that make more intuitive sense.  Still a few TODOs and tests to update.
2018-02-27 18:20:44 +00:00
dgp 544d338e0e Work In Progress on index value reform -- not working. 2018-02-27 13:13:11 +00:00
dkf 5b5bd699ff Starting to build the implementation of the private methods and variables. Definition support. 2018-02-25 12:04:55 +00:00
dgp 3b3a5ff07f Better range checking in "string index". Add test-case to prove point.
This opens a large discussion on what the right valid range for index
values should be and what overflow behavior should be. New branch opened
to answer those questions completely.
2018-02-15 17:24:40 +00:00
jan.nijtmans 69868ee129 merge core-8-branch. Now tested as well with new nmake system. 2018-01-20 14:36:36 +00:00
hypnotoad e16df96d28 Fixed a problem where a Windows hack was occuring after it was called in the
tclZipfs.c file, preventing it from compiling properly.
2018-01-19 20:27:15 +00:00
hypnotoad 608373fcb1 Modifications to allow the mounting of zip file systems from data blocks
Added a new stubs entry to mount a data block as a zip file system
2018-01-17 15:56:32 +00:00
hypnotoad a866c42f19 Modifications to index zip file systems by mountpoint, and separate the process
of mounting a zip archive from the process of indexing its contents. This work
is progress towards being able to pass a data block to the zipfs system
as a new file system to be mounted.
2018-01-17 01:09:07 +00:00
hypnotoad 3502aebe10 Tweaks to the tclZipfs.c file to allow the same C source to be used both
in the core and as a static package for external shells (Via TEA)
2018-01-16 23:25:50 +00:00
hypnotoad 9947048fbd Tweaks to zipfs.test 2018-01-11 16:45:52 +00:00
hypnotoad 37b48e808c Fix tests dependent on other tests in zipfs.test
Add a workaround for the fact that dynamic libraries called out from a non-install
location can't be located and mounted in time to be a candidate for tcl_library
when running under the constraints of "make test"
2018-01-09 18:10:06 +00:00
hypnotoad 3fc7771456 Pulling changes from core-8-branch 2018-01-09 16:28:11 +00:00
dgp 7aa147800f Minimal fixes to stop the [package files] machinery writing to freed mem.
This contribution needs a careful review from someone who actually knows
how Tcl_Preserve, etc. work.
2018-01-04 02:23:37 +00:00
hypnotoad b533731c50 Modifications to clean up warnings on compile 2017-12-29 21:41:00 +00:00
hypnotoad 983b089edb Removing the standalone pkgIndex.tcl. There is enough stuff that needs to be
manually edited in the init.tcl script for new releases as it is, there is no
sense in having yet another file to edit.

Marking which distributed packages are safe to load in a safe interpreter
2017-12-29 20:40:29 +00:00
hypnotoad 47c7771af1 Pulling changes from core-8-branch 2017-12-29 15:13:23 +00:00
jan.nijtmans 1dd89810eb merge core-8-branch 2017-12-23 20:22:54 +00:00
jan.nijtmans 53795bd199 merge core-8-branch 2017-12-21 13:26:56 +00:00
hypnotoad 72af38dd32 Pulling changes from core-8-branch 2017-12-16 03:33:44 +00:00
hypnotoad 7f1c241ea2 Update the config.test with new keys needed for zipfs 2017-12-16 03:30:58 +00:00
hypnotoad 45a3c74a04 Removing static package declaration of zipfs. 2017-12-16 03:24:21 +00:00
hypnotoad 71cf0dba40 Re-arranging code and providing forward prototypes to allow the C infrastructure of
Zipfs to be activated from withing the first call to TclZipfs_Mount(). This keeps up
from having to expose TclZipfs_Init in the stubs table.
2017-12-16 03:22:04 +00:00
jan.nijtmans 603e23c2a9 merge core-8-branch 2017-12-15 16:08:14 +00:00
jan.nijtmans 3f03f8189e Oops, couldn't build tclWinPanic.o. Fixed now. 2017-12-15 13:04:15 +00:00
jan.nijtmans c576cbec93 merge core-8-branch. Fully functioning now, including with the new vc-reform implementation. 2017-12-15 12:55:59 +00:00
jan.nijtmans 5c4f8d88b5 fix comment 2017-12-14 14:38:30 +00:00
jan.nijtmans 9c5c1a721f merge core-8-branch. Fully tested now, works fine. 2017-12-14 13:41:37 +00:00
hypnotoad 2756d01872 Pulling changes from core-8-branch 2017-12-13 15:52:05 +00:00
jan.nijtmans bf868c1c56 Initial implementation of TIP #491. Not tested yet. 2017-12-11 14:19:48 +00:00
jan.nijtmans a69614b432 merge 8.7 2017-12-06 12:24:26 +00:00
hypnotoad 9b22762d4c Pulling changes from core-8-branch 2017-11-29 01:59:41 +00:00
hypnotoad 0951ca5344 Closing leaf 2017-11-29 01:59:12 +00:00
hypnotoad bb48fae153 Pulling changes from the last core-8-branch that doesn't cause a segfault in kits 2017-11-28 18:06:22 +00:00
hypnotoad ae2707f558 Pulling changes from core-8-branch 2017-11-26 18:27:33 +00:00
tne 99dc87a51d Restoring the Makefile.in for the win/ directory after an unfortunate copy/paste error 2017-11-25 10:54:15 +00:00
hypnotoad 7154cc9c47 Tweak to ensure mount points for zipfs are corralled into the //zipfs:/ prefix space 2017-11-24 11:46:34 +00:00
hypnotoad b3ff8cc20c Pulling changes from Androwish 2017-11-24 11:21:55 +00:00
hypnotoad 2fcfa34fcf Restoring whitespace to tclZipfs.c to improve legibility. 2017-11-24 10:32:10 +00:00
hypnotoad 2d811a0adf Fixing a goof, Zipfs was looking for the Dll where the installer put the file,
which is not necessarily where the file will be found at runtime.
2017-11-23 11:55:03 +00:00
hypnotoad 09f849cabd Pulling changes from core-8-branch 2017-11-21 22:34:06 +00:00
hypnotoad d997aa477d Added additional functions to the "install" command in tclsh 2017-11-21 18:57:31 +00:00
hypnotoad 8225859a93 Eliminated the need for a preinit script in Tip 430's AppHook.
tcl_findLibrary now knows to scan the dll offered up by [info loaded] to see if
an attached zipfile could possibly contain the files the extension is looking for.
2017-11-21 16:49:24 +00:00
hypnotoad 35adf8c728 Removing the pool of literal values within the internals of tclZipfs.c. Replaced with
a single pointer to a const string once discovery has sorted out where tcl_library 
is to be loaded from.

Fixed a goof in the build system if tcl is compiled outside of the source directory
2017-11-21 14:21:48 +00:00
tne 334149646f Fixes to "make clean" to do a better job of cleaning up zip files and vfs directories
Fixed a type that was keeping minizip from building
2017-11-21 04:26:37 +00:00
hypnotoad d8a921174e Added an implementation of tinydir.h, and spliced it into minizip to allow
minizip to recurse directory structures (and get us out of having to feed `find`
via autoconf)
2017-11-21 04:07:45 +00:00
tne d7b40297d2 Final tweaks to make "./tclsh install" work properly on Windows
NOTE: We still seem to be screwing up minizip on MinGW. the `find . -type f` substitution is not working
2017-11-21 01:14:05 +00:00
hypnotoad 9ef614086a Typo fixes for minizip 2017-11-21 00:41:04 +00:00
hypnotoad 6b40a5dc5a Added a new function to the Zipfs: TclZipfs_TclLibrary, which returns a previously
discovered /library file system from a zip archive, performs the search to see
if the current dll has one (and return that), or NULL if zipfs cannot locate
/library.

Injected a call to [zipfs tcl_library] (which invokes TclZipfs_TclLibrary) inside
if interp.c as the first command to try to locate Tcl_Library (if a preinit
script hasn't already pointed one out to us.)
2017-11-21 00:36:55 +00:00
tne 3cd8b86e50 Change to TclZipfs_AppHook to accomidate Windows 2017-11-20 23:34:21 +00:00
hypnotoad d2fc7a6ed5 Fixing the quoting for arguments to minizip 2017-11-20 22:45:35 +00:00
hypnotoad 12a14f4954 Updating tcl.m4 in windows to fix a typo 2017-11-20 21:29:57 +00:00
tne 1f34b918b9 Removing debugging printf() statement 2017-11-20 19:35:40 +00:00
tne 4a8bb308e8 Fixes to determing the dll location on Windows using GetModuleFileName() 2017-11-20 19:21:12 +00:00
hypnotoad 3640513caf Autoconf fixes 2017-11-20 18:08:12 +00:00
hypnotoad 4e97c16367 Modifications to allow the Tcl build system to exploit either a native zip
executable in the path or a tclsh that understands the new "install" keyword
from the command line

Added a new file to /library which is run when the user executes "tclsh install ..."

Embedded in installer.tcl is a facility for building zip archives
2017-11-20 17:09:44 +00:00
hypnotoad 280b6aa62e Added handling to allow Tclsh to intercept a zip file fed as the first command line argument, and open it as a kit 2017-11-19 18:16:43 +00:00
hypnotoad fe346634a7 Pulling changes from core-8-branch 2017-11-18 20:28:20 +00:00
tne 1d444f5610 Now that UNC paths work correctly on Windows, removing the platform specific zipfs mount point for windows 2017-11-18 20:25:25 +00:00
hypnotoad 30938251a2 Adjust the rule to look for libtcl_XXX.zip ONLY in the directory that contains
the executable or the install location for tcl. The directory adjacent copy
is only looked for and mounted in an install location version cannot be located.
2017-11-18 20:21:13 +00:00
aspect 157e55c7bc Reserve paths matching //[^/]*: for VFS mount points, and prevent calling
native filesystem ops during normalization for them.  This is permitted by UNC
standards (which do not allow : at the end), and should prevent observed slow
[glob] operations (and others) on Windows when using such paths.
2017-11-18 17:07:48 +00:00
aspect d8a0c08bbc add some tests for join and normalize 2017-11-18 17:04:03 +00:00
aspect 3730061388 fix zipfs tests 2017-11-18 17:02:08 +00:00
hypnotoad b171f5cc41 Added documentation for the zipfs root command and working of TclZipfs_AppHook 2017-11-18 12:21:35 +00:00
tne 02a019458f Updated zipfs tests to recognize the mount points are different on different platforms 2017-11-18 11:59:20 +00:00
hypnotoad b59255450b Added a pool of literal strings to zipfs to manage constants that are being belched out by the file system.
Created a separate mount point for Unix and Windows, with a new "zipfs root" command to tell the user which
location to use for their platform
2017-11-18 11:48:08 +00:00
hypnotoad c6d82079ea Added a package manifest to init to allow core distributed packages to
auto-populate [package ifneeded] on startup
2017-11-17 17:23:01 +00:00
hypnotoad 52d32b1033 Integrating fixes from aspect that make the //zipfs:/ mount point viable, and
also allow one archive to be mounted in multiple locations
2017-11-17 12:54:56 +00:00
hypnotoad f85da9c9fd Pulling changes from core-zip-vfs 2017-11-17 12:39:06 +00:00
hypnotoad f20b58c6a9 Pulling changes from core-8-branch 2017-11-17 12:29:40 +00:00
hypnotoad 9513859f8c Closing a fork 2017-11-17 12:28:37 +00:00
aspect f81c2ae724 fix [glob] handling of leading // 2017-11-17 11:53:19 +00:00
aspect 7c1f63bb60 clean up stray unused dstrings 2017-11-17 10:24:45 +00:00
aspect 4515103846 whitespace consistency 2017-11-17 10:21:41 +00:00
aspect 87d37d3101 Zipfs: Nix AbsolutePath() and most uses of CanonicalPath(). Tcl_FSNormalizePath is to be trusted. 2017-11-17 10:17:47 +00:00
aspect da76cd286c Zipfs: Use //zipfs:/ as mount point. Use Tcl_FSNormalizePath() on the way in to most VFS operations. Add some tests. 2017-11-17 08:39:31 +00:00
hypnotoad 3c532f6336 Rebuilt the configure files without the call to the missing SC_ENABLE_ZIPFS macro 2017-11-17 04:47:16 +00:00
tne ded3368d3c Final tweaks to get Msys Zipfs build working 2017-11-17 04:45:07 +00:00
hypnotoad e84763748b First pass on the Msys style windows build. Moving Zipfs features closer together in the autoconf 2017-11-17 04:13:48 +00:00
hypnotoad 8079a467a7 Pulling changes from core-8-6-branch 2017-11-17 03:10:54 +00:00
hypnotoad be47788793 Moved Zipfs initialization and path hinting out of tclInterp.c and into
a preinit script populated by TclZipfs_AppHook
2017-11-17 03:09:26 +00:00
hypnotoad 62fbfd89d7 Pulling changes from core-8-branch 2017-11-11 13:22:35 +00:00
hypnotoad 932afb0105 Improvements to tip430 to embed the /library file system within a shared library
or as a zip archive with a canonical name matching the current patch level

This new version also builds a native executable version of minizip to 
allow archive to be built within make, even when cross compiling

Added a new function TclZipfs_AppHook which implements tip430 core
behavior startups to stock tclsh

Embedding the file system as a zip archive can be defeated with --enable-zipfs=no
2017-11-11 09:18:09 +00:00
hypnotoad b2722c42b1 Pairing down the tip#430 branch to only include files and utilities
called out by the tip. Eliminated the header files tclZipfs.h and
zcrypt.h. The only public calls for tclZipfs.h are now in the stubs
table and the contents of zcrypt.h are already part of the minizip
implementation that Tcl keeps around in the compat/zlib/contrib/minizip
directory. tclBootVFS.h hasn't been used by the implementation in a while.

Alos eliminated the mkzip.tcl facility from tools/. The C based mkzip is
much faster and more reliable
2017-11-08 09:41:00 +00:00
hypnotoad c2dfae0758 Removing kit building facilities. They aren't part of the tip430 spec 2017-11-07 19:51:53 +00:00
hypnotoad 23440fcbd7 Removing patches for Androwish that are not needed for tip430 2017-11-07 19:26:21 +00:00
hypnotoad 399ff79e21 Adding a [file normalize] to zipfs tests that are looking for absolute filenames.
On Linux symlinks can cause a discrepency in what the tests think they are looking for.
2017-11-07 19:13:34 +00:00
hypnotoad 338e92cb28 Updated the zipfs portion of the testsuite to tip430 standards 2017-11-07 18:45:24 +00:00
tne 433dff0c14 Pulling changes from core-8-branch 2017-11-07 16:46:38 +00:00
jan.nijtmans ef7ea2c390 merge trunk 2017-10-24 13:59:13 +00:00
jan.nijtmans 5470f13299 tclWinPanic.c is in the \win directory, not in \generic! 2017-10-23 13:47:57 +00:00
jan.nijtmans c0effc5b46 merge trunk 2017-10-23 13:23:08 +00:00
hypnotoad fc947a1ad4 Pulling changes from trunk 2017-10-16 20:35:30 +00:00
hypnotoad 54bc992b81 Improvements to Tip#430 based on community input. Added a forward declaration of TclZipfs_Init. Added TclZipfs_Mount() and TclZifs_Unmount to stubs table. 2017-09-25 16:23:56 +00:00
hypnotoad e55f59bd83 Pull changes from Trunk 2017-09-25 13:36:58 +00:00
jan.nijtmans 15f27ca8f2 Rebase to trunk 2017-09-08 11:04:34 +00:00
hypnotoad c55b8ed591 Pulling changes from trunk 2017-09-05 16:44:09 +00:00
hypnotoad 522456ba98 Removed the package style loader from tclAppInit. Zipfs now loads as part of the interpreter. 2017-09-05 16:33:37 +00:00
jan.nijtmans b5273bc1fa merge trunk 2017-05-04 14:19:52 +00:00
hypnotoad 627f0a4d6a Pulling changes from zipfs 2017-03-10 17:03:10 +00:00
jan.nijtmans b645469c95 merge core-8-6-branch 2017-03-07 12:21:28 +00:00
jan.nijtmans e295641767 merge core-8-6-branch 2017-03-07 09:09:44 +00:00
jan.nijtmans c3a18ac8f4 merge core-8-6-branch 2017-02-27 16:04:00 +00:00
jan.nijtmans f9dda45e97 merge core-8-6-branch 2017-02-25 15:57:39 +00:00
jan.nijtmans a5c310f993 merge core-8-6-branch 2017-01-17 09:06:45 +00:00
jan.nijtmans 80d9aa777b Merge core-8-6-branch. Better deal with patterns regarding hidden files in ZIP filesystem (taken over from upstream androwish) 2017-01-16 12:46:42 +00:00
jan.nijtmans c745f44e3a Merge core-8-6-branch 2017-01-06 11:47:15 +00:00
jan.nijtmans 21d4596064 Merge core-8-6-branch. Remove (temporarily) write-functions from zipfs. Let first TIP-version handle read-only functions only. 2016-11-14 15:51:03 +00:00
jan.nijtmans 5f738db586 Merge core-8-6-branch. Update upstream changes to zipfs.c 2016-11-07 11:16:52 +00:00
jan.nijtmans 76bb4d1ea4 merge core-8-6-branch 2016-11-02 12:09:04 +00:00
jan.nijtmans 4db368d595 merge core-8-6-branch 2016-10-03 14:56:00 +00:00
hypnotoad 9dfe53af4a Re-created the build mods for tip#340. Something I was doing was screwing with building
a proper shell
2016-10-02 18:42:56 +00:00
hypnotoad e58a9dabbe Typo fix for Makefile.in 2016-10-02 18:30:43 +00:00
hypnotoad 3e0c5c6c90 Pulling change from trunk 2016-10-02 12:00:56 +00:00
jan.nijtmans e9e40f5f02 merge core-8-6-branch 2016-09-26 15:03:11 +00:00
hypnotoad a4dbdda700 Adding build scripts to implement Tip#453 2016-09-14 15:11:12 +00:00
hypnotoad 5bf83d86b6 Further adaptations and improvements to practcl.
And get, tclsh make.tcl basekit even works now
2016-09-14 15:04:41 +00:00
hypnotoad 3c85e6e0ef Pulling changes from trunk 2016-09-14 13:38:30 +00:00
hypnotoad 58ab27bf86 Fixed the line endings on practcl.tcl 2016-09-14 13:36:27 +00:00
hypnotoad 824b71f959 Beginning work in earnest on Tip#430 and Tip#453
Renamed zipfs.c to tclZipfs.c. Eliminated tclZipfs.h.

Removed the bootstrap introduced by Odie/Androwish. With zipfs in the core
one only needs to specify the TclPreInitScript

The project at least builds on OSX. Working on Windows under MSYS/MinGW next

Added a local snapshot of practcl.
2016-09-14 13:33:32 +00:00
jan.nijtmans c3c935369d merge core-8-6-branch 2016-09-08 07:24:06 +00:00
hypnotoad e14a1e9e3d Pulling changes from Trunk 2016-09-08 03:01:05 +00:00
hypnotoad 5c93243c18 Pulling changes from zipfs 2016-09-08 03:00:04 +00:00
jan.nijtmans bd1370959e merge core-8-6-branch 2016-08-30 13:42:21 +00:00
jan.nijtmans a852495cf6 merge zipfs 2016-08-19 13:42:12 +00:00
jan.nijtmans 9a7f1bd48c merge core-8-6-branch 2016-08-19 08:58:35 +00:00
jan.nijtmans 47cb19c83f merge core-8-6-branch 2016-06-23 11:51:36 +00:00
jan.nijtmans f4cc5617a6 merge core-8-6-branch 2016-06-14 10:00:04 +00:00
jan.nijtmans e48602d674 Merge core-8-6-branch 2016-06-03 13:22:58 +00:00
jan.nijtmans e9a8c42972 merge core-8-6-branch 2016-05-19 11:46:43 +00:00
jan.nijtmans 5bcc7fa342 merge core-8-6-branch 2016-04-24 16:14:07 +00:00
jan.nijtmans b0c45c3ad0 merge core-8-6-branch 2016-04-18 09:35:33 +00:00
jan.nijtmans e1e49c9dd1 Merge core-8-6-branch, cherry-pick [http://www.androwish.org/index.html/info/04ea31271c40789d|04ea31271c40789d] 2016-04-08 14:55:57 +00:00
jan.nijtmans 18ba46bf37 merge core-8-6-branch 2016-04-07 09:19:05 +00:00
jan.nijtmans 5b719a2281 merge core-8-6-branch 2016-04-05 08:23:23 +00:00
jan.nijtmans edbf30e23a merge core-8-6-branch 2016-03-30 09:20:54 +00:00
jan.nijtmans 395d0889b0 merge core-8-6-branch 2016-03-30 07:52:15 +00:00
jan.nijtmans ba0d107038 merge core-8-6-branch 2016-03-23 15:12:01 +00:00
jan.nijtmans 763f9dff55 minor upstream changes 2016-03-02 15:39:32 +00:00
jan.nijtmans bbcef5b648 merge trunk 2016-03-02 15:10:48 +00:00
hypnotoad b3b6f6ff99 Pulling *more* changes from zipfs 2016-02-08 21:59:46 +00:00
hypnotoad 71b97d16f3 Merging changes from zipfs 2016-02-08 21:58:12 +00:00
jan.nijtmans 25d1f4aa03 Merge trunk 2016-02-08 16:11:13 +00:00
jan.nijtmans 22f5c55560 Upstream zipfs change and unbreak zipfs test-case 2016-01-29 09:17:55 +00:00
jan.nijtmans 3cf33e9e9f merge trunk 2016-01-24 16:57:57 +00:00
jan.nijtmans a288c5e54a Merge trunk.
Depend on ensemble now, adapt documentation.
2016-01-23 20:33:38 +00:00
jan.nijtmans c3e9d3205f Add "zipfs" ensemble. 2016-01-22 08:45:38 +00:00
jan.nijtmans 227fbec0fc Merge trunk, upstream fixes to zipfs.c for win32 2016-01-19 10:43:40 +00:00
jan.nijtmans dc21089720 Merge trunk 2016-01-18 14:33:32 +00:00
jan.nijtmans f6bb864fc7 Minor tweaks in documentation/testcases. Don't use deprecated Tcl methods any more 2016-01-18 09:28:55 +00:00
hypnotoad bd7d14f293 Reconciled the inner workings of the core_zip_vfs and zipfs branch of Tcl
core_zip_vfs now uses the same C implementation. More fixes to come as I
tweak the userspace and Makefile tools. The goal is to fold core_zip_vfs
into the zipfs branch.
2016-01-12 19:03:55 +00:00
jan.nijtmans 982211da16 Merge trunk. Update documentation 2016-01-09 23:02:42 +00:00
jan.nijtmans a1740d9766 Make al zipfs command Tcl_Obj-based 2016-01-01 16:50:52 +00:00
jan.nijtmans e9795fb407 first shot at documentation 2015-12-22 11:39:28 +00:00
jan.nijtmans 299924e512 Remove TIP #414 fragment, not strictly needed for the zipfs TIP.
Add more zipfs test-cases
2015-12-22 09:11:57 +00:00
jan.nijtmans a03e74efc1 USE_TCL_STUBS is not defined anyway 2015-12-21 21:25:40 +00:00
jan.nijtmans 3c03a492f9 Start with a few simple basic test-cases 2015-12-21 15:21:21 +00:00
jan.nijtmans 56c5833c4a Eliminate all use of ZIPFS_IN_TCL 2015-12-21 14:01:57 +00:00
jan.nijtmans 63b07461da Fix android compilation (zipfsFilesystem.loadFileProc is a constant, so it cannot be written) 2015-12-21 12:43:54 +00:00
jan.nijtmans 1c3288f038 Finally, make it compile warning-free using Visual Studio, if ZIPFS_IN_TCL is defined 2015-12-21 11:59:08 +00:00
jan.nijtmans 8ecd6aeb5b Make it compile warning-free with MSVC compiler (VS2013, at least). Other tweaks. 2015-12-21 11:29:38 +00:00
jan.nijtmans 4d00715902 CONST -> const 2015-12-21 10:49:36 +00:00
jan.nijtmans 95aeb2a3d6 Merge trunk.
Remove utf-32 encoding, will not be part of the "zipfs" TIP.
2015-12-21 10:38:12 +00:00
jan.nijtmans b0a98f480d Undo more Android-specific changes, which don't form part of Zipfs, as further preparation for Zipfs TIP.
Rename zipfs.h to tclZipfs.h, so it can be installed together with tcl.h
2015-12-21 10:03:06 +00:00
jan.nijtmans cb73551e8d Start of "zipfs" branch, meant for keeping track of the proposed changes for a new TIP. Remove some android-specific build/configure files. 2015-12-21 09:31:36 +00:00
jan.nijtmans 4d946107e7 Put back the stub entries for TclpGetDate/TclpLocaltime/TclpGmtime. Although those functions are dead (they will be removed in Tcl 9, already done in the "novem" branch), removing those functions is a good idea, this cannot be done in any 8.x release. It hinders the acceptance of a "zipfs" TIP, therefore this change should not be part of the "androwish" change-set. 2015-12-21 09:16:38 +00:00
jan.nijtmans c795f44ea5 upstream androwish change 2015-12-18 12:39:24 +00:00
jan.nijtmans ecd9567624 Minor tweaks on ZIPFS_IN_TCL 2015-12-17 15:23:27 +00:00
jan.nijtmans d6fdfa4624 minor tweaks for MSVC 2015-12-17 12:04:22 +00:00
jan.nijtmans 58ace2b1dc remove unnecessary Tclzipfs defines in tclStubInit.c 2015-12-16 15:18:59 +00:00
jan.nijtmans 8f6089f225 No need for more than tcl.h in zipfs.h 2015-12-16 13:37:20 +00:00
jan.nijtmans 19627fed47 Remove zipfs symbols from stub table. Those symbols should be exported as-is, without using the stub mechanism. 2015-12-16 13:26:54 +00:00
jan.nijtmans 83145e2bb1 merge trunk 2015-12-16 13:21:58 +00:00
jan.nijtmans 621c76324a Merge trunk. Upstream zipfs change 2015-12-15 09:31:57 +00:00
jan.nijtmans e961e1c08a Merge trunk. Upstream androwish changes 2015-12-11 22:56:07 +00:00
jan.nijtmans e740674cb8 Merge trunk. Upstream zipfs change 2015-12-09 10:20:02 +00:00
jan.nijtmans 23ced66a6b merge trunk 2015-11-30 07:37:05 +00:00
jan.nijtmans b637222a5d merge trunk 2015-11-25 21:07:55 +00:00
jan.nijtmans 9a0f7dd2c8 merge trunk 2015-11-22 16:06:02 +00:00
jan.nijtmans 440e5fc7dc Merge trunk 2015-11-18 08:53:34 +00:00
jan.nijtmans 74ed7238b0 merge trunk 2015-11-14 21:37:35 +00:00
jan.nijtmans 38d734ddcf better handle out-of-memory conditions in ZIP filesystem
hard-wire initial encoding on Android to UTF-8
2015-11-03 13:13:14 +00:00
jan.nijtmans cbeed9da92 Merge trunk. Added comments in ZIP filesystem (no functional changes) 2015-11-01 22:04:02 +00:00
jan.nijtmans a369d46795 merge trunk 2015-10-28 09:04:46 +00:00
dkf 1956f4b66b merge trunk 2015-10-26 07:23:58 +00:00
hypnotoad 90b38da321 Merged with trunk, fixes to allow builds outside of the tcl/unix|win directory 2015-10-26 04:02:36 +00:00
jan.nijtmans 4594b4f27a merge trunk 2015-10-25 22:59:16 +00:00
jan.nijtmans ff3f0131bd Merge trunk 2015-10-25 20:14:13 +00:00
jan.nijtmans 5b793fef99 merge trunk 2015-10-23 08:52:41 +00:00
jan.nijtmans 13aa1642ac Merge trunk 2015-10-23 08:13:49 +00:00
jan.nijtmans d905cc4737 merge trunk 2015-10-18 10:48:54 +00:00
jan.nijtmans d954f3c4ee Merge trunk 2015-10-14 19:04:36 +00:00
jan.nijtmans c770024ce1 merge trunk 2015-10-09 19:11:11 +00:00
jan.nijtmans c1f95640c4 merge trunk 2015-10-07 07:23:01 +00:00
jan.nijtmans 48ef2b50eb merge trunk 2015-10-06 10:50:56 +00:00
jan.nijtmans 071aa09c6e merge trunk 2015-10-04 09:42:24 +00:00
jan.nijtmans 10cd3c906d merge trunk 2015-09-30 13:57:25 +00:00
jan.nijtmans 0fca37f803 merge trunk 2015-09-29 21:20:04 +00:00
jan.nijtmans 9dd94f7396 Don't use mutex retry mechanism on Android. (problems ???) 2015-09-28 10:58:30 +00:00
jan.nijtmans ce65c7b396 merge trunk 2015-09-27 12:59:23 +00:00
jan.nijtmans a80a084de9 merge trunk 2015-09-23 11:35:03 +00:00
jan.nijtmans ddc625f2fe merge trunk 2015-09-22 08:06:16 +00:00
jan.nijtmans 842b15b839 fixed bug in zipfs error handling (backported from androwish) 2015-09-17 11:47:04 +00:00
jan.nijtmans 4506b4536b Merge trunk 2015-09-02 07:16:50 +00:00
jan.nijtmans dbe627594e Dependancies from androwish upstream 2015-08-31 17:30:01 +00:00
jan.nijtmans 130fe11f2b Merge trunk, but remove experimental tip-389-impl merge. 2015-08-31 10:22:29 +00:00
jan.nijtmans 3bce1ab6f2 Merge tip-389-impl (experimental) 2015-08-24 19:39:40 +00:00
jan.nijtmans fe773c0a46 merge trunk 2015-08-24 19:35:08 +00:00
jan.nijtmans ecc90e3787 one more.... 2015-08-24 08:01:23 +00:00
jan.nijtmans 6e0d4b6761 Remove unused internal stub entries as well. 2015-08-24 07:58:42 +00:00
jan.nijtmans 53ad2ab17d Merge trunk.
Throw away TclpGetDate, TclpLocaltime and TclpGmtime and all related dead code. It makes the androwish binary (somewhat) smaller.
2015-08-21 13:29:06 +00:00
jan.nijtmans a2a59dfb75 merge trunk 2015-08-19 09:06:22 +00:00
jan.nijtmans 829af34165 merge trunk. Put back some (actually unused) Tclp*UnixTime functions. 2015-08-17 14:48:56 +00:00
jan.nijtmans 1579eae899 merge trunk 2015-08-06 04:33:49 +00:00
jan.nijtmans 6fcdce9c74 merge trunk 2015-07-16 05:31:51 +00:00
jan.nijtmans ac785323be merge trunk. Undo unnecessary changes in tclEncoding.c, making it equal to trunk again (thanks to Christian Werner for testing this on androidwish). 2015-07-15 14:52:25 +00:00
jan.nijtmans d68207f7ca Remove unused local variables. Now unix/tclUnixTime.c is idential in "androwish" compared to "novem". (Yes, those functions are planned to be removed in Tcl 9.0!) 2015-07-15 09:31:11 +00:00
jan.nijtmans ddc615491d Merge trunk.
Remove TclpLocaltime, TclpGmtime and TclpGetDate completely, in order to prove that those functions are not used anywhere within Tcl any more. They are only retained for the internal stub entries, which might be used by extensions, but androwish doesn't use that.
2015-07-15 09:22:01 +00:00
jan.nijtmans b1031c0d07 merge trunk 2015-07-15 07:52:41 +00:00
jan.nijtmans cdba31b9d5 merge trunk 2015-07-13 09:41:02 +00:00
jan.nijtmans 83da0d6374 merge trunk 2015-07-02 13:18:19 +00:00
jan.nijtmans bb504b06b4 merge trunk 2015-07-02 12:19:15 +00:00
jan.nijtmans 55717aeaea merge trunk 2015-07-02 12:10:35 +00:00
jan.nijtmans e886aae69e merge trunk 2015-07-02 09:18:59 +00:00
jan.nijtmans adceea62b6 Branch for androwish, as help to keep track on which android-specific changes could be included into the core without harm. 2015-06-21 22:29:11 +00:00
jan.nijtmans 348f13ad57 Merge trunk. Upgrade to Unicode 8.0 2015-06-18 13:09:52 +00:00
hypnotoad e448db56ee Checkpointing the core_zip_vfs branch against the lastest release 2015-03-17 01:07:44 +00:00
jan.nijtmans dd60d52814 apply contributed patch which fixes a segfault 2015-01-17 18:40:19 +00:00
jan.nijtmans 428c3163c5 merge trunk 2015-01-17 17:42:53 +00:00
hypnotoad 339d4879a0 Bringing core_zip_vfs up to date with trunk 2014-12-05 15:05:08 +00:00
hypnotoad ded95f89d3 Added the zvfstools file to the installer 2014-11-17 15:04:05 +00:00
hypnotoad 5949095693 For the feature branch we now enable Zip file functions for all shells in Unix, and
explicitly name a new executable "basekit", which is a statically linked tclsh
with an attached library VFS
2014-11-15 00:12:00 +00:00
jan.nijtmans 410178bb88 Merge trunk.
Update to Unicode 8 beta
2014-11-14 12:29:54 +00:00
hypnotoad 9cbfbd034e Add a mode for injecting the TkDll into the VFS 2014-11-13 15:50:08 +00:00
hypnotoad 3b50f8bcd6 Removed _ANSI_ARGS_ macros. They were not compiling in Tk for some reason today... 2014-11-13 14:58:01 +00:00
hypnotoad 85442c797c Tweak to delete the tclzsh.vfs directory before the rm -rf tclvfs* statement
in "make clean"
2014-11-13 14:30:26 +00:00
hypnotoad 3e723b7f5e Merging in changes from trunk 2014-11-13 14:13:08 +00:00
hypnotoad 6b423f0d9e Fixes to allow a standard tclsh build to do the zip file encoding, instead of
having to do it all through the zip enabled shell.
2014-10-21 01:20:10 +00:00
hypnotoad bdc43f8241 Tweaked zvfstools to always allows the zvfs::mkzip command,
and defer the check for the rest of the zvfs tools until 
the first call to zvfs::unzip
2014-10-21 01:11:22 +00:00
hypnotoad 9171dde346 Replaced calls to zip with calls to the new pure-tcl zipfile encoder embedded
in zvfstools.

Fixed a bug in the encoder for zvfstools. It was exporting files, but not directories.
This lack of directories was causing the bootloader to miss that /zvfs/boot/tcl/init.tcl
existed, because it was checking for the existance of /zvfs/boot/tcl. I compared the 
archives created by zvfstools::mkzip to the archives created by zip, and the 
difference came down to the fact that zip did create TOC entries for directories
and zvfstools::mkzip was failing to do so. (So I'm pretty sure the new behavior 
is "standard.")
2014-10-21 01:04:07 +00:00
hypnotoad 6826dbab46 Added the zipfile::encode routine from Tcllib, and a rudimentary zipfile decode as a package "zvfstools" 2014-10-20 20:54:05 +00:00
hypnotoad b2164040ac Renamed "tclkit" to "tclzsh"
Removed tclzsh from "make binaries". (It the user wants it, they have to ask for it. It requires a working Tclsh and an exernal Zip)
2014-10-20 19:59:19 +00:00
hypnotoad 307bb5f72d Removed the dual ported canonical path mapping scheme to allow Odie and FreeWrap to coexist. The results of both functions were functionally identical. 2014-10-20 01:23:11 +00:00
hypnotoad 963de5ae2a Added thread mutex/release calls around the potentially contested regions of the code:
Mounting a file system
Unmounting a file system
Reading data from an archive file

The mutexes, as implemented, allow only one thread at a time access to the innards of ZipVfs. It does not try to handle the cases where two archives may be open by two different threads. (One will still have to wait until the other has finished.)

Removed all of the compiler warnings under Unix

(Still have to test the code under Windows.)
2014-10-20 01:20:54 +00:00
hypnotoad 2b022e6979 Added a "_bare" stage to capture the kit executable before the VFS is wrapped to it. 2014-10-19 20:20:09 +00:00
hypnotoad cfd9edb0fe Update the zipvfs implementation with additional code from both Odie and
Dennis LaBelle's FreeWrap.

Split the boot loader code out of tclZipVfs.c and into its own File.

Altered the structure of tclZipVfs.c to better mirror that which is distributed
in Odie and FreeWrap to make popping and swapping improvements easier.
2014-10-19 20:03:00 +00:00
seandeelywoods 74b45809d1 Bringing in the latest fixes from trunk 2014-10-19 11:06:00 +00:00
hypnotoad 507bab4b21 Merge with trunk 2014-09-22 18:27:45 +00:00
hypnotoad f45b6c1066 Merge from trunk 2014-09-19 06:36:34 +00:00
tne ebebb29be9 Walked back modifications to tclConfig.sh.in
(Builds don't require them anymore)
2014-09-17 08:33:16 +00:00
tne 2e0b2484a9 Removed non-working tclkit-direct makefile technique 2014-09-17 08:31:21 +00:00
hypnotoad ff7a13136d Added a "make tclkit" to makefile
Removed debugging fprintf
2014-09-16 23:07:44 +00:00
hypnotoad 4b8398a6ed Removed non-working code from the end of the mkVfs.tcl script 2014-09-15 14:59:20 +00:00
hypnotoad a684c1a281 Modified the makefile to produce a distinct name for a kit depending on whether
it was compiled statically or dynamically.

This allows builders to run and install successive builds of Tcl both
statically and dynamically.
2014-09-15 10:04:50 +00:00
hypnotoad b25f4f5272 The unix build has been pared down to the minimum hooks required to build a
VFS enabled Tclsh with a simple compile flag. Modified the BC and Visual Studio
makefiles for Windows, but these are untested.

The default for Tcl is now to build a static or dynamic shell in the same
way it would build a static or dynamic shell for Tclsh. Controlled by the
--enable-shared flag. Note however that ZLib is compiled in to every
VFS enabled shell. (Rather than rely on a dylib.)

The "direct" build is maintained in the Makefile, mostly as a h(istor|yster)ical
reference. The technique is not portable to Windows, and may not work outside of
OSX.
2014-09-15 09:44:39 +00:00
hypnotoad c003b95ed4 Backing out code that inserted a debug statement into the http package 2014-09-12 16:13:00 +00:00
hypnotoad 0cbfed0c55 Merging in changes from trunk 2014-09-12 16:06:13 +00:00
hypnotoad ee30b1c0ab Developed an improved bootloader built around TclSetPreInitScript. The new bootloader
now mounts the VFS before the interpreter is initialized, and gives it enough
hints to point to the VFS for init.tcl and main.tcl (If present)

Also, Tcl_ZVfs_Boot now takes and additional argument: the name of the file to mount.

As the difference between a normal shell and a zvfs enabled shell is one again, several
lines of code, the example shells is folded back into tclAppInit.c and controlled with
macros.

The ZVFS commands are now loaded in as a static package.

Removed the Stubs entry for Tcl_Boot_ZVFS, it's now intended that shells build
their own copy of tclZipVfs.o
2014-09-12 16:03:20 +00:00
hypnotoad b3362b7dfd Folding the core_zip_vfs_static work back into main branch. The pure-dynamic line
of research was not panning out
2014-09-09 15:23:16 +00:00
hypnotoad 99d72ae892 Added the "run tcl dll from vfs" magic to windows 2014-09-09 15:09:23 +00:00
hypnotoad 39145d45d1 Add tclkit to "make all" and install 2014-09-09 15:02:11 +00:00
hypnotoad 627a5bfa73 Instead of statically link the tclkit executable, pack the tcl dll in
the VFS
2014-09-09 14:47:12 +00:00
hypnotoad ab35383fda Add Static library link instructions to tclConfig.sh 2014-09-09 13:59:09 +00:00
hypnotoad 9f12483ed2 Instead of statically compiling the Tclkit executable straight from
.o files, generate a static library (libtclkit.a), and compile against
that.
2014-09-09 07:55:45 +00:00
hypnotoad 4e331e27f8 Added the tclkit binaries to install 2014-09-09 06:54:36 +00:00
hypnotoad 71e02d5298 Created a designated bootloader for Tclkits under windows
On windows, tclkits build a private VFS instead of relying on make install

Added a tool to build the tcl kit's VFS, as well as index the bundled packages
2014-09-06 11:41:26 +00:00
hypnotoad 0008ed9ea4 Preliminary checkin for Windows tclkit builds 2014-09-06 01:21:54 +00:00
hypnotoad 3bd1370dbc New build process for Tcl kits in Unix (Windows port to follow...)
Rather than force a "make install" to build the vfs, the tclkit now
performs it's own "install" to a subdirectory (using destdir) to collect
the files it needs for its vfs.

tclkits no longer link to the tcl library. Instead, all of the obj files that
are used to assemble the lib are instead packed into the executable. Thus,
"make tclkit" produces the tclkit. That's it. No dlls. No tclsh. Makes no
other mark on the file system save the bare essentials it needs. It uses the
same variables in the makefile as the tcl libraries, so as they are updated
so too is tclkit.

Zlib files are *always* build for tclkits. Tclkits can never rely on the
presence of zlib on the systems in which they will be installed.
2014-09-06 00:58:23 +00:00
hypnotoad a426ba29d5 Updating to the latest trunk 2014-09-05 20:34:55 +00:00
hypnotoad a813938bef Removed a typo 2014-09-04 01:27:55 +00:00
hypnotoad 295272b73c Removed some debugging code of mine... 2014-09-04 01:23:45 +00:00
hypnotoad 703177e26a Adapted the Unix startup process to ifdef out the KIT specific behaviors.
tclkit is now build as a standalone exectuble.
2014-09-04 01:22:20 +00:00
hypnotoad b992e62207 Re-engineered the windows kitbuilding process to produce a standalone
executable (in a similar process as tcltest is made).

The kit specific functions of tclAppInit have been wrapped around define 
macros, and are only active if TCL_KIT is defined. (Which is only done
when building the tclkit executable)
2014-09-04 00:30:04 +00:00
tne 4691bea988 Typo Fix 2014-09-03 22:03:08 +00:00
hypnotoad fce753c3d5 Merging changes from trunk 2014-09-03 21:24:17 +00:00
tne 670a31f84f Closing the hypnotoad branch 2014-09-03 21:11:30 +00:00
tne 25358e0ba4 Updating hypnotoad branch 2014-09-03 21:10:46 +00:00
hypnotoad b6f9bc7ca8 More tweaks to makefiles 2014-09-03 20:41:12 +00:00
hypnotoad 79ccab2fd2 Merging in changes from Tcl
Reduced the code necessary to bootstrap a shell to a single C call.

Reduced the number of new stub entries to 1

Fixed a Makefile goof that was preventing kits from running properly.
2014-09-03 20:32:08 +00:00
hypnotoad 8d1d673760 Backported dkf's documentation effort to the main core_zip_vfs branch 2014-09-03 10:50:06 +00:00
dkf 6c2512bc35 Clean up of docs, import basic text from comments in code, format. 2014-09-03 10:24:53 +00:00
hypnotoad 2c1a55d314 Merging in the "official" windows hang patch 2014-09-02 22:06:21 +00:00
hypnotoad e88bbb7296 Merging with fix_windows_zip 2014-09-02 21:19:56 +00:00
hypnotoad 06547a29be Fix for the cases where a dynamic build is used 2014-09-02 21:16:20 +00:00
hypnotoad 8ca1a78b1a Revised patch (per ferrieux) 2014-09-02 20:26:50 +00:00
hypnotoad 6c59decfba Merging in changes from core_zip_vfs 2014-09-02 20:17:57 +00:00
hypnotoad 732a963e04 Added a hac^H^H^Hpatch from ferrieux to mask around the exit hang on windows until
the issues are fixed at the core level.
2014-09-02 20:16:54 +00:00
hypnotoad cd9922f497 Pared down tclZipVfs to eliminate #ifdef branches that we don't have to worry
about with a modern Tcl.

Replaced dummy calls to VFS with NULL 

Where practical, replaced string-based Tcl IO calls with their new obj-based
successors. (Tcl_FSOpenChannel, Tcl_FSStat, etc)

Eliminated compiler warnings under Windows
2014-09-02 18:30:23 +00:00
hypnotoad 9554b52dba Start of the "hypnotoad" branch, combining the various patches I'm testing
against.
2014-09-02 15:23:56 +00:00
hypnotoad 8c90b3ae99 Patch to make the default behavior for Tcl under Windows to embed the Zlib
sources rather than add a dependency to a dynamic zlib.dll
2014-09-02 15:21:23 +00:00
hypnotoad 811d367c49 Rather than make a special executable, tclkits are now a copy of tclsh with an attached zip file 2014-09-02 11:04:53 +00:00
hypnotoad 1d9824ec60 Tweaking the Makefile instructions for Tclkits under unix 2014-09-01 23:23:37 +00:00
dkf 5c6730bd0f Squelch most warnings. 2014-09-01 13:51:59 +00:00
dkf 78b3c04320 Bring the source more into line with Tcl style. 2014-09-01 10:45:41 +00:00
hypnotoad 0ce217e309 Merging in changes from core. 2014-09-01 10:03:54 +00:00
hypnotoad d1536b7378 Tweaks to the Windows makefile. 2014-09-01 09:41:09 +00:00
hypnotoad eb664a3d72 Tweak the Windows implementation of Tcl_AppInit() to match Unix 2014-09-01 09:36:58 +00:00
hypnotoad 96dd5baf98 Adding the ability for the Tcl core to build self-contained Zip-based executables
* Integrated a pure-C implementation of ZipVfs
* Modified Tcl_AppInit() to look for a zipvfs mounted on the executable
2014-09-01 07:15:40 +00:00
jan.nijtmans 18eed1d727 merge trunk 2014-07-10 14:23:25 +00:00
jan.nijtmans ce72e40607 Merge trunk.
Update Unicode tables to Unicode 7.0 beta.
2014-05-01 09:40:52 +00:00
jan.nijtmans 8615597984 rebase TIP [http://tip.tcl.tk/425|425] implementation 2013-11-08 14:57:44 +00:00
jan.nijtmans a333bbaa12 rebase TIP [http://tip.tcl.tk/425|425] implementation 2013-08-19 09:10:36 +00:00
jan.nijtmans 2bc847ac57 rebase 2013-08-11 15:19:42 +00:00
dkf 24197ad684 merge trunk 2013-08-08 20:19:42 +00:00
dgp 92323ee89f merge trunk 2013-08-05 14:47:27 +00:00
dkf 0f2d93b3a6 merge trunk 2013-08-01 13:40:45 +00:00
dkf f96b9f2783 And documentation 2013-08-01 13:27:37 +00:00
dkf f370c68d92 Support type discovery in coroutines. 2013-08-01 13:21:04 +00:00
dkf f8e147cb73 Improving the test suite for [info cmdtype]. 2013-08-01 06:44:24 +00:00
dkf ceb88b82f1 merge trunk 2013-07-31 20:05:00 +00:00
dkf a6c0992f47 Added tests 2013-07-31 20:03:43 +00:00
jan.nijtmans 9283692888 rebase 2013-07-29 10:51:05 +00:00
dkf 9acc153698 merge trunk 2013-07-26 13:30:31 +00:00
jan.nijtmans 017b8b10b6 Fix Cygwin build: put Tcl_ConsolePanic in the stub library, not the dll. 2013-07-24 14:14:34 +00:00
jan.nijtmans 4ddfe70ae2 implement for Cygwin as well 2013-07-23 12:42:52 +00:00
jan.nijtmans 53dc25e532 Add documentation 2013-07-23 11:54:49 +00:00
jan.nijtmans 542b57cf21 rebase 2013-07-23 10:57:22 +00:00
dkf afd4d17b3c Changed subcommand name following community feedback. 2013-07-16 14:12:40 +00:00
dkf 82132b6c4c Some documentation. 2013-07-10 13:45:52 +00:00
dkf 21d8621d11 Added a mechanism for discovering the "type" of a command. 2013-07-07 11:15:08 +00:00
jan.nijtmans e36fd891e4 rebase 2013-06-27 09:07:04 +00:00
jan.nijtmans 954b241f34 rebase 2013-06-26 08:23:31 +00:00
jan.nijtmans f038b7fc3d merge trunk 2013-06-18 13:46:12 +00:00
jan.nijtmans 3f56494834 rebase 2013-06-18 09:52:53 +00:00
jan.nijtmans 6a811b97b9 rebase 2013-06-14 11:21:00 +00:00
jan.nijtmans 30dbc0a75b Update Unicode tables to Unicode 6.3 beta.
Merge trunk
2013-06-10 07:36:47 +00:00
jan.nijtmans 1900da6d24 rebase 2013-06-07 13:22:20 +00:00
jan.nijtmans 8f38d12eee TIP #414 implementation 2013-06-04 08:34:32 +00:00
jan.nijtmans 3f5f45f002 fix directory where tclWinPanic.c resides 2013-05-17 14:09:20 +00:00
jan.nijtmans e6528cb48d rebase 2013-05-17 07:36:01 +00:00
jan.nijtmans 041184928d rebase 2013-04-11 15:10:36 +00:00
jan.nijtmans b108063f75 rebase 2013-04-11 10:18:15 +00:00
jan.nijtmans 9ce336b3d1 rebase 2013-04-03 21:24:39 +00:00
jan.nijtmans b5da760544 rebase 2013-04-03 21:07:40 +00:00
jan.nijtmans 7e520e2089 rebase
increase limit to 26000 characters
2013-04-03 13:12:14 +00:00
jan.nijtmans 07af7d5337 better comments 2013-04-03 12:38:46 +00:00
jan.nijtmans 696a9ba3f9 Use Tcl_InitSubsystems in Tcl_Main macro 2013-04-01 21:48:51 +00:00
jan.nijtmans 9db6776dbe initsubsystems 2013-04-01 16:45:36 +00:00
jan.nijtmans 1c6a242b2e 2 lines not used any more 2013-03-31 22:09:40 +00:00
jan.nijtmans a58db736cf Fix Tcl_Main macro 2013-03-31 20:27:33 +00:00
jan.nijtmans 449ea43718 Going forward trying to define a better Tcl_InitStubsystems() 2013-03-31 20:17:46 +00:00
jan.nijtmans 260c2634b9 better leave tclPanic.c as it was 2013-03-31 19:32:57 +00:00
jan.nijtmans 6d0db57c02 Better Windows console panic proc, still to be TIPped. 2013-03-30 21:44:39 +00:00
dgp 11593d64b8 merge trunk so review patch/diff is smaller 2013-03-26 18:00:54 +00:00
jan.nijtmans e4a0b9dbfd Looks like TCL_INIT_CUSTOM (previously known as TCL_INIT_STUFF) is not a bad idea at all,
provided it has a Tcl_Interp* argument as well, so it can initialize the stub table.
A typedef for the function is not necessary, as a variable-argument function doesn't do any type checking. It's for the experienced developer anyway.
2013-03-26 15:57:45 +00:00
jan.nijtmans bb770e33f8 Add TCL_INIT_STUFF 2013-03-26 13:58:53 +00:00
jan.nijtmans d048128004 Version having TCL_INIT_PANIC as only Tcl_InitSubsystems() flag 2013-03-26 10:20:03 +00:00
jan.nijtmans eecece2afe TCL_INIT_ENCODINGPATH 2013-03-25 15:00:55 +00:00
jan.nijtmans 74c7068a25 merge trunk 2013-03-22 11:35:07 +00:00
jan.nijtmans 59360240b3 merge trunk 2013-03-06 13:38:05 +00:00
jan.nijtmans 57d33c5027 merge trunk 2013-03-06 13:37:19 +00:00
jan.nijtmans e1c5526cb2 Merge trunk.
Unicode 6.3 does not have that many spaces.....
2013-02-25 16:03:26 +00:00
jan.nijtmans 290c2ef84f Merge trunk.
Upgrade all tables to Unicode 6.3 (not released yet)
2013-02-25 13:38:06 +00:00
jan.nijtmans 91ba235b3c merge trunk.
Comment improvements, styling.
2013-02-23 20:16:30 +00:00
jan.nijtmans d13fe1e431 merge trunk.
Simplify dummy "interp" struct.
2013-02-23 11:19:13 +00:00
jan.nijtmans f361c1805c merge trunk.
doc improvements
2013-02-20 12:47:12 +00:00
jan.nijtmans 52b8ad45d1 Doc improvements.
Use freeProc field of pseudo interpreter to store the magic value.
2013-02-17 13:02:40 +00:00
jan.nijtmans 9b6c85d82e Merge trunk.
Move Tcl_InitSubsystems documentation to its own manpage
2013-02-15 10:29:05 +00:00
jan.nijtmans 88b8fc30a2 merge trunk 2013-02-14 10:11:58 +00:00
jan.nijtmans 1a0463ea04 merge trunk 2013-02-05 13:55:53 +00:00
jan.nijtmans cab91124b4 merge trunk 2013-02-04 22:58:38 +00:00
jan.nijtmans 8d9ea7c132 merge trunk 2013-02-03 16:07:32 +00:00
jan.nijtmans c5558280d7 merge trunk 2013-02-01 09:11:18 +00:00
jan.nijtmans 3913f5f7ae merge trunk 2013-01-26 17:04:32 +00:00
jan.nijtmans e8c69aa654 merge trunk
doc improvements
2013-01-26 00:45:01 +00:00
jan.nijtmans b2b37d97cf merge trunk 2013-01-25 13:12:01 +00:00
jan.nijtmans 4796adf5cb Another memory leak, and one Tcl_Free -> ckfree 2013-01-25 13:07:06 +00:00
jan.nijtmans 2c02c2ae5d Eliminate some unneeded usages of Tcl_SetResult, Tcl_AddObjErrorInfo
Fix "make test-packages" on cygwin
2013-01-25 11:45:17 +00:00
jan.nijtmans ef824b7395 merge trunk 2013-01-21 13:56:51 +00:00
jan.nijtmans 2930daf68c Implement TCL_INIT_CREATE_UTF8/TCL_INIT_CREATE_UNICODE 2013-01-10 09:23:39 +00:00
jan.nijtmans 0481e3ca74 New function Tcl_InitSubsystems, still to be TIP'ed 2013-01-09 10:30:00 +00:00
jan.nijtmans 073618d375 Merge trunk 2012-09-26 12:00:50 +00:00
jan.nijtmans 5ddf03d324 merge trunk 2012-04-22 20:51:02 +00:00
jan.nijtmans ac98be85ce merge trunk 2012-02-03 21:25:41 +00:00
jan.nijtmans 048fae9de6 merge trunk 2012-01-26 21:58:18 +00:00
jan.nijtmans 81735df1fa merge trunk 2012-01-23 22:19:24 +00:00
jan.nijtmans 9c32ab0d8b Merge to feature branch 2011-10-05 14:23:40 +00:00
jan.nijtmans 861e75f503 Merge to feature branch 2011-09-21 09:03:42 +00:00
jan.nijtmans e891120584 merge to feature branch 2011-09-17 07:19:28 +00:00
jan.nijtmans 2045bb3c21 merge to feature branch 2011-09-16 08:14:27 +00:00
jan.nijtmans a498488c59 Merge to feature branch 2011-08-29 07:44:12 +00:00
jan.nijtmans dd43ee3dbf Merge to feature branch 2011-08-25 12:11:24 +00:00
jan.nijtmans 39ad9eb8f3 fix tests utf-2.8 and utf-2.9 2011-08-24 08:32:39 +00:00
jan.nijtmans b30ba5a92b Upcoming TIP implementation: Full support for Unicode 6.0 2011-08-24 07:50:13 +00:00
225 changed files with 22727 additions and 4641 deletions
+1
View File
@@ -4,6 +4,7 @@ compat/zlib/win64/zdll.lib
compat/zlib/win64/zlib1.dll
compat/zlib/win64/libz.dll.a
compat/zlib/zlib.3.pdf
tools/empty.zip
*.bmp
*.gif
*.png
+3
View File
@@ -0,0 +1,3 @@
Important Note
==========
Please do not file issues with Tcl on Github. They are unlikely to be noticed in a timely fashion. Tcl issues are hosted in the [tcl fossil repository on core.tcl.tk](https://core.tcl.tk/tcl/tktnew); please post them there.
+3
View File
@@ -0,0 +1,3 @@
Important Note
==========
Please do not file pull requests with Tcl on Github. They are unlikely to be noticed in a timely fashion. Tcl issues (including patches) are hosted in the [tcl fossil repository on core.tcl.tk](https://core.tcl.tk/tcl/tktnew); please post them there.
+151 -113
View File
@@ -12,7 +12,6 @@
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
*/
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
#ifndef __USE_FILE_OFFSET64
#define __USE_FILE_OFFSET64
@@ -39,8 +38,7 @@
#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
#endif
#include "tinydir.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -172,6 +170,7 @@ void do_banner()
void do_help()
{
printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \
" -r Scan directories recursively\n" \
" -o Overwrite existing file.zip\n" \
" -a Append to existing file.zip\n" \
" -0 Store only\n" \
@@ -243,12 +242,153 @@ int isLargeFile(const char* filename)
return largeFile;
}
void addFileToZip(zipFile zf, const char *filenameinzip, const char *password, int opt_exclude_path,int opt_compress_level) {
FILE * fin;
int size_read;
const char *savefilenameinzip;
zip_fileinfo zi;
unsigned long crcFile=0;
int zip64 = 0;
int err=0;
int size_buf=WRITEBUFFERSIZE;
unsigned char buf[WRITEBUFFERSIZE];
zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
zi.dosDate = 0;
zi.internal_fa = 0;
zi.external_fa = 0;
filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
/*
err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
NULL,0,NULL,0,NULL / * comment * /,
(opt_compress_level != 0) ? Z_DEFLATED : 0,
opt_compress_level);
*/
if ((password != NULL) && (err==ZIP_OK))
err = getFileCrc(filenameinzip,buf,size_buf,&crcFile);
zip64 = isLargeFile(filenameinzip);
/* The path name saved, should not include a leading slash. */
/*if it did, windows/xp and dynazip couldn't read the zip file. */
savefilenameinzip = filenameinzip;
while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' )
{
savefilenameinzip++;
}
/*should the zip file contain any path at all?*/
if( opt_exclude_path )
{
const char *tmpptr;
const char *lastslash = 0;
for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++)
{
if( *tmpptr == '\\' || *tmpptr == '/')
{
lastslash = tmpptr;
}
}
if( lastslash != NULL )
{
savefilenameinzip = lastslash+1; // base filename follows last slash.
}
}
/**/
err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi,
NULL,0,NULL,0,NULL /* comment*/,
(opt_compress_level != 0) ? Z_DEFLATED : 0,
opt_compress_level,0,
/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
password,crcFile, zip64);
if (err != ZIP_OK)
printf("error in opening %s in zipfile\n",filenameinzip);
else
{
fin = FOPEN_FUNC(filenameinzip,"rb");
if (fin==NULL)
{
err=ZIP_ERRNO;
printf("error in opening %s for reading\n",filenameinzip);
}
}
if (err == ZIP_OK)
do
{
err = ZIP_OK;
size_read = (int)fread(buf,1,size_buf,fin);
if (size_read < size_buf)
if (feof(fin)==0)
{
printf("error in reading %s\n",filenameinzip);
err = ZIP_ERRNO;
}
if (size_read>0)
{
err = zipWriteInFileInZip (zf,buf,size_read);
if (err<0)
{
printf("error in writing %s in the zipfile\n",
filenameinzip);
}
}
} while ((err == ZIP_OK) && (size_read>0));
if (fin)
fclose(fin);
if (err<0)
err=ZIP_ERRNO;
else
{
err = zipCloseFileInZip(zf);
if (err!=ZIP_OK)
printf("error in closing %s in the zipfile\n",
filenameinzip);
}
}
void addPathToZip(zipFile zf, const char *filenameinzip, const char *password, int opt_exclude_path,int opt_compress_level) {
tinydir_dir dir;
int i;
char *newname[512];
tinydir_open_sorted(&dir, filenameinzip);
for (i = 0; i < dir.n_files; i++)
{
tinydir_file file;
tinydir_readfile_n(&dir, &file, i);
if(strcmp(file.name,".")==0) continue;
if(strcmp(file.name,"..")==0) continue;
sprintf(newname,"%s/%s",dir.path,file.name);
if (file.is_dir)
{
addPathToZip(zf,newname,password,opt_exclude_path,opt_compress_level);
} else {
addFileToZip(zf,newname,password,opt_exclude_path,opt_compress_level);
}
}
tinydir_close(&dir);
}
int main(argc,argv)
int argc;
char *argv[];
{
int i;
int opt_overwrite=0;
int opt_recursive=0;
int opt_overwrite=1;
int opt_compress_level=Z_DEFAULT_COMPRESSION;
int opt_exclude_path=0;
int zipfilenamearg = 0;
@@ -285,7 +425,8 @@ int main(argc,argv)
opt_compress_level = c-'0';
if ((c=='j') || (c=='J'))
opt_exclude_path = 1;
if ((c=='r') || (c=='R'))
opt_recursive = 1;
if (((c=='p') || (c=='P')) && (i+1<argc))
{
password=argv[i+1];
@@ -392,117 +533,14 @@ int main(argc,argv)
((argv[i][1]=='o') || (argv[i][1]=='O') ||
(argv[i][1]=='a') || (argv[i][1]=='A') ||
(argv[i][1]=='p') || (argv[i][1]=='P') ||
(argv[i][1]=='r') || (argv[i][1]=='R') ||
((argv[i][1]>='0') || (argv[i][1]<='9'))) &&
(strlen(argv[i]) == 2)))
{
FILE * fin;
int size_read;
const char* filenameinzip = argv[i];
const char *savefilenameinzip;
zip_fileinfo zi;
unsigned long crcFile=0;
int zip64 = 0;
zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
zi.dosDate = 0;
zi.internal_fa = 0;
zi.external_fa = 0;
filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
/*
err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
NULL,0,NULL,0,NULL / * comment * /,
(opt_compress_level != 0) ? Z_DEFLATED : 0,
opt_compress_level);
*/
if ((password != NULL) && (err==ZIP_OK))
err = getFileCrc(filenameinzip,buf,size_buf,&crcFile);
zip64 = isLargeFile(filenameinzip);
/* The path name saved, should not include a leading slash. */
/*if it did, windows/xp and dynazip couldn't read the zip file. */
savefilenameinzip = filenameinzip;
while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' )
{
savefilenameinzip++;
}
/*should the zip file contain any path at all?*/
if( opt_exclude_path )
{
const char *tmpptr;
const char *lastslash = 0;
for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++)
{
if( *tmpptr == '\\' || *tmpptr == '/')
{
lastslash = tmpptr;
}
}
if( lastslash != NULL )
{
savefilenameinzip = lastslash+1; // base filename follows last slash.
}
}
/**/
err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi,
NULL,0,NULL,0,NULL /* comment*/,
(opt_compress_level != 0) ? Z_DEFLATED : 0,
opt_compress_level,0,
/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
password,crcFile, zip64);
if (err != ZIP_OK)
printf("error in opening %s in zipfile\n",filenameinzip);
else
{
fin = FOPEN_FUNC(filenameinzip,"rb");
if (fin==NULL)
{
err=ZIP_ERRNO;
printf("error in opening %s for reading\n",filenameinzip);
}
}
if (err == ZIP_OK)
do
{
err = ZIP_OK;
size_read = (int)fread(buf,1,size_buf,fin);
if (size_read < size_buf)
if (feof(fin)==0)
{
printf("error in reading %s\n",filenameinzip);
err = ZIP_ERRNO;
}
if (size_read>0)
{
err = zipWriteInFileInZip (zf,buf,size_read);
if (err<0)
{
printf("error in writing %s in the zipfile\n",
filenameinzip);
}
}
} while ((err == ZIP_OK) && (size_read>0));
if (fin)
fclose(fin);
if (err<0)
err=ZIP_ERRNO;
else
{
err = zipCloseFileInZip(zf);
if (err!=ZIP_OK)
printf("error in closing %s in the zipfile\n",
filenameinzip);
if(opt_recursive) {
addPathToZip(zf,argv[i],password,opt_exclude_path,opt_compress_level);
} else {
addFileToZip(zf,argv[i],password,opt_exclude_path,opt_compress_level);
}
}
}
+816
View File
@@ -0,0 +1,816 @@
/*
Copyright (c) 2013-2017, tinydir authors:
- Cong Xu
- Lautis Sun
- Baudouin Feildel
- Andargor <andargor@yahoo.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TINYDIR_H
#define TINYDIR_H
#ifdef __cplusplus
extern "C" {
#endif
#if ((defined _UNICODE) && !(defined UNICODE))
#define UNICODE
#endif
#if ((defined UNICODE) && !(defined _UNICODE))
#define _UNICODE
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <tchar.h>
# pragma warning(push)
# pragma warning (disable : 4996)
#else
# include <dirent.h>
# include <libgen.h>
# include <sys/stat.h>
# include <stddef.h>
#endif
#ifdef __MINGW32__
# include <tchar.h>
#endif
/* types */
/* Windows UNICODE wide character support */
#if defined _MSC_VER || defined __MINGW32__
# define _tinydir_char_t TCHAR
# define TINYDIR_STRING(s) _TEXT(s)
# define _tinydir_strlen _tcslen
# define _tinydir_strcpy _tcscpy
# define _tinydir_strcat _tcscat
# define _tinydir_strcmp _tcscmp
# define _tinydir_strrchr _tcsrchr
# define _tinydir_strncmp _tcsncmp
#else
# define _tinydir_char_t char
# define TINYDIR_STRING(s) s
# define _tinydir_strlen strlen
# define _tinydir_strcpy strcpy
# define _tinydir_strcat strcat
# define _tinydir_strcmp strcmp
# define _tinydir_strrchr strrchr
# define _tinydir_strncmp strncmp
#endif
#if (defined _MSC_VER || defined __MINGW32__)
# include <windows.h>
# define _TINYDIR_PATH_MAX MAX_PATH
#elif defined __linux__
# include <limits.h>
# define _TINYDIR_PATH_MAX PATH_MAX
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# include <sys/param.h>
# if defined(BSD)
# include <limits.h>
# define _TINYDIR_PATH_MAX PATH_MAX
# endif
#endif
#ifndef _TINYDIR_PATH_MAX
#define _TINYDIR_PATH_MAX 4096
#endif
#ifdef _MSC_VER
/* extra chars for the "\\*" mask */
# define _TINYDIR_PATH_EXTRA 2
#else
# define _TINYDIR_PATH_EXTRA 0
#endif
#define _TINYDIR_FILENAME_MAX 256
#if (defined _MSC_VER || defined __MINGW32__)
#define _TINYDIR_DRIVE_MAX 3
#endif
#ifdef _MSC_VER
# define _TINYDIR_FUNC static __inline
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
# define _TINYDIR_FUNC static __inline__
#else
# define _TINYDIR_FUNC static inline
#endif
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
#ifdef TINYDIR_USE_READDIR_R
/* readdir_r is a POSIX-only function, and may not be available under various
* environments/settings, e.g. MinGW. Use readdir fallback */
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
_POSIX_SOURCE
# define _TINYDIR_HAS_READDIR_R
#endif
#if _POSIX_C_SOURCE >= 200112L
# define _TINYDIR_HAS_FPATHCONF
# include <unistd.h>
#endif
#if _BSD_SOURCE || _SVID_SOURCE || \
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
# define _TINYDIR_HAS_DIRFD
# include <sys/types.h>
#endif
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
defined _PC_NAME_MAX
# define _TINYDIR_USE_FPATHCONF
#endif
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
# define _TINYDIR_USE_READDIR
#endif
/* Use readdir by default */
#else
# define _TINYDIR_USE_READDIR
#endif
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
#ifndef _MSC_VER
#if (defined __MINGW32__) && (defined _UNICODE)
#define _TINYDIR_DIR _WDIR
#define _tinydir_dirent _wdirent
#define _tinydir_opendir _wopendir
#define _tinydir_readdir _wreaddir
#define _tinydir_closedir _wclosedir
#else
#define _TINYDIR_DIR DIR
#define _tinydir_dirent dirent
#define _tinydir_opendir opendir
#define _tinydir_readdir readdir
#define _tinydir_closedir closedir
#endif
#endif
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
#else
#error "Either define both alloc and free or none of them!"
#endif
#if !defined(_TINYDIR_MALLOC)
#define _TINYDIR_MALLOC(_size) malloc(_size)
#define _TINYDIR_FREE(_ptr) free(_ptr)
#endif /* !defined(_TINYDIR_MALLOC) */
typedef struct tinydir_file
{
_tinydir_char_t path[_TINYDIR_PATH_MAX];
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
_tinydir_char_t *extension;
int is_dir;
int is_reg;
#ifndef _MSC_VER
#ifdef __MINGW32__
struct _stat _s;
#else
struct stat _s;
#endif
#endif
} tinydir_file;
typedef struct tinydir_dir
{
_tinydir_char_t path[_TINYDIR_PATH_MAX];
int has_next;
size_t n_files;
tinydir_file *_files;
#ifdef _MSC_VER
HANDLE _h;
WIN32_FIND_DATA _f;
#else
_TINYDIR_DIR *_d;
struct _tinydir_dirent *_e;
#ifndef _TINYDIR_USE_READDIR
struct _tinydir_dirent *_ep;
#endif
#endif
} tinydir_dir;
/* declarations */
_TINYDIR_FUNC
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
_TINYDIR_FUNC
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
_TINYDIR_FUNC
void tinydir_close(tinydir_dir *dir);
_TINYDIR_FUNC
int tinydir_next(tinydir_dir *dir);
_TINYDIR_FUNC
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
_TINYDIR_FUNC
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
_TINYDIR_FUNC
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
_TINYDIR_FUNC
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
_TINYDIR_FUNC
void _tinydir_get_ext(tinydir_file *file);
_TINYDIR_FUNC
int _tinydir_file_cmp(const void *a, const void *b);
#ifndef _MSC_VER
#ifndef _TINYDIR_USE_READDIR
_TINYDIR_FUNC
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
#endif
#endif
/* definitions*/
_TINYDIR_FUNC
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
{
#ifndef _MSC_VER
#ifndef _TINYDIR_USE_READDIR
int error;
int size; /* using int size */
#endif
#else
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
#endif
_tinydir_char_t *pathp;
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
{
errno = EINVAL;
return -1;
}
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
/* initialise dir */
dir->_files = NULL;
#ifdef _MSC_VER
dir->_h = INVALID_HANDLE_VALUE;
#else
dir->_d = NULL;
#ifndef _TINYDIR_USE_READDIR
dir->_ep = NULL;
#endif
#endif
tinydir_close(dir);
_tinydir_strcpy(dir->path, path);
/* Remove trailing slashes */
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
{
*pathp = TINYDIR_STRING('\0');
pathp++;
}
#ifdef _MSC_VER
_tinydir_strcpy(path_buf, dir->path);
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
#else
dir->_h = FindFirstFile(path_buf, &dir->_f);
#endif
if (dir->_h == INVALID_HANDLE_VALUE)
{
errno = ENOENT;
#else
dir->_d = _tinydir_opendir(path);
if (dir->_d == NULL)
{
#endif
goto bail;
}
/* read first file */
dir->has_next = 1;
#ifndef _MSC_VER
#ifdef _TINYDIR_USE_READDIR
dir->_e = _tinydir_readdir(dir->_d);
#else
/* allocate dirent buffer for readdir_r */
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
if (size == -1) return -1;
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
if (dir->_ep == NULL) return -1;
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
if (error != 0) return -1;
#endif
if (dir->_e == NULL)
{
dir->has_next = 0;
}
#endif
return 0;
bail:
tinydir_close(dir);
return -1;
}
_TINYDIR_FUNC
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
{
/* Count the number of files first, to pre-allocate the files array */
size_t n_files = 0;
if (tinydir_open(dir, path) == -1)
{
return -1;
}
while (dir->has_next)
{
n_files++;
if (tinydir_next(dir) == -1)
{
goto bail;
}
}
tinydir_close(dir);
if (tinydir_open(dir, path) == -1)
{
return -1;
}
dir->n_files = 0;
dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
if (dir->_files == NULL)
{
goto bail;
}
while (dir->has_next)
{
tinydir_file *p_file;
dir->n_files++;
p_file = &dir->_files[dir->n_files - 1];
if (tinydir_readfile(dir, p_file) == -1)
{
goto bail;
}
if (tinydir_next(dir) == -1)
{
goto bail;
}
/* Just in case the number of files has changed between the first and
second reads, terminate without writing into unallocated memory */
if (dir->n_files == n_files)
{
break;
}
}
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
return 0;
bail:
tinydir_close(dir);
return -1;
}
_TINYDIR_FUNC
void tinydir_close(tinydir_dir *dir)
{
if (dir == NULL)
{
return;
}
memset(dir->path, 0, sizeof(dir->path));
dir->has_next = 0;
dir->n_files = 0;
_TINYDIR_FREE(dir->_files);
dir->_files = NULL;
#ifdef _MSC_VER
if (dir->_h != INVALID_HANDLE_VALUE)
{
FindClose(dir->_h);
}
dir->_h = INVALID_HANDLE_VALUE;
#else
if (dir->_d)
{
_tinydir_closedir(dir->_d);
}
dir->_d = NULL;
dir->_e = NULL;
#ifndef _TINYDIR_USE_READDIR
_TINYDIR_FREE(dir->_ep);
dir->_ep = NULL;
#endif
#endif
}
_TINYDIR_FUNC
int tinydir_next(tinydir_dir *dir)
{
if (dir == NULL)
{
errno = EINVAL;
return -1;
}
if (!dir->has_next)
{
errno = ENOENT;
return -1;
}
#ifdef _MSC_VER
if (FindNextFile(dir->_h, &dir->_f) == 0)
#else
#ifdef _TINYDIR_USE_READDIR
dir->_e = _tinydir_readdir(dir->_d);
#else
if (dir->_ep == NULL)
{
return -1;
}
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
{
return -1;
}
#endif
if (dir->_e == NULL)
#endif
{
dir->has_next = 0;
#ifdef _MSC_VER
if (GetLastError() != ERROR_SUCCESS &&
GetLastError() != ERROR_NO_MORE_FILES)
{
tinydir_close(dir);
errno = EIO;
return -1;
}
#endif
}
return 0;
}
_TINYDIR_FUNC
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
{
if (dir == NULL || file == NULL)
{
errno = EINVAL;
return -1;
}
#ifdef _MSC_VER
if (dir->_h == INVALID_HANDLE_VALUE)
#else
if (dir->_e == NULL)
#endif
{
errno = ENOENT;
return -1;
}
if (_tinydir_strlen(dir->path) +
_tinydir_strlen(
#ifdef _MSC_VER
dir->_f.cFileName
#else
dir->_e->d_name
#endif
) + 1 + _TINYDIR_PATH_EXTRA >=
_TINYDIR_PATH_MAX)
{
/* the path for the file will be too long */
errno = ENAMETOOLONG;
return -1;
}
if (_tinydir_strlen(
#ifdef _MSC_VER
dir->_f.cFileName
#else
dir->_e->d_name
#endif
) >= _TINYDIR_FILENAME_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
_tinydir_strcpy(file->path, dir->path);
_tinydir_strcat(file->path, TINYDIR_STRING("/"));
_tinydir_strcpy(file->name,
#ifdef _MSC_VER
dir->_f.cFileName
#else
dir->_e->d_name
#endif
);
_tinydir_strcat(file->path, file->name);
#ifndef _MSC_VER
#ifdef __MINGW32__
if (_tstat(
#else
if (stat(
#endif
file->path, &file->_s) == -1)
{
return -1;
}
#endif
_tinydir_get_ext(file);
file->is_dir =
#ifdef _MSC_VER
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
#else
S_ISDIR(file->_s.st_mode);
#endif
file->is_reg =
#ifdef _MSC_VER
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
(
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
#endif
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
#endif
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
#else
S_ISREG(file->_s.st_mode);
#endif
return 0;
}
_TINYDIR_FUNC
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
{
if (dir == NULL || file == NULL)
{
errno = EINVAL;
return -1;
}
if (i >= dir->n_files)
{
errno = ENOENT;
return -1;
}
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
_tinydir_get_ext(file);
return 0;
}
_TINYDIR_FUNC
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
{
_tinydir_char_t path[_TINYDIR_PATH_MAX];
if (dir == NULL)
{
errno = EINVAL;
return -1;
}
if (i >= dir->n_files || !dir->_files[i].is_dir)
{
errno = ENOENT;
return -1;
}
_tinydir_strcpy(path, dir->_files[i].path);
tinydir_close(dir);
if (tinydir_open_sorted(dir, path) == -1)
{
return -1;
}
return 0;
}
/* Open a single file given its path */
_TINYDIR_FUNC
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
{
tinydir_dir dir;
int result = 0;
int found = 0;
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
_tinydir_char_t *dir_name;
_tinydir_char_t *base_name;
#if (defined _MSC_VER || defined __MINGW32__)
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
#endif
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
{
errno = EINVAL;
return -1;
}
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
/* Get the parent path */
#if (defined _MSC_VER || defined __MINGW32__)
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
_tsplitpath_s(
path,
drive_buf, _TINYDIR_DRIVE_MAX,
dir_name_buf, _TINYDIR_FILENAME_MAX,
file_name_buf, _TINYDIR_FILENAME_MAX,
ext_buf, _TINYDIR_FILENAME_MAX);
#else
_tsplitpath(
path,
drive_buf,
dir_name_buf,
file_name_buf,
ext_buf);
#endif
/* _splitpath_s not work fine with only filename and widechar support */
#ifdef _UNICODE
if (drive_buf[0] == L'\xFEFE')
drive_buf[0] = '\0';
if (dir_name_buf[0] == L'\xFEFE')
dir_name_buf[0] = '\0';
#endif
if (errno)
{
errno = EINVAL;
return -1;
}
/* Emulate the behavior of dirname by returning "." for dir name if it's
empty */
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
{
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
}
/* Concatenate the drive letter and dir name to form full dir name */
_tinydir_strcat(drive_buf, dir_name_buf);
dir_name = drive_buf;
/* Concatenate the file name and extension to form base name */
_tinydir_strcat(file_name_buf, ext_buf);
base_name = file_name_buf;
#else
_tinydir_strcpy(dir_name_buf, path);
dir_name = dirname(dir_name_buf);
_tinydir_strcpy(file_name_buf, path);
base_name =basename(file_name_buf);
#endif
/* Open the parent directory */
if (tinydir_open(&dir, dir_name) == -1)
{
return -1;
}
/* Read through the parent directory and look for the file */
while (dir.has_next)
{
if (tinydir_readfile(&dir, file) == -1)
{
result = -1;
goto bail;
}
if (_tinydir_strcmp(file->name, base_name) == 0)
{
/* File found */
found = 1;
break;
}
tinydir_next(&dir);
}
if (!found)
{
result = -1;
errno = ENOENT;
}
bail:
tinydir_close(&dir);
return result;
}
_TINYDIR_FUNC
void _tinydir_get_ext(tinydir_file *file)
{
_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
if (period == NULL)
{
file->extension = &(file->name[_tinydir_strlen(file->name)]);
}
else
{
file->extension = period + 1;
}
}
_TINYDIR_FUNC
int _tinydir_file_cmp(const void *a, const void *b)
{
const tinydir_file *fa = (const tinydir_file *)a;
const tinydir_file *fb = (const tinydir_file *)b;
if (fa->is_dir != fb->is_dir)
{
return -(fa->is_dir - fb->is_dir);
}
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
}
#ifndef _MSC_VER
#ifndef _TINYDIR_USE_READDIR
/*
The following authored by Ben Hutchings <ben@decadent.org.uk>
from https://womble.decadent.org.uk/readdir_r-advisory.html
*/
/* Calculate the required buffer size (in bytes) for directory *
* entries read from the given directory handle. Return -1 if this *
* this cannot be done. *
* *
* This code does not trust values of NAME_MAX that are less than *
* 255, since some systems (including at least HP-UX) incorrectly *
* define it to be a smaller value. */
_TINYDIR_FUNC
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
{
long name_max;
size_t name_end;
/* parameter may be unused */
(void)dirp;
#if defined _TINYDIR_USE_FPATHCONF
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
if (name_max == -1)
#if defined(NAME_MAX)
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
#else
return (size_t)(-1);
#endif
#elif defined(NAME_MAX)
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
#else
#error "buffer size for readdir_r cannot be determined"
#endif
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
return (name_end > sizeof(struct _tinydir_dirent) ?
name_end : sizeof(struct _tinydir_dirent));
}
#endif
#endif
#ifdef __cplusplus
}
#endif
# if defined (_MSC_VER)
# pragma warning(pop)
# endif
#endif
Executable → Regular
View File
+28 -1
View File
@@ -8,7 +8,7 @@
.so man.macros
.BS
.SH NAME
Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, Tcl_GetCommandInfo, Tcl_GetCommandInfoFromToken, Tcl_SetCommandInfo, Tcl_SetCommandInfoFromToken, Tcl_GetCommandName, Tcl_GetCommandFullName, Tcl_GetCommandFromObj \- implement new commands in C
Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, Tcl_GetCommandInfo, Tcl_GetCommandInfoFromToken, Tcl_SetCommandInfo, Tcl_SetCommandInfoFromToken, Tcl_GetCommandName, Tcl_GetCommandFullName, Tcl_GetCommandFromObj Tcl_RegisterCommandTypeName, Tcl_GetCommandTypeName \- implement new commands in C
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
@@ -42,6 +42,14 @@ void
.sp
Tcl_Command
\fBTcl_GetCommandFromObj\fR(\fIinterp, objPtr\fR)
.sp
.VS "info cmdtype feature"
void
\fBTcl_RegisterCommandTypeName\fR(\fIproc, typeName\fR)
.sp
const char *
\fBTcl_GetCommandTypeName\fR(\fItoken\fR)
.VE "info cmdtype feature"
.SH ARGUMENTS
.AS Tcl_CmdDeleteProc *deleteProc in/out
.AP Tcl_Interp *interp in
@@ -65,6 +73,9 @@ Pointer to structure containing various information about a
Tcl command.
.AP Tcl_Obj *objPtr in
Value containing the name of a Tcl command.
.AP "const char" *typeName in
Indicates the name of the type of command implementation associated
with a particular \fIproc\fR, or NULL to break the association.
.BE
.SH DESCRIPTION
.PP
@@ -296,6 +307,22 @@ is appended to the value specified by \fIobjPtr\fR.
specified by the name in a \fBTcl_Obj\fR.
The command name is resolved relative to the current namespace.
Returns NULL if the command is not found.
.PP
.VS "info cmdtype feature"
\fBTcl_RegisterCommandTypeName\fR is used to associate a name (the
\fItypeName\fR argument) with a particular implementation function so that it
can then be looked up with \fBTcl_GetCommandTypeName\fR, which in turn is
called with a command token that information is wanted for and which returns
the name of the type that was registered for the implementation function used
for that command. (The lookup functionality is surfaced virtually directly in Tcl via
\fBinfo cmdtype\fR.) If there is no function registered for a particular
function, the result will be the string literal
.QW \fBnative\fR .
The registration of a name can be undone by registering a mapping to NULL
instead. The result from \fBTcl_GetCommandTypeName\fR will be exactly that
string which was registered, and not a copy; use of a compile-time constant
string is \fIstrongly recommended\fR.
.VE "info cmdtype feature"
.SH "SEE ALSO"
Tcl_CreateCommand(3), Tcl_ResetResult(3), Tcl_SetObjResult(3)
.SH KEYWORDS
+31 -13
View File
@@ -9,18 +9,18 @@
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_ClassSetConstructor, Tcl_ClassSetDestructor, Tcl_MethodDeclarerClass, Tcl_MethodDeclarerObject, Tcl_MethodIsPublic, Tcl_MethodIsType, Tcl_MethodName, Tcl_NewInstanceMethod, Tcl_NewMethod, Tcl_ObjectContextInvokeNext, Tcl_ObjectContextIsFiltering, Tcl_ObjectContextMethod, Tcl_ObjectContextObject, Tcl_ObjectContextSkippedArgs \- manipulate methods and method-call contexts
Tcl_ClassSetConstructor, Tcl_ClassSetDestructor, Tcl_MethodDeclarerClass, Tcl_MethodDeclarerObject, Tcl_MethodIsPublic, Tcl_MethodIsPrivate, Tcl_MethodIsType, Tcl_MethodName, Tcl_NewInstanceMethod, Tcl_NewMethod, Tcl_ObjectContextInvokeNext, Tcl_ObjectContextIsFiltering, Tcl_ObjectContextMethod, Tcl_ObjectContextObject, Tcl_ObjectContextSkippedArgs \- manipulate methods and method-call contexts
.SH SYNOPSIS
.nf
\fB#include <tclOO.h>\fR
.sp
Tcl_Method
\fBTcl_NewMethod\fR(\fIinterp, class, nameObj, isPublic,
methodTypePtr, clientData\fR)
\fBTcl_NewMethod\fR(\fIinterp, class, nameObj, flags, methodTypePtr,
clientData\fR)
.sp
Tcl_Method
\fBTcl_NewInstanceMethod\fR(\fIinterp, object, nameObj, isPublic,
methodTypePtr, clientData\fR)
\fBTcl_NewInstanceMethod\fR(\fIinterp, object, nameObj, flags, methodTypePtr,
clientData\fR)
.sp
\fBTcl_ClassSetConstructor\fR(\fIinterp, class, method\fR)
.sp
@@ -35,8 +35,13 @@ Tcl_Object
Tcl_Obj *
\fBTcl_MethodName\fR(\fImethod\fR)
.sp
.VS TIP500
int
\fBTcl_MethodIsPublic\fR(\fImethod\fR)
.VE TIP500
.sp
int
\fBTcl_MethodIsPrivate\fR(\fImethod\fR)
.sp
int
\fBTcl_MethodIsType\fR(\fImethod, methodTypePtr, clientDataPtr\fR)
@@ -66,10 +71,15 @@ The class to create the method in.
.AP Tcl_Obj *nameObj in
The name of the method to create. Should not be NULL unless creating
constructors or destructors.
.AP int isPublic in
A flag saying what the visibility of the method is. The only supported public
values of this flag are 0 for a non-exported method, and 1 for an exported
method.
.AP int flags in
A flag saying (currently) what the visibility of the method is. The supported
public values of this flag are \fBTCL_OO_METHOD_PUBLIC\fR (which is fixed at 1
for backward compatibility) for an exported method,
\fBTCL_OO_METHOD_UNEXPORTED\fR (which is fixed at 0 for backward
compatibility) for a non-exported method,
.VS TIP500
and \fBTCL_OO_METHOD_PRIVATE\fR for a private method.
.VE TIP500
.AP Tcl_MethodType *methodTypePtr in
A description of the type of the method to create, or the type of method to
compare against.
@@ -105,8 +115,12 @@ Given a method, the entity that declared it can be found using
attached to (or NULL if the method is not attached to any class) and
\fBTcl_MethodDeclarerObject\fR which returns the object that the method is
attached to (or NULL if the method is not attached to an object). The name of
the method can be retrieved with \fBTcl_MethodName\fR and whether the method
is exported is retrieved with \fBTcl_MethodIsPublic\fR. The type of the method
the method can be retrieved with \fBTcl_MethodName\fR, whether the method
is exported is retrieved with \fBTcl_MethodIsPublic\fR,
.VS TIP500
and whether the method is private is retrieved with \fBTcl_MethodIsPrivate\fR.
.VE TIP500
The type of the method
can also be introspected upon to a limited degree; the function
\fBTcl_MethodIsType\fR returns whether a method is of a particular type,
assigning the per-method \fIclientData\fR to the variable pointed to by
@@ -117,8 +131,12 @@ Methods are created by \fBTcl_NewMethod\fR and \fBTcl_NewInstanceMethod\fR,
which
create a method attached to a class or an object respectively. In both cases,
the \fInameObj\fR argument gives the name of the method to create, the
\fIisPublic\fR argument states whether the method should be exported
initially, the \fImethodTypePtr\fR argument describes the implementation of
\fIflags\fR argument states whether the method should be exported
initially
.VS TIP500
or be marked as a private method,
.VE TIP500
the \fImethodTypePtr\fR argument describes the implementation of
the method (see the \fBMETHOD TYPES\fR section below) and the \fIclientData\fR
argument gives some implementation-specific data that is passed on to the
implementation of the method when it is called.
+1 -1
View File
@@ -1,6 +1,6 @@
.\"
.\" Copyright (c) 2008 by Kevin B. Kenny.
.\" Copyright (c) 2018 by Nathan Coulter.
.\" Copyright (c) 2018 by Nathan Coulter.
.\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+12 -1
View File
@@ -7,7 +7,7 @@
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc \- report fatal error and abort
Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc, Tcl_ConsolePanic \- report fatal error and abort
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
@@ -21,6 +21,9 @@ void
void
\fBTcl_SetPanicProc\fR(\fIpanicProc\fR)
.sp
void
\fBTcl_ConsolePanic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR)
.sp
.SH ARGUMENTS
.AS Tcl_PanicProc *panicProc
.AP "const char*" format in
@@ -54,6 +57,14 @@ message is sent to the debugger in stead. If the windows executable
does not have a stderr channel (e.g. \fBwish.exe\fR), then a
system dialog box is used to display the panic message.
.PP
If your application doesn't use \fBTcl_Main\fR or \fBTk_Main\fR
and you want to implicitly use the stderr channel of your
application's C runtime (in stead of the stderr channel of the
C runtime used by Tcl), you can call \fBTcl_SetPanicProc\fR
with \fBTcl_ConsolePanic\fR as its argument. On platforms which
only have one C runtime (almost all platforms except Windows)
\fBTcl_ConsolePanic\fR is equivalent to NULL.
.PP
\fBTcl_SetPanicProc\fR may be used to modify the behavior of
\fBTcl_Panic\fR. The \fIpanicProc\fR argument should match the
type \fBTcl_PanicProc\fR:
+36 -71
View File
@@ -1,6 +1,7 @@
'\"
'\" Copyright (c) 1997 by Sun Microsystems, Inc.
'\" Contributions from Don Porter, NIST, 2004. (not subject to US copyright)
'\" Copyright (c) 2018 Nathan Coulter.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -9,7 +10,9 @@
.so man.macros
.BS
.SH NAME
Tcl_SaveInterpState, Tcl_RestoreInterpState, Tcl_DiscardInterpState, Tcl_SaveResult, Tcl_RestoreResult, Tcl_DiscardResult \- save and restore an interpreter's state
Tcl_SaveInterpState, Tcl_RestoreInterpState, Tcl_DiscardInterpState,
Tcl_SaveResult, Tcl_RestoreResult, Tcl_DiscardResult \- Save and restore the
state of an an interpreter.
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
@@ -30,91 +33,53 @@ int
.SH ARGUMENTS
.AS Tcl_InterpState savedPtr
.AP Tcl_Interp *interp in
Interpreter for which state should be saved.
The interpreter for the operation.
.AP int status in
Return code value to save as part of interpreter state.
The return code for the state.
.AP Tcl_InterpState state in
Saved state token to be restored or discarded.
A token for saved state.
.AP Tcl_SavedResult *savedPtr in
Pointer to location where interpreter result should be saved or restored.
A pointer to storage for saved state.
.BE
.SH DESCRIPTION
.PP
These routines allows a C procedure to take a snapshot of the current
state of an interpreter so that it can be restored after a call
to \fBTcl_Eval\fR or some other routine that modifies the interpreter
state. There are two triplets of routines meant to work together.
These routines save the state of an interpreter before a call to a routine such
as \fBTcl_Eval\fR, and restore the state afterwards.
.PP
The first triplet stores the snapshot of interpreter state in
an opaque token returned by \fBTcl_SaveInterpState\fR. That token
value may then be passed back to one of \fBTcl_RestoreInterpState\fR
or \fBTcl_DiscardInterpState\fR, depending on whether the interp
state is to be restored. So long as one of the latter two routines
is called, Tcl will take care of memory management.
\fBTcl_SaveInterpState\fR saves the parts of \fIinterp\fR that comprise the
result of a script, including the resulting value, the return code passed as
\fIstatus\fR, and any options such as \fB\-errorinfo\fR and \fB\-errorcode\fR.
It returns a token for the saved state. The interpreter result is not reset
and no interpreter state is changed.
.PP
The second triplet stores the snapshot of only the interpreter
result (not its complete state) in memory allocated by the caller.
These routines are passed a pointer to \fBTcl_SavedResult\fR
that is used to store enough information to restore the interpreter result.
\fBTcl_SavedResult\fR can be allocated on the stack of the calling
procedure. These routines do not save the state of any error
information in the interpreter (e.g. the \fB\-errorcode\fR or
\fB\-errorinfo\fR return options, when an error is in progress).
\fBTcl_RestoreInterpState\fR restores the state indicated by \fIstate\fR and
returns the \fIstatus\fR originally passed in the corresponding call to
\fBTcl_SaveInterpState\fR.
.PP
Because the routines \fBTcl_SaveInterpState\fR,
\fBTcl_RestoreInterpState\fR, and \fBTcl_DiscardInterpState\fR perform
a superset of the functions provided by the other routines,
any new code should only make use of the more powerful routines.
The older, weaker routines \fBTcl_SaveResult\fR, \fBTcl_RestoreResult\fR,
and \fBTcl_DiscardResult\fR continue to exist only for the sake
of existing programs that may already be using them.
If a saved state is not restored, \fBTcl_DiscardInterpState\fR must be called
to release it. A token used to discard or restore state must not be used
again.
.PP
\fBTcl_SaveInterpState\fR takes a snapshot of those portions of
interpreter state that make up the full result of script evaluation.
This include the interpreter result, the return code (passed in
as the \fIstatus\fR argument, and any return options, including
\fB\-errorinfo\fR and \fB\-errorcode\fR when an error is in progress.
This snapshot is returned as an opaque token of type \fBTcl_InterpState\fR.
The call to \fBTcl_SaveInterpState\fR does not itself change the
state of the interpreter. Unlike \fBTcl_SaveResult\fR, it does
not reset the interpreter.
\fBTcl_SaveResult\fR, \fBTcl_RestoreResult\fR, and \fBTcl_DiscardResult\fR are
deprecated. Instead use \fBTcl_SaveInterpState\fR,
\fBTcl_RestoreInterpState\fR, and \fBTcl_DiscardInterpState\fR, which are more
capable.
.PP
\fBTcl_RestoreInterpState\fR accepts a \fBTcl_InterpState\fR token
previously returned by \fBTcl_SaveInterpState\fR and restores the
state of the interp to the state held in that snapshot. The return
value of \fBTcl_RestoreInterpState\fR is the status value originally
passed to \fBTcl_SaveInterpState\fR when the snapshot token was
created.
\fBTcl_SaveResult\fR moves the result of \fIinterp\fR to the location
\fIstatePtr\fR points to and returns the interpreter result to its initial
state. It does not save options such as \fB\-errorcode\fR or
\fB\-errorinfo\fR.
.PP
\fBTcl_DiscardInterpState\fR is called to release a \fBTcl_InterpState\fR
token previously returned by \fBTcl_SaveInterpState\fR when that
snapshot is not to be restored to an interp.
.PP
The \fBTcl_InterpState\fR token returned by \fBTcl_SaveInterpState\fR
must eventually be passed to either \fBTcl_RestoreInterpState\fR
or \fBTcl_DiscardInterpState\fR to avoid a memory leak. Once
the \fBTcl_InterpState\fR token is passed to one of them, the
token is no longer valid and should not be used anymore.
.PP
\fBTcl_SaveResult\fR moves the string and value results
of \fIinterp\fR into the location specified by \fIstatePtr\fR.
\fBTcl_SaveResult\fR clears the result for \fIinterp\fR and
leaves the result in its normal empty initialized state.
.PP
\fBTcl_RestoreResult\fR moves the string and value results from
\fIstatePtr\fR back into \fIinterp\fR. Any result or error that was
already in the interpreter will be cleared. The \fIstatePtr\fR is left
in an uninitialized state and cannot be used until another call to
\fBTcl_RestoreResult\fR clears any existing result or error in \fIinterp\fR and
moves the result from \fIstatePtr\fR back to \fIinterp\fR. \fIstatePtr\fR is
then in an undefined state and must not be used until passed again to
\fBTcl_SaveResult\fR.
.PP
\fBTcl_DiscardResult\fR releases the saved interpreter state
stored at \fBstatePtr\fR. The state structure is left in an
uninitialized state and cannot be used until another call to
\fBTcl_DiscardResult\fR releases the state stored at \fBstatePtr\fR, which is
then in an undefined state and must not be used until passed again to
\fBTcl_SaveResult\fR.
.PP
Once \fBTcl_SaveResult\fR is called to save the interpreter
result, either \fBTcl_RestoreResult\fR or
\fBTcl_DiscardResult\fR must be called to properly clean up the
memory associated with the saved state.
If a saved result is not restored, \fBTcl_DiscardResult\fR must be called to
release it.
.SH KEYWORDS
result, state, interp
+9 -3
View File
@@ -45,7 +45,9 @@ int
.AP Tcl_Condition *condPtr in
A condition variable, which must be associated with a mutex lock.
.AP Tcl_Mutex *mutexPtr in
A mutex lock.
.VS TIP509
A recursive mutex lock.
.VE TIP509
.AP "const Tcl_Time" *timePtr in
A time limit on the condition wait. NULL to wait forever.
Note that a polling value of 0 seconds does not make much sense.
@@ -140,8 +142,12 @@ of code by calling \fBTcl_MutexLock\fR and \fBTcl_MutexUnlock\fR.
If one thread holds a mutex, any other thread calling \fBTcl_MutexLock\fR will
block until \fBTcl_MutexUnlock\fR is called.
A mutex can be destroyed after its use by calling \fBTcl_MutexFinalize\fR.
The result of locking a mutex twice from the same thread is undefined.
On some platforms it will result in a deadlock.
.VS TIP509
Mutexes are reentrant: they can be locked several times from the same
thread. However there must be exactly one call to
\fBTcl_MutexUnlock\fR for each call to \fBTcl_MutexLock\fR in order
for a thread to release a mutex completely.
.VE TIP509
The \fBTcl_MutexLock\fR, \fBTcl_MutexUnlock\fR and \fBTcl_MutexFinalize\fR
procedures are defined as empty macros if not compiling with threads enabled.
For declaration of mutexes the \fBTCL_DECLARE_MUTEX\fR macro should be used.
+10 -7
View File
@@ -121,8 +121,8 @@ case-insensitive (1).
.SH DESCRIPTION
.PP
These routines convert between UTF-8 strings and Tcl_UniChars. A
Tcl_UniChar is a Unicode character represented as an unsigned, fixed-size
These routines convert between UTF-8 strings and Unicode characters. An
Unicode character represented as an unsigned, fixed-size
quantity. A UTF-8 character is a Unicode character represented as
a varying-length sequence of up to \fBTCL_UTF_MAX\fR bytes. A multibyte UTF-8
sequence consists of a lead byte followed by some number of trail bytes.
@@ -130,9 +130,12 @@ sequence consists of a lead byte followed by some number of trail bytes.
\fBTCL_UTF_MAX\fR is the maximum number of bytes that it takes to
represent one Unicode character in the UTF-8 representation.
.PP
\fBTcl_UniCharToUtf\fR stores the Tcl_UniChar \fIch\fR as a UTF-8 string
\fBTcl_UniCharToUtf\fR stores the character \fIch\fR as a UTF-8 string
in starting at \fIbuf\fR. The return value is the number of bytes stored
in \fIbuf\fR.
in \fIbuf\fR. If ch is an upper surrogate (range U+D800 - U+DBFF), then
the return value will be 0 and nothing will be stored. If you still
want to produce UTF-8 output for it (even though knowing it's an illegal
code-point on its own), just call \fBTcl_UniCharToUtf\fR again using ch = -1.
.PP
\fBTcl_UtfToUniChar\fR reads one UTF-8 character starting at \fIsrc\fR
and stores it as a Tcl_UniChar in \fI*chPtr\fR. The return value is the
@@ -203,7 +206,7 @@ of \fIlength\fR bytes is long enough to be decoded by
\fBTcl_UtfToUniChar\fR, or 0 otherwise. This function does not guarantee
that the UTF-8 string is properly formed. This routine is used by
procedures that are operating on a byte at a time and need to know if a
full Tcl_UniChar has been seen.
full Unicode character has been seen.
.PP
\fBTcl_NumUtfChars\fR corresponds to \fBstrlen\fR for UTF-8 strings. It
returns the number of Tcl_UniChars that are represented by the UTF-8 string
@@ -211,12 +214,12 @@ returns the number of Tcl_UniChars that are represented by the UTF-8 string
length is negative, all bytes up to the first null byte are used.
.PP
\fBTcl_UtfFindFirst\fR corresponds to \fBstrchr\fR for UTF-8 strings. It
returns a pointer to the first occurrence of the Tcl_UniChar \fIch\fR
returns a pointer to the first occurrence of the Unicode character \fIch\fR
in the null-terminated UTF-8 string \fIsrc\fR. The null terminator is
considered part of the UTF-8 string.
.PP
\fBTcl_UtfFindLast\fR corresponds to \fBstrrchr\fR for UTF-8 strings. It
returns a pointer to the last occurrence of the Tcl_UniChar \fIch\fR
returns a pointer to the last occurrence of the Unicode character \fIch\fR
in the null-terminated UTF-8 string \fIsrc\fR. The null terminator is
considered part of the UTF-8 string.
.PP
+77
View File
@@ -0,0 +1,77 @@
'\"
'\" Copyright (c) 2018 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH abstract n 0.3 TclOO "TclOO Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
oo::abstract \- a class that does not allow direct instances of itself
.SH SYNOPSIS
.nf
package require TclOO
\fBoo::abstract\fI method \fR?\fIarg ...\fR?
.fi
.SH "CLASS HIERARCHY"
.nf
\fBoo::object\fR
\(-> \fBoo::class\fR
\(-> \fBoo::abstract\fR
.fi
.BE
.SH DESCRIPTION
Abstract classes are classes that can contain definitions, but which cannot be
directly manufactured; they are intended to only ever be inherited from and
instantiated indirectly. The characteristic methods of \fBoo::class\fR
(\fBcreate\fR and \fBnew\fR) are not exported by an instance of
\fBoo::abstract\fR.
.PP
Note that \fBoo::abstract\fR is not itself an instance of \fBoo::abstract\fR.
.SS CONSTRUCTOR
The \fBoo::abstract\fR class does not define an explicit constructor; this
means that it is effectively the same as the constructor of the
\fBoo::class\fR class.
.SS DESTRUCTOR
The \fBoo::abstract\fR class does not define an explicit destructor;
destroying an instance of it is just like destroying an ordinary class (and
will destroy all its subclasses).
.SS "EXPORTED METHODS"
The \fBoo::abstract\fR class defines no new exported methods.
.SS "NON-EXPORTED METHODS"
The \fBoo::abstract\fR class explicitly states that \fBcreate\fR,
\fBcreateWithNamespace\fR, and \fBnew\fR are unexported.
.SH EXAMPLES
.PP
This example defines a simple class hierarchy and creates a new instance of
it. It then invokes a method of the object before destroying the hierarchy and
showing that the destruction is transitive.
.PP
.CS
\fBoo::abstract\fR create fruit {
method eat {} {
puts "yummy!"
}
}
oo::class create banana {
superclass fruit
method peel {} {
puts "skin now off"
}
}
set b [banana \fBnew\fR]
$b peel \fI\(-> prints 'skin now off'\fR
$b eat \fI\(-> prints 'yummy!'\fR
set f [fruit new] \fI\(-> error 'unknown method "new"...'\fR
.CE
.SH "SEE ALSO"
oo::define(n), oo::object(n)
.SH KEYWORDS
abstract class, class, metaclass, object
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+9 -3
View File
@@ -20,6 +20,11 @@ Append all of the \fIvalue\fR arguments to the current value
of variable \fIvarName\fR. If \fIvarName\fR does not exist,
it is given a value equal to the concatenation of all the
\fIvalue\fR arguments.
.VS TIP508
If \fIvarName\fR indicate an element that does not exist of an array that has
a default value set, the concatenation of the default value and all the
\fIvalue\fR arguments will be stored in the array element.
.VE TIP508
The result of this command is the new value stored in variable
\fIvarName\fR.
This command provides an efficient way to build up long
@@ -44,6 +49,7 @@ puts $var
concat(n), lappend(n)
.SH KEYWORDS
append, variable
'\" Local Variables:
'\" mode: nroff
'\" End:
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+52 -1
View File
@@ -5,7 +5,7 @@
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH array n 8.3 Tcl "Tcl Built-In Commands"
.TH array n 8.7 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
@@ -36,6 +36,53 @@ with an empty name, since the return value from
\fBarray nextelement\fR will not indicate whether the search
has been completed.
.TP
\fBarray default \fIsubcommand arrayName args...\fR
.VS TIP508
Manages the default value of the array. Arrays initially have no default
value, but this command allows you to set one; the default value will be
returned when reading from an element of the array \farrayName\fR if the read
would otherwise result in an error. Note that this may cause the \fBappend\fR,
\fBdict\fR, \fBincr\fR and \fBlappend\fR commands to change their behavior in
relation to non-existing array elements.
.RS
.PP
The \fIsubcommand\fR argument controls what exact operation will be performed
on the default value of \fIarrayName\fR. Supported \fIsubcommand\fRs are:
.VE TIP508
.TP
\fBarray default exists \fIarrayName\fR
.VS TIP508
This returns a boolean value indicating whether a default value has been set
for the array \fIarrayName\fR. Returns a false value if \fIarrayName\fR does
not exist. Raises an error if \fIarrayName\fR is an existing variable that is
not an array.
.VE TIP508
.TP
\fBarray default get \fIarrayName\fR
.VS TIP508
This returns the current default value for the array \fIarrayName\fR. Raises
an error if \fIarrayName\fR is an existing variable that is not an array, or
if \fIarrayName\fR is an array without a default value.
.VE TIP508
.TP
\fBarray default set \fIarrayName value\fR
.VS TIP508
This sets the default value for the array \fIarrayName\fR to \fIvalue\fR.
Returns the empty string. Raises an error if \fIarrayName\fR is an existing
variable that is not an array, or if \fIarrayName\fR is an illegal name for an
array. If \fIarrayName\fR does not currently exist, it is created as an empty
array as well as having its default value set.
.VE TIP508
.TP
\fBarray default unset \fIarrayName\fR
.VS TIP508
This removes the default value for the array \fIarrayName\fR and returns the
empty string. Does nothing if \fIarrayName\fR does not have a default
value. Raises an error if \fIarrayName\fR is an existing variable that is not
an array.
.VE TIP508
.RE
.TP
\fBarray donesearch \fIarrayName searchId\fR
This command terminates an array search and destroys all the
state associated with that search. \fISearchId\fR indicates
@@ -194,3 +241,7 @@ foreach color [lsort [\fBarray names\fR colorcount]] {
list(n), string(n), variable(n), trace(n), foreach(n)
.SH KEYWORDS
array, element names, search
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+88
View File
@@ -0,0 +1,88 @@
'\"
'\" Copyright (c) 2018 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH callback n 0.3 TclOO "TclOO Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
callback, mymethod \- generate callbacks to methods
.SH SYNOPSIS
.nf
package require TclOO
\fBcallback\fR \fImethodName\fR ?\fIarg ...\fR?
\fBmymethod\fR \fImethodName\fR ?\fIarg ...\fR?
.fi
.BE
.SH DESCRIPTION
The \fBcallback\fR command,
'\" Based on notes in the tcllib docs, we know the provenance of mymethod
also called \fBmymethod\fR for compatibility with the ooutil and snit packages
of Tcllib,
and which should only be used from within the context of a call to a method
(i.e. inside a method, constructor or destructor body) is used to generate a
script fragment that will invoke the method, \fImethodName\fR, on the current
object (as reported by \fBself\fR) when executed. Any additional arguments
provided will be provided as leading arguments to the callback. The resulting
script fragment shall be a proper list.
.PP
Note that it is up to the caller to ensure that the current object is able to
handle the call of \fImethodName\fR; this command does not check that.
\fImethodName\fR may refer to any exported or unexported method, but may not
refer to a private method as those can only be invoked directly from within
methods. If there is no such method present at the point when the callback is
invoked, the standard \fBunknown\fR method handler will be called.
.SH EXAMPLE
This is a simple echo server class. The \fBcallback\fR command is used in two
places, to arrange for the incoming socket connections to be handled by the
\fIAccept\fR method, and to arrange for the incoming bytes on those
connections to be handled by the \fIReceive\fR method.
.PP
.CS
oo::class create EchoServer {
variable server clients
constructor {port} {
set server [socket -server [\fBcallback\fR Accept] $port]
set clients {}
}
destructor {
chan close $server
foreach client [dict keys $clients] {
chan close $client
}
}
method Accept {channel clientAddress clientPort} {
dict set clients $channel [dict create \e
address $clientAddress port $clientPort]
chan event $channel readable [\fBcallback\fR Receive $channel]
}
method Receive {channel} {
if {[chan gets $channel line] >= 0} {
my echo $channel $line
} else {
chan close $channel
dict unset clients $channel
}
}
method echo {channel line} {
dict with clients $channel {
chan puts $channel \e
[format {[%s:%d] %s} $address $port $line]
}
}
}
.CE
.SH "SEE ALSO"
chan(n), fileevent(n), my(n), self(n), socket(n), trace(n)
.SH KEYWORDS
callback, object
.\" Local Variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+78
View File
@@ -0,0 +1,78 @@
'\"
'\" Copyright (c) 2011-2015 Andreas Kupries
'\" Copyright (c) 2018 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH classvariable n 0.3 TclOO "TclOO Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
classvariable \- create link from local variable to variable in class
.SH SYNOPSIS
.nf
package require TclOO
\fBclassvariable\fR \fIvariableName\fR ?\fI...\fR?
.fi
.BE
.SH DESCRIPTION
The \fBclassvariable\fR command is available within methods. It takes a series
of one or more variable names and makes them available in the method's scope;
those variable names must not be qualified and must not refer to array
elements. The originating scope for the variables is the namespace of the
class that the method was defined by. In other words, the referenced variables
are shared between all instances of that class.
.PP
Note: This command is equivalent to the command \fBtypevariable\fR provided by
the snit package in tcllib for approximately the same purpose. If used in a
method defined directly on a class instance (e.g., through the
\fBoo::objdefine\fR \fBmethod\fR definition) this is very much like just
using:
.PP
.CS
namespace upvar [namespace current] $var $var
.CE
.PP
for each variable listed to \fBclassvariable\fR.
.SH EXAMPLE
This class counts how many instances of it have been made.
.PP
.CS
oo::class create Counted {
initialise {
variable count 0
}
variable number
constructor {} {
\fBclassvariable\fR count
set number [incr count]
}
method report {} {
\fBclassvariable\fR count
puts "This is instance $number of $count"
}
}
set a [Counted new]
set b [Counted new]
$a report
\fI\(-> This is instance 1 of 2\fR
set c [Counted new]
$b report
\fI\(-> This is instance 2 of 3\fR
$c report
\fI\(-> This is instance 3 of 3\fR
.CE
.SH "SEE ALSO"
global(n), namespace(n), oo::class(n), oo::define(n), upvar(n), variable(n)
.SH KEYWORDS
class, class variable, variable
.\" Local Variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+13
View File
@@ -452,6 +452,19 @@ If this situation occurs, the first occurrence of the time is chosen.
(For this reason, it is wise to have the input string contain the
time zone when converting local times. This caveat does not apply to
UTC times.)
.PP
If the interpretation of the groups yields an impossible time because
a field is out of range, enough of that field's unit will be added to
or subtracted from the time to bring it in range. Thus, if attempting to
scan or format day 0 of the month, one day will be subtracted from day
1 of the month, yielding the last day of the previous month.
.PP
If the interpretation of the groups yields an impossible time because
a Daylight Saving Time change skips over that time, or an ambiguous
time because a Daylight Saving Time change skips back so that the clock
observes the given time twice, and no time zone specifier (\fB%z\fR
or \fB%Z\fR) is present in the format, the time is interpreted as
if the clock had not changed.
.SH "FORMAT GROUPS"
.PP
The following format groups are recognized by the \fBclock scan\fR and
+293 -43
View File
@@ -1,5 +1,5 @@
'\"
'\" Copyright (c) 2007 Donal K. Fellows
'\" Copyright (c) 2007-2018 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -39,6 +39,27 @@ used as the \fIdefScript\fR argument.
The following commands are supported in the \fIdefScript\fR for
\fBoo::define\fR, each of which may also be used in the \fIsubcommand\fR form:
.TP
\fBclassmethod\fI name\fR ?\fIargList bodyScrip\fR?
.VS TIP478
This creates a class method, or (if \fIargList\fR and \fIbodyScript\fR are
omitted) promotes an existing method on the class object to be a class
method. The \fIname\fR, \fIargList\fR and \fIbodyScript\fR arguments are as in
the \fBmethod\fR definition, below.
.RS
.PP
Class methods can be called on either the class itself or on the instances of
that class. When they are called, the current object (see the \fBself\R and
\fBmy\fR commands) is the class on which they are called or the class of the
instance on which they are called, depending on whether they are called on the
class or an instance of the class, respectively. If called on a subclass or
instance of the subclass, the current object is the subclass.
.PP
In a private definition context, the methods as invoked on classes are
\fInot\fR private, but the methods as invoked on instances of classes are
private.
.RE
.VE TIP478
.TP
\fBconstructor\fI argList bodyScript\fR
.
This creates or updates the constructor for a class. The formal arguments to
@@ -82,17 +103,14 @@ by a superclass; subclass exports override superclass visibility, and may in
turn be overridden by instances.
.TP
\fBfilter\fR ?\fI\-slotOperation\fR? ?\fImethodName ...\fR?
.VS
.
This slot (see \fBSLOTTED DEFINITIONS\fR below)
.VE
sets or updates the list of method names that are used to guard whether
method call to instances of the class may be called and what the method's
results are. Each \fImethodName\fR names a single filtering method (which may
be exposed or not exposed); it is not an error for a non-existent method to be
named since they may be defined by subclasses.
.VS
By default, this slot works by appending.
.VE
.TP
\fBforward\fI name cmdName \fR?\fIarg ...\fR?
.
@@ -105,6 +123,22 @@ fully-qualified, the command will be searched for in each object's namespace,
using the instances' namespace's path, or by looking in the global namespace.
The method will be exported if \fIname\fR starts with a lower-case letter, and
non-exported otherwise.
.RS
.PP
.VS TIP500
If in a private definition context (see the \fBprivate\fR definition command,
below), this command creates private forwarded methods.
.VE TIP500
.RE
.TP
\fBinitialise\fI script\fR
.TP
\fBinitialize\fI script\fR
.VS TIP478
This evaluates \fIscript\fR in a context which supports local variables and
where the current namespace is the instance namespace of the class object
itself. This is useful for setting up, e.g., class-scoped variables.
.VE TIP478
.TP
\fBmethod\fI name argList bodyScript\fR
.
@@ -117,17 +151,40 @@ be a namespace that is unique to the current object. The method will be
exported if \fIname\fR starts with a lower-case letter, and non-exported
otherwise; this behavior can be overridden via \fBexport\fR and
\fBunexport\fR.
.RS
.PP
.VS TIP500
If in a private definition context (see the \fBprivate\fR definition command,
below), this command creates private procedure-like methods.
.VE TIP500
.RE
.TP
\fBmixin\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
.VS
.
This slot (see \fBSLOTTED DEFINITIONS\fR below)
.VE
sets or updates the list of additional classes that are to be mixed into
all the instances of the class being defined. Each \fIclassName\fR argument
names a single class that is to be mixed in.
.VS
By default, this slot works by replacement.
.VE
.TP
\fBprivate \fIcmd arg...\fR
.TP
\fBprivate \fIscript\fR
.
.VS TIP500
This evaluates the \fIscript\fR (or the list of command and arguments given by
\fIcmd\fR and \fIarg\fRs) in a context where the definitions made on the
current class will be private definitions.
.RS
.PP
The following class definition commands are affected by \fBprivate\fR:
\fBforward\fR, \fBmethod\fR, \fBself\fR, and \fBvariable\fR. Nesting
\fBprivate\fR inside \fBprivate\fR has no cumulative effect; the innermost
definition context is just a private definition context. All other definition
commands have no difference in behavior when used in a private definition
context.
.RE
.VE TIP500
.TP
\fBrenamemethod\fI fromName toName\fR
.
@@ -159,21 +216,23 @@ operates identically to
If no arguments at all are used, this gives the name of the class currently
being configured.
.VE TIP470
.VS TIP500
If in a private definition context (see the \fBprivate\fR definition command,
below), the definitions on the class object will also be made in a private
definition context.
.VE TIP500
.RE
.TP
\fBsuperclass\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
.VS
.
This slot (see \fBSLOTTED DEFINITIONS\fR below)
.VE
allows the alteration of the superclasses of the class being defined.
Each \fIclassName\fR argument names one class that is to be a superclass of
the defined class. Note that objects must not be changed from being classes to
being non-classes or vice-versa, that an empty parent class is equivalent to
\fBoo::object\fR, and that the parent classes of \fBoo::object\fR and
\fBoo::class\fR may not be modified.
.VS
By default, this slot works by replacement.
.VE
.TP
\fBunexport\fI name \fR?\fIname ...\fR?
.
@@ -185,18 +244,31 @@ actually defined by a superclass; subclass unexports override superclass
visibility, and may be overridden by instance unexports.
.TP
\fBvariable\fR ?\fI\-slotOperation\fR? ?\fIname ...\fR?
.VS
.
This slot (see \fBSLOTTED DEFINITIONS\fR below) arranges for each of the named
variables to be automatically made
available in the methods, constructor and destructor declared by the class
being defined. Each variable name must not have any namespace
separators and must not look like an array access. All variables will be
actually present in the instance object on which the method is executed. Note
actually present in the namespace of the instance object on which the method
is executed. Note
that the variable lists declared by a superclass or subclass are completely
disjoint, as are variable lists declared by instances; the list of variable
names is just for methods (and constructors and destructors) declared by this
class. By default, this slot works by appending.
.VE
.RS
.PP
.VS TIP500
If in a private definition context (see the \fBprivate\fR definition command,
below), this slot manipulates the list of private variable bindings for this
class. In a private variable binding, the name of the variable within the
instance object is different to the name given in the definition; the name
used in the definition is the name that you use to access the variable within
the methods of this class, and the name of the variable in the instance
namespace has a unique prefix that makes accidental use from other classes
extremely unlikely.
.VE TIP500
.RE
.SS "CONFIGURING OBJECTS"
.PP
The following commands are supported in the \fIdefScript\fR for
@@ -223,18 +295,15 @@ being defined. Note that the methods themselves may be actually defined by a
class or superclass; object exports override class visibility.
.TP
\fBfilter\fR ?\fI\-slotOperation\fR? ?\fImethodName ...\fR?
.VS
.
This slot (see \fBSLOTTED DEFINITIONS\fR below)
.VE
sets or updates the list of method names that are used to guard whether a
method call to the object may be called and what the method's results are.
Each \fImethodName\fR names a single filtering method (which may be exposed or
not exposed); it is not an error for a non-existent method to be named. Note
that the actual list of filters also depends on the filters set upon any
classes that the object is an instance of.
.VS
By default, this slot works by appending.
.VE
.TP
\fBforward\fI name cmdName \fR?\fIarg ...\fR?
.
@@ -244,6 +313,13 @@ additional arguments, \fIarg\fR etc., added before those arguments specified
by the caller of the method. Forwarded methods should be deleted using the
\fBmethod\fR subcommand. The method will be exported if \fIname\fR starts with
a lower-case letter, and non-exported otherwise.
.RS
.PP
.VS TIP500
If in a private definition context (see the \fBprivate\fR definition command,
below), this command creates private forwarded methods.
.VE TIP500
.RE
.TP
\fBmethod\fI name argList bodyScript\fR
.
@@ -254,17 +330,38 @@ method will be \fIbodyScript\fR. When the body of the method is evaluated, the
current namespace of the method will be a namespace that is unique to the
object. The method will be exported if \fIname\fR starts with a lower-case
letter, and non-exported otherwise.
.RS
.PP
.VS TIP500
If in a private definition context (see the \fBprivate\fR definition command,
below), this command creates private procedure-like methods.
.VE TIP500
.RE
.TP
\fBmixin\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
.VS
.
This slot (see \fBSLOTTED DEFINITIONS\fR below)
.VE
sets or updates a per-object list of additional classes that are to be
mixed into the object. Each argument, \fIclassName\fR, names a single class
that is to be mixed in.
.VS
By default, this slot works by replacement.
.VE
.TP
\fBprivate \fIcmd arg...\fR
.TP
\fBprivate \fIscript\fR
.VS TIP500
This evaluates the \fIscript\fR (or the list of command and arguments given by
\fIcmd\fR and \fIarg\fRs) in a context where the definitions made on the
current object will be private definitions.
.RS
.PP
The following class definition commands are affected by \fBprivate\fR:
\fBforward\fR, \fBmethod\fR, and \fBvariable\fR. Nesting \fBprivate\fR inside
\fBprivate\fR has no cumulative effect; the innermost definition context is
just a private definition context. All other definition commands have no
difference in behavior when used in a private definition context.
.RE
.VE TIP500
.TP
\fBrenamemethod\fI fromName toName\fR
.
@@ -275,7 +372,6 @@ that the object is an instance of. Does not change the export status of the
method; if it was exported before, it will be afterwards.
.TP
\fBself \fR
.
.VS TIP470
This gives the name of the object currently being configured.
.VE TIP470
@@ -289,36 +385,70 @@ object being defined. Note that the methods themselves may be actually defined
by a class; instance unexports override class visibility.
.TP
\fBvariable\fR ?\fI\-slotOperation\fR? ?\fIname ...\fR?
.VS
.
This slot (see \fBSLOTTED DEFINITIONS\fR below) arranges for each of the named
variables to be automatically made available in the methods declared by the
object being defined. Each variable name must not have any namespace
separators and must not look like an array access. All variables will be
actually present in the object on which the method is executed. Note that the
actually present in the namespace of the object on which the method is
executed. Note that the
variable lists declared by the classes and mixins of which the object is an
instance are completely disjoint; the list of variable names is just for
methods declared by this object. By default, this slot works by appending.
.RS
.PP
.VS TIP500
If in a private definition context (see the \fBprivate\fR definition command,
below), this slot manipulates the list of private variable bindings for this
object. In a private variable binding, the name of the variable within the
instance object is different to the name given in the definition; the name
used in the definition is the name that you use to access the variable within
the methods of this instance object, and the name of the variable in the
instance namespace has a unique prefix that makes accidental use from
superclass methods extremely unlikely.
.VE TIP500
.RE
.SH "PRIVATE METHODS"
.VS TIP500
When a class or instance has a private method, that private method can only be
invoked from within methods of that class or instance. Other callers of the
object's methods \fIcannot\fR invoke private methods, it is as if the private
methods do not exist. However, a private method of a class \fIcan\fR be
invoked from the class's methods when those methods are being used on another
instance object; this means that a class can use them to coordinate behaviour
between several instances of itself without interfering with how other
classes (especially either subclasses or superclasses) interact. Private
methods precede all mixed in classes in the method call order (as reported by
\fBself call\fR).
.VE TIP500
.SH "SLOTTED DEFINITIONS"
Some of the configurable definitions of a class or object are \fIslotted
definitions\fR. This means that the configuration is implemented by a slot
object, that is an instance of the class \fBoo::Slot\fR, which manages a list
of values (class names, variable names, etc.) that comprises the contents of
the slot. The class defines three operations (as methods) that may be done on
the slot. The class defines five operations (as methods) that may be done on
the slot:
.VE
.TP
\fIslot\fR \fB\-append\fR ?\fImember ...\fR?
.VS
.
This appends the given \fImember\fR elements to the slot definition.
.VE
.TP
\fIslot\fR \fB\-clear\fR
.VS
.
This sets the slot definition to the empty list.
.VE
.TP
\fIslot\fR \fB\-prepend\fR ?\fImember ...\fR?
.VS TIP516
This prepends the given \fImember\fR elements to the slot definition.
.VE TIP516
.TP
\fIslot\fR \fB\-remove\fR ?\fImember ...\fR?
.VS TIP516
This removes the given \fImember\fR elements from the slot definition.
.VE TIP516
.TP
\fIslot\fR \fB\-set\fR ?\fImember ...\fR?
.VS
.
This replaces the slot definition with the given \fImember\fR elements.
.PP
A consequence of this is that any use of a slot's default operation where the
@@ -331,20 +461,55 @@ which is forwarded to the default operation of the slot (thus, for the class
slot, this is forwarded to
.QW "\fBmy \-append\fR" ),
and these methods which provide the implementation interface:
.VE
.TP
\fIslot\fR \fBGet\fR
.VS
Returns a list that is the current contents of the slot. This method must
always be called from a stack frame created by a call to \fBoo::define\fR or
\fBoo::objdefine\fR.
.VE
.
Returns a list that is the current contents of the slot, but does not modify
the slot. This method must always be called from a stack frame created by a
call to \fBoo::define\fR or \fBoo::objdefine\fR. This method \fIshould not\fR
return an error unless it is called from outside a definition context or with
the wrong number of arguments.
.RS
.PP
.VS TIP516
The elements of the list should be fully resolved, if that is a meaningful
concept to the slot.
.VE TIP516
.RE
.TP
\fIslot\fR \fBResolve\fR \fIslotElement\fR
.VS TIP516
Returns \fIslotElement\fR with a resolution operation applied to it, but does
not modify the slot. For slots of simple strings, this is an operation that
does nothing, whereas for slots of classes, this maps a class name to its
fully-qualified class name. This method must always be called from a stack
frame created by a call to \fBoo::define\fR or \fBoo::objdefine\fR. This
method \fIshould not\fR return an error unless it is called from outside a
definition context or with the wrong number of arguments; unresolvable
arguments should be returned as is (as not all slot operations strictly
require that values are resolvable to work).
.RS
.PP
Implementations \fIshould not\fR enforce uniqueness and ordering constraints
in this method; that is the responsibility of the \fBSet\fR method.
.RE
.VE TIP516
.TP
\fIslot\fR \fBSet \fIelementList\fR
.VS
.
Sets the contents of the slot to the list \fIelementList\fR and returns the
empty string. This method must always be called from a stack frame created by
a call to \fBoo::define\fR or \fBoo::objdefine\fR.
a call to \fBoo::define\fR or \fBoo::objdefine\fR. This method may return an
error if it rejects the change to the slot contents (e.g., because of invalid
values) as well as if it is called from outside a definition context or with
the wrong number of arguments.
.RS
.PP
This method \fImay\fR reorder and filter the elements if this is necessary in
order to satisfy the underlying constraints of the slot. (For example, slots
of classes enforce a uniqueness constraint that places each element in the
earliest location in the slot that it can.)
.RE
.PP
The implementation of these methods is slot-dependent (and responsible for
accessing the correct part of the class or object definition). Slots also have
@@ -352,7 +517,14 @@ an unknown method handler to tie all these pieces together, and they hide
their \fBdestroy\fR method so that it is not invoked inadvertently. It is
\fIrecommended\fR that any user changes to the slot mechanism be restricted to
defining new operations whose names start with a hyphen.
.VE
.PP
.VS TIP516
Most slot operations will initially \fBResolve\fR their argument list, combine
it with the results of the \fBGet\fR method, and then \fBSet\fR the result.
Some operations omit one or both of the first two steps; omitting the third
would result in an idempotent read-only operation (but the standard mechanism
for reading from slots is via \fBinfo class\fR and \fBinfo object\fR).
.VE TIP516
.SH EXAMPLES
This example demonstrates how to use both forms of the \fBoo::define\fR and
\fBoo::objdefine\fR commands (they work in the same way), as well as
@@ -409,6 +581,84 @@ oo::class create B {
inst m1 \fI\(-> prints "red brick"\fR
inst m2 \fI\(-> prints "blue brick"\fR
.CE
.PP
.VS TIP478
This example shows how to create and use class variables. It is a class that
counts how many instances of itself have been made.
.PP
.CS
oo::class create Counted
\fBoo::define\fR Counted {
\fBinitialise\fR {
variable count 0
}
\fBvariable\fR number
\fBconstructor\fR {} {
classvariable count
set number [incr count]
}
\fBmethod\fR report {} {
classvariable count
puts "This is instance $number of $count"
}
}
set a [Counted new]
set b [Counted new]
$a report
\fI\(-> This is instance 1 of 2\fR
set c [Counted new]
$b report
\fI\(-> This is instance 2 of 3\fR
$c report
\fI\(-> This is instance 3 of 3\fR
.CE
.PP
This example demonstrates how to use class methods. (Note that the constructor
for \fBoo::class\fR calls \fBoo::define\fR on the class.)
.PP
.CS
oo::class create DBTable {
\fBclassmethod\fR find {description} {
puts "DB: locate row from [self] matching $description"
return [my new]
}
\fBclassmethod\fR insert {description} {
puts "DB: create row in [self] matching $description"
return [my new]
}
\fBmethod\fR update {description} {
puts "DB: update row [self] with $description"
}
\fBmethod\fR delete {} {
puts "DB: delete row [self]"
my destroy; # Just delete the object, not the DB row
}
}
oo::class create Users {
\fBsuperclass\fR DBTable
}
oo::class create Groups {
\fBsuperclass\fR DBTable
}
set u1 [Users insert "username=abc"]
\fI\(-> DB: create row from ::Users matching username=abc\fR
set u2 [Users insert "username=def"]
\fI\(-> DB: create row from ::Users matching username=def\fR
$u2 update "group=NULL"
\fI\(-> DB: update row ::oo::Obj124 with group=NULL\fR
$u1 delete
\fI\(-> DB: delete row ::oo::Obj123\fR
set g [Group find "groupname=webadmins"]
\fI\(-> DB: locate row ::Group with groupname=webadmins\fR
$g update "emailaddress=admins"
\fI\(-> DB: update row ::oo::Obj125 with emailaddress=admins\fR
.CE
.VE TIP478
.SH "SEE ALSO"
next(n), oo::class(n), oo::object(n)
.SH KEYWORDS
+35
View File
@@ -27,6 +27,11 @@ key maps to in the dictionary value contained in the given variable,
writing the resulting dictionary value back to that variable.
Non-existent keys are treated as if they map to an empty string. The
updated dictionary value is returned.
.VS TIP508
If \fIdictionaryVarable\fR indicates an element that does not exist of an
array that has a default value set, the default value and will be used as the
value of the dictionary prior to the appending operation.
.VE TIP508
.TP
\fBdict create \fR?\fIkey value ...\fR?
.
@@ -124,6 +129,11 @@ resulting dictionary value back to that variable. Non-existent keys
are treated as if they map to 0. It is an error to increment a value
for an existing key if that value is not an integer. The updated
dictionary value is returned.
.VS TIP508
If \fIdictionaryVarable\fR indicates an element that does not exist of an
array that has a default value set, the default value and will be used as the
value of the dictionary prior to the incrementing operation.
.VE TIP508
.TP
\fBdict info \fIdictionaryValue\fR
.
@@ -149,6 +159,11 @@ keys are treated as if they map to an empty list, and it is legal for
there to be no items to append to the list. It is an error for the
value that the key maps to to not be representable as a list. The
updated dictionary value is returned.
.VS TIP508
If \fIdictionaryVarable\fR indicates an element that does not exist of an
array that has a default value set, the default value and will be used as the
value of the dictionary prior to the list-appending operation.
.VE TIP508
.TP
\fBdict map \fR{\fIkeyVariable valueVariable\fR} \fIdictionaryValue body\fR
.
@@ -206,6 +221,11 @@ value and places an updated dictionary value in that variable
containing a mapping from the given key to the given value. When
multiple keys are present, this operation creates or updates a chain
of nested dictionaries. The updated dictionary value is returned.
.VS TIP508
If \fIdictionaryVarable\fR indicates an element that does not exist of an
array that has a default value set, the default value and will be used as the
value of the dictionary prior to the value insert/update operation.
.VE TIP508
.TP
\fBdict size \fIdictionaryValue\fR
.
@@ -221,6 +241,11 @@ through nested dictionaries to the mapping to remove. At least one key
must be specified, but the last key on the key-path need not exist.
All other components on the path must exist. The updated dictionary
value is returned.
.VS TIP508
If \fIdictionaryVarable\fR indicates an element that does not exist of an
array that has a default value set, the default value and will be used as the
value of the dictionary prior to the value remove operation.
.VE TIP508
.TP
\fBdict update \fIdictionaryVariable key varName \fR?\fIkey varName ...\fR? \fIbody\fR
.
@@ -236,6 +261,11 @@ are silently discarded), even if the result of \fIbody\fR is an error
or some other kind of exceptional exit. The result of \fBdict
update\fR is (unless some kind of error occurs) the result of the
evaluation of \fIbody\fR.
.VS TIP508
If \fIdictionaryVarable\fR indicates an element that does not exist of an
array that has a default value set, the default value and will be used as the
value of the dictionary prior to the update operation.
.VE TIP508
.RS
.PP
Each \fIvarName\fR is mapped in the scope enclosing the \fBdict update\fR;
@@ -270,6 +300,11 @@ dictionary be discarded, and this also happens if the contents of
dictionaries no longer exists. The result of \fBdict with\fR is
(unless some kind of error occurs) the result of the evaluation of
\fIbody\fR.
.VS TIP508
If \fIdictionaryVarable\fR indicates an element that does not exist of an
array that has a default value set, the default value and will be used as the
value of the dictionary prior to the updating operation.
.VE TIP508
.RS
.PP
The variables are mapped in the scope enclosing the \fBdict with\fR;
+17
View File
@@ -217,6 +217,19 @@ information is instead sent to the console, if one is present, or is
discarded.
.RS
.PP
Note that the current escape resp. quoting of arguments for windows works only
with executables using CommandLineToArgv, CRT-library or similar, as well as
with the windows batch files (excepting the newline, see below).
Although it is the common escape algorithm, but, in fact, the way how the
executable parses the command-line (resp. splits it into single arguments)
is decisive.
.PP
Unfortunately, there is currently no way to supply newline character within
an argument to the batch files (\fB.cmd\fR or \fB.bat\fR) or to the command
processor (\fBcmd.exe /c\fR), because this causes truncation of command-line
(also the argument chain) on the first newline character.
But it works properly with an executable (using CommandLineToArgv, etc).
.PP
The Tk console text widget does not provide real standard IO capabilities.
Under Tk, when redirecting from standard input, all applications will see an
immediate end-of-file; information redirected to standard output or standard
@@ -409,6 +422,10 @@ that sometimes pop up:
With the file \fIcmp.bat\fR looking something like:
.PP
.CS
@gcc %*
.CE
or like another variant using single parameters:
.CS
@gcc %1 %2 %3 %4 %5 %6 %7 %8 %9
.CE
.SS "WORKING WITH COMMAND BUILT-INS"
+177 -9
View File
@@ -6,14 +6,14 @@
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH "http" n 2.7 http "Tcl Bundled Packages"
.TH "http" n 2.9 http "Tcl Bundled Packages"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
http \- Client-side implementation of the HTTP/1.1 protocol
.SH SYNOPSIS
\fBpackage require http ?2.7?\fR
\fBpackage require http ?2.8?\fR
.\" See Also -useragent option documentation in body!
.sp
\fB::http::config ?\fI\-option value\fR ...?
@@ -22,6 +22,8 @@ http \- Client-side implementation of the HTTP/1.1 protocol
.sp
\fB::http::formatQuery\fR \fIkey value\fR ?\fIkey value\fR ...?
.sp
\fB::http::quoteString\fR \fIvalue\fR
.sp
\fB::http::reset\fR \fItoken\fR ?\fIwhy\fR?
.sp
\fB::http::wait \fItoken\fR
@@ -44,12 +46,14 @@ http \- Client-side implementation of the HTTP/1.1 protocol
.sp
\fB::http::register \fIproto port command\fR
.sp
\fB::http::registerError \fIport\fR ?\fImessage\fR?
.sp
\fB::http::unregister \fIproto\fR
.BE
.SH DESCRIPTION
.PP
The \fBhttp\fR package provides the client side of the HTTP/1.1
protocol, as defined in RFC 2616.
protocol, as defined in RFC 7230 to RFC 7235, which supersede RFC 2616.
The package implements the GET, POST, and HEAD operations
of HTTP/1.1. It allows configuration of a proxy host to get through
firewalls. The package is compatible with the \fBSafesock\fR security
@@ -95,6 +99,19 @@ comma-separated list of mime type patterns that you are
willing to receive. For example,
.QW "image/gif, image/jpeg, text/*" .
.TP
\fB\-pipeline\fR \fIboolean\fR
.
Specifies whether HTTP/1.1 transactions on a persistent socket will be
pipelined. See the \fBPERSISTENT SOCKETS\fR section for details. The default
is 1.
.TP
\fB\-postfresh\fR \fIboolean\fR
.
Specifies whether requests that use the \fBPOST\fR method will always use a
fresh socket, overriding the \fB-keepalive\fR option of
command \fBhttp::geturl\fR. See the \fBPERSISTENT SOCKETS\fR section for details.
The default is 0.
.TP
\fB\-proxyhost\fR \fIhostname\fR
.
The name of the proxy host, if any. If this value is the
@@ -116,20 +133,47 @@ an empty list. The default filter returns the values of the
\fB\-proxyhost\fR and \fB\-proxyport\fR settings if they are
non-empty.
.TP
\fB\-repost\fR \fIboolean\fR
.
Specifies what to do if a POST request over a persistent connection fails
because the server has half-closed the connection. If boolean \fBtrue\fR, the
request
will be automatically retried; if boolean \fBfalse\fR it will not, and the
application
that uses \fBhttp::geturl\fR is expected to seek user confirmation before
retrying the POST. The value \fBtrue\fR should be used only under certain
conditions. See the \fBPERSISTENT SOCKETS\fR section for details. The
default is 0.
.TP
\fB\-urlencoding\fR \fIencoding\fR
.
The \fIencoding\fR used for creating the x-url-encoded URLs with
\fB::http::formatQuery\fR. The default is \fButf-8\fR, as specified by RFC
\fB::http::formatQuery\fR and \fB::http::quoteString\fR.
The default is \fButf-8\fR, as specified by RFC
2718. Prior to http 2.5 this was unspecified, and that behavior can be
returned by specifying the empty string (\fB{}\fR), although
\fIiso8859-1\fR is recommended to restore similar behavior but without the
\fB::http::formatQuery\fR throwing an error processing non-latin-1
characters.
\fB::http::formatQuery\fR or \fB::http::quoteString\fR
throwing an error processing non-latin-1 characters.
.TP
\fB\-useragent\fR \fIstring\fR
.
The value of the User-Agent header in the HTTP request. The default is
.QW "\fBTcl http client package 2.7\fR" .
The value of the User-Agent header in the HTTP request. In an unsafe
interpreter, the default value depends upon the operating system, and
the version numbers of \fBhttp\fR and \fBTcl\fR, and is (for example)
.QW "\fBMozilla/5.0 (Windows; U; Windows NT 10.0) http/2.8.12 Tcl/8.6.8\fR" .
A safe interpreter cannot determine its operating system, and so the default
in a safe interpreter is to use a Windows 10 value with the current version
numbers of \fBhttp\fR and \fBTcl\fR.
.TP
\fB\-zip\fR \fIboolean\fR
.
If the value is boolean \fBtrue\fR, then by default requests will send a header
.QW "\fBAccept-Encoding: gzip,deflate,compress\fR" .
If the value is boolean \fBfalse\fR, then by default this header will not be sent.
In either case the default can be overridden for an individual request by
supplying a custom \fBAccept-Encoding\fR header in the \fB-headers\fR option
of \fBhttp::geturl\fR. The default is 1.
.RE
.TP
\fB::http::geturl\fR \fIurl\fR ?\fIoptions\fR?
@@ -227,7 +271,7 @@ Pragma: no-cache
.TP
\fB\-keepalive\fR \fIboolean\fR
.
If true, attempt to keep the connection open for servicing
If boolean \fBtrue\fR, attempt to keep the connection open for servicing
multiple requests. Default is 0.
.TP
\fB\-method\fR \fItype\fR
@@ -334,6 +378,11 @@ encodes the keys and values, and generates one string that has the
proper & and = separators. The result is suitable for the
\fB\-query\fR value passed to \fB::http::geturl\fR.
.TP
\fB::http::quoteString\fR \fIvalue\fR
.
This procedure does x-url-encoding of string. It takes a single argument and
encodes it.
.TP
\fB::http::reset\fR \fItoken\fR ?\fIwhy\fR?
.
This command resets the HTTP transaction identified by \fItoken\fR, if any.
@@ -415,6 +464,17 @@ set token [::http::geturl https://my.secure.site/]
.CE
.RE
.TP
\fB::http::registerError\fR \fIport\fR ?\fImessage\fR?
.
This procedure allows a registered protocol handler to deliver an error
message for use by \fBhttp\fR. Calling this command does not raise an
error. The command is useful when a registered protocol detects an problem
(for example, an invalid TLS certificate) that will cause an error to
propagate to \fBhttp\fR. The command allows \fBhttp\fR to provide a
precise error message rather than a general one. The command returns the
value provided by the last call with argument \fImessage\fR, or the empty
string if no such call has been made.
.TP
\fB::http::unregister\fR \fIproto\fR
.
This procedure unregisters a protocol handler that was previously
@@ -504,6 +564,14 @@ The following elements of
the array are supported:
.RS
.TP
\fBbinary\fR
.
This is boolean \fBtrue\fR if (after decoding any compression specified
by the
.QW "Content-Encoding"
response header) the HTTP response is binary. It is boolean \fBfalse\fR
if the HTTP response is text.
.TP
\fBbody\fR
.
The contents of the URL. This will be empty if the \fB\-channel\fR
@@ -602,6 +670,106 @@ A copy of the \fBContent-Type\fR meta-data value.
.
The requested URL.
.RE
.SH "PERSISTENT CONNECTIONS"
.PP
.SS "BASICS"
.PP
See RFC 7230 Sec 6, which supersedes RFC 2616 Sec 8.1.
.PP
A persistent connection allows multiple HTTP/1.1 transactions to be
carried over the same TCP connection. Pipelining allows a
client to make multiple requests over a persistent connection without
waiting for each response. The server sends responses in the same order
that the requests were received.
.PP
If a POST request fails to complete, typically user confirmation is
needed before sending the request again. The user may wish to verify
whether the server was modified by the failed POST request, before
sending the same request again.
.PP
A HTTP request will use a persistent socket if the call to
\fBhttp::geturl\fR has the option \fB-keepalive true\fR. It will use
pipelining where permitted if the \fBhttp::config\fR option
\fB-pipeline\fR is boolean \fBtrue\fR (its default value).
.PP
The http package maintains no more than one persistent connection to each
server (i.e. each value of
.QW "domain:port" ).
If \fBhttp::geturl\fR is called to make a request over a persistent
connection while the connection is busy with another request, the new
request will be held in a queue until the connection is free.
.PP
The http package does not support HTTP/1.0 persistent connections
controlled by the \fBKeep-Alive\fR header.
.SS "SPECIAL CASES"
.PP
This subsection discusses issues related to closure of the
persistent connection by the server, automatic retry of failed requests,
the special treatment necessary for POST requests, and the options for
dealing with these cases.
.PP
In accordance with RFC 7230, \fBhttp::geturl\fR does not pipeline
requests that use the POST method. If a POST uses a persistent
connection and is not the first request on that connection,
\fBhttp::geturl\fR waits until it has received the response for the previous
request; or (if \fBhttp::config\fR option \fB-postfresh\fR is boolean \fBtrue\fR) it
uses a new connection for each POST.
.PP
If the server is processing a number of pipelined requests, and sends a
response header
.QW "\fBConnection: close\fR"
with one of the responses (other than the last), then subsequent responses
are unfulfilled. \fBhttp::geturl\fR will send the unfulfilled requests again
over a new connection.
.PP
A difficulty arises when a HTTP client sends a request over a persistent
connection that has been idle for a while. The HTTP server may
half-close an apparently idle connection while the client is sending a
request, but before the request arrives at the server: in this case (an
.QW "asynchronous close event" )
the request will fail. The difficulty arises because the client cannot
be certain whether the POST modified the state of the server. For HEAD or
GET requests, \fBhttp::geturl\fR opens another connection and retransmits
the failed request. However, if the request was a POST, RFC 7230 forbids
automatic retry by default, suggesting either user confirmation, or
confirmation by user-agent software that has semantic understanding of
the application. The \fBhttp::config\fR option \fB-repost\fR allows for
either possibility.
.PP
Asynchronous close events can occur only in a short interval of time. The
\fBhttp\fR package monitors each persistent connection for closure by the
server. Upon detection, the connection is also closed at the client end,
and subsequent requests will use a fresh connection.
.PP
If the \fBhttp::geturl\fR command is called with option \fB-keepalive true\fR,
then it will both try to use an existing persistent connection
(if one is available), and it will send the server a
.QW "\fBConnection: keep-alive\fR"
request header asking to keep the connection open for future requests.
.PP
The \fBhttp::config\fR options \fB-pipeline\fR, \fB-postfresh\fR, and
\fB-repost\fR relate to persistent connections.
.PP
Option \fB-pipeline\fR, if boolean \fBtrue\fR, will pipeline GET and HEAD requests
made
over a persistent connection. POST requests will not be pipelined - if the
POST is not the first transaction on the connection, its request will not
be sent until the previous response has finished. GET and HEAD requests
made after a POST will not be sent until the POST response has been
delivered, and will not be sent if the POST fails.
.PP
Option \fB-postfresh\fR, if boolean \fBtrue\fR, will override the \fBhttp::geturl\fR option
\fB-keepalive\fR, and always open a fresh connection for a POST request.
.PP
Option \fB-repost\fR, if \fBtrue\fR, permits automatic retry of a POST request
that fails because it uses a persistent connection that the server has
half-closed (an
.QW "asynchronous close event" ).
Subsequent GET and HEAD requests in a failed pipeline will also be retried.
\fIThe -repost option should be used only if the application understands
that the retry is appropriate\fR - specifically, the application must know
that if the failed POST successfully modified the state of the server, a repeat POST
would have no adverse effect.
.SH EXAMPLE
.PP
This example creates a procedure to copy a URL to a file while printing a
+9
View File
@@ -27,6 +27,11 @@ and also returned as result.
Starting with the Tcl 8.5 release, the variable \fIvarName\fR passed
to \fBincr\fR may be unset, and in that case, it will be set to
the value \fIincrement\fR or to the default increment value of \fB1\fR.
.VS TIP508
If \fIvarName\fR indicate an element that does not exist of an array that has
a default value set, the sum of the default value and the \fIincrement\fR (or
1) will be stored in the array element.
.VE TIP508
.SH EXAMPLES
.PP
Add one to the contents of the variable \fIx\fR:
@@ -59,3 +64,7 @@ an error if it is not):
expr(n), set(n)
.SH KEYWORDS
add, increment, variable, value
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+188 -98
View File
@@ -35,16 +35,51 @@ Returns the body of procedure \fIprocname\fR. \fIProcname\fR must be
the name of a Tcl command procedure.
.TP
\fBinfo class\fI subcommand class\fR ?\fIarg ...\fR
.VS 8.6
.
Returns information about the class, \fIclass\fR. The \fIsubcommand\fRs are
described in \fBCLASS INTROSPECTION\fR below.
.VE 8.6
.TP
\fBinfo cmdcount\fR
.
Returns a count of the total number of commands that have been invoked
in this interpreter.
.TP
\fBinfo cmdtype \fIcommandName\fR
.VS TIP426
Returns a description of the kind of command named by \fIcommandName\fR. The
supported types are:
.RS
.IP \fBalias\fR
Indicates that \fIcommandName\fR was created by \fBinterp alias\fR. Note that
safe interpreters can only see a subset of aliases (specifically those between
two commands within themselves).
.IP \fBcoroutine\fR
Indicates that \fIcommandName\fR was created by \fBcoroutine\fR.
.IP \fBensemble\fR
Indicates that \fIcommandName\fR was created by \fBnamespace ensemble\fR.
.IP \fBimport\fR
Indicates that \fIcommandName\fR was created by \fBnamespace import\fR.
.IP \fBnative\fR
Indicates that \fIcommandName\fR was created by the \fBTcl_CreateObjProc\fR
interface directly without further registration of the type of command.
.IP \fBobject\fR
Indicates that \fIcommandName\fR is the public command that represents an
instance of \fBoo::object\fR or one of its subclasses.
.IP \fBprivateObject\fR
Indicates that \fIcommandName\fR is the private command (\fBmy\fR by default)
that represents an instance of \fBoo::object\fR or one of its subclasses.
.IP \fBproc\fR
Indicates that \fIcommandName\fR was created by \fBproc\fR.
.IP \fBslave\fR
Indicates that \fIcommandName\fR was created by \fBinterp create\fR.
.IP \fBzlibStream\fR
Indicates that \fIcommandName\fR was created by \fBzlib stream\fR.
.PP
There may be other registered types as well; this is a set that is extensible
at the implementation level with \fBTcl_RegisterCommandTypeName\fR.
.RE
.VE TIP426
.TP
\fBinfo commands \fR?\fIpattern\fR?
.
If \fIpattern\fR is not specified,
@@ -78,11 +113,10 @@ command is not complete, the script can delay evaluating it until additional
lines have been typed to complete the command.
.TP
\fBinfo coroutine\fR
.VS 8.6
.
Returns the name of the currently executing \fBcoroutine\fR, or the empty
string if either no coroutine is currently executing, or the current coroutine
has been deleted (but has not yet returned or yielded since deletion).
.VE 8.6
.TP
\fBinfo default \fIprocname arg varname\fR
.
@@ -93,7 +127,7 @@ Otherwise it returns \fB1\fR and places the default value of \fIarg\fR
into variable \fIvarname\fR.
.TP
\fBinfo errorstack \fR?\fIinterp\fR?
.VS 8.6
.
Returns, in a form that is programmatically easy to parse, the function names
and arguments at each level from the call stack of the last error in the given
\fIinterp\fR, or in the current one if not specified.
@@ -118,7 +152,6 @@ options dictionary returned by 3-argument \fBcatch\fR; \fBinfo errorstack\fR
is a convenient way of retrieving it for uncaught errors at top-level in an
interactive \fBtclsh\fR.
.RE
.VE 8.6
.TP
\fBinfo exists \fIvarName\fR
.
@@ -329,10 +362,9 @@ was invoked. If Tcl was unable to identify the file, then an empty
string is returned.
.TP
\fBinfo object\fI subcommand object\fR ?\fIarg ...\fR
.VS 8.6
.
Returns information about the object, \fIobject\fR. The \fIsubcommand\fRs are
described in \fBOBJECT INTROSPECTION\fR below.
.VE 8.6
.TP
\fBinfo patchlevel\fR
.
@@ -399,20 +431,22 @@ Note that a currently-visible variable may not yet
if it has not
been set (e.g. a variable declared but not set by \fBvariable\fR).
.SS "CLASS INTROSPECTION"
.VS 8.6
.PP
The following \fIsubcommand\fR values are supported by \fBinfo class\fR:
.VE 8.6
.TP
\fBinfo class call\fI class method\fR
.VS
.
Returns a description of the method implementations that are used to provide a
stereotypical instance of \fIclass\fR's implementation of \fImethod\fR
(stereotypical instances being objects instantiated by a class without having
any object-specific definitions added). This consists of a list of lists of
four elements, where each sublist consists of a word that describes the
general type of method implementation (being one of \fBmethod\fR for an
ordinary method, \fBfilter\fR for an applied filter, and \fBunknown\fR for a
ordinary method, \fBfilter\fR for an applied filter,
.VS TIP500
\fBprivate\fR for a private method,
.VE TIP500
and \fBunknown\fR for a
method that is invoked as part of unknown method handling), a word giving the
name of the particular method invoked (which is always the same as
\fImethod\fR for the \fBmethod\fR type, and
@@ -423,122 +457,149 @@ implementation (see \fBinfo class methodtype\fR).
.RS
.PP
Note that there is no inspection of whether the method implementations
actually use \fBnext\fR to transfer control along the call chain.
actually use \fBnext\fR to transfer control along the call chain,
.VS TIP500
and the call chains that this command files do not actually contain private
methods.
.VE TIP500
.RE
.VE 8.6
.TP
\fBinfo class constructor\fI class\fR
.VS 8.6
.
This subcommand returns a description of the definition of the constructor of
class \fIclass\fR. The definition is described as a two element list; the first
element is the list of arguments to the constructor in a form suitable for
passing to another call to \fBproc\fR or a method definition, and the second
element is the body of the constructor. If no constructor is present, this
returns the empty list.
.VE 8.6
.TP
\fBinfo class definition\fI class method\fR
.VS 8.6
.
This subcommand returns a description of the definition of the method named
\fImethod\fR of class \fIclass\fR. The definition is described as a two element
list; the first element is the list of arguments to the method in a form
suitable for passing to another call to \fBproc\fR or a method definition, and
the second element is the body of the method.
.VE 8.6
.TP
\fBinfo class destructor\fI class\fR
.VS 8.6
.
This subcommand returns the body of the destructor of class \fIclass\fR. If no
destructor is present, this returns the empty string.
.VE 8.6
.TP
\fBinfo class filters\fI class\fR
.VS 8.6
.
This subcommand returns the list of filter methods set on the class.
.VE 8.6
.TP
\fBinfo class forward\fI class method\fR
.VS 8.6
.
This subcommand returns the argument list for the method forwarding called
\fImethod\fR that is set on the class called \fIclass\fR.
.VE 8.6
.TP
\fBinfo class instances\fI class\fR ?\fIpattern\fR?
.VS 8.6
.
This subcommand returns a list of instances of class \fIclass\fR. If the
optional \fIpattern\fR argument is present, it constrains the list of returned
instances to those that match it according to the rules of \fBstring match\fR.
.VE 8.6
.TP
\fBinfo class methods\fI class\fR ?\fIoptions...\fR?
.VS 8.6
.
This subcommand returns a list of all public (i.e. exported) methods of the
class called \fIclass\fR. Any of the following \fIoption\fRs may be
specified, controlling exactly which method names are returned:
.RS
.VE 8.6
.TP
\fB\-all\fR
.VS 8.6
If the \fB\-all\fR flag is given, the list of methods will include those
.
If the \fB\-all\fR flag is given,
.VS TIP500
and the \fB\-scope\fR flag is not given,
.VE TIP500
the list of methods will include those
methods defined not just by the class, but also by the class's superclasses
and mixins.
.VE 8.6
.TP
\fB\-private\fR
.VS 8.6
If the \fB\-private\fR flag is given, the list of methods will also include
the private (i.e. non-exported) methods of the class (and superclasses and
.
If the \fB\-private\fR flag is given,
.VS TIP500
and the \fB\-scope\fR flag is not given,
.VE TIP500
the list of methods will also include
the non-exported methods of the class (and superclasses and
mixins, if \fB\-all\fR is also given).
.VS TIP500
Note that this naming is an unfortunate clash with true private methods; this
option name is retained for backward compatibility.
.VE TIP500
.TP
\fB\-scope\fI scope\fR
.VS TIP500
Returns a list of all methods on \fIclass\fR that have the given visibility
\fIscope\fR. When this option is supplied, both the \fB\-all\fR and
\fB\-private\fR options are ignored. The valid values for \fIscope\fR are:
.RS
.IP \fBpublic\fR 3
Only methods with \fIpublic\fR scope (i.e., callable from anywhere by any instance
of this class) are to be returned.
.IP \fBunexported\fR 3
Only methods with \fIunexported\fR scope (i.e., only callable via \fBmy\fR) are to
be returned.
.IP \fBprivate\fR 3
Only methods with \fIprivate\fR scope (i.e., only callable from within this class's
methods) are to be returned.
.RE
.VE TIP500
.RE
.VE 8.6
.TP
\fBinfo class methodtype\fI class method\fR
.VS 8.6
.
This subcommand returns a description of the type of implementation used for
the method named \fImethod\fR of class \fIclass\fR. When the result is
\fBmethod\fR, further information can be discovered with \fBinfo class
definition\fR, and when the result is \fBforward\fR, further information can
be discovered with \fBinfo class forward\fR.
.VE 8.6
.TP
\fBinfo class mixins\fI class\fR
.VS 8.6
.
This subcommand returns a list of all classes that have been mixed into the
class named \fIclass\fR.
.VE 8.6
.TP
\fBinfo class subclasses\fI class\fR ?\fIpattern\fR?
.VS 8.6
.
This subcommand returns a list of direct subclasses of class \fIclass\fR. If
the optional \fIpattern\fR argument is present, it constrains the list of
returned classes to those that match it according to the rules of
\fBstring match\fR.
.VE 8.6
.TP
\fBinfo class superclasses\fI class\fR
.VS 8.6
.
This subcommand returns a list of direct superclasses of class \fIclass\fR in
inheritance precedence order.
.VE 8.6
.TP
\fBinfo class variables\fI class\fR
.VS 8.6
\fBinfo class variables\fI class\fR ?\fB\-private\fR?
.
This subcommand returns a list of all variables that have been declared for
the class named \fIclass\fR (i.e. that are automatically present in the
class's methods, constructor and destructor).
.VS TIP500
If the \fB\-private\fR option is specified, this lists the private variables
declared instead.
.VE TIP500
.SS "OBJECT INTROSPECTION"
.PP
The following \fIsubcommand\fR values are supported by \fBinfo object\fR:
.VE 8.6
.TP
\fBinfo object call\fI object method\fR
.VS 8.6
.
Returns a description of the method implementations that are used to provide
\fIobject\fR's implementation of \fImethod\fR. This consists of a list of
lists of four elements, where each sublist consists of a word that describes
the general type of method implementation (being one of \fBmethod\fR for an
ordinary method, \fBfilter\fR for an applied filter, and \fBunknown\fR for a
ordinary method, \fBfilter\fR for an applied filter,
.VS TIP500
\fBprivate\fR for a private method,
.VE TIP500
and \fBunknown\fR for a
method that is invoked as part of unknown method handling), a word giving the
name of the particular method invoked (which is always the same as
\fImethod\fR for the \fBmethod\fR type, and
@@ -550,128 +611,160 @@ implementation (see \fBinfo object methodtype\fR).
.RS
.PP
Note that there is no inspection of whether the method implementations
actually use \fBnext\fR to transfer control along the call chain.
actually use \fBnext\fR to transfer control along the call chain,
.VS TIP500
and the call chains that this command files do not actually contain private
methods.
.VE TIP500
.RE
.VE 8.6
.TP
\fBinfo object class\fI object\fR ?\fIclassName\fR?
.VS 8.6
.
If \fIclassName\fR is unspecified, this subcommand returns class of the
\fIobject\fR object. If \fIclassName\fR is present, this subcommand returns a
boolean value indicating whether the \fIobject\fR is of that class.
.VE 8.6
.TP
\fBinfo object creationid\fI object\fR
.VS TIP500
Returns the unique creation identifier for the \fIobject\fR object. This
creation identifier is unique to the object (within a Tcl interpreter) and
cannot be controlled at object creation time or altered afterwards.
.RS
.PP
\fIImplementation note:\fR the creation identifier is used to generate unique
identifiers associated with the object, especially for private variables.
.RE
.VE TIP500
.TP
\fBinfo object definition\fI object method\fR
.VS 8.6
.
This subcommand returns a description of the definition of the method named
\fImethod\fR of object \fIobject\fR. The definition is described as a two
element list; the first element is the list of arguments to the method in a
form suitable for passing to another call to \fBproc\fR or a method definition,
and the second element is the body of the method.
.VE 8.6
.TP
\fBinfo object filters\fI object\fR
.VS 8.6
.
This subcommand returns the list of filter methods set on the object.
.VE 8.6
.TP
\fBinfo object forward\fI object method\fR
.VS 8.6
.
This subcommand returns the argument list for the method forwarding called
\fImethod\fR that is set on the object called \fIobject\fR.
.VE 8.6
.TP
\fBinfo object isa\fI category object\fR ?\fIarg\fR?
.VS 8.6
.
This subcommand tests whether an object belongs to a particular category,
returning a boolean value that indicates whether the \fIobject\fR argument
meets the criteria for the category. The supported categories are:
.VE 8.6
.RS
.TP
\fBinfo object isa class\fI object\fR
.VS 8.6
.
This returns whether \fIobject\fR is a class (i.e. an instance of
\fBoo::class\fR or one of its subclasses).
.VE 8.6
.TP
\fBinfo object isa metaclass\fI object\fR
.VS 8.6
.
This returns whether \fIobject\fR is a class that can manufacture classes
(i.e. is \fBoo::class\fR or a subclass of it).
.VE 8.6
.TP
\fBinfo object isa mixin\fI object class\fR
.VS 8.6
.
This returns whether \fIclass\fR is directly mixed into \fIobject\fR.
.VE 8.6
.TP
\fBinfo object isa object\fI object\fR
.VS 8.6
.
This returns whether \fIobject\fR really is an object.
.VE 8.6
.TP
\fBinfo object isa typeof\fI object class\fR
.VS 8.6
.
This returns whether \fIclass\fR is the type of \fIobject\fR (i.e. whether
\fIobject\fR is an instance of \fIclass\fR or one of its subclasses, whether
direct or indirect).
.RE
.VE 8.6
.TP
\fBinfo object methods\fI object\fR ?\fIoption...\fR?
.VS 8.6
.
This subcommand returns a list of all public (i.e. exported) methods of the
object called \fIobject\fR. Any of the following \fIoption\fRs may be
specified, controlling exactly which method names are returned:
.RS
.VE 8.6
.TP
\fB\-all\fR
.VS 8.6
If the \fB\-all\fR flag is given, the list of methods will include those
.
If the \fB\-all\fR flag is given,
.VS TIP500
and the \fB\-scope\fR flag is not given,
.VE TIP500
the list of methods will include those
methods defined not just by the object, but also by the object's class and
mixins, plus the superclasses of those classes.
.VE 8.6
.TP
\fB\-private\fR
.VS 8.6
If the \fB\-private\fR flag is given, the list of methods will also include
the private (i.e. non-exported) methods of the object (and classes, if
.
If the \fB\-private\fR flag is given,
.VS TIP500
and the \fB\-scope\fR flag is not given,
.VE TIP500
the list of methods will also include
the non-exported methods of the object (and classes, if
\fB\-all\fR is also given).
.VS TIP500
Note that this naming is an unfortunate clash with true private methods; this
option name is retained for backward compatibility.
.VE TIP500
.TP
\fB\-scope\fI scope\fR
.VS TIP500
Returns a list of all methods on \fIobject\fR that have the given visibility
\fIscope\fR. When this option is supplied, both the \fB\-all\fR and
\fB\-private\fR options are ignored. The valid values for \fIscope\fR are:
.RS
.IP \fBpublic\fR 3
Only methods with \fIpublic\fR scope (i.e., callable from anywhere) are to be
returned.
.IP \fBunexported\fR 3
Only methods with \fIunexported\fR scope (i.e., only callable via \fBmy\fR) are to
be returned.
.IP \fBprivate\fR 3
Only methods with \fIprivate\fR scope (i.e., only callable from within this object's
instance methods) are to be returned.
.RE
.VE TIP500
.RE
.VE 8.6
.TP
\fBinfo object methodtype\fI object method\fR
.VS 8.6
.
This subcommand returns a description of the type of implementation used for
the method named \fImethod\fR of object \fIobject\fR. When the result is
\fBmethod\fR, further information can be discovered with \fBinfo object
definition\fR, and when the result is \fBforward\fR, further information can
be discovered with \fBinfo object forward\fR.
.VE 8.6
.TP
\fBinfo object mixins\fI object\fR
.VS 8.6
.
This subcommand returns a list of all classes that have been mixed into the
object named \fIobject\fR.
.VE 8.6
.TP
\fBinfo object namespace\fI object\fR
.VS 8.6
.
This subcommand returns the name of the internal namespace of the object named
\fIobject\fR.
.VE 8.6
.TP
\fBinfo object variables\fI object\fR
.VS 8.6
\fBinfo object variables\fI object\fRR ?\fB\-private\fR?
.
This subcommand returns a list of all variables that have been declared for
the object named \fIobject\fR (i.e. that are automatically present in the
object's methods).
.VE 8.6
.VS TIP500
If the \fB\-private\fR option is specified, this lists the private variables
declared instead.
.VE TIP500
.TP
\fBinfo object vars\fI object\fR ?\fIpattern\fR?
.VS 8.6
.
This subcommand returns a list of all variables in the private namespace of
the object named \fIobject\fR. If the optional \fIpattern\fR argument is
given, it is a filter (in the syntax of a \fBstring match\fR glob pattern)
@@ -680,7 +773,6 @@ from the list returned by \fBinfo object variables\fR; that can include
variables that are currently unset, whereas this can include variables that
are not automatically included by any of \fIobject\fR's methods (or those of
its class, superclasses or mixins).
.VE 8.6
.SH EXAMPLES
.PP
This command prints out a procedure suitable for saving in a Tcl
@@ -703,7 +795,6 @@ proc printProc {procName} {
}
.CE
.SS "EXAMPLES WITH OBJECTS"
.VS 8.6
.PP
Every object necessarily knows what its class is; this information is
trivially extractable through introspection:
@@ -724,8 +815,10 @@ method and get how it is defined. This procedure illustrates how:
proc getDef {obj method} {
foreach inf [\fBinfo object call\fR $obj $method] {
lassign $inf calltype name locus methodtype
# Assume no forwards or filters, and hence no $calltype
# or $methodtype checks...
if {$locus eq "object"} {
return [\fBinfo object definition\fR $obj $name]
} else {
@@ -748,7 +841,9 @@ proc getDef {obj method} {
# Assume no forwards
return [\fBinfo object definition\fR $obj $method]
}
set cls [\fBinfo object class\fR $obj]
while {$method ni [\fBinfo class methods\fR $cls]} {
# Assume the simple case
set cls [lindex [\fBinfo class superclass\fR $cls] 0]
@@ -756,22 +851,17 @@ proc getDef {obj method} {
error "no definition for $method"
}
}
# Assume no forwards
return [\fBinfo class definition\fR $cls $method]
}
.CE
.VE 8.6
.SH "SEE ALSO"
.VS 8.6
global(n), oo::class(n), oo::define(n), oo::object(n), proc(n), self(n),
.VE 8.6
tcl_library(n), tcl_patchLevel(n), tcl_version(n)
.SH KEYWORDS
command, information, interpreter, introspection, level, namespace,
.VS 8.6
object,
.VE 8.6
procedure, variable
object, procedure, variable
'\" Local Variables:
'\" mode: nroff
'\" fill-column: 78
+10
View File
@@ -22,6 +22,12 @@ and appends each of the \fIvalue\fR arguments to that list as a separate
element, with spaces between elements.
If \fIvarName\fR does not exist, it is created as a list with elements
given by the \fIvalue\fR arguments.
.VS TIP508
If \fIvarName\fR indicate an element that does not exist of an array that has
a default value set, list that is comprised of the default value with all the
\fIvalue\fR arguments appended as elements will be stored in the array
element.
.VE TIP508
\fBLappend\fR is similar to \fBappend\fR except that the \fIvalue\fRs
are appended as list elements rather than raw text.
This command provides a relatively efficient way to build up
@@ -47,3 +53,7 @@ list(n), lindex(n), linsert(n), llength(n), lset(n),
lsort(n), lrange(n)
.SH KEYWORDS
append, element, list, variable
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+124
View File
@@ -0,0 +1,124 @@
'\"
'\" Copyright (c) 2011-2015 Andreas Kupries
'\" Copyright (c) 2018 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH link n 0.3 TclOO "TclOO Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
link \- create link from command to method of object
.SH SYNOPSIS
.nf
package require TclOO
\fBlink\fR \fImethodName\fR ?\fI...\fR?
\fBlink\fR \fB{\fIcommandName methodName\fB}\fR ?\fI...\fR?
.fi
.BE
.SH DESCRIPTION
The \fBlink\fR command is available within methods. It takes a series of one
or more method names (\fImethodName ...\fR) and/or pairs of command- and
method-name (\fB{\fIcommandName methodName\fB}\fR) and makes the named methods
available as commands without requiring the explicit use of the name of the
object or the \fBmy\fR command. The method does not need to exist at the time
that the link is made; if the link command is invoked when the method does not
exist, the standard \fBunknown\fR method handling system is used.
.PP
The command name under which the method becomes available defaults to the
method name, except where explicitly specified through an alias/method pair.
Formally, every argument must be a list; if the list has two elements, the
first element is the name of the command to create and the second element is
the name of the method of the current object to which the command links;
otherwise, the name of the command and the name of the method are the same
string (the first element of the list).
.PP
If the name of the command is not a fully-qualified command name, it will be
resolved with respect to the current namespace (i.e., the object namespace).
.SH EXAMPLES
This demonstrates linking a single method in various ways. First it makes a
simple link, then a renamed link, then an external link. Note that the method
itself is unexported, but that it can still be called directly from outside
the class.
.PP
.CS
oo::class create ABC {
method Foo {} {
puts "This is Foo in [self]"
}
constructor {} {
\fBlink\fR Foo
# The method foo is now directly accessible as foo here
\fBlink\fR {bar Foo}
# The method foo is now directly accessible as bar
\fBlink\fR {::ExternalCall Foo}
# The method foo is now directly accessible in the global
# namespace as ExternalCall
}
method grill {} {
puts "Step 1:"
Foo
puts "Step 2:"
bar
}
}
ABC create abc
abc grill
\fI\(-> Step 1:\fR
\fI\(-> This is foo in ::abc\fR
\fI\(-> Step 2:\fR
\fI\(-> This is foo in ::abc\fR
# Direct access via the linked command
puts "Step 3:"; ExternalCall
\fI\(-> Step 3:\fR
\fI\(-> This is foo in ::abc\fR
.CE
.PP
This example shows that multiple linked commands can be made in a call to
\fBlink\fR, and that they can handle arguments.
.PP
.CS
oo::class create Ex {
constructor {} {
\fBlink\fR a b c
# The methods a, b, and c (defined below) are all now
# directly acessible within methods under their own names.
}
method a {} {
puts "This is a"
}
method b {x} {
puts "This is b($x)"
}
method c {y z} {
puts "This is c($y,$z)"
}
method call {p q r} {
a
b $p
c $q $r
}
}
set o [Ex new]
$o 3 5 7
\fI\(-> This is a\fR
\fI\(-> This is b(3)\fR
\fI\(-> This is c(5,7)\fR
.CE
.SH "SEE ALSO"
interp(n), my(n), oo::class(n), oo::define(n)
.SH KEYWORDS
command, method, object
.\" Local Variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+32 -2
View File
@@ -30,13 +30,26 @@ list, and \fBend\fR refers to the last element of the list.
If \fIlist\fR is empty, then \fIfirst\fR and \fIlast\fR are ignored.
.PP
If \fIfirst\fR is less than zero, it is considered to refer to before the
first element of the list. For non-empty lists, the element indicated
by \fIfirst\fR must exist or \fIfirst\fR must indicate before the
first element of the list.
.VS TIP505
If \fIfirst\fR indicates a position greater than the index of the last element
of the list, it is treated as if it is an index one greater than the last
element. This allows this command to append elements to the list.
.VE TIP505
For non-empty lists, the element indicated
by \fIfirst\fR must exist, or \fIfirst\fR must indicate before the
start of the list.
.PP
If \fIlast\fR is less than \fIfirst\fR, then any specified elements
will be inserted into the list before the point specified by \fIfirst\fR
with no elements being deleted.
.VS TIP505
If \fIlast\fR is greater than the index of the last item of the list, it is
treated as if it is an index one greater than the last element. This means
that if it is also greater than than \fIfirst\fR, all elements from
\fIfirst\fR to the end of the list will be replaced, and otherwise the
elements will be appended.
.VE TIP505
.PP
The \fIelement\fR arguments specify zero or more new arguments to
be added to the list in place of those that were deleted.
@@ -78,9 +91,26 @@ proc lremove {listVariable value} {
set var [\fBlreplace\fR $var $idx $idx]
}
.CE
.PP
.VS TIP505
Adding elements to the end of the list; note that \fBend+2\fR will initially
be treated as if it is \fB6\fR here, but both that and \fB12345\fR are greater
than the index of the final item so they behave identically:
.PP
.CS
% set var {a b c d e}
a b c d e
% set var [\fBlreplace\fR $var 12345 end+2 f g h i]
a b c d e f g h i
.CE
.VE TIP505
.SH "SEE ALSO"
list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n),
lset(n), lrange(n), lsort(n),
string(n)
.SH KEYWORDS
element, list, replace
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+84 -9
View File
@@ -9,25 +9,45 @@
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
my \- invoke any method of current object
my, myclass \- invoke any method of current object or its class
.SH SYNOPSIS
.nf
package require TclOO
\fBmy\fI methodName\fR ?\fIarg ...\fR?
\fBmyclass\fI methodName\fR ?\fIarg ...\fR?
.fi
.BE
.SH DESCRIPTION
.PP
The \fBmy\fR command is used to allow methods of objects to invoke any method
of the object (or its class). In particular, the set of valid values for
The \fBmy\fR command is used to allow methods of objects to invoke methods
of the object (or its class),
.VS TIP478
and he \fBmyclass\fR command is used to allow methods of objects to invoke
methods of the current class of the object \fIas an object\fR.
.VE TIP478
In particular, the set of valid values for
\fImethodName\fR is the set of all methods supported by an object and its
superclasses, including those that are not exported. The object upon which the
method is invoked is always the one that is the current context of the method
(i.e. the object that is returned by \fBself object\fR) from which the
\fBmy\fR command is invoked.
superclasses, including those that are not exported
.VS TIP500
and private methods of the object or class when used within another method
defined by that object or class.
.VE TIP500
.PP
Each object has its own \fBmy\fR command, contained in its instance namespace.
The object upon which the method is invoked via \fBmy\fR is the one that owns
the namespace that the \fBmy\fR command is contained in initially (\fBNB:\fR the link
remains if the command is renamed), which is the currently invoked object by
default.
.VS TIP478
Similarly, the object on which the method is invoked via \fBmyclass\fR is the
object that is the current class of the object that owns the namespace that
the \fBmyclass\fR command is contained in initially. As with \fBmy\fR, the
link remains even if the command is renamed into another namespace, and
defaults to being the manufacturing class of the current object.
.VE TIP478
.PP
Each object has its own \fBmy\fR and \fBmyclass\fR commands, contained in its
instance namespace.
.SH EXAMPLES
.PP
This example shows basic use of \fBmy\fR to use the \fBvariables\fR method of
@@ -40,16 +60,71 @@ oo::class create c {
puts [incr counter]
}
}
c create o
o count \fI\(-> prints "1"\fR
o count \fI\(-> prints "2"\fR
o count \fI\(-> prints "3"\fR
.CE
.PP
This example shows how you can use \fBmy\fR to make callbacks to private
methods from outside the object (from a \fBtrace\fR), using
\fBnamespace code\fR to enter the correct context. (See the \fBcallback\fR
command for the recommended way of doing this.)
.PP
.CS
oo::class create HasCallback {
method makeCallback {} {
return [namespace code {
\fBmy\fR Callback
}]
}
method Callback {args} {
puts "callback: $args"
}
}
set o [HasCallback new]
trace add variable xyz write [$o makeCallback]
set xyz "called" \fI\(-> prints "callback: xyz {} write"\fR
.CE
.PP
.VS TIP478
This example shows how to access a private method of a class from an instance
of that class. (See the \fBclassmethod\fR declaration in \fBoo::define\fR for
a higher level interface for doing this.)
.PP
.CS
oo::class create CountedSteps {
self {
variable count
method Count {} {
return [incr count]
}
}
method advanceTwice {} {
puts "in [self] step A: [\fBmyclass\fR Count]"
puts "in [self] step B: [\fBmyclass\fR Count]"
}
}
CountedSteps create x
CountedSteps create y
x advanceTwice \fI\(-> prints "in ::x step A: 1"\fR
\fI\(-> prints "in ::x step B: 2"\fR
y advanceTwice \fI\(-> prints "in ::y step A: 3"\fR
\fI\(-> prints "in ::y step B: 4"\fR
x advanceTwice \fI\(-> prints "in ::x step A: 5"\fR
\fI\(-> prints "in ::x step B: 6"\fR
y advanceTwice \fI\(-> prints "in ::y step A: 7"\fR
\fI\(-> prints "in ::y step B: 8"\fR
.CE
.VE TIP478
.SH "SEE ALSO"
next(n), oo::object(n), self(n)
.SH KEYWORDS
method, method visibility, object, private method, public method
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
+5
View File
@@ -112,6 +112,7 @@ oo::class create theSuperclass {
puts "in the superclass, args = $args"
}
}
oo::class create theSubclass {
superclass theSuperclass
method example {args} {
@@ -121,6 +122,7 @@ oo::class create theSubclass {
puts "after chaining from subclass"
}
}
theSubclass create obj
oo::objdefine obj method example args {
puts "per-object method, args = $args"
@@ -167,6 +169,7 @@ oo::class create cache {
\fI# Compute value, insert into cache, and return it\fR
return [set ValueCache($key) [\fBnext\fR {*}$args]]
}
method flushCache {} {
my variable ValueCache
unset ValueCache
@@ -178,10 +181,12 @@ oo::class create cache {
oo::object create demo
oo::objdefine demo {
mixin cache
method compute {a b c} {
after 3000 \fI;# Simulate deep thought\fR
return [expr {$a + $b * $c}]
}
method compute2 {a b c} {
after 3000 \fI;# Simulate deep thought\fR
return [expr {$a * $b + $c}]
+131
View File
@@ -0,0 +1,131 @@
'\"
'\" Copyright (c) 2017 Frederic Bonnet.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH process n 8.7 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
tcl::process \- Subprocess management
.SH SYNOPSIS
\fB::tcl::process \fIoption \fR?\fIarg arg ...\fR?
.BE
.SH DESCRIPTION
.PP
This command provides a way to manage subprocesses created by the \fBopen\fR
and \fBexec\fR commands. The legal \fIoptions\fR (which may be abbreviated) are:
.TP
\fB::tcl::process list\fR
.
Returns the list of subprocess PIDs.
.TP
\fB::tcl::process status\fR ?\fIswitches\fR? ?\fIpids\fR?
.
Returns a dictionary mapping subprocess PIDs to their respective status. If
\fIpids\fR is specified as a list of PIDs then the command only returns the
status of the matching subprocesses if they exist, and raises an error
otherwise. For active processes, the status is an empty value. For terminated
processes, the status is a list with the following format:
.QW "{code ?\fImsg errorCode\fR?}" ,
where:
.RS
.TP
\fBcode\fR\0
.
is a standard Tcl return code,
.TP
\fBmsg\fR\0
.
is the human-readable error message,
.TP
\fBerrorCode\fR\0
.
uses the same format as the \fBerrorCode\fR global variable
.RE
Note that \fBmsg\fR and \fBerrorCode\fR are only present for abnormally
terminated processes (i.e. those where \fBcode\fR is nonzero). Under the hood
this command calls \fBTcl_WaitPid\fR with the \fBWNOHANG\fR flag set for
non-blocking behavior, unless the \fB\-wait\fR switch is set (see below).
.RS
.PP
Additionally, \fB::tcl::process status\fR accepts the following switches:
.TP
\fB\-wait\fR\0
.
By default the command returns immediately (the underlying \fBTcl_WaitPid\fR is
called with the \fBWNOHANG\fR flag set) unless this switch is set. If \fBpids\fR
is specified as a list of PIDs then the command waits until the status of the
matching subprocesses are available. If \fBpids\fR is not specified then it
waits for all known subprocesses.
.TP
\fB\-\|\-\fR
.
Marks the end of switches. The argument following this one will
be treated as the first \fIarg\fR even if it starts with a \fB\-\fR.
.RE
.TP
\fB::tcl::process purge ?\fIpids\fR?
.
Cleans up all data associated with terminated subprocesses. If \fBpids\fR is
specified as a list of PIDs then the command only cleanup data for the matching
subprocesses if they exist, and raises an error otherwise. If the process is
still active then it does nothing.
.TP
\fB::tcl::process autopurge ?\fIflag\fR?
.
Automatic purge facility. If \fBflag\fR is specified as a boolean value then it
activates or deactivate autopurge. In all cases it returns the current status as
a boolean value. When autopurge is active, \fBTcl_ReapDetachedProcs\fR is called
each time the exec command is executed or a pipe channel created by open is
closed. When autopurge is inactive, \fB::tcl::process\fR purge must be called
explicitly. By default autopurge is active.
.RE
.SH "EXAMPLES"
.PP
.CS
\fB::tcl::process autopurge\fR
\fI\(-> true\fR
\fB::tcl::process autopurge\fR false
\fI\(-> false\fR
set pid1 [exec command1 a b c | command2 d e f &]
\fI\(-> 123 456\fR
set chan [open "|command1 a b c | command2 d e f"]
\fI\(-> file123\fR
set pid2 [pid $chan]
\fI\(-> 789 1011\fR
\fB::tcl::process list\fR
\fI\(-> 123 456 789 1011\fR
\fB::tcl::process status\fR
\fI\(-> 123 0 456 {1 "child killed: write on pipe with no readers" {CHILDKILLED 456 SIGPIPE "write on pipe with no readers"}} 789 {1 "child suspended: background tty read" {CHILDSUSP 789 SIGTTIN "background tty read"}} 1011 {}\fR
\fB::tcl::process status\fR 123
\fI\(-> 123 0\fR
\fB::tcl::process status\fR 1011
\fI\(-> 1011 {}\fR
\fB::tcl::process status\fR -wait
\fI\(-> 123 0 456 {1 "child killed: write on pipe with no readers" {CHILDKILLED 456 SIGPIPE "write on pipe with no readers"}} 789 {1 "child suspended: background tty read" {CHILDSUSP 789 SIGTTIN "background tty read"}} 1011 {1 "child process exited abnormally" {CHILDSTATUS 1011 -1}}\fR
\fB::tcl::process status\fR 1011
\fI\(-> 1011 {1 "child process exited abnormally" {CHILDSTATUS 1011 -1}}\fR
\fB::tcl::process purge\fR
exec command1 1 2 3 &
\fI\(-> 1213\fR
\fB::tcl::process list\fR
\fI\(-> 1213\fR
.CE
.SH "SEE ALSO"
exec(n), open(n), Tcl_DetachPids(3), Tcl_WaitPid(3), Tcl_ReapDetachedProcs(3)
.SH "KEYWORDS"
background, child, detach, process, wait
'\" Local Variables:
'\" mode: nroff
'\" End:
+6 -1
View File
@@ -32,7 +32,12 @@ implement the current call chain. The first element is the same as would be
reported by \fBinfo object\fR \fBcall\fR for the current method (except that this
also reports useful values from within constructors and destructors, whose
names are reported as \fB<constructor>\fR and \fB<destructor>\fR
respectively), and the second element is an index into the first element's
respectively,
.VS TIP500
and for private methods, which are described as being \fBprivate\fR instead of
being a \fBmethod\fR),
.VE TIP500
and the second element is an index into the first element's
list that indicates which actual implementation is currently executing (the
first implementation to execute is always at index 0).
.TP
+99
View File
@@ -0,0 +1,99 @@
'\"
'\" Copyright (c) 2018 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH singleton n 0.3 TclOO "TclOO Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
oo::singleton \- a class that does only allows one instance of itself
.SH SYNOPSIS
.nf
package require TclOO
\fBoo::singleton\fI method \fR?\fIarg ...\fR?
.fi
.SH "CLASS HIERARCHY"
.nf
\fBoo::object\fR
\(-> \fBoo::class\fR
\(-> \fBoo::singleton\fR
.fi
.BE
.SH DESCRIPTION
Singleton classes are classes that only permit at most one instance of
themselves to exist. They unexport the \fBcreate\fR and
\fBcreateWithNamespace\fR methods entirely, and override the \fBnew\fR method
so that it only makes a new instance if there is no existing instance. It is
not recommended to inherit from a singleton class; singleton-ness is \fInot\fR
inherited. It is not recommended that a singleton class's constructor take any
arguments.
.PP
Instances have their\fB destroy\fR method overridden with a method that always
returns an error in order to discourage destruction of the object, but
destruction remains possible if strictly necessary (e.g., by destroying the
class or using \fBrename\fR to delete it). They also have a (non-exported)
\fB<cloned>\fR method defined on them that similarly always returns errors to
make attempts to use the singleton instance with \fBoo::copy\fR fail.
.SS CONSTRUCTOR
The \fBoo::singleton\fR class does not define an explicit constructor; this
means that it is effectively the same as the constructor of the
\fBoo::class\fR class.
.SS DESTRUCTOR
The \fBoo::singleton\fR class does not define an explicit destructor;
destroying an instance of it is just like destroying an ordinary class (and
will destroy the singleton object).
.SS "EXPORTED METHODS"
.TP
\fIcls \fBnew \fR?\fIarg ...\fR?
.
This returns the current instance of the singleton class, if one exists, and
creates a new instance only if there is no existing instance. The additional
arguments, \fIarg ...\fR, are only used if a new instance is actually
manufactured; that construction is via the \fBoo::class\fR class's \fBnew\fR
method.
.RS
.PP
This is an override of the behaviour of a superclass's method with an
identical call signature to the superclass's implementation.
.RE
.SS "NON-EXPORTED METHODS"
The \fBoo::singleton\fR class explicitly states that \fBcreate\fR and
\fBcreateWithNamespace\fR are unexported; callers should not assume that they
have control over either the name or the namespace name of the singleton instance.
.SH EXAMPLE
.PP
This example demonstrates that there is only one instance even though the
\fBnew\fR method is called three times.
.PP
.CS
\fBoo::singleton\fR create Highlander {
method say {} {
puts "there can be only one"
}
}
set h1 [Highlander new]
set h2 [Highlander new]
if {$h1 eq $h2} {
puts "equal objects" \fI\(-> prints "equal objects"\fR
}
set h3 [Highlander new]
if {$h1 eq $h3} {
puts "equal objects" \fI\(-> prints "equal objects"\fR
}
.CE
.PP
Note that the name of the instance of the singleton is not guaranteed to be
anything in particular.
.SH "SEE ALSO"
oo::class(n)
.SH KEYWORDS
class, metaclass, object, single instance
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:
+9
View File
@@ -143,6 +143,15 @@ incomplete commands.
.SH "STANDARD CHANNELS"
.PP
See \fBTcl_StandardChannels\fR for more explanations.
.SH ZIPVFS
.PP
When a zipfile is concatenated to the end of a \fBtclsh\fR, on
startup the contents of the zip archive will be mounted as the
virtual file system /zvfs. If a top level directory tcl8.6 is
present in the zip archive, it will become the directory loaded
as env(TCL_LIBRARY). If a file named \fBmain.tcl\fR is present
in the top level directory of the zip archive, it will be sourced
instead of the shell's normal command line handing.
.SH "SEE ALSO"
auto_path(n), encoding(n), env(n), fconfigure(n)
.SH KEYWORDS
+2 -2
View File
@@ -24,9 +24,9 @@ the result of that evaluation.
If \fIlevel\fR is an integer then
it gives a distance (up the procedure calling stack) to move before
executing the command. If \fIlevel\fR consists of \fB#\fR followed by
a number then the number gives an absolute level number. If \fIlevel\fR
a integer then the level gives an absolute level. If \fIlevel\fR
is omitted then it defaults to \fB1\fR. \fILevel\fR cannot be
defaulted if the first \fIcommand\fR argument starts with a digit or \fB#\fR.
defaulted if the first \fIcommand\fR argument is an integer or starts with \fB#\fR.
.PP
For example, suppose that procedure \fBa\fR was invoked
from top-level, and that it called \fBb\fR, and that \fBb\fR called \fBc\fR.
+70
View File
@@ -0,0 +1,70 @@
'\"
'\" Copyright (c) 2015 Jan Nijtmans <jan.nijtmans@gmail.com>
'\" Copyright (c) 2015 Christian Werner <chw@ch-werner.de>
'\" Copyright (c) 2017 Sean Woods <yoda@etoyoc.com>
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH Tclzipfs 3 8.7 Tcl "Tcl Library Procedures"
.so man.macros
.BS
.SH NAME
TclZipfs_AppHook, Tclzipfs_Mount, Tclzipfs_Unmount, \- handle ZIP files as VFS
.SH SYNOPSIS
.nf
.sp
int
\fBTclZipfs_AppHook(\fIint *argc, char ***argv\fR)
.sp
int
\fBTclzipfs_Mount\fR(\fIinterp, mntpt, zipname, passwd\fR)
.sp
int
\fBTclzipfs_Unmount\fR(\fIinterp, zipname\fR)
.SH ARGUMENTS
.AP "int" *argc in
Number of command line arguments from main()
.AP "char" ***argv in
Pointer to an array of strings containing the command
line arguments to main()
.AS Tcl_Interp **termPtr
.AP Tcl_Interp *interp in
Interpreter in which the zip file system is mounted. The interpreter's result is
modified to hold the result or error message from the script.
.AP "const char" *zipname in
Name of a zipfile.
.AP "const char" *mntpt in
Name of a mount point.
.AP "const char" *passwd in
An (optional) password.
.BE
.SH DESCRIPTION
\fBTclZipfs_AppHook()\fR is a utility function to perform standard
application initialization procedures. If the current application has
a mountable zip file system, that file system is mounted under \fIZIPROOT\fR\fB/app\fR.
If a file named \fBmain.tcl\fR is located in that file system, it is treated
as the startup script for the process. If the file \fIZIPROOT\fR\fB/app/tcl_library/init.tcl\fR
is present, \fBtcl_library\fR is set to \fIZIPROOT\fR\fB/app/tcl_library.
.PP
On Windows, \fBTclZipfs_AppHook()\fR has a slightly different signature, it uses
WCHAR in stead of char. As a result, it only works if your application is compiled
using -DUNICODE.
.PP
If the \fBtcl_library\fR was not found in the application, the system will then search for it
as either a VFS attached to the application dynamic library, or as a zip archive named
libtcl_\fIMAJOR\fR_\fIMINOR\fR_\fIpatchLevel\fR.zip either in the present working directory
or in the standard tcl install location.
.PP
\fBTclzipfs_Mount()\fR mount the ZIP archive \fIzipname\fR on the mount
point given in \fImntpt\fR using the optional ZIP password \fIpasswd\fR.
Errors during that process are reported in the interpreter \fIinterp\fR.
If \fImountpoint\fR is a NULL pointer, information on all currently mounted
ZIP file systems is written into \fIinterp\fR's result as a sequence of
mount points and ZIP file names.
.PP
\fBTclzipfs_Unmount()\fR undoes the effect of \fBTclzipfs_Mount()\fR,
i.e. it unmounts the mounted ZIP file system at \fImountpoint\fR. Errors are
reported in the interpreter \fIinterp\fR.
.SH KEYWORDS
compress, filesystem, zip
+125
View File
@@ -0,0 +1,125 @@
'\"
'\" Copyright (c) 2015 Jan Nijtmans <jan.nijtmans@gmail.com>
'\" Copyright (c) 2015 Christian Werner <chw@ch-werner.de>
'\" Copyright (c) 2015 Sean Woods <yoda@etoyoc.com>
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH zipfs n 1.0 Zipfs "zipfs Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
zipfs \- Mount and work with ZIP files within Tcl
.SH SYNOPSIS
.nf
\fBpackage require zipfs \fR?\fB1.0\fR?
.sp
\fBzipfs exists\fR \fIfilename\fR
\fBzipfs find\fR \fIdir\fR
\fBzipfs info\fR \fIfilename\fR
\fBzipfs list\fR \fB?(-glob|-regexp)?\fR \fI?pattern?\fR
\fBzipfs mkimg\fR \fIoutfile\fR \fIindir\fR \fI?strip?\fR \fI?password?\fR \fI?infile?\fR
\fBzipfs mkkey\fR \fIpassword\fR
\fBzipfs mkzip\fR \fIoutfile\fR \fIindir\fR \fI?strip?\fR \fI?password?\fR
\fBzipfs mount\fR \fI?mountpoint?\fR \fI?zipfile?\fR \fI?password?\fR
\fBzipfs root\fR
\fBzipfs unmount\fR \fImountpoint\fR
.fi
.BE
.SH DESCRIPTION
.PP
The \fBzipfs\fR package provides tcl with the ability to mount
the contents of a zip file as a virtual file system.
.TP
\fBzipfs exists\fR \fIfilename\fR
.
Return 1 if the given filename exists in the mounted zipfs and 0 if it does not.
.TP
\fBzipfs find\fR \fIdir\fR
.
Recursively lists files including and below the directory \fIdir\fR.
The result list consists of relative path names starting from the
given directory. This command is also used by the \fBzipfs mkzip\fR
and \fBzipfs mkimg\fR commands.
.TP
\fBzipfs info\fR \fIfile\fR
.
Return information about the given file in the mounted zipfs. The information
consists of (1) the name of the ZIP archive file that contains the file,
(2) the size of the file after decompressions, (3) the compressed size of
the file, and (4) the offset of the compressed data in the ZIP archive file.
.RS
.PP
Note: querying the mount point gives the start of zip data offset in (4),
which can be used to truncate the zip info off an executable.
.RE
.TP
\fBzipfs list\fR \fB?(-glob|-regexp)?\fR \fI?pattern?\fR
.
Return a list of all files in the mounted zipfs. The order of the names
in the list is arbitrary.
.TP
\fBzipfs mkimg\fR \fIoutfile\fR \fIindir\fR \fI?strip?\fR \fI?password?\fR \fI?infile?\fR
.
Creates an image (potentially a new executable file) similar to
\fBzipfs mkzip\fR. If the \fIinfile\fR parameter is specified,
this file is prepended in front of the ZIP archive, otherwise the file
returned by \fBTcl_NameOfExecutable(3)\fR (i.e. the executable file of
the running process) is used. If the \fIpassword\fR parameter is not empty,
an obfuscated version of that password is placed between the image and ZIP
chunks of the output file and the contents of the ZIP chunk are protected
with that password.
.RS
.PP
Caution: highly experimental, not usable on Android, only partially tested
on Linux and Windows.
.RE
.TP
\fBzipfs mkkey\fR \fIpassword\fR
.
For the clear text \fIpassword\fR argument an obfuscated string version
is returned with the same format used in the \fBzipfs mkimg\fR command.
.TP
\fBzipfs mkzip\fR \fIoutfile\fR \fIindir\fR \fI?strip?\fR \fI?password?\fR
.
Creates a ZIP archive file named \fIoutfile\fR from the contents of the input
directory \fIindir\fR (contained regular files only) with optional ZIP
password \fIpassword\fR. While processing the files below \fIindir\fR the
optional file name prefix given in \fIstrip\fR is stripped off the beginning
of the respective file name.
.RS
.PP
Caution: the choice of the \fIindir\fR parameter
(less the optional stripped prefix) determines the later root name of the
archive's content.
.RE
.TP
\fBzipfs mount ?\fImountpoint\fR? ?\fIzipfile\fR? ?\fIpassword\fR?
.
The \fBzipfs mount\fR command mounts a ZIP archive file as a VFS.
After this command executes, files contained in \fIzipfile\fR
will appear to Tcl to be regular files at the mount point.
.RS
.PP
With no \fIzipfile\fR, returns the zipfile mounted at \fImountpoint\fR.
With no \fImountpoint\fR, return all zipfile/mount pairs.
If \fImountpoint\fR is specified as an empty string, mount on file path.
.RE
.TP
\fBzipfs root\fR
Returns a constant string which indicates the mount point for zipfs volumes
for the current platform. On Windows, this value is zipfs:/. On Unux, //zipfs:/
.RE
.TP
\fBzipfs unmount \fImountpoint\fR
.
Unmounts a previously mounted ZIP archive mounted to \fImountpoint\fR.
.SH "SEE ALSO"
tclsh(1), file(n), zlib(n)
.SH "KEYWORDS"
compress, filesystem, zip
'\" Local Variables:
'\" mode: nroff
'\" End:
+51 -26
View File
@@ -104,7 +104,7 @@ declare 20 {
declare 21 {
int Tcl_DbIsShared(Tcl_Obj *objPtr, const char *file, int line)
}
declare 22 {
declare 22 {deprecated {No longer in use, changed to macro}} {
Tcl_Obj *Tcl_DbNewBooleanObj(int boolValue, const char *file, int line)
}
declare 23 {
@@ -119,7 +119,7 @@ declare 25 {
Tcl_Obj *Tcl_DbNewListObj(int objc, Tcl_Obj *const *objv,
const char *file, int line)
}
declare 26 {
declare 26 {deprecated {No longer in use, changed to macro}} {
Tcl_Obj *Tcl_DbNewLongObj(long longValue, const char *file, int line)
}
declare 27 {
@@ -152,7 +152,7 @@ declare 35 {
int Tcl_GetDoubleFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
double *doublePtr)
}
declare 36 {
declare 36 {deprecated {No longer in use, changed to macro}} {
int Tcl_GetIndexFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
const char *const *tablePtr, const char *msg, int flags, int *indexPtr)
}
@@ -198,7 +198,7 @@ declare 48 {
int Tcl_ListObjReplace(Tcl_Interp *interp, Tcl_Obj *listPtr, int first,
int count, int objc, Tcl_Obj *const objv[])
}
declare 49 {
declare 49 {deprecated {No longer in use, changed to macro}} {
Tcl_Obj *Tcl_NewBooleanObj(int boolValue)
}
declare 50 {
@@ -207,13 +207,13 @@ declare 50 {
declare 51 {
Tcl_Obj *Tcl_NewDoubleObj(double doubleValue)
}
declare 52 {
declare 52 {deprecated {No longer in use, changed to macro}} {
Tcl_Obj *Tcl_NewIntObj(int intValue)
}
declare 53 {
Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[])
}
declare 54 {
declare 54 {deprecated {No longer in use, changed to macro}} {
Tcl_Obj *Tcl_NewLongObj(long longValue)
}
declare 55 {
@@ -222,7 +222,7 @@ declare 55 {
declare 56 {
Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length)
}
declare 57 {
declare 57 {deprecated {No longer in use, changed to macro}} {
void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue)
}
declare 58 {
@@ -235,13 +235,13 @@ declare 59 {
declare 60 {
void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue)
}
declare 61 {
declare 61 {deprecated {No longer in use, changed to macro}} {
void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue)
}
declare 62 {
void Tcl_SetListObj(Tcl_Obj *objPtr, int objc, Tcl_Obj *const objv[])
}
declare 63 {
declare 63 {deprecated {No longer in use, changed to macro}} {
void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue)
}
declare 64 {
@@ -250,10 +250,10 @@ declare 64 {
declare 65 {
void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes, int length)
}
declare 66 {
declare 66 {deprecated {No longer in use, changed to macro}} {
void Tcl_AddErrorInfo(Tcl_Interp *interp, const char *message)
}
declare 67 {
declare 67 {deprecated {No longer in use, changed to macro}} {
void Tcl_AddObjErrorInfo(Tcl_Interp *interp, const char *message,
int length)
}
@@ -472,7 +472,7 @@ declare 129 {
declare 130 {
int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName)
}
declare 131 {
declare 131 {deprecated {No longer in use, changed to macro}} {
int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr)
}
declare 132 {
@@ -624,7 +624,7 @@ declare 173 {
declare 174 {
const char *Tcl_GetStringResult(Tcl_Interp *interp)
}
declare 175 {
declare 175 {deprecated {No longer in use, changed to macro}} {
const char *Tcl_GetVar(Tcl_Interp *interp, const char *varName,
int flags)
}
@@ -635,7 +635,7 @@ declare 176 {
declare 177 {
int Tcl_GlobalEval(Tcl_Interp *interp, const char *command)
}
declare 178 {
declare 178 {deprecated {No longer in use, changed to macro}} {
int Tcl_GlobalEvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr)
}
declare 179 {
@@ -834,7 +834,7 @@ declare 235 {
declare 236 {
void Tcl_SetStdChannel(Tcl_Channel channel, int type)
}
declare 237 {
declare 237 {deprecated {No longer in use, changed to macro}} {
const char *Tcl_SetVar(Tcl_Interp *interp, const char *varName,
const char *newValue, int flags)
}
@@ -869,7 +869,7 @@ declare 245 {
declare 246 {deprecated {}} {
int Tcl_TellOld(Tcl_Channel chan)
}
declare 247 {
declare 247 {deprecated {No longer in use, changed to macro}} {
int Tcl_TraceVar(Tcl_Interp *interp, const char *varName, int flags,
Tcl_VarTraceProc *proc, ClientData clientData)
}
@@ -890,14 +890,14 @@ declare 251 {
declare 252 {
int Tcl_UnregisterChannel(Tcl_Interp *interp, Tcl_Channel chan)
}
declare 253 {
declare 253 {deprecated {No longer in use, changed to macro}} {
int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName, int flags)
}
declare 254 {
int Tcl_UnsetVar2(Tcl_Interp *interp, const char *part1, const char *part2,
int flags)
}
declare 255 {
declare 255 {deprecated {No longer in use, changed to macro}} {
void Tcl_UntraceVar(Tcl_Interp *interp, const char *varName, int flags,
Tcl_VarTraceProc *proc, ClientData clientData)
}
@@ -909,7 +909,7 @@ declare 256 {
declare 257 {
void Tcl_UpdateLinkedVar(Tcl_Interp *interp, const char *varName)
}
declare 258 {
declare 258 {deprecated {No longer in use, changed to macro}} {
int Tcl_UpVar(Tcl_Interp *interp, const char *frameName,
const char *varName, const char *localName, int flags)
}
@@ -920,7 +920,7 @@ declare 259 {
declare 260 {
int Tcl_VarEval(Tcl_Interp *interp, ...)
}
declare 261 {
declare 261 {deprecated {No longer in use, changed to macro}} {
ClientData Tcl_VarTraceInfo(Tcl_Interp *interp, const char *varName,
int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData)
}
@@ -955,7 +955,7 @@ declare 270 {
const char *Tcl_ParseVar(Tcl_Interp *interp, const char *start,
const char **termPtr)
}
declare 271 {
declare 271 {deprecated {No longer in use, changed to macro}} {
const char *Tcl_PkgPresent(Tcl_Interp *interp, const char *name,
const char *version, int exact)
}
@@ -964,12 +964,12 @@ declare 272 {
const char *name, const char *version, int exact,
void *clientDataPtr)
}
declare 273 {
declare 273 {deprecated {No longer in use, changed to macro}} {
int Tcl_PkgProvide(Tcl_Interp *interp, const char *name,
const char *version)
}
# TIP #268: The internally used new Require function is in slot 573.
declare 274 {
declare 274 {deprecated {No longer in use, changed to macro}} {
const char *Tcl_PkgRequire(Tcl_Interp *interp, const char *name,
const char *version, int exact)
}
@@ -1350,7 +1350,7 @@ declare 380 {
declare 381 {
int Tcl_GetUniChar(Tcl_Obj *objPtr, int index)
}
declare 382 {
declare 382 {deprecated {No longer in use, changed to macro}} {
Tcl_UniChar *Tcl_GetUnicode(Tcl_Obj *objPtr)
}
declare 383 {
@@ -2330,10 +2330,31 @@ declare 631 {
ClientData callbackData)
}
# TIP #430
declare 632 {
int TclZipfs_Mount(
Tcl_Interp *interp,
const char *mntpt,
const char *zipname,
const char *passwd)
}
declare 633 {
int TclZipfs_Unmount(Tcl_Interp *interp, const char *zipname)
}
declare 634 {
Tcl_Obj *TclZipfs_TclLibrary(void)
}
declare 635 {
int TclZipfs_Mount_Buffer(
Tcl_Interp *interp,
const char *mntpt,
unsigned char *data,
size_t datalen,
int copy)
}
# ----- BASELINE -- FOR -- 8.7.0 ----- #
##############################################################################
# Define the platform specific public Tcl interface. These functions are only
@@ -2378,6 +2399,10 @@ declare 1 macosx {
export {
void Tcl_Main(int argc, char **argv, Tcl_AppInitProc *appInitProc)
}
export {
void Tcl_MainEx(int argc, char **argv, Tcl_AppInitProc *appInitProc,
Tcl_Interp *interp)
}
export {
const char *Tcl_InitStubs(Tcl_Interp *interp, const char *version,
int exact)
+17 -31
View File
@@ -89,6 +89,10 @@ extern "C" {
# define JOIN(a,b) JOIN1(a,b)
# define JOIN1(a,b) a##b
#endif
#ifndef TCL_THREADS
# define TCL_THREADS 1
#endif
#endif /* !TCL_NO_DEPRECATED */
/*
@@ -103,15 +107,10 @@ extern "C" {
#ifndef RC_INVOKED
/*
* Special macro to define mutexes, that doesn't do anything if we are not
* using threads.
* Special macro to define mutexes.
*/
#ifdef TCL_THREADS
#define TCL_DECLARE_MUTEX(name) static Tcl_Mutex name;
#else
#define TCL_DECLARE_MUTEX(name)
#endif
/*
* Tcl's public routine Tcl_FSSeek() uses the values SEEK_SET, SEEK_CUR, and
@@ -2146,9 +2145,9 @@ typedef struct Tcl_EncodingType {
/*
* The maximum number of bytes that are necessary to represent a single
* Unicode character in UTF-8. The valid values should be 3, 4 or 6
* (or perhaps 1 if we want to support a non-unicode enabled core). If 3 or
* 4, then Tcl_UniChar must be 2-bytes in size (UCS-2) (the default). If 6,
* Unicode character in UTF-8. The valid values are 4 and 6
* (or perhaps 1 if we want to support a non-unicode enabled core). If 4,
* then Tcl_UniChar must be 2-bytes in size (UCS-2) (the default). If 6,
* then Tcl_UniChar must be 4-bytes in size (UCS-4). At this time UCS-2 mode
* is the default and recommended mode. UCS-4 is experimental and not
* recommended. It works for the core, but most extensions expect UCS-2.
@@ -2361,6 +2360,11 @@ const char * Tcl_InitStubs(Tcl_Interp *interp, const char *version,
int exact, int magic);
const char * TclTomMathInitializeStubs(Tcl_Interp *interp,
const char *version, int epoch, int revision);
#if defined(_WIN32)
TCL_NORETURN void Tcl_ConsolePanic(const char *format, ...);
#else
# define Tcl_ConsolePanic ((Tcl_PanicProc *)0)
#endif
#ifdef USE_TCL_STUBS
#if TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE
@@ -2392,12 +2396,15 @@ const char * TclTomMathInitializeStubs(Tcl_Interp *interp,
*/
#define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \
((Tcl_CreateInterp)()))
(((Tcl_SetPanicProc)(Tcl_ConsolePanic), Tcl_CreateInterp)()))
EXTERN void Tcl_MainEx(int argc, char **argv,
Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);
EXTERN const char * Tcl_PkgInitStubsCheck(Tcl_Interp *interp,
const char *version, int exact);
EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr);
#ifndef _WIN32
EXTERN int TclZipfs_AppHook(int *argc, char ***argv);
#endif
/*
*----------------------------------------------------------------------------
@@ -2550,27 +2557,6 @@ EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr);
#define Tcl_CreateHashEntry(tablePtr, key, newPtr) \
(*((tablePtr)->createProc))(tablePtr, (const char *)(key), newPtr)
/*
*----------------------------------------------------------------------------
* Macros that eliminate the overhead of the thread synchronization functions
* when compiling without thread support.
*/
#ifndef TCL_THREADS
#undef Tcl_MutexLock
#define Tcl_MutexLock(mutexPtr)
#undef Tcl_MutexUnlock
#define Tcl_MutexUnlock(mutexPtr)
#undef Tcl_MutexFinalize
#define Tcl_MutexFinalize(mutexPtr)
#undef Tcl_ConditionNotify
#define Tcl_ConditionNotify(condPtr)
#undef Tcl_ConditionWait
#define Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
#undef Tcl_ConditionFinalize
#define Tcl_ConditionFinalize(condPtr)
#endif /* TCL_THREADS */
/*
*----------------------------------------------------------------------------
* Deprecated Tcl functions:
+3 -3
View File
@@ -22,7 +22,7 @@
*/
#include "tclInt.h"
#if !defined(TCL_THREADS) || !defined(USE_THREAD_ALLOC)
#if !TCL_THREADS || !defined(USE_THREAD_ALLOC)
#if USE_TCLALLOC
@@ -121,7 +121,7 @@ static struct block bigBlocks={ /* Big blocks aren't suballocated. */
* variable.
*/
#ifdef TCL_THREADS
#if TCL_THREADS
static Tcl_Mutex *allocMutexPtr;
#endif
static int allocInit = 0;
@@ -171,7 +171,7 @@ TclInitAlloc(void)
{
if (!allocInit) {
allocInit = 1;
#ifdef TCL_THREADS
#if TCL_THREADS
allocMutexPtr = Tcl_GetAllocMutex();
#endif
}
+1 -1
View File
@@ -2253,7 +2253,7 @@ GetListIndexOperand(
if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &value) != TCL_OK) {
return TCL_ERROR;
}
/* Convert to an integer, advance to the next token and return. */
/*
* NOTE: Indexing a list with an index before it yields the
+152 -91
View File
@@ -71,7 +71,18 @@ typedef struct {
} CancelInfo;
static Tcl_HashTable cancelTable;
static int cancelTableInitialized = 0; /* 0 means not yet initialized. */
TCL_DECLARE_MUTEX(cancelLock)
TCL_DECLARE_MUTEX(cancelLock);
/*
* Table used to map command implementation functions to a human-readable type
* name, for [info type]. The keys in the table are function addresses, and
* the values in the table are static char* containing strings in Tcl's
* internal encoding (almost UTF-8).
*/
static Tcl_HashTable commandTypeTable;
static int commandTypeInit = 0;
TCL_DECLARE_MUTEX(commandTypeLock);
/*
* Declarations for managing contexts for non-recursive coroutines. Contexts
@@ -431,6 +442,13 @@ TclFinalizeEvaluation(void)
cancelTableInitialized = 0;
}
Tcl_MutexUnlock(&cancelLock);
Tcl_MutexLock(&commandTypeLock);
if (commandTypeInit) {
Tcl_DeleteHashTable(&commandTypeTable);
commandTypeInit = 0;
}
Tcl_MutexUnlock(&commandTypeLock);
}
/*
@@ -504,9 +522,23 @@ Tcl_CreateInterp(void)
Tcl_InitHashTable(&cancelTable, TCL_ONE_WORD_KEYS);
cancelTableInitialized = 1;
}
Tcl_MutexUnlock(&cancelLock);
}
if (commandTypeInit == 0) {
TclRegisterCommandTypeName(TclObjInterpProc, "proc");
TclRegisterCommandTypeName(TclEnsembleImplementationCmd, "ensemble");
TclRegisterCommandTypeName(TclAliasObjCmd, "alias");
TclRegisterCommandTypeName(TclLocalAliasObjCmd, "alias");
TclRegisterCommandTypeName(TclSlaveObjCmd, "slave");
TclRegisterCommandTypeName(TclInvokeImportedCmd, "import");
TclRegisterCommandTypeName(TclOOPublicObjectCmd, "object");
TclRegisterCommandTypeName(TclOOPrivateObjectCmd, "privateObject");
TclRegisterCommandTypeName(TclOOMyClassObjCmd, "privateClass");
TclRegisterCommandTypeName(TclNRInterpCoroutine, "coroutine");
}
/*
* Initialize support for namespaces and create the global namespace
* (whose name is ""; an alias is "::"). This also initializes the Tcl
@@ -749,7 +781,7 @@ Tcl_CreateInterp(void)
* cache was already initialised by the call to alloc the interp struct.
*/
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
iPtr->allocCache = TclpGetAllocCache();
#else
iPtr->allocCache = NULL;
@@ -964,7 +996,7 @@ Tcl_CreateInterp(void)
#endif /* !TCL_NO_DEPRECATED */
TclpSetVariables(interp);
#ifdef TCL_THREADS
#if TCL_THREADS
/*
* The existence of the "threaded" element of the tcl_platform array
* indicates that this particular Tcl shell has been compiled with threads
@@ -999,6 +1031,9 @@ Tcl_CreateInterp(void)
if (TclZlibInit(interp) != TCL_OK) {
Tcl_Panic("%s", TclGetString(Tcl_GetObjResult(interp)));
}
if (TclZipfs_Init(interp) != TCL_OK) {
Tcl_Panic("%s", Tcl_GetString(Tcl_GetObjResult(interp)));
}
#endif
TOP_CB(iPtr) = NULL;
@@ -1014,6 +1049,71 @@ DeleteOpCmdClientData(
ckfree(occdPtr);
}
/*
* ---------------------------------------------------------------------
*
* TclRegisterCommandTypeName, TclGetCommandTypeName --
*
* Command type registration and lookup mechanism. Everything is keyed by
* the Tcl_ObjCmdProc for the command, and that is used as the *key* into
* the hash table that maps to constant strings that are names. (It is
* recommended that those names be ASCII.)
*
* ---------------------------------------------------------------------
*/
void
TclRegisterCommandTypeName(
Tcl_ObjCmdProc *implementationProc,
const char *nameStr)
{
Tcl_HashEntry *hPtr;
Tcl_MutexLock(&commandTypeLock);
if (commandTypeInit == 0) {
Tcl_InitHashTable(&commandTypeTable, TCL_ONE_WORD_KEYS);
commandTypeInit = 1;
}
if (nameStr != NULL) {
int isNew;
hPtr = Tcl_CreateHashEntry(&commandTypeTable,
(void *) implementationProc, &isNew);
Tcl_SetHashValue(hPtr, (void *) nameStr);
} else {
hPtr = Tcl_FindHashEntry(&commandTypeTable,
(void *) implementationProc);
if (hPtr != NULL) {
Tcl_DeleteHashEntry(hPtr);
}
}
Tcl_MutexUnlock(&commandTypeLock);
}
const char *
TclGetCommandTypeName(
Tcl_Command command)
{
Command *cmdPtr = (Command *) command;
void *procPtr = cmdPtr->objProc;
const char *name = "native";
if (procPtr == NULL) {
procPtr = cmdPtr->nreProc;
}
Tcl_MutexLock(&commandTypeLock);
if (commandTypeInit) {
Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&commandTypeTable, procPtr);
if (hPtr && Tcl_GetHashValue(hPtr)) {
name = (const char *) Tcl_GetHashValue(hPtr);
}
}
Tcl_MutexUnlock(&commandTypeLock);
return name;
}
/*
*----------------------------------------------------------------------
*
@@ -2295,30 +2395,33 @@ Tcl_CreateObjCommand(
}
Tcl_Command
TclCreateObjCommandInNs (
TclCreateObjCommandInNs(
Tcl_Interp *interp,
const char *cmdName, /* Name of command, without any namespace components */
const char *cmdName, /* Name of command, without any namespace
* components. */
Tcl_Namespace *namespace, /* The namespace to create the command in */
Tcl_ObjCmdProc *proc, /* Object-based function to associate with
* name. */
ClientData clientData, /* Arbitrary value to pass to object
* function. */
Tcl_CmdDeleteProc *deleteProc
Tcl_CmdDeleteProc *deleteProc)
/* If not NULL, gives a function to call when
* this command is deleted. */
) {
{
int deleted = 0, isNew = 0;
Command *cmdPtr;
ImportRef *oldRefPtr = NULL;
ImportedCmdData *dataPtr;
Tcl_HashEntry *hPtr;
Namespace *nsPtr = (Namespace *) namespace;
/*
* If the command name we seek to create already exists, we need to
* delete that first. That can be tricky in the presence of traces.
* Loop until we no longer find an existing command in the way, or
* until we've deleted one command and that didn't finish the job.
* If the command name we seek to create already exists, we need to delete
* that first. That can be tricky in the presence of traces. Loop until we
* no longer find an existing command in the way, or until we've deleted
* one command and that didn't finish the job.
*/
while (1) {
hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, cmdName, &isNew);
@@ -2330,16 +2433,18 @@ TclCreateObjCommandInNs (
break;
}
/*
* An existing command conflicts. Try to delete it.
*/
/* An existing command conflicts. Try to delete it.. */
cmdPtr = Tcl_GetHashValue(hPtr);
/*
* [***] This is wrong. See Tcl Bug a16752c252.
* However, this buggy behavior is kept under particular
* circumstances to accommodate deployed binaries of the
* "tclcompiler" program. http://sourceforge.net/projects/tclpro/
* that crash if the bug is fixed.
* [***] This is wrong. See Tcl Bug a16752c252. However, this buggy
* behavior is kept under particular circumstances to accommodate
* deployed binaries of the "tclcompiler" program
* http://sourceforge.net/projects/tclpro/
* that crash if the bug is fixed.
*/
if (cmdPtr->objProc == TclInvokeStringCommand
@@ -2363,12 +2468,15 @@ TclCreateObjCommandInNs (
cmdPtr->flags |= CMD_REDEF_IN_PROGRESS;
}
/* Make sure namespace doesn't get deallocated. */
/*
* Make sure namespace doesn't get deallocated.
*/
cmdPtr->nsPtr->refCount++;
Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
nsPtr = (Namespace *) TclEnsureNamespace(interp,
(Tcl_Namespace *)cmdPtr->nsPtr);
(Tcl_Namespace *) cmdPtr->nsPtr);
TclNsDecrRefCount(cmdPtr->nsPtr);
if (cmdPtr->flags & CMD_REDEF_IN_PROGRESS) {
@@ -2380,9 +2488,9 @@ TclCreateObjCommandInNs (
}
if (!isNew) {
/*
* If the deletion callback recreated the command, just throw away
* the new command (if we try to delete it again, we could get
* stuck in an infinite loop).
* If the deletion callback recreated the command, just throw away the
* new command (if we try to delete it again, we could get stuck in an
* infinite loop).
*/
ckfree(Tcl_GetHashValue(hPtr));
@@ -2437,6 +2545,7 @@ TclCreateObjCommandInNs (
cmdPtr->importRefPtr = oldRefPtr;
while (oldRefPtr != NULL) {
Command *refCmdPtr = oldRefPtr->importedCmdPtr;
dataPtr = refCmdPtr->objClientData;
dataPtr->realCmdPtr = cmdPtr;
oldRefPtr = oldRefPtr->nextPtr;
@@ -7504,7 +7613,7 @@ ExprAbsFunc(
}
}
goto unChanged;
} else if (l == LLONG_MIN) {
} else if (l == WIDE_MIN) {
TclInitBignumFromWideInt(&big, l);
goto tooLarge;
}
@@ -7629,7 +7738,7 @@ ExprEntierFunc(
if (type == TCL_NUMBER_DOUBLE) {
d = *((const double *) ptr);
if ((d >= (double)LONG_MAX) || (d <= (double)LONG_MIN)) {
if ((d >= (double)WIDE_MAX) || (d <= (double)WIDE_MIN)) {
mp_int big;
if (Tcl_InitBignumFromDouble(interp, d, &big) != TCL_OK) {
@@ -7639,9 +7748,9 @@ ExprEntierFunc(
Tcl_SetObjResult(interp, Tcl_NewBignumObj(&big));
return TCL_OK;
} else {
long result = (long) d;
Tcl_WideInt result = (Tcl_WideInt) d;
Tcl_SetObjResult(interp, Tcl_NewLongObj(result));
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(result));
return TCL_OK;
}
}
@@ -7671,27 +7780,14 @@ ExprIntFunc(
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter vector. */
{
long iResult;
Tcl_WideInt wResult;
Tcl_Obj *objPtr;
if (ExprEntierFunc(NULL, interp, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
objPtr = Tcl_GetObjResult(interp);
if (TclGetLongFromObj(NULL, objPtr, &iResult) != TCL_OK) {
/*
* Truncate the bignum; keep only bits in long range.
*/
mp_int big;
Tcl_GetBignumFromObj(NULL, objPtr, &big);
mp_mod_2d(&big, (int) CHAR_BIT * sizeof(long), &big);
objPtr = Tcl_NewBignumObj(&big);
Tcl_IncrRefCount(objPtr);
TclGetLongFromObj(NULL, objPtr, &iResult);
Tcl_DecrRefCount(objPtr);
}
Tcl_SetObjResult(interp, Tcl_NewLongObj(iResult));
TclGetWideBitsFromObj(NULL, objPtr, &wResult);
Tcl_SetObjResult(interp, Tcl_NewLongObj((long)wResult));
return TCL_OK;
}
@@ -7704,26 +7800,11 @@ ExprWideFunc(
Tcl_Obj *const *objv) /* Actual parameter vector. */
{
Tcl_WideInt wResult;
Tcl_Obj *objPtr;
if (ExprEntierFunc(NULL, interp, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
objPtr = Tcl_GetObjResult(interp);
if (TclGetWideIntFromObj(NULL, objPtr, &wResult) != TCL_OK) {
/*
* Truncate the bignum; keep only bits in wide int range.
*/
mp_int big;
Tcl_GetBignumFromObj(NULL, objPtr, &big);
mp_mod_2d(&big, (int) CHAR_BIT * sizeof(Tcl_WideInt), &big);
objPtr = Tcl_NewBignumObj(&big);
Tcl_IncrRefCount(objPtr);
TclGetWideIntFromObj(NULL, objPtr, &wResult);
Tcl_DecrRefCount(objPtr);
}
TclGetWideBitsFromObj(NULL, Tcl_GetObjResult(interp), &wResult);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(wResult));
return TCL_OK;
}
@@ -7826,7 +7907,7 @@ ExprRandFunc(
* Make sure 1 <= randSeed <= (2^31) - 2. See below.
*/
iPtr->randSeed &= (unsigned long) 0x7fffffff;
iPtr->randSeed &= 0x7fffffff;
if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) {
iPtr->randSeed ^= 123459876;
}
@@ -7970,7 +8051,7 @@ ExprSrandFunc(
Tcl_Obj *const *objv) /* Parameter vector. */
{
Interp *iPtr = (Interp *) interp;
long i = 0; /* Initialized to avoid compiler warning. */
Tcl_WideInt w = 0; /* Initialized to avoid compiler warning. */
/*
* Convert argument and use it to reset the seed.
@@ -7981,20 +8062,8 @@ ExprSrandFunc(
return TCL_ERROR;
}
if (TclGetLongFromObj(NULL, objv[1], &i) != TCL_OK) {
Tcl_Obj *objPtr;
mp_int big;
if (Tcl_GetBignumFromObj(interp, objv[1], &big) != TCL_OK) {
/* TODO: more ::errorInfo here? or in caller? */
return TCL_ERROR;
}
mp_mod_2d(&big, (int) CHAR_BIT * sizeof(long), &big);
objPtr = Tcl_NewBignumObj(&big);
Tcl_IncrRefCount(objPtr);
TclGetLongFromObj(NULL, objPtr, &i);
Tcl_DecrRefCount(objPtr);
if (TclGetWideBitsFromObj(NULL, objv[1], &w) != TCL_OK) {
return TCL_ERROR;
}
/*
@@ -8003,8 +8072,7 @@ ExprSrandFunc(
*/
iPtr->flags |= RAND_SEED_INITIALIZED;
iPtr->randSeed = i;
iPtr->randSeed &= (unsigned long) 0x7fffffff;
iPtr->randSeed = (long) w & 0x7fffffff;
if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) {
iPtr->randSeed ^= 123459876;
}
@@ -8276,23 +8344,26 @@ Tcl_NRCreateCommand(
* this command is deleted. */
{
Command *cmdPtr = (Command *)
Tcl_CreateObjCommand(interp,cmdName,proc,clientData,deleteProc);
Tcl_CreateObjCommand(interp, cmdName, proc, clientData,
deleteProc);
cmdPtr->nreProc = nreProc;
return (Tcl_Command) cmdPtr;
}
Tcl_Command
TclNRCreateCommandInNs (
TclNRCreateCommandInNs(
Tcl_Interp *interp,
const char *cmdName,
Tcl_Namespace *nsPtr,
Tcl_ObjCmdProc *proc,
Tcl_ObjCmdProc *nreProc,
ClientData clientData,
Tcl_CmdDeleteProc *deleteProc) {
Tcl_CmdDeleteProc *deleteProc)
{
Command *cmdPtr = (Command *)
TclCreateObjCommandInNs(interp,cmdName,nsPtr,proc,clientData,deleteProc);
TclCreateObjCommandInNs(interp, cmdName, nsPtr, proc, clientData,
deleteProc);
cmdPtr->nreProc = nreProc;
return (Tcl_Command) cmdPtr;
@@ -8396,7 +8467,6 @@ TclPushTailcallPoint(
TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL);
((Interp *) interp)->numLevels++;
}
/*
*----------------------------------------------------------------------
@@ -8432,7 +8502,6 @@ TclSetTailcall(
}
runPtr->data[1] = listPtr;
}
/*
*----------------------------------------------------------------------
@@ -8490,25 +8559,18 @@ TclNRTailcallObjCmd(
if (objc > 1) {
Tcl_Obj *listPtr, *nsObjPtr;
Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
Tcl_Namespace *ns1Ptr;
/* The tailcall data is in a Tcl list: the first element is the
* namespace, the rest the command to be tailcalled. */
listPtr = Tcl_NewListObj(objc, objv);
nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1);
if ((TCL_OK != TclGetNamespaceFromObj(interp, nsObjPtr, &ns1Ptr))
|| (nsPtr != ns1Ptr)) {
Tcl_Panic("Tailcall failed to find the proper namespace");
}
listPtr = Tcl_NewListObj(objc, objv);
TclListObjSetElement(interp, listPtr, 0, nsObjPtr);
iPtr->varFramePtr->tailcallPtr = listPtr;
}
return TCL_RETURN;
}
/*
*----------------------------------------------------------------------
@@ -8576,7 +8638,6 @@ TclNRReleaseValues(
}
return result;
}
void
Tcl_NRAddCallback(
+17 -18
View File
@@ -1963,7 +1963,6 @@ FormatNumber(
Tcl_Obj *src, /* Number to format. */
unsigned char **cursorPtr) /* Pointer to index into destination buffer. */
{
long value;
double dvalue;
Tcl_WideInt wvalue;
float fvalue;
@@ -2025,7 +2024,7 @@ FormatNumber(
case 'w':
case 'W':
case 'm':
if (Tcl_GetWideIntFromObj(interp, src, &wvalue) != TCL_OK) {
if (TclGetWideBitsFromObj(interp, src, &wvalue) != TCL_OK) {
return TCL_ERROR;
}
if (NeedReversing(type)) {
@@ -2055,19 +2054,19 @@ FormatNumber(
case 'i':
case 'I':
case 'n':
if (TclGetLongFromObj(interp, src, &value) != TCL_OK) {
if (TclGetWideBitsFromObj(interp, src, &wvalue) != TCL_OK) {
return TCL_ERROR;
}
if (NeedReversing(type)) {
*(*cursorPtr)++ = UCHAR(value);
*(*cursorPtr)++ = UCHAR(value >> 8);
*(*cursorPtr)++ = UCHAR(value >> 16);
*(*cursorPtr)++ = UCHAR(value >> 24);
*(*cursorPtr)++ = UCHAR(wvalue);
*(*cursorPtr)++ = UCHAR(wvalue >> 8);
*(*cursorPtr)++ = UCHAR(wvalue >> 16);
*(*cursorPtr)++ = UCHAR(wvalue >> 24);
} else {
*(*cursorPtr)++ = UCHAR(value >> 24);
*(*cursorPtr)++ = UCHAR(value >> 16);
*(*cursorPtr)++ = UCHAR(value >> 8);
*(*cursorPtr)++ = UCHAR(value);
*(*cursorPtr)++ = UCHAR(wvalue >> 24);
*(*cursorPtr)++ = UCHAR(wvalue >> 16);
*(*cursorPtr)++ = UCHAR(wvalue >> 8);
*(*cursorPtr)++ = UCHAR(wvalue);
}
return TCL_OK;
@@ -2077,15 +2076,15 @@ FormatNumber(
case 's':
case 'S':
case 't':
if (TclGetLongFromObj(interp, src, &value) != TCL_OK) {
if (TclGetWideBitsFromObj(interp, src, &wvalue) != TCL_OK) {
return TCL_ERROR;
}
if (NeedReversing(type)) {
*(*cursorPtr)++ = UCHAR(value);
*(*cursorPtr)++ = UCHAR(value >> 8);
*(*cursorPtr)++ = UCHAR(wvalue);
*(*cursorPtr)++ = UCHAR(wvalue >> 8);
} else {
*(*cursorPtr)++ = UCHAR(value >> 8);
*(*cursorPtr)++ = UCHAR(value);
*(*cursorPtr)++ = UCHAR(wvalue >> 8);
*(*cursorPtr)++ = UCHAR(wvalue);
}
return TCL_OK;
@@ -2093,10 +2092,10 @@ FormatNumber(
* 8-bit integer values.
*/
case 'c':
if (TclGetLongFromObj(interp, src, &value) != TCL_OK) {
if (TclGetWideBitsFromObj(interp, src, &wvalue) != TCL_OK) {
return TCL_ERROR;
}
*(*cursorPtr)++ = UCHAR(value);
*(*cursorPtr)++ = UCHAR(wvalue);
return TCL_OK;
default:
+1 -1
View File
@@ -156,7 +156,7 @@ TclInitDbCkalloc(void)
if (!ckallocInit) {
ckallocInit = 1;
ckallocMutexPtr = Tcl_GetAllocMutex();
#ifndef TCL_THREADS
#if !TCL_THREADS
/* Silence compiler warning */
(void)ckallocMutexPtr;
#endif
+4 -61
View File
@@ -513,63 +513,6 @@ Tcl_ContinueObjCmd(
return TCL_CONTINUE;
}
/*
*----------------------------------------------------------------------
*
* Tcl_EncodingObjCmd --
*
* This command manipulates encodings.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
int
Tcl_EncodingObjCmd(
ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int index;
static const char *const optionStrings[] = {
"convertfrom", "convertto", "dirs", "names", "system",
NULL
};
enum options {
ENC_CONVERTFROM, ENC_CONVERTTO, ENC_DIRS, ENC_NAMES, ENC_SYSTEM
};
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
&index) != TCL_OK) {
return TCL_ERROR;
}
switch ((enum options) index) {
case ENC_CONVERTTO:
return EncodingConverttoObjCmd(dummy, interp, objc, objv);
case ENC_CONVERTFROM:
return EncodingConvertfromObjCmd(dummy, interp, objc, objv);
case ENC_DIRS:
return EncodingDirsObjCmd(dummy, interp, objc, objv);
case ENC_NAMES:
return EncodingNamesObjCmd(dummy, interp, objc, objv);
case ENC_SYSTEM:
return EncodingSystemObjCmd(dummy, interp, objc, objv);
}
return TCL_OK;
}
/*
*-----------------------------------------------------------------------------
*
@@ -1455,9 +1398,9 @@ FileAttrAccessTimeCmd(
* platforms. [Bug 698146]
*/
long newTime;
Tcl_WideInt newTime;
if (TclGetLongFromObj(interp, objv[2], &newTime) != TCL_OK) {
if (TclGetWideIntFromObj(interp, objv[2], &newTime) != TCL_OK) {
return TCL_ERROR;
}
@@ -1536,9 +1479,9 @@ FileAttrModifyTimeCmd(
* platforms. [Bug 698146]
*/
long newTime;
Tcl_WideInt newTime;
if (TclGetLongFromObj(interp, objv[2], &newTime) != TCL_OK) {
if (TclGetWideIntFromObj(interp, objv[2], &newTime) != TCL_OK) {
return TCL_ERROR;
}
+62 -16
View File
@@ -138,6 +138,8 @@ static int InfoScriptCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static int InfoSharedlibCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static int InfoCmdTypeCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static int InfoTclVersionCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static SortElement * MergeLists(SortElement *leftPtr, SortElement *rightPtr,
@@ -156,6 +158,7 @@ static const EnsembleImplMap defaultInfoMap[] = {
{"args", InfoArgsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"body", InfoBodyCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"cmdcount", InfoCmdCountCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0},
{"cmdtype", InfoCmdTypeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"commands", InfoCommandsCmd, TclCompileInfoCommandsCmd, NULL, NULL, 0},
{"complete", InfoCompleteCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"coroutine", TclInfoCoroutineCmd, TclCompileInfoCoroutineCmd, NULL, NULL, 0},
@@ -2129,6 +2132,60 @@ InfoTclVersionCmd(
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* InfoCmdTypeCmd --
*
* Called to implement the "info cmdtype" command that returns the type
* of a given command. Handles the following syntax:
*
* info cmdtype cmdName
*
* Results:
* Returns TCL_OK if successful and TCL_ERROR if there is an error.
*
* Side effects:
* Returns a type name. If there is an error, the result is an error
* message.
*
*----------------------------------------------------------------------
*/
static int
InfoCmdTypeCmd(
ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Command command;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "commandName");
return TCL_ERROR;
}
command = Tcl_FindCommand(interp, Tcl_GetString(objv[1]), NULL,
TCL_LEAVE_ERR_MSG);
if (command == NULL) {
return TCL_ERROR;
}
/*
* There's one special case: safe slave interpreters can't see aliases as
* aliases as they're part of the security mechanisms.
*/
if (Tcl_IsSafe(interp)
&& (((Command *) command)->objProc == TclAliasObjCmd)) {
Tcl_AppendResult(interp, "native", NULL);
} else {
Tcl_SetObjResult(interp,
Tcl_NewStringObj(TclGetCommandTypeName(command), -1));
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
@@ -2730,21 +2787,10 @@ Tcl_LreplaceObjCmd(
if (first < 0) {
first = 0;
}
/*
* Complain if the user asked for a start element that is greater than the
* list length. This won't ever trigger for the "end-*" case as that will
* be properly constrained by TclGetIntForIndex because we use listLen-1
* (to allow for replacing the last elem).
*/
if ((first >= listLen) && (listLen > 0)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"list doesn't contain element %s", TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LREPLACE", "BADIDX",
NULL);
return TCL_ERROR;
if (first > listLen) {
first = listLen;
}
if (last >= listLen) {
last = listLen - 1;
}
@@ -3333,7 +3379,7 @@ Tcl_LsearchObjCmd(
* sense in doing this when the match sense is inverted.
*/
/*
/*
* With -stride, lower, upper and i are kept as multiples of groupSize.
*/
@@ -4015,7 +4061,7 @@ Tcl_LsortObjCmd(
/*
* Do not shrink the actual memory block used; that doesn't
* work with TclStackAlloc-allocated memory. [Bug 2918962]
*
*
* TODO: Consider a pointer increment to replace this
* array shift.
*/
+51 -180
View File
@@ -258,7 +258,7 @@ Tcl_RegexpObjCmd(
stringLength = Tcl_GetCharLength(objPtr);
if (startIndex) {
TclGetIntForIndexM(NULL, startIndex, stringLength, &offset);
TclGetIntForIndexM(interp, startIndex, stringLength, &offset);
Tcl_DecrRefCount(startIndex);
if (offset < 0) {
offset = 0;
@@ -582,7 +582,7 @@ Tcl_RegsubObjCmd(
if (startIndex) {
int stringLength = Tcl_GetCharLength(objv[1]);
TclGetIntForIndexM(NULL, startIndex, stringLength, &offset);
TclGetIntForIndexM(interp, startIndex, stringLength, &offset);
Tcl_DecrRefCount(startIndex);
if (offset < 0) {
offset = 0;
@@ -597,9 +597,9 @@ Tcl_RegsubObjCmd(
* slightly modified version of the one pair STR_MAP code.
*/
int slen, nocase;
int slen, nocase, wsrclc;
int (*strCmpFn)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned long);
Tcl_UniChar *p, wsrclc;
Tcl_UniChar *p;
numMatches = 0;
nocase = (cflags & TCL_REG_NOCASE);
@@ -1447,6 +1447,9 @@ StringIndexCmd(
char buf[4];
length = Tcl_UniCharToUtf(ch, buf);
if (!length) {
length = Tcl_UniCharToUtf(-1, buf);
}
Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, length));
}
}
@@ -2001,8 +2004,8 @@ StringMapCmd(
* larger strings.
*/
int mapLen;
Tcl_UniChar *mapString, u2lc;
int mapLen, u2lc;
Tcl_UniChar *mapString;
ustring2 = Tcl_GetUnicodeFromObj(mapElemv[0], &length2);
p = ustring1;
@@ -2033,8 +2036,8 @@ StringMapCmd(
}
}
} else {
Tcl_UniChar **mapStrings, *u2lc = NULL;
int *mapLens;
Tcl_UniChar **mapStrings;
int *mapLens, *u2lc = NULL;
/*
* Precompute pointers to the unicode string and length. This saves us
@@ -2046,7 +2049,7 @@ StringMapCmd(
mapStrings = TclStackAlloc(interp, mapElemc*2*sizeof(Tcl_UniChar *));
mapLens = TclStackAlloc(interp, mapElemc * 2 * sizeof(int));
if (nocase) {
u2lc = TclStackAlloc(interp, mapElemc * sizeof(Tcl_UniChar));
u2lc = TclStackAlloc(interp, mapElemc * sizeof(int));
}
for (index = 0; index < mapElemc; index++) {
mapStrings[index] = Tcl_GetUnicodeFromObj(mapElemv[index],
@@ -2546,10 +2549,8 @@ StringEqualCmd(
* the expr string comparison in INST_EQ/INST_NEQ/INST_LT/...).
*/
const char *string1, *string2;
int length1, length2, i, match, length, nocase = 0, reqlength = -1;
typedef int (*strCmpFn_t)(const char *, const char *, unsigned int);
strCmpFn_t strCmpFn;
const char *string2;
int length, i, match, nocase = 0, reqlength = -1;
if (objc < 3 || objc > 6) {
str_cmp_args:
@@ -2559,11 +2560,11 @@ StringEqualCmd(
}
for (i = 1; i < objc-2; i++) {
string2 = TclGetStringFromObj(objv[i], &length2);
if ((length2 > 1) && !strncmp(string2, "-nocase", (size_t)length2)) {
string2 = TclGetStringFromObj(objv[i], &length);
if ((length > 1) && !strncmp(string2, "-nocase", (size_t)length)) {
nocase = 1;
} else if ((length2 > 1)
&& !strncmp(string2, "-length", (size_t)length2)) {
} else if ((length > 1)
&& !strncmp(string2, "-length", (size_t)length)) {
if (i+1 >= objc-2) {
goto str_cmp_args;
}
@@ -2588,78 +2589,7 @@ StringEqualCmd(
objv += objc-2;
if ((reqlength == 0) || (objv[0] == objv[1])) {
/*
* Always match at 0 chars of if it is the same obj.
*/
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
return TCL_OK;
}
if (!nocase && TclIsPureByteArray(objv[0]) &&
TclIsPureByteArray(objv[1])) {
/*
* Use binary versions of comparisons since that won't cause undue
* type conversions and it is much faster. Only do this if we're
* case-sensitive (which is all that really makes sense with byte
* arrays anyway, and we have no memcasecmp() for some reason... :^)
*/
string1 = (char *) Tcl_GetByteArrayFromObj(objv[0], &length1);
string2 = (char *) Tcl_GetByteArrayFromObj(objv[1], &length2);
strCmpFn = (strCmpFn_t) memcmp;
} else if ((objv[0]->typePtr == &tclStringType)
&& (objv[1]->typePtr == &tclStringType)) {
/*
* Do a unicode-specific comparison if both of the args are of String
* type. In benchmark testing this proved the most efficient check
* between the unicode and string comparison operations.
*/
string1 = (char *) Tcl_GetUnicodeFromObj(objv[0], &length1);
string2 = (char *) Tcl_GetUnicodeFromObj(objv[1], &length2);
strCmpFn = (strCmpFn_t)
(nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp);
} else {
/*
* As a catch-all we will work with UTF-8. We cannot use memcmp() as
* that is unsafe with any string containing NUL (\xC0\x80 in Tcl's
* utf rep). We can use the more efficient TclpUtfNcmp2 if we are
* case-sensitive and no specific length was requested.
*/
string1 = (char *) TclGetStringFromObj(objv[0], &length1);
string2 = (char *) TclGetStringFromObj(objv[1], &length2);
if ((reqlength < 0) && !nocase) {
strCmpFn = (strCmpFn_t) TclpUtfNcmp2;
} else {
length1 = Tcl_NumUtfChars(string1, length1);
length2 = Tcl_NumUtfChars(string2, length2);
strCmpFn = (strCmpFn_t) (nocase ? Tcl_UtfNcasecmp : Tcl_UtfNcmp);
}
}
if ((reqlength < 0) && (length1 != length2)) {
match = 1; /* This will be reversed below. */
} else {
length = (length1 < length2) ? length1 : length2;
if (reqlength > 0 && reqlength < length) {
length = reqlength;
} else if (reqlength < 0) {
/*
* The requested length is negative, so we ignore it by setting it
* to length + 1 so we correct the match var.
*/
reqlength = length + 1;
}
match = strCmpFn(string1, string2, (unsigned) length);
if ((match == 0) && (reqlength > length)) {
match = length1 - length2;
}
}
match = TclStringCmp(objv[0], objv[1], 0, nocase, reqlength);
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(match ? 0 : 1));
return TCL_OK;
@@ -2696,11 +2626,31 @@ StringCmpCmd(
* the expr string comparison in INST_EQ/INST_NEQ/INST_LT/...).
*/
const char *string1, *string2;
int length1, length2, i, match, length, nocase = 0, reqlength = -1;
typedef int (*strCmpFn_t)(const char *, const char *, unsigned int);
strCmpFn_t strCmpFn;
int match, nocase, reqlength, status;
status = TclStringCmpOpts(interp, objc, objv, &nocase, &reqlength);
if (status != TCL_OK) {
return status;
}
objv += objc-2;
match = TclStringCmp(objv[0], objv[1], 0, nocase, reqlength);
Tcl_SetObjResult(interp, Tcl_NewIntObj(match));
return TCL_OK;
}
int TclStringCmpOpts(
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[], /* Argument objects. */
int *nocase,
int *reqlength)
{
int i, length;
const char *string;
*reqlength = -1;
*nocase = 0;
if (objc < 3 || objc > 6) {
str_cmp_args:
Tcl_WrongNumArgs(interp, 1, objv,
@@ -2709,106 +2659,27 @@ StringCmpCmd(
}
for (i = 1; i < objc-2; i++) {
string2 = TclGetStringFromObj(objv[i], &length2);
if ((length2 > 1) && !strncmp(string2, "-nocase", (size_t)length2)) {
nocase = 1;
} else if ((length2 > 1)
&& !strncmp(string2, "-length", (size_t)length2)) {
string = TclGetStringFromObj(objv[i], &length);
if ((length > 1) && !strncmp(string, "-nocase", (size_t)length)) {
*nocase = 1;
} else if ((length > 1)
&& !strncmp(string, "-length", (size_t)length)) {
if (i+1 >= objc-2) {
goto str_cmp_args;
}
i++;
if (TclGetIntFromObj(interp, objv[i], &reqlength) != TCL_OK) {
if (TclGetIntFromObj(interp, objv[i], reqlength) != TCL_OK) {
return TCL_ERROR;
}
} else {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad option \"%s\": must be -nocase or -length",
string2));
string));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "option",
string2, NULL);
string, NULL);
return TCL_ERROR;
}
}
/*
* From now on, we only access the two objects at the end of the argument
* array.
*/
objv += objc-2;
if ((reqlength == 0) || (objv[0] == objv[1])) {
/*
* Always match at 0 chars of if it is the same obj.
*/
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
return TCL_OK;
}
if (!nocase && TclIsPureByteArray(objv[0]) &&
TclIsPureByteArray(objv[1])) {
/*
* Use binary versions of comparisons since that won't cause undue
* type conversions and it is much faster. Only do this if we're
* case-sensitive (which is all that really makes sense with byte
* arrays anyway, and we have no memcasecmp() for some reason... :^)
*/
string1 = (char *) Tcl_GetByteArrayFromObj(objv[0], &length1);
string2 = (char *) Tcl_GetByteArrayFromObj(objv[1], &length2);
strCmpFn = (strCmpFn_t) memcmp;
} else if ((objv[0]->typePtr == &tclStringType)
&& (objv[1]->typePtr == &tclStringType)) {
/*
* Do a unicode-specific comparison if both of the args are of String
* type. In benchmark testing this proved the most efficient check
* between the unicode and string comparison operations.
*/
string1 = (char *) Tcl_GetUnicodeFromObj(objv[0], &length1);
string2 = (char *) Tcl_GetUnicodeFromObj(objv[1], &length2);
strCmpFn = (strCmpFn_t)
(nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp);
} else {
/*
* As a catch-all we will work with UTF-8. We cannot use memcmp() as
* that is unsafe with any string containing NUL (\xC0\x80 in Tcl's
* utf rep). We can use the more efficient TclpUtfNcmp2 if we are
* case-sensitive and no specific length was requested.
*/
string1 = (char *) TclGetStringFromObj(objv[0], &length1);
string2 = (char *) TclGetStringFromObj(objv[1], &length2);
if ((reqlength < 0) && !nocase) {
strCmpFn = (strCmpFn_t) TclpUtfNcmp2;
} else {
length1 = Tcl_NumUtfChars(string1, length1);
length2 = Tcl_NumUtfChars(string2, length2);
strCmpFn = (strCmpFn_t) (nocase ? Tcl_UtfNcasecmp : Tcl_UtfNcmp);
}
}
length = (length1 < length2) ? length1 : length2;
if (reqlength > 0 && reqlength < length) {
length = reqlength;
} else if (reqlength < 0) {
/*
* The requested length is negative, so we ignore it by setting it to
* length + 1 so we correct the match var.
*/
reqlength = length + 1;
}
match = strCmpFn(string1, string2, (unsigned) length);
if ((match == 0) && (reqlength > length)) {
match = length1 - length2;
}
Tcl_SetObjResult(interp,
Tcl_NewIntObj((match > 0) ? 1 : (match < 0) ? -1 : 0));
return TCL_OK;
}
+28 -77
View File
@@ -27,7 +27,6 @@ static void CompileReturnInternal(CompileEnv *envPtr,
Tcl_Obj *returnOpts);
static int IndexTailVarIfKnown(Tcl_Interp *interp,
Tcl_Token *varTokenPtr, CompileEnv *envPtr);
/*
*----------------------------------------------------------------------
@@ -35,7 +34,7 @@ static int IndexTailVarIfKnown(Tcl_Interp *interp,
* TclGetIndexFromToken --
*
* Parse a token to determine if an index value is known at
* compile time.
* compile time.
*
* Returns:
* TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
@@ -127,9 +126,12 @@ TclCompileGlobalCmd(
return TCL_ERROR;
}
/* TODO: Consider what value can pass through the
* IndexTailVarIfKnown() screen. Full CompileWord()
* likely does not apply here. Push known value instead. */
/*
* TODO: Consider what value can pass through the
* IndexTailVarIfKnown() screen. Full CompileWord() likely does not
* apply here. Push known value instead.
*/
CompileWord(envPtr, varTokenPtr, interp, i);
TclEmitInstInt4( INST_NSUPVAR, localIndex, envPtr);
}
@@ -270,7 +272,7 @@ TclCompileIfCmd(
jumpIndex = jumpFalseFixupArray.next;
jumpFalseFixupArray.next++;
TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
jumpFalseFixupArray.fixup+jumpIndex);
jumpFalseFixupArray.fixup + jumpIndex);
}
code = TCL_OK;
}
@@ -317,7 +319,7 @@ TclCompileIfCmd(
}
jumpEndFixupArray.next++;
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
jumpEndFixupArray.fixup+jumpIndex);
jumpEndFixupArray.fixup + jumpIndex);
/*
* Fix the target of the jumpFalse after the test. Generate a 4
@@ -329,7 +331,7 @@ TclCompileIfCmd(
TclAdjustStackDepth(-1, envPtr);
if (TclFixupForwardJumpToHere(envPtr,
jumpFalseFixupArray.fixup+jumpIndex, 120)) {
jumpFalseFixupArray.fixup + jumpIndex, 120)) {
/*
* Adjust the code offset for the proceeding jump to the end
* of the "if" command.
@@ -412,7 +414,7 @@ TclCompileIfCmd(
for (j = jumpEndFixupArray.next; j > 0; j--) {
jumpIndex = (j - 1); /* i.e. process the closest jump first. */
if (TclFixupForwardJumpToHere(envPtr,
jumpEndFixupArray.fixup+jumpIndex, 127)) {
jumpEndFixupArray.fixup + jumpIndex, 127)) {
/*
* Adjust the immediately preceeding "ifFalse" jump. We moved it's
* target (just after this jump) down three bytes.
@@ -920,7 +922,7 @@ TclCompileLappendCmd(
CompileWord(envPtr, valueTokenPtr, interp, i);
valueTokenPtr = TokenAfter(valueTokenPtr);
}
TclEmitInstInt4( INST_LIST, numWords-2, envPtr);
TclEmitInstInt4( INST_LIST, numWords - 2, envPtr);
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_LAPPEND_LIST_STK, envPtr);
@@ -997,7 +999,7 @@ TclCompileLassignCmd(
*/
PushVarNameWord(interp, tokenPtr, envPtr, 0, &localIndex,
&isScalar, idx+2);
&isScalar, idx + 2);
/*
* Emit instructions to get the idx'th item out of the list value on
@@ -1414,7 +1416,7 @@ TclCompileLinsertCmd(
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
}
TclEmitInstInt4( INST_LIST, i-3, envPtr);
TclEmitInstInt4( INST_LIST, i - 3, envPtr);
if (idx == TCL_INDEX_START) {
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
@@ -1439,7 +1441,7 @@ TclCompileLinsertCmd(
}
TclEmitInstInt4( INST_OVER, 1, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( idx-1, envPtr);
TclEmitInt4( idx - 1, envPtr);
TclEmitInstInt4( INST_REVERSE, 3, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
TclEmitInt4( TCL_INDEX_END, envPtr);
@@ -1472,7 +1474,7 @@ TclCompileLreplaceCmd(
{
Tcl_Token *tokenPtr, *listTokenPtr;
DefineLineInformation; /* TIP #280 */
int idx1, idx2, i, offset, offset2;
int idx1, idx2, i;
int emptyPrefix=1, suffixStart = 0;
if (parsePtr->numWords < 4) {
@@ -1492,23 +1494,6 @@ TclCompileLreplaceCmd(
return TCL_ERROR;
}
/*
* idx1, idx2 are the conventional encoded forms of the tokens parsed
* as all forms of index values. Values of idx1 that come before the
* list are treated the same as if they were the start of the list.
* Values of idx2 that come after the list are treated the same as if
* they were the end of the list.
*/
if (idx1 == TCL_INDEX_AFTER) {
/*
* [lreplace] treats idx1 value end+1 differently from end+2, etc.
* The operand encoding cannot distinguish them, so we must bail
* out to direct evaluation.
*/
return TCL_ERROR;
}
/*
* General structure of the [lreplace] result is
* prefix replacement suffix
@@ -1520,7 +1505,9 @@ TclCompileLreplaceCmd(
* we must defer to direct evaluation.
*/
if (idx2 == TCL_INDEX_BEFORE) {
if (idx1 == TCL_INDEX_AFTER) {
suffixStart = idx1;
} else if (idx2 == TCL_INDEX_BEFORE) {
suffixStart = idx1;
} else if (idx2 == TCL_INDEX_END) {
suffixStart = TCL_INDEX_AFTER;
@@ -1551,42 +1538,6 @@ TclCompileLreplaceCmd(
emptyPrefix = 0;
}
/*
* [lreplace] raises an error when idx1 points after the list, but
* only when the list is not empty. This is maximum stupidity.
*
* TODO: TIP this nonsense away!
*/
if (idx1 >= TCL_INDEX_START) {
if (emptyPrefix) {
TclEmitOpcode( INST_DUP, envPtr);
} else {
TclEmitInstInt4( INST_OVER, 1, envPtr);
}
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
TclEmitOpcode( INST_DUP, envPtr);
offset = CurrentOffset(envPtr);
TclEmitInstInt1( INST_JUMP_FALSE1, 0, envPtr);
/* List is not empty */
TclEmitPush(TclAddLiteralObj(envPtr, Tcl_NewIntObj(idx1),
NULL), envPtr);
TclEmitOpcode( INST_GT, envPtr);
offset2 = CurrentOffset(envPtr);
TclEmitInstInt1( INST_JUMP_TRUE1, 0, envPtr);
/* Idx1 >= list length ===> raise an error */
TclEmitPush(TclAddLiteralObj(envPtr, Tcl_ObjPrintf(
"list doesn't contain element %d", idx1), NULL), envPtr);
CompileReturnInternal(envPtr, INST_RETURN_IMM, TCL_ERROR, 0,
Tcl_ObjPrintf("-errorcode {TCL OPERATION LREPLACE BADIDX}"));
TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset,
envPtr->codeStart + offset + 1);
TclEmitOpcode( INST_POP, envPtr);
TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset2,
envPtr->codeStart + offset2 + 1);
}
if ((idx1 == suffixStart) && (parsePtr->numWords == 4)) {
/*
@@ -2234,7 +2185,7 @@ TclCompileRegexpCmd(
}
if (!simple) {
CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords-2);
CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords - 2);
}
/*
@@ -2242,7 +2193,7 @@ TclCompileRegexpCmd(
*/
varTokenPtr = TokenAfter(varTokenPtr);
CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords-1);
CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords - 1);
if (simple) {
if (exact && !nocase) {
@@ -2426,7 +2377,7 @@ TclCompileRegsubCmd(
PushLiteral(envPtr, bytes, len);
bytes = TclGetStringFromObj(replacementObj, &len);
PushLiteral(envPtr, bytes, len);
CompileWord(envPtr, stringTokenPtr, interp, parsePtr->numWords-2);
CompileWord(envPtr, stringTokenPtr, interp, parsePtr->numWords - 2);
TclEmitOpcode( INST_STR_MAP, envPtr);
done:
@@ -2555,7 +2506,7 @@ TclCompileReturnCmd(
*/
if (explicitResult) {
CompileWord(envPtr, wordTokenPtr, interp, numWords-1);
CompileWord(envPtr, wordTokenPtr, interp, numWords - 1);
} else {
/*
* No explict result argument, so default result is empty string.
@@ -2633,7 +2584,7 @@ TclCompileReturnCmd(
*/
if (explicitResult) {
CompileWord(envPtr, wordTokenPtr, interp, numWords-1);
CompileWord(envPtr, wordTokenPtr, interp, numWords - 1);
} else {
PushStringLiteral(envPtr, "");
}
@@ -2864,12 +2815,12 @@ TclCompileVariableCmd(
CompileWord(envPtr, varTokenPtr, interp, i);
TclEmitInstInt4( INST_VARIABLE, localIndex, envPtr);
if (i+1 < numWords) {
if (i + 1 < numWords) {
/*
* A value has been given: set the variable, pop the value
*/
CompileWord(envPtr, valueTokenPtr, interp, i+1);
CompileWord(envPtr, valueTokenPtr, interp, i + 1);
Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
@@ -2945,7 +2896,7 @@ IndexTailVarIfKnown(
tailName = TclGetStringFromObj(tailPtr, &len);
if (len) {
if (*(tailName+len-1) == ')') {
if (*(tailName + len - 1) == ')') {
/*
* Possible array: bail out
*/
@@ -2959,7 +2910,7 @@ IndexTailVarIfKnown(
*/
for (p = tailName + len -1; p > tailName; p--) {
if ((*p == ':') && (*(p-1) == ':')) {
if ((*p == ':') && (*(p - 1) == ':')) {
p++;
break;
}
+7 -7
View File
@@ -1002,13 +1002,13 @@ TclCompileStringReplaceCmd(
if (parsePtr->numWords < 4 || parsePtr->numWords > 5) {
return TCL_ERROR;
}
/* Bytecode to compute/push string argument being replaced */
valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, valueTokenPtr, interp, 1);
/*
* Check for first index known and useful at compile time.
* Check for first index known and useful at compile time.
*/
tokenPtr = TokenAfter(valueTokenPtr);
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_AFTER,
@@ -1017,7 +1017,7 @@ TclCompileStringReplaceCmd(
}
/*
* Check for last index known and useful at compile time.
* Check for last index known and useful at compile time.
*/
tokenPtr = TokenAfter(tokenPtr);
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_AFTER,
@@ -1025,7 +1025,7 @@ TclCompileStringReplaceCmd(
goto genericReplace;
}
/*
/*
* [string replace] is an odd bird. For many arguments it is
* a conventional substring replacer. However it also goes out
* of its way to become a no-op for many cases where it would be
@@ -1108,12 +1108,12 @@ TclCompileStringReplaceCmd(
* Finally we need, third:
*
* (first <= last)
*
*
* Considered in combination with the constraints we already have,
* we see that we can proceed when (first == TCL_INDEX_BEFORE)
* or (last == TCL_INDEX_AFTER). These also permit simplification
* of the prefix|replace|suffix construction. The other constraints,
* though, interfere with getting a guarantee that first <= last.
* though, interfere with getting a guarantee that first <= last.
*/
if ((first == TCL_INDEX_BEFORE) && (last >= TCL_INDEX_START)) {
@@ -1141,7 +1141,7 @@ TclCompileStringReplaceCmd(
/* FLOW THROUGH TO genericReplace */
} else {
/*
/*
* When we have no replacement string to worry about, we may
* have more luck, because the forbidden empty string replacements
* are harmless when they are replaced by another empty string.
+1 -1
View File
@@ -1473,7 +1473,7 @@ MODULE_SCOPE int TclPushProcCallFrame(ClientData clientData,
#endif
#define TclGetInt4AtPtr(p) \
(((int) TclGetInt1AtPtr(p) << 24) | \
(((int) (TclGetUInt1AtPtr(p) << 24)) | \
(*((p)+1) << 16) | \
(*((p)+2) << 8) | \
(*((p)+3)))
+1 -1
View File
@@ -1348,7 +1348,7 @@ yyparse (info)
int yychar;
/* The semantic value of the look-ahead symbol. */
YYSTYPE yylval;
YYSTYPE yylval = {0};
/* Number of syntax errors so far. */
int yynerrs;
+101 -53
View File
@@ -119,7 +119,8 @@ EXTERN void Tcl_DbIncrRefCount(Tcl_Obj *objPtr, const char *file,
EXTERN int Tcl_DbIsShared(Tcl_Obj *objPtr, const char *file,
int line);
/* 22 */
EXTERN Tcl_Obj * Tcl_DbNewBooleanObj(int boolValue, const char *file,
TCL_DEPRECATED("No longer in use, changed to macro")
Tcl_Obj * Tcl_DbNewBooleanObj(int boolValue, const char *file,
int line);
/* 23 */
EXTERN Tcl_Obj * Tcl_DbNewByteArrayObj(const unsigned char *bytes,
@@ -131,7 +132,8 @@ EXTERN Tcl_Obj * Tcl_DbNewDoubleObj(double doubleValue,
EXTERN Tcl_Obj * Tcl_DbNewListObj(int objc, Tcl_Obj *const *objv,
const char *file, int line);
/* 26 */
EXTERN Tcl_Obj * Tcl_DbNewLongObj(long longValue, const char *file,
TCL_DEPRECATED("No longer in use, changed to macro")
Tcl_Obj * Tcl_DbNewLongObj(long longValue, const char *file,
int line);
/* 27 */
EXTERN Tcl_Obj * Tcl_DbNewObj(const char *file, int line);
@@ -158,7 +160,8 @@ EXTERN int Tcl_GetDouble(Tcl_Interp *interp, const char *src,
EXTERN int Tcl_GetDoubleFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, double *doublePtr);
/* 36 */
EXTERN int Tcl_GetIndexFromObj(Tcl_Interp *interp,
TCL_DEPRECATED("No longer in use, changed to macro")
int Tcl_GetIndexFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, const char *const *tablePtr,
const char *msg, int flags, int *indexPtr);
/* 37 */
@@ -198,24 +201,28 @@ EXTERN int Tcl_ListObjReplace(Tcl_Interp *interp,
Tcl_Obj *listPtr, int first, int count,
int objc, Tcl_Obj *const objv[]);
/* 49 */
EXTERN Tcl_Obj * Tcl_NewBooleanObj(int boolValue);
TCL_DEPRECATED("No longer in use, changed to macro")
Tcl_Obj * Tcl_NewBooleanObj(int boolValue);
/* 50 */
EXTERN Tcl_Obj * Tcl_NewByteArrayObj(const unsigned char *bytes,
int length);
/* 51 */
EXTERN Tcl_Obj * Tcl_NewDoubleObj(double doubleValue);
/* 52 */
EXTERN Tcl_Obj * Tcl_NewIntObj(int intValue);
TCL_DEPRECATED("No longer in use, changed to macro")
Tcl_Obj * Tcl_NewIntObj(int intValue);
/* 53 */
EXTERN Tcl_Obj * Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
/* 54 */
EXTERN Tcl_Obj * Tcl_NewLongObj(long longValue);
TCL_DEPRECATED("No longer in use, changed to macro")
Tcl_Obj * Tcl_NewLongObj(long longValue);
/* 55 */
EXTERN Tcl_Obj * Tcl_NewObj(void);
/* 56 */
EXTERN Tcl_Obj * Tcl_NewStringObj(const char *bytes, int length);
/* 57 */
EXTERN void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue);
TCL_DEPRECATED("No longer in use, changed to macro")
void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue);
/* 58 */
EXTERN unsigned char * Tcl_SetByteArrayLength(Tcl_Obj *objPtr, int length);
/* 59 */
@@ -224,22 +231,26 @@ EXTERN void Tcl_SetByteArrayObj(Tcl_Obj *objPtr,
/* 60 */
EXTERN void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue);
/* 61 */
EXTERN void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue);
TCL_DEPRECATED("No longer in use, changed to macro")
void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue);
/* 62 */
EXTERN void Tcl_SetListObj(Tcl_Obj *objPtr, int objc,
Tcl_Obj *const objv[]);
/* 63 */
EXTERN void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue);
TCL_DEPRECATED("No longer in use, changed to macro")
void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue);
/* 64 */
EXTERN void Tcl_SetObjLength(Tcl_Obj *objPtr, int length);
/* 65 */
EXTERN void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes,
int length);
/* 66 */
EXTERN void Tcl_AddErrorInfo(Tcl_Interp *interp,
TCL_DEPRECATED("No longer in use, changed to macro")
void Tcl_AddErrorInfo(Tcl_Interp *interp,
const char *message);
/* 67 */
EXTERN void Tcl_AddObjErrorInfo(Tcl_Interp *interp,
TCL_DEPRECATED("No longer in use, changed to macro")
void Tcl_AddObjErrorInfo(Tcl_Interp *interp,
const char *message, int length);
/* 68 */
EXTERN void Tcl_AllowExceptions(Tcl_Interp *interp);
@@ -422,7 +433,8 @@ EXTERN int Tcl_Eval(Tcl_Interp *interp, const char *script);
EXTERN int Tcl_EvalFile(Tcl_Interp *interp,
const char *fileName);
/* 131 */
EXTERN int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
TCL_DEPRECATED("No longer in use, changed to macro")
int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
/* 132 */
EXTERN void Tcl_EventuallyFree(ClientData clientData,
Tcl_FreeProc *freeProc);
@@ -549,7 +561,8 @@ EXTERN Tcl_Channel Tcl_GetStdChannel(int type);
/* 174 */
EXTERN const char * Tcl_GetStringResult(Tcl_Interp *interp);
/* 175 */
EXTERN const char * Tcl_GetVar(Tcl_Interp *interp, const char *varName,
TCL_DEPRECATED("No longer in use, changed to macro")
const char * Tcl_GetVar(Tcl_Interp *interp, const char *varName,
int flags);
/* 176 */
EXTERN const char * Tcl_GetVar2(Tcl_Interp *interp, const char *part1,
@@ -558,7 +571,8 @@ EXTERN const char * Tcl_GetVar2(Tcl_Interp *interp, const char *part1,
EXTERN int Tcl_GlobalEval(Tcl_Interp *interp,
const char *command);
/* 178 */
EXTERN int Tcl_GlobalEvalObj(Tcl_Interp *interp,
TCL_DEPRECATED("No longer in use, changed to macro")
int Tcl_GlobalEvalObj(Tcl_Interp *interp,
Tcl_Obj *objPtr);
/* 179 */
EXTERN int Tcl_HideCommand(Tcl_Interp *interp,
@@ -713,7 +727,8 @@ EXTERN void Tcl_SetObjResult(Tcl_Interp *interp,
/* 236 */
EXTERN void Tcl_SetStdChannel(Tcl_Channel channel, int type);
/* 237 */
EXTERN const char * Tcl_SetVar(Tcl_Interp *interp, const char *varName,
TCL_DEPRECATED("No longer in use, changed to macro")
const char * Tcl_SetVar(Tcl_Interp *interp, const char *varName,
const char *newValue, int flags);
/* 238 */
EXTERN const char * Tcl_SetVar2(Tcl_Interp *interp, const char *part1,
@@ -743,7 +758,8 @@ EXTERN int Tcl_StringMatch(const char *str, const char *pattern);
TCL_DEPRECATED("")
int Tcl_TellOld(Tcl_Channel chan);
/* 247 */
EXTERN int Tcl_TraceVar(Tcl_Interp *interp, const char *varName,
TCL_DEPRECATED("No longer in use, changed to macro")
int Tcl_TraceVar(Tcl_Interp *interp, const char *varName,
int flags, Tcl_VarTraceProc *proc,
ClientData clientData);
/* 248 */
@@ -764,13 +780,15 @@ EXTERN void Tcl_UnlinkVar(Tcl_Interp *interp,
EXTERN int Tcl_UnregisterChannel(Tcl_Interp *interp,
Tcl_Channel chan);
/* 253 */
EXTERN int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName,
TCL_DEPRECATED("No longer in use, changed to macro")
int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName,
int flags);
/* 254 */
EXTERN int Tcl_UnsetVar2(Tcl_Interp *interp, const char *part1,
const char *part2, int flags);
/* 255 */
EXTERN void Tcl_UntraceVar(Tcl_Interp *interp,
TCL_DEPRECATED("No longer in use, changed to macro")
void Tcl_UntraceVar(Tcl_Interp *interp,
const char *varName, int flags,
Tcl_VarTraceProc *proc,
ClientData clientData);
@@ -783,7 +801,8 @@ EXTERN void Tcl_UntraceVar2(Tcl_Interp *interp,
EXTERN void Tcl_UpdateLinkedVar(Tcl_Interp *interp,
const char *varName);
/* 258 */
EXTERN int Tcl_UpVar(Tcl_Interp *interp, const char *frameName,
TCL_DEPRECATED("No longer in use, changed to macro")
int Tcl_UpVar(Tcl_Interp *interp, const char *frameName,
const char *varName, const char *localName,
int flags);
/* 259 */
@@ -793,7 +812,8 @@ EXTERN int Tcl_UpVar2(Tcl_Interp *interp, const char *frameName,
/* 260 */
EXTERN int Tcl_VarEval(Tcl_Interp *interp, ...);
/* 261 */
EXTERN ClientData Tcl_VarTraceInfo(Tcl_Interp *interp,
TCL_DEPRECATED("No longer in use, changed to macro")
ClientData Tcl_VarTraceInfo(Tcl_Interp *interp,
const char *varName, int flags,
Tcl_VarTraceProc *procPtr,
ClientData prevClientData);
@@ -825,17 +845,20 @@ EXTERN char * Tcl_HashStats(Tcl_HashTable *tablePtr);
EXTERN const char * Tcl_ParseVar(Tcl_Interp *interp, const char *start,
const char **termPtr);
/* 271 */
EXTERN const char * Tcl_PkgPresent(Tcl_Interp *interp, const char *name,
TCL_DEPRECATED("No longer in use, changed to macro")
const char * Tcl_PkgPresent(Tcl_Interp *interp, const char *name,
const char *version, int exact);
/* 272 */
EXTERN const char * Tcl_PkgPresentEx(Tcl_Interp *interp,
const char *name, const char *version,
int exact, void *clientDataPtr);
/* 273 */
EXTERN int Tcl_PkgProvide(Tcl_Interp *interp, const char *name,
TCL_DEPRECATED("No longer in use, changed to macro")
int Tcl_PkgProvide(Tcl_Interp *interp, const char *name,
const char *version);
/* 274 */
EXTERN const char * Tcl_PkgRequire(Tcl_Interp *interp, const char *name,
TCL_DEPRECATED("No longer in use, changed to macro")
const char * Tcl_PkgRequire(Tcl_Interp *interp, const char *name,
const char *version, int exact);
/* 275 */
TCL_DEPRECATED("see TIP #422")
@@ -1125,7 +1148,8 @@ EXTERN int Tcl_GetCharLength(Tcl_Obj *objPtr);
/* 381 */
EXTERN int Tcl_GetUniChar(Tcl_Obj *objPtr, int index);
/* 382 */
EXTERN Tcl_UniChar * Tcl_GetUnicode(Tcl_Obj *objPtr);
TCL_DEPRECATED("No longer in use, changed to macro")
Tcl_UniChar * Tcl_GetUnicode(Tcl_Obj *objPtr);
/* 383 */
EXTERN Tcl_Obj * Tcl_GetRange(Tcl_Obj *objPtr, int first, int last);
/* 384 */
@@ -1838,6 +1862,18 @@ EXTERN Tcl_Channel Tcl_OpenTcpServerEx(Tcl_Interp *interp,
unsigned int flags,
Tcl_TcpAcceptProc *acceptProc,
ClientData callbackData);
/* 632 */
EXTERN int TclZipfs_Mount(Tcl_Interp *interp, const char *mntpt,
const char *zipname, const char *passwd);
/* 633 */
EXTERN int TclZipfs_Unmount(Tcl_Interp *interp,
const char *zipname);
/* 634 */
EXTERN Tcl_Obj * TclZipfs_TclLibrary(void);
/* 635 */
EXTERN int TclZipfs_Mount_Buffer(Tcl_Interp *interp,
const char *mntpt, unsigned char *data,
size_t datalen, int copy);
typedef struct {
const struct TclPlatStubs *tclPlatStubs;
@@ -1887,11 +1923,11 @@ typedef struct TclStubs {
void (*tcl_DbDecrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 19 */
void (*tcl_DbIncrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 20 */
int (*tcl_DbIsShared) (Tcl_Obj *objPtr, const char *file, int line); /* 21 */
Tcl_Obj * (*tcl_DbNewBooleanObj) (int boolValue, const char *file, int line); /* 22 */
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_DbNewBooleanObj) (int boolValue, const char *file, int line); /* 22 */
Tcl_Obj * (*tcl_DbNewByteArrayObj) (const unsigned char *bytes, int length, const char *file, int line); /* 23 */
Tcl_Obj * (*tcl_DbNewDoubleObj) (double doubleValue, const char *file, int line); /* 24 */
Tcl_Obj * (*tcl_DbNewListObj) (int objc, Tcl_Obj *const *objv, const char *file, int line); /* 25 */
Tcl_Obj * (*tcl_DbNewLongObj) (long longValue, const char *file, int line); /* 26 */
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_DbNewLongObj) (long longValue, const char *file, int line); /* 26 */
Tcl_Obj * (*tcl_DbNewObj) (const char *file, int line); /* 27 */
Tcl_Obj * (*tcl_DbNewStringObj) (const char *bytes, int length, const char *file, int line); /* 28 */
Tcl_Obj * (*tcl_DuplicateObj) (Tcl_Obj *objPtr); /* 29 */
@@ -1901,7 +1937,7 @@ typedef struct TclStubs {
unsigned char * (*tcl_GetByteArrayFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 33 */
int (*tcl_GetDouble) (Tcl_Interp *interp, const char *src, double *doublePtr); /* 34 */
int (*tcl_GetDoubleFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr); /* 35 */
int (*tcl_GetIndexFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *const *tablePtr, const char *msg, int flags, int *indexPtr); /* 36 */
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_GetIndexFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *const *tablePtr, const char *msg, int flags, int *indexPtr); /* 36 */
int (*tcl_GetInt) (Tcl_Interp *interp, const char *src, int *intPtr); /* 37 */
int (*tcl_GetIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 38 */
int (*tcl_GetLongFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr); /* 39 */
@@ -1914,25 +1950,25 @@ typedef struct TclStubs {
int (*tcl_ListObjIndex) (Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj **objPtrPtr); /* 46 */
int (*tcl_ListObjLength) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr); /* 47 */
int (*tcl_ListObjReplace) (Tcl_Interp *interp, Tcl_Obj *listPtr, int first, int count, int objc, Tcl_Obj *const objv[]); /* 48 */
Tcl_Obj * (*tcl_NewBooleanObj) (int boolValue); /* 49 */
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_NewBooleanObj) (int boolValue); /* 49 */
Tcl_Obj * (*tcl_NewByteArrayObj) (const unsigned char *bytes, int length); /* 50 */
Tcl_Obj * (*tcl_NewDoubleObj) (double doubleValue); /* 51 */
Tcl_Obj * (*tcl_NewIntObj) (int intValue); /* 52 */
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_NewIntObj) (int intValue); /* 52 */
Tcl_Obj * (*tcl_NewListObj) (int objc, Tcl_Obj *const objv[]); /* 53 */
Tcl_Obj * (*tcl_NewLongObj) (long longValue); /* 54 */
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_Obj * (*tcl_NewLongObj) (long longValue); /* 54 */
Tcl_Obj * (*tcl_NewObj) (void); /* 55 */
Tcl_Obj * (*tcl_NewStringObj) (const char *bytes, int length); /* 56 */
void (*tcl_SetBooleanObj) (Tcl_Obj *objPtr, int boolValue); /* 57 */
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_SetBooleanObj) (Tcl_Obj *objPtr, int boolValue); /* 57 */
unsigned char * (*tcl_SetByteArrayLength) (Tcl_Obj *objPtr, int length); /* 58 */
void (*tcl_SetByteArrayObj) (Tcl_Obj *objPtr, const unsigned char *bytes, int length); /* 59 */
void (*tcl_SetDoubleObj) (Tcl_Obj *objPtr, double doubleValue); /* 60 */
void (*tcl_SetIntObj) (Tcl_Obj *objPtr, int intValue); /* 61 */
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_SetIntObj) (Tcl_Obj *objPtr, int intValue); /* 61 */
void (*tcl_SetListObj) (Tcl_Obj *objPtr, int objc, Tcl_Obj *const objv[]); /* 62 */
void (*tcl_SetLongObj) (Tcl_Obj *objPtr, long longValue); /* 63 */
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_SetLongObj) (Tcl_Obj *objPtr, long longValue); /* 63 */
void (*tcl_SetObjLength) (Tcl_Obj *objPtr, int length); /* 64 */
void (*tcl_SetStringObj) (Tcl_Obj *objPtr, const char *bytes, int length); /* 65 */
void (*tcl_AddErrorInfo) (Tcl_Interp *interp, const char *message); /* 66 */
void (*tcl_AddObjErrorInfo) (Tcl_Interp *interp, const char *message, int length); /* 67 */
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_AddErrorInfo) (Tcl_Interp *interp, const char *message); /* 66 */
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_AddObjErrorInfo) (Tcl_Interp *interp, const char *message, int length); /* 67 */
void (*tcl_AllowExceptions) (Tcl_Interp *interp); /* 68 */
void (*tcl_AppendElement) (Tcl_Interp *interp, const char *element); /* 69 */
void (*tcl_AppendResult) (Tcl_Interp *interp, ...); /* 70 */
@@ -1996,7 +2032,7 @@ typedef struct TclStubs {
const char * (*tcl_ErrnoMsg) (int err); /* 128 */
int (*tcl_Eval) (Tcl_Interp *interp, const char *script); /* 129 */
int (*tcl_EvalFile) (Tcl_Interp *interp, const char *fileName); /* 130 */
int (*tcl_EvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 131 */
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_EvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 131 */
void (*tcl_EventuallyFree) (ClientData clientData, Tcl_FreeProc *freeProc); /* 132 */
TCL_NORETURN1 void (*tcl_Exit) (int status); /* 133 */
int (*tcl_ExposeCommand) (Tcl_Interp *interp, const char *hiddenCmdToken, const char *cmdName); /* 134 */
@@ -2048,10 +2084,10 @@ typedef struct TclStubs {
Tcl_Interp * (*tcl_GetSlave) (Tcl_Interp *interp, const char *slaveName); /* 172 */
Tcl_Channel (*tcl_GetStdChannel) (int type); /* 173 */
const char * (*tcl_GetStringResult) (Tcl_Interp *interp); /* 174 */
const char * (*tcl_GetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 175 */
TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_GetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 175 */
const char * (*tcl_GetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 176 */
int (*tcl_GlobalEval) (Tcl_Interp *interp, const char *command); /* 177 */
int (*tcl_GlobalEvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 178 */
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_GlobalEvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 178 */
int (*tcl_HideCommand) (Tcl_Interp *interp, const char *cmdName, const char *hiddenCmdToken); /* 179 */
int (*tcl_Init) (Tcl_Interp *interp); /* 180 */
void (*tcl_InitHashTable) (Tcl_HashTable *tablePtr, int keyType); /* 181 */
@@ -2110,7 +2146,7 @@ typedef struct TclStubs {
void (*tcl_SetObjErrorCode) (Tcl_Interp *interp, Tcl_Obj *errorObjPtr); /* 234 */
void (*tcl_SetObjResult) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr); /* 235 */
void (*tcl_SetStdChannel) (Tcl_Channel channel, int type); /* 236 */
const char * (*tcl_SetVar) (Tcl_Interp *interp, const char *varName, const char *newValue, int flags); /* 237 */
TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_SetVar) (Tcl_Interp *interp, const char *varName, const char *newValue, int flags); /* 237 */
const char * (*tcl_SetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, const char *newValue, int flags); /* 238 */
const char * (*tcl_SignalId) (int sig); /* 239 */
const char * (*tcl_SignalMsg) (int sig); /* 240 */
@@ -2120,21 +2156,21 @@ typedef struct TclStubs {
void (*tcl_StaticPackage) (Tcl_Interp *interp, const char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc); /* 244 */
int (*tcl_StringMatch) (const char *str, const char *pattern); /* 245 */
TCL_DEPRECATED_API("") int (*tcl_TellOld) (Tcl_Channel chan); /* 246 */
int (*tcl_TraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 247 */
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_TraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 247 */
int (*tcl_TraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 248 */
char * (*tcl_TranslateFileName) (Tcl_Interp *interp, const char *name, Tcl_DString *bufferPtr); /* 249 */
int (*tcl_Ungets) (Tcl_Channel chan, const char *str, int len, int atHead); /* 250 */
void (*tcl_UnlinkVar) (Tcl_Interp *interp, const char *varName); /* 251 */
int (*tcl_UnregisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 252 */
int (*tcl_UnsetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 253 */
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_UnsetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 253 */
int (*tcl_UnsetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 254 */
void (*tcl_UntraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 255 */
TCL_DEPRECATED_API("No longer in use, changed to macro") void (*tcl_UntraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 255 */
void (*tcl_UntraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 256 */
void (*tcl_UpdateLinkedVar) (Tcl_Interp *interp, const char *varName); /* 257 */
int (*tcl_UpVar) (Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags); /* 258 */
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_UpVar) (Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags); /* 258 */
int (*tcl_UpVar2) (Tcl_Interp *interp, const char *frameName, const char *part1, const char *part2, const char *localName, int flags); /* 259 */
int (*tcl_VarEval) (Tcl_Interp *interp, ...); /* 260 */
ClientData (*tcl_VarTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 261 */
TCL_DEPRECATED_API("No longer in use, changed to macro") ClientData (*tcl_VarTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 261 */
ClientData (*tcl_VarTraceInfo2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 262 */
int (*tcl_Write) (Tcl_Channel chan, const char *s, int slen); /* 263 */
void (*tcl_WrongNumArgs) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *message); /* 264 */
@@ -2144,10 +2180,10 @@ typedef struct TclStubs {
TCL_DEPRECATED_API("see TIP #422") void (*tcl_AppendStringsToObjVA) (Tcl_Obj *objPtr, va_list argList); /* 268 */
char * (*tcl_HashStats) (Tcl_HashTable *tablePtr); /* 269 */
const char * (*tcl_ParseVar) (Tcl_Interp *interp, const char *start, const char **termPtr); /* 270 */
const char * (*tcl_PkgPresent) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 271 */
TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_PkgPresent) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 271 */
const char * (*tcl_PkgPresentEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 272 */
int (*tcl_PkgProvide) (Tcl_Interp *interp, const char *name, const char *version); /* 273 */
const char * (*tcl_PkgRequire) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 274 */
TCL_DEPRECATED_API("No longer in use, changed to macro") int (*tcl_PkgProvide) (Tcl_Interp *interp, const char *name, const char *version); /* 273 */
TCL_DEPRECATED_API("No longer in use, changed to macro") const char * (*tcl_PkgRequire) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 274 */
TCL_DEPRECATED_API("see TIP #422") void (*tcl_SetErrorCodeVA) (Tcl_Interp *interp, va_list argList); /* 275 */
TCL_DEPRECATED_API("see TIP #422") int (*tcl_VarEvalVA) (Tcl_Interp *interp, va_list argList); /* 276 */
Tcl_Pid (*tcl_WaitPid) (Tcl_Pid pid, int *statPtr, int options); /* 277 */
@@ -2255,7 +2291,7 @@ typedef struct TclStubs {
void (*tcl_SetUnicodeObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int numChars); /* 379 */
int (*tcl_GetCharLength) (Tcl_Obj *objPtr); /* 380 */
int (*tcl_GetUniChar) (Tcl_Obj *objPtr, int index); /* 381 */
Tcl_UniChar * (*tcl_GetUnicode) (Tcl_Obj *objPtr); /* 382 */
TCL_DEPRECATED_API("No longer in use, changed to macro") Tcl_UniChar * (*tcl_GetUnicode) (Tcl_Obj *objPtr); /* 382 */
Tcl_Obj * (*tcl_GetRange) (Tcl_Obj *objPtr, int first, int last); /* 383 */
void (*tcl_AppendUnicodeToObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int length); /* 384 */
int (*tcl_RegExpMatchObj) (Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj); /* 385 */
@@ -2505,6 +2541,10 @@ typedef struct TclStubs {
int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */
void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */
Tcl_Channel (*tcl_OpenTcpServerEx) (Tcl_Interp *interp, const char *service, const char *host, unsigned int flags, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData); /* 631 */
int (*tclZipfs_Mount) (Tcl_Interp *interp, const char *mntpt, const char *zipname, const char *passwd); /* 632 */
int (*tclZipfs_Unmount) (Tcl_Interp *interp, const char *zipname); /* 633 */
Tcl_Obj * (*tclZipfs_TclLibrary) (void); /* 634 */
int (*tclZipfs_Mount_Buffer) (Tcl_Interp *interp, const char *mntpt, unsigned char *data, size_t datalen, int copy); /* 635 */
} TclStubs;
extern const TclStubs *tclStubsPtr;
@@ -3799,6 +3839,14 @@ extern const TclStubs *tclStubsPtr;
(tclStubsPtr->tcl_ZlibStreamSetCompressionDictionary) /* 630 */
#define Tcl_OpenTcpServerEx \
(tclStubsPtr->tcl_OpenTcpServerEx) /* 631 */
#define TclZipfs_Mount \
(tclStubsPtr->tclZipfs_Mount) /* 632 */
#define TclZipfs_Unmount \
(tclStubsPtr->tclZipfs_Unmount) /* 633 */
#define TclZipfs_TclLibrary \
(tclStubsPtr->tclZipfs_TclLibrary) /* 634 */
#define TclZipfs_Mount_Buffer \
(tclStubsPtr->tclZipfs_Mount_Buffer) /* 635 */
#endif /* defined(USE_TCL_STUBS) */
@@ -3810,15 +3858,12 @@ extern const TclStubs *tclStubsPtr;
# undef Tcl_GetStringResult
# undef Tcl_Init
# undef Tcl_SetPanicProc
# undef Tcl_SetVar
# undef Tcl_ObjSetVar2
# undef Tcl_StaticPackage
# define Tcl_CreateInterp() (tclStubsPtr->tcl_CreateInterp())
# define Tcl_GetStringResult(interp) (tclStubsPtr->tcl_GetStringResult(interp))
# define Tcl_Init(interp) (tclStubsPtr->tcl_Init(interp))
# define Tcl_SetPanicProc(proc) (tclStubsPtr->tcl_SetPanicProc(proc))
# define Tcl_SetVar(interp, varName, newValue, flags) \
(tclStubsPtr->tcl_SetVar(interp, varName, newValue, flags))
# define Tcl_ObjSetVar2(interp, part1, part2, newValue, flags) \
(tclStubsPtr->tcl_ObjSetVar2(interp, part1, part2, newValue, flags))
#endif
@@ -3828,6 +3873,7 @@ extern const TclStubs *tclStubsPtr;
# define Tcl_MainEx Tcl_MainExW
EXTERN void Tcl_MainExW(int argc, wchar_t **argv,
Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);
EXTERN int TclZipfs_AppHook(int *argc, wchar_t ***argv);
#endif
#undef TCL_STORAGE_CLASS
@@ -3974,9 +4020,11 @@ extern const TclStubs *tclStubsPtr;
#undef Tcl_DbNewLongObj
#define Tcl_DbNewLongObj(value, file, line) Tcl_DbNewWideIntObj((long)(value), file, line)
#undef Tcl_SetIntObj
#define Tcl_SetIntObj(objPtr, value) Tcl_SetWideIntObj(objPtr, (int)(value))
#define Tcl_SetIntObj(objPtr, value) Tcl_SetWideIntObj((objPtr), (int)(value))
#undef Tcl_SetLongObj
#define Tcl_SetLongObj(objPtr, value) Tcl_SetWideIntObj(objPtr, (long)(value))
#define Tcl_SetLongObj(objPtr, value) Tcl_SetWideIntObj((objPtr), (long)(value))
#undef Tcl_GetUnicode
#define Tcl_GetUnicode(objPtr) Tcl_GetUnicodeFromObj((objPtr), NULL)
/*
* Deprecated Tcl procedures:
+1 -1
View File
@@ -153,7 +153,7 @@ typedef struct Dict {
* must be assignable as well as readable.
*/
#define DICT(dictObj) (*((Dict **)&(dictObj)->internalRep.twoPtrValue.ptr1))
#define DICT(dictObj) ((dictObj)->internalRep.twoPtrValue.ptr1)
/*
* The structure below defines the dictionary object type by means of
+1 -1
View File
@@ -894,7 +894,7 @@ PrintSourceToObj(
Tcl_AppendPrintfToObj(appendObj, "\\U%08x", ch);
i += 10;
} else
#elif TCL_UTF_MAX > 3
#else
/* If len == 0, this means we have a char > 0xffff, resulting in
* TclUtfToUniChar producing a surrogate pair. We want to output
* this pair as a single Unicode character.
+76 -71
View File
@@ -21,8 +21,6 @@ static inline Tcl_Obj * NewNsObj(Tcl_Namespace *namespacePtr);
static inline int EnsembleUnknownCallback(Tcl_Interp *interp,
EnsembleConfig *ensemblePtr, int objc,
Tcl_Obj *const objv[], Tcl_Obj **prefixObjPtr);
static int NsEnsembleImplementationCmd(ClientData clientData,
Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
static int NsEnsembleImplementationCmdNR(ClientData clientData,
Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
static void BuildEnsembleConfig(EnsembleConfig *ensemblePtr);
@@ -87,8 +85,8 @@ static const Tcl_ObjType ensembleCmdType = {
};
/*
* The internal rep for caching ensemble subcommand lookups and
* spell corrections.
* The internal rep for caching ensemble subcommand lookups and spelling
* corrections.
*/
typedef struct {
@@ -98,10 +96,9 @@ typedef struct {
Command *token; /* Reference to the command for which this
* structure is a cache of the resolution. */
Tcl_Obj *fix; /* Corrected spelling, if needed. */
Tcl_HashEntry *hPtr; /* Direct link to entry in the subcommand
* hash table. */
Tcl_HashEntry *hPtr; /* Direct link to entry in the subcommand hash
* table. */
} EnsembleCmdRep;
static inline Tcl_Obj *
NewNsObj(
@@ -111,9 +108,8 @@ NewNsObj(
if (namespacePtr == TclGetGlobalNamespace(nsPtr->interp)) {
return Tcl_NewStringObj("::", 2);
} else {
return Tcl_NewStringObj(nsPtr->fullName, -1);
}
return Tcl_NewStringObj(nsPtr->fullName, -1);
}
/*
@@ -147,7 +143,7 @@ TclNamespaceEnsembleCmd(
{
Tcl_Namespace *namespacePtr;
Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp), *cxtPtr,
*foundNsPtr, *altFoundNsPtr, *actualCxtPtr;
*foundNsPtr, *altFoundNsPtr, *actualCxtPtr;
Tcl_Command token;
Tcl_DictSearch search;
Tcl_Obj *listObj;
@@ -302,7 +298,8 @@ TclNamespaceEnsembleCmd(
Tcl_DictObjPut(NULL, patchedDict, subcmdWordsObj,
newList);
}
Tcl_DictObjNext(&search, &subcmdWordsObj,&listObj, &done);
Tcl_DictObjNext(&search, &subcmdWordsObj, &listObj,
&done);
} while (!done);
if (allocatedMapFlag) {
@@ -336,8 +333,8 @@ TclNamespaceEnsembleCmd(
}
TclGetNamespaceForQualName(interp, name, cxtPtr,
TCL_CREATE_NS_IF_UNKNOWN, &foundNsPtr, &altFoundNsPtr, &actualCxtPtr,
&simpleName);
TCL_CREATE_NS_IF_UNKNOWN, &foundNsPtr, &altFoundNsPtr,
&actualCxtPtr, &simpleName);
/*
* Create the ensemble. Note that this might delete another ensemble
@@ -347,8 +344,8 @@ TclNamespaceEnsembleCmd(
*/
token = TclCreateEnsembleInNs(interp, simpleName,
(Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr,
(permitPrefix ? TCL_ENSEMBLE_PREFIX : 0));
(Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr,
(permitPrefix ? TCL_ENSEMBLE_PREFIX : 0));
Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj);
Tcl_SetEnsembleMappingDict(interp, token, mapObj);
Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj);
@@ -576,7 +573,8 @@ TclNamespaceEnsembleCmd(
Tcl_AppendStringsToObj(newCmd, "::", NULL);
}
Tcl_AppendObjToObj(newCmd, listv[0]);
Tcl_ListObjReplace(NULL, newList, 0,1, 1,&newCmd);
Tcl_ListObjReplace(NULL, newList, 0, 1, 1,
&newCmd);
if (patchedDict == NULL) {
patchedDict = Tcl_DuplicateObj(objv[1]);
}
@@ -650,15 +648,13 @@ TclNamespaceEnsembleCmd(
Tcl_Command
TclCreateEnsembleInNs(
Tcl_Interp *interp,
const char *name, /* Simple name of command to create (no */
/* namespace components). */
Tcl_Namespace /* Name of namespace to create the command in. */
*nameNsPtr,
Tcl_Namespace
*ensembleNsPtr, /* Name of the namespace for the ensemble. */
int flags
)
const char *name, /* Simple name of command to create (no
* namespace components). */
Tcl_Namespace *nameNsPtr, /* Name of namespace to create the command
* in. */
Tcl_Namespace *ensembleNsPtr,
/* Name of the namespace for the ensemble. */
int flags)
{
Namespace *nsPtr = (Namespace *) ensembleNsPtr;
EnsembleConfig *ensemblePtr;
@@ -666,8 +662,8 @@ TclCreateEnsembleInNs(
ensemblePtr = ckalloc(sizeof(EnsembleConfig));
token = TclNRCreateCommandInNs(interp, name,
(Tcl_Namespace *) nameNsPtr, NsEnsembleImplementationCmd,
NsEnsembleImplementationCmdNR, ensemblePtr, DeleteEnsembleConfig);
(Tcl_Namespace *) nameNsPtr, TclEnsembleImplementationCmd,
NsEnsembleImplementationCmdNR, ensemblePtr, DeleteEnsembleConfig);
if (token == NULL) {
ckfree(ensemblePtr);
return NULL;
@@ -701,18 +697,15 @@ TclCreateEnsembleInNs(
}
return ensemblePtr->token;
}
/*
*----------------------------------------------------------------------
*
* Tcl_CreateEnsemble
*
* Create a simple ensemble attached to the given namespace.
*
* Deprecated by TclCreateEnsembleInNs.
* Create a simple ensemble attached to the given namespace. Deprecated
* (internally) by TclCreateEnsembleInNs.
*
* Value
*
@@ -732,8 +725,8 @@ Tcl_CreateEnsemble(
Tcl_Namespace *namespacePtr,
int flags)
{
Namespace *nsPtr = (Namespace *)namespacePtr, *foundNsPtr, *altNsPtr,
*actualNsPtr;
Namespace *nsPtr = (Namespace *) namespacePtr, *foundNsPtr, *altNsPtr,
*actualNsPtr;
const char * simpleName;
if (nsPtr == NULL) {
@@ -741,11 +734,10 @@ Tcl_CreateEnsemble(
}
TclGetNamespaceForQualName(interp, name, nsPtr, TCL_CREATE_NS_IF_UNKNOWN,
&foundNsPtr, &altNsPtr, &actualNsPtr, &simpleName);
&foundNsPtr, &altNsPtr, &actualNsPtr, &simpleName);
return TclCreateEnsembleInNs(interp, simpleName,
(Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr, flags);
(Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr, flags);
}
/*
*----------------------------------------------------------------------
@@ -774,7 +766,7 @@ Tcl_SetEnsembleSubcommandList(
EnsembleConfig *ensemblePtr;
Tcl_Obj *oldList;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
@@ -850,7 +842,7 @@ Tcl_SetEnsembleParameterList(
Tcl_Obj *oldList;
int length;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
@@ -926,7 +918,7 @@ Tcl_SetEnsembleMappingDict(
EnsembleConfig *ensemblePtr;
Tcl_Obj *oldDict;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
@@ -1025,7 +1017,7 @@ Tcl_SetEnsembleUnknownHandler(
EnsembleConfig *ensemblePtr;
Tcl_Obj *oldList;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
@@ -1091,7 +1083,7 @@ Tcl_SetEnsembleFlags(
EnsembleConfig *ensemblePtr;
int wasCompiled;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL);
@@ -1167,7 +1159,7 @@ Tcl_GetEnsembleSubcommandList(
Command *cmdPtr = (Command *) token;
EnsembleConfig *ensemblePtr;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
@@ -1209,7 +1201,7 @@ Tcl_GetEnsembleParameterList(
Command *cmdPtr = (Command *) token;
EnsembleConfig *ensemblePtr;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
@@ -1251,7 +1243,7 @@ Tcl_GetEnsembleMappingDict(
Command *cmdPtr = (Command *) token;
EnsembleConfig *ensemblePtr;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
@@ -1292,7 +1284,7 @@ Tcl_GetEnsembleUnknownHandler(
Command *cmdPtr = (Command *) token;
EnsembleConfig *ensemblePtr;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
@@ -1333,7 +1325,7 @@ Tcl_GetEnsembleFlags(
Command *cmdPtr = (Command *) token;
EnsembleConfig *ensemblePtr;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
@@ -1374,7 +1366,7 @@ Tcl_GetEnsembleNamespace(
Command *cmdPtr = (Command *) token;
EnsembleConfig *ensemblePtr;
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", -1));
@@ -1424,7 +1416,7 @@ Tcl_FindEnsemble(
return NULL;
}
if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
/*
* Reuse existing infrastructure for following import link chains
* rather than duplicating it.
@@ -1432,7 +1424,8 @@ Tcl_FindEnsemble(
cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
if (cmdPtr == NULL || cmdPtr->objProc != NsEnsembleImplementationCmd){
if (cmdPtr == NULL
|| cmdPtr->objProc != TclEnsembleImplementationCmd) {
if (flags & TCL_LEAVE_ERR_MSG) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"%s\" is not an ensemble command",
@@ -1470,11 +1463,11 @@ Tcl_IsEnsemble(
{
Command *cmdPtr = (Command *) token;
if (cmdPtr->objProc == NsEnsembleImplementationCmd) {
if (cmdPtr->objProc == TclEnsembleImplementationCmd) {
return 1;
}
cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
if (cmdPtr == NULL || cmdPtr->objProc != NsEnsembleImplementationCmd) {
if (cmdPtr == NULL || cmdPtr->objProc != TclEnsembleImplementationCmd) {
return 0;
}
return 1;
@@ -1645,7 +1638,7 @@ TclMakeEnsemble(
/*
*----------------------------------------------------------------------
*
* NsEnsembleImplementationCmd --
* TclEnsembleImplementationCmd --
*
* Implements an ensemble of commands (being those exported by a
* namespace other than the global namespace) as a command with the same
@@ -1664,8 +1657,8 @@ TclMakeEnsemble(
*----------------------------------------------------------------------
*/
static int
NsEnsembleImplementationCmd(
int
TclEnsembleImplementationCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -2117,22 +2110,27 @@ TclSpellFix(
iPtr->ensembleRewrite.numInsertedObjs = 0;
}
/* Compute the valid length of the ensemble root */
/*
* Compute the valid length of the ensemble root.
*/
size = iPtr->ensembleRewrite.numRemovedObjs + objc
- iPtr->ensembleRewrite.numInsertedObjs;
- iPtr->ensembleRewrite.numInsertedObjs;
search = iPtr->ensembleRewrite.sourceObjs;
if (search[0] == NULL) {
/* Awful casting abuse here */
/*
* Awful casting abuse here...
*/
search = (Tcl_Obj *const *) search[1];
}
if (badIdx < iPtr->ensembleRewrite.numInsertedObjs) {
/*
* Misspelled value was inserted. We cannot directly jump
* to the bad value, but have to search.
* Misspelled value was inserted. We cannot directly jump to the bad
* value, but have to search.
*/
idx = 1;
while (idx < size) {
if (search[idx] == bad) {
@@ -2156,13 +2154,14 @@ TclSpellFix(
search = iPtr->ensembleRewrite.sourceObjs;
if (search[0] == NULL) {
store = (Tcl_Obj **)search[2];
} else {
store = (Tcl_Obj **) search[2];
} else {
Tcl_Obj **tmp = ckalloc(3 * sizeof(Tcl_Obj *));
tmp[0] = NULL;
tmp[1] = (Tcl_Obj *)iPtr->ensembleRewrite.sourceObjs;
tmp[2] = (Tcl_Obj *)ckalloc(size * sizeof(Tcl_Obj *));
memcpy(tmp[2], tmp[1], size*sizeof(Tcl_Obj *));
tmp[1] = (Tcl_Obj *) iPtr->ensembleRewrite.sourceObjs;
tmp[2] = (Tcl_Obj *) ckalloc(size * sizeof(Tcl_Obj *));
memcpy(tmp[2], tmp[1], size * sizeof(Tcl_Obj *));
iPtr->ensembleRewrite.sourceObjs = (Tcl_Obj *const *) tmp;
TclNRAddCallback(interp, FreeER, tmp, NULL, NULL, NULL);
@@ -2589,7 +2588,9 @@ BuildEnsembleConfig(
}
}
} else {
/* Usual case where we can freely act on the list and dict. */
/*
* Usual case where we can freely act on the list and dict.
*/
for (i = 0; i < subc; i++) {
name = TclGetString(subv[i]);
@@ -2598,7 +2599,10 @@ BuildEnsembleConfig(
continue;
}
/* Lookup target in the dictionary */
/*
* Lookup target in the dictionary.
*/
if (mapDict) {
Tcl_DictObjGet(NULL, mapDict, subv[i], &target);
if (target) {
@@ -2610,10 +2614,11 @@ BuildEnsembleConfig(
/*
* target was not in the dictionary so map onto the namespace.
* Note in this case that we do not guarantee that the
* command is actually there; that is the programmer's
* responsibility (or [::unknown] of course).
* Note in this case that we do not guarantee that the command
* is actually there; that is the programmer's responsibility
* (or [::unknown] of course).
*/
cmdObj = Tcl_NewStringObj(name, -1);
cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
Tcl_SetHashValue(hPtr, cmdPrefixObj);
+12 -1
View File
@@ -723,14 +723,25 @@ TclFinalizeEnvironment(void)
* strings. This may leak more memory that strictly necessary, since some
* of the strings may no longer be in the environment. However,
* determining which ones are ok to delete is n-squared, and is pretty
* unlikely, so we don't bother.
* unlikely, so we don't bother. However, in the case of DPURIFY, just
* free all strings in the cache.
*/
if (env.cache) {
#ifdef PURIFY
int i;
for (i = 0; i < env.cacheSize; i++) {
ckfree(env.cache[i]);
}
#endif
ckfree(env.cache);
env.cache = NULL;
env.cacheSize = 0;
#ifndef USE_PUTENV
if ((env.ourEnviron != NULL)) {
ckfree(env.ourEnviron);
env.ourEnviron = NULL;
}
env.ourEnvironSize = 0;
#endif
}
+5 -5
View File
@@ -100,7 +100,7 @@ typedef struct ThreadSpecificData {
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
#ifdef TCL_THREADS
#if TCL_THREADS
typedef struct {
Tcl_ThreadCreateProc *proc; /* Main() function of the thread */
ClientData clientData; /* The one argument to Main() */
@@ -1043,7 +1043,7 @@ TclInitSubsystems(void)
#if USE_TCLALLOC
TclInitAlloc(); /* Process wide mutex init */
#endif
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
TclInitThreadAlloc(); /* Setup thread allocator caches */
#endif
#ifdef TCL_MEM_DEBUG
@@ -1220,7 +1220,7 @@ Tcl_Finalize(void)
* Close down the thread-specific object allocator.
*/
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
TclFinalizeThreadAlloc();
#endif
@@ -1538,7 +1538,7 @@ Tcl_UpdateObjCmd(
return TCL_OK;
}
#ifdef TCL_THREADS
#if TCL_THREADS
/*
*----------------------------------------------------------------------
*
@@ -1601,7 +1601,7 @@ Tcl_CreateThread(
int flags) /* Flags controlling behaviour of the new
* thread. */
{
#ifdef TCL_THREADS
#if TCL_THREADS
ThreadClientData *cdPtr = ckalloc(sizeof(ThreadClientData));
int result;
+38 -105
View File
@@ -4070,10 +4070,7 @@ TEBCresume(
TRACE_ERROR(interp);
goto gotError;
}
TclSetVarArray(varPtr);
varPtr->value.tablePtr = ckalloc(sizeof(TclVarHashTable));
TclInitVarHashTable(varPtr->value.tablePtr,
TclGetVarNsPtr(varPtr));
TclInitArrayVar(varPtr);
#ifdef TCL_COMPILE_DEBUG
TRACE_APPEND(("done\n"));
} else {
@@ -4764,7 +4761,7 @@ TEBCresume(
if ((TclListObjGetElements(interp, valuePtr, &objc, &objv) == TCL_OK)
&& (value2Ptr->typePtr != &tclListType)
&& (TclGetIntForIndexM(NULL , value2Ptr, objc-1,
&& (TclGetIntForIndexM(NULL, value2Ptr, objc-1,
&index) == TCL_OK)) {
TclDecrRefCount(value2Ptr);
tosPtr--;
@@ -4964,7 +4961,7 @@ TEBCresume(
/* Decode index value operands. */
/*
/*
assert ( toIdx != TCL_INDEX_AFTER);
*
* Extra safety for legacy bytecodes:
@@ -5088,88 +5085,10 @@ TEBCresume(
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
if (valuePtr == value2Ptr) {
match = 0;
} else {
/*
* We only need to check (in)equality when we have equal length
* strings. We can use memcmp in all (n)eq cases because we
* don't need to worry about lexical LE/BE variance.
*/
typedef int (*memCmpFn_t)(const void*, const void*, size_t);
memCmpFn_t memCmpFn;
{
int checkEq = ((*pc == INST_EQ) || (*pc == INST_NEQ)
|| (*pc == INST_STR_EQ) || (*pc == INST_STR_NEQ));
if (TclIsPureByteArray(valuePtr)
&& TclIsPureByteArray(value2Ptr)) {
s1 = (char *) Tcl_GetByteArrayFromObj(valuePtr, &s1len);
s2 = (char *) Tcl_GetByteArrayFromObj(value2Ptr, &s2len);
memCmpFn = memcmp;
} else if ((valuePtr->typePtr == &tclStringType)
&& (value2Ptr->typePtr == &tclStringType)) {
/*
* Do a unicode-specific comparison if both of the args are of
* String type. If the char length == byte length, we can do a
* memcmp. In benchmark testing this proved the most efficient
* check between the unicode and string comparison operations.
*/
s1len = Tcl_GetCharLength(valuePtr);
s2len = Tcl_GetCharLength(value2Ptr);
if ((s1len == valuePtr->length)
&& (valuePtr->bytes != NULL)
&& (s2len == value2Ptr->length)
&& (value2Ptr->bytes != NULL)) {
s1 = valuePtr->bytes;
s2 = value2Ptr->bytes;
memCmpFn = memcmp;
} else {
s1 = (char *) Tcl_GetUnicode(valuePtr);
s2 = (char *) Tcl_GetUnicode(value2Ptr);
if (
#ifdef WORDS_BIGENDIAN
1
#else
checkEq
#endif
) {
memCmpFn = memcmp;
s1len *= sizeof(Tcl_UniChar);
s2len *= sizeof(Tcl_UniChar);
} else {
memCmpFn = (memCmpFn_t) Tcl_UniCharNcmp;
}
}
} else {
/*
* strcmp can't do a simple memcmp in order to handle the
* special Tcl \xC0\x80 null encoding for utf-8.
*/
s1 = TclGetStringFromObj(valuePtr, &s1len);
s2 = TclGetStringFromObj(value2Ptr, &s2len);
if (checkEq) {
memCmpFn = memcmp;
} else {
memCmpFn = (memCmpFn_t) TclpUtfNcmp2;
}
}
if (checkEq && (s1len != s2len)) {
match = 1;
} else {
/*
* The comparison function should compare up to the minimum
* byte length only.
*/
match = memCmpFn(s1, s2,
(size_t) ((s1len < s2len) ? s1len : s2len));
if (match == 0) {
match = s1len - s2len;
}
}
match = TclStringCmp(valuePtr, value2Ptr, checkEq, 0, -1);
}
/*
@@ -5301,9 +5220,15 @@ TEBCresume(
* but creating the object as a string seems to be faster in
* practical use.
*/
length = (ch != -1) ? Tcl_UniCharToUtf(ch, buf) : 0;
objResultPtr = Tcl_NewStringObj(buf, length);
if (ch == -1) {
objResultPtr = Tcl_NewObj();
} else {
length = Tcl_UniCharToUtf(ch, buf);
if (!length) {
length = Tcl_UniCharToUtf(-1, buf);
}
objResultPtr = Tcl_NewStringObj(buf, length);
}
}
TRACE_APPEND(("\"%s\"\n", O2S(objResultPtr)));
@@ -5707,17 +5632,17 @@ TEBCresume(
if (GetNumberFromObj(NULL, OBJ_AT_TOS, &ptr1, &type1) != TCL_OK) {
type1 = 0;
} else if (type1 == TCL_NUMBER_WIDE) {
/* value is between LLONG_MIN and LLONG_MAX */
/* value is between WIDE_MIN and WIDE_MAX */
/* [string is integer] is -UINT_MAX to UINT_MAX range */
/* [string is wideinteger] is -ULLONG_MAX to ULLONG_MAX range */
/* [string is wideinteger] is -UWIDE_MAX to UWIDE_MAX range */
int i;
if (Tcl_GetIntFromObj(NULL, OBJ_AT_TOS, &i) == TCL_OK) {
type1 = TCL_NUMBER_LONG;
}
} else if (type1 == TCL_NUMBER_BIG) {
/* value is an integer outside the LLONG_MIN to LLONG_MAX range */
/* [string is wideinteger] is -ULLONG_MAX to ULLONG_MAX range */
/* value is an integer outside the WIDE_MIN to WIDE_MAX range */
/* [string is wideinteger] is -UWIDE_MAX to UWIDE_MAX range */
Tcl_WideInt w;
if (Tcl_GetWideIntFromObj(NULL, OBJ_AT_TOS, &w) == TCL_OK) {
@@ -5739,6 +5664,14 @@ TEBCresume(
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
/*
Try to determine, without triggering generation of a string
representation, whether one value is not a number.
*/
if (TclCheckEmptyString(valuePtr) > 0 || TclCheckEmptyString(value2Ptr) > 0) {
goto stringCompare;
}
if (GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK
|| GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK) {
/*
@@ -6125,9 +6058,9 @@ TEBCresume(
TRACE(("%s %s => DIVIDE BY ZERO\n",
O2S(valuePtr), O2S(value2Ptr)));
goto divideByZero;
} else if ((w1 == LLONG_MIN) && (w2 == -1)) {
} else if ((w1 == WIDE_MIN) && (w2 == -1)) {
/*
* Can't represent (-LLONG_MIN) as a Tcl_WideInt.
* Can't represent (-WIDE_MIN) as a Tcl_WideInt.
*/
goto overflow;
@@ -6260,7 +6193,7 @@ TEBCresume(
NEXT_INST_F(1, 0, 0);
case TCL_NUMBER_WIDE:
w1 = *((const Tcl_WideInt *) ptr1);
if (w1 != LLONG_MIN) {
if (w1 != WIDE_MIN) {
if (Tcl_IsShared(valuePtr)) {
TclNewIntObj(objResultPtr, -w1);
TRACE_APPEND(("%s\n", O2S(objResultPtr)));
@@ -8734,10 +8667,10 @@ ExecuteExtendedBinaryMathOp(
}
/*
* Need a bignum to represent (LLONG_MIN / -1)
* Need a bignum to represent (WIDE_MIN / -1)
*/
if ((w1 == LLONG_MIN) && (w2 == -1)) {
if ((w1 == WIDE_MIN) && (w2 == -1)) {
goto overflowBasic;
}
wResult = w1 / w2;
@@ -8840,7 +8773,7 @@ ExecuteExtendedUnaryMathOp(
DOUBLE_RESULT(-(*((const double *) ptr)));
case TCL_NUMBER_WIDE:
w = *((const Tcl_WideInt *) ptr);
if (w != LLONG_MIN) {
if (w != WIDE_MIN) {
WIDE_RESULT(-w);
}
TclInitBignumFromWideInt(&big, w);
@@ -8926,10 +8859,10 @@ TclCompareTwoNumbers(
* integer comparison can tell the difference.
*/
if (d2 < (double)LLONG_MIN) {
if (d2 < (double)WIDE_MIN) {
return MP_GT;
}
if (d2 > (double)LLONG_MAX) {
if (d2 > (double)WIDE_MAX) {
return MP_LT;
}
w2 = (Tcl_WideInt) d2;
@@ -8959,10 +8892,10 @@ TclCompareTwoNumbers(
|| w2 == (Tcl_WideInt) d2 || modf(d1, &tmp) != 0.0) {
goto doubleCompare;
}
if (d1 < (double)LLONG_MIN) {
if (d1 < (double)WIDE_MIN) {
return MP_LT;
}
if (d1 > (double)LLONG_MAX) {
if (d1 > (double)WIDE_MAX) {
return MP_GT;
}
w1 = (Tcl_WideInt) d1;
@@ -8972,7 +8905,7 @@ TclCompareTwoNumbers(
return (d1 > 0.0) ? MP_GT : MP_LT;
}
Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
if ((d1 < (double)LLONG_MAX) && (d1 > (double)LLONG_MIN)) {
if ((d1 < (double)WIDE_MAX) && (d1 > (double)WIDE_MIN)) {
if (mp_isneg(&big2)) {
compare = MP_GT;
} else {
@@ -9005,7 +8938,7 @@ TclCompareTwoNumbers(
mp_clear(&big1);
return compare;
}
if ((d2 < (double)LLONG_MAX) && (d2 > (double)LLONG_MIN)) {
if ((d2 < (double)WIDE_MAX) && (d2 > (double)WIDE_MIN)) {
compare = mp_cmp_d(&big1, 0);
mp_clear(&big1);
return compare;
+20 -14
View File
@@ -240,9 +240,13 @@ TclFileMakeDirsCmd(
break;
}
for (j = 0; j < pobjc; j++) {
int errCount = 2;
target = Tcl_FSJoinPath(split, j + 1);
Tcl_IncrRefCount(target);
createDir:
/*
* Call Tcl_FSStat() so that if target is a symlink that points to
* a directory we will create subdirectories in that directory.
@@ -269,23 +273,25 @@ TclFileMakeDirsCmd(
* subdirectory.
*/
if (errno != EEXIST) {
errfile = target;
goto done;
} else if ((Tcl_FSStat(target, &statBuf) == 0)
&& S_ISDIR(statBuf.st_mode)) {
/*
* It is a directory that wasn't there before, so keep
* going without error.
*/
Tcl_ResetResult(interp);
} else {
errfile = target;
goto done;
if (errno == EEXIST) {
/* Be aware other workers could delete it immediately after
* creation, so give this worker still one chance (repeat once),
* see [270f78ca95] for description of the race-condition.
* Don't repeat the create always (to avoid endless loop). */
if (--errCount > 0) {
goto createDir;
}
/* Already tried, with delete in-between directly after
* creation, so just continue (assume created successful). */
goto nextPart;
}
/* return with error */
errfile = target;
goto done;
}
nextPart:
/*
* Forget about this sub-path.
*/
+1 -1
View File
@@ -1881,7 +1881,7 @@ TclGlob(
separators = "/\\";
} else if (tclPlatform == TCL_PLATFORM_UNIX) {
if (pathPrefix == NULL && tail[0] == '/') {
if (pathPrefix == NULL && tail[0] == '/' && tail[1] != '/') {
pathPrefix = Tcl_NewStringObj(tail, 1);
tail++;
Tcl_IncrRefCount(pathPrefix);
+17 -17
View File
@@ -482,13 +482,13 @@ ChanSeek(
offset, mode, errnoPtr);
}
if (offset<Tcl_LongAsWide(LONG_MIN) || offset>Tcl_LongAsWide(LONG_MAX)) {
if (offset<LONG_MIN || offset>LONG_MAX) {
*errnoPtr = EOVERFLOW;
return Tcl_LongAsWide(-1);
return -1;
}
return Tcl_LongAsWide(chanPtr->typePtr->seekProc(chanPtr->instanceData,
Tcl_WideAsLong(offset), mode, errnoPtr));
return chanPtr->typePtr->seekProc(chanPtr->instanceData,
offset, mode, errnoPtr);
}
static inline void
@@ -6953,7 +6953,7 @@ Tcl_Seek(
* non-blocking mode after the seek. */
if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) {
return Tcl_LongAsWide(-1);
return -1;
}
/*
@@ -6964,7 +6964,7 @@ Tcl_Seek(
*/
if (CheckForDeadChannel(NULL, statePtr)) {
return Tcl_LongAsWide(-1);
return -1;
}
/*
@@ -6980,7 +6980,7 @@ Tcl_Seek(
if (chanPtr->typePtr->seekProc == NULL) {
Tcl_SetErrno(EINVAL);
return Tcl_LongAsWide(-1);
return -1;
}
/*
@@ -6993,7 +6993,7 @@ Tcl_Seek(
if ((inputBuffered != 0) && (outputBuffered != 0)) {
Tcl_SetErrno(EFAULT);
return Tcl_LongAsWide(-1);
return -1;
}
/*
@@ -7036,7 +7036,7 @@ Tcl_Seek(
wasAsync = 1;
result = StackSetBlockMode(chanPtr, TCL_MODE_BLOCKING);
if (result != 0) {
return Tcl_LongAsWide(-1);
return -1;
}
ResetFlag(statePtr, CHANNEL_NONBLOCKING);
if (GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
@@ -7061,7 +7061,7 @@ Tcl_Seek(
*/
curPos = ChanSeek(chanPtr, offset, mode, &result);
if (curPos == Tcl_LongAsWide(-1)) {
if (curPos == -1) {
Tcl_SetErrno(result);
}
}
@@ -7077,7 +7077,7 @@ Tcl_Seek(
SetFlag(statePtr, CHANNEL_NONBLOCKING);
result = StackSetBlockMode(chanPtr, TCL_MODE_NONBLOCKING);
if (result != 0) {
return Tcl_LongAsWide(-1);
return -1;
}
}
@@ -7117,7 +7117,7 @@ Tcl_Tell(
Tcl_WideInt curPos; /* Position on device. */
if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) {
return Tcl_LongAsWide(-1);
return -1;
}
/*
@@ -7128,7 +7128,7 @@ Tcl_Tell(
*/
if (CheckForDeadChannel(NULL, statePtr)) {
return Tcl_LongAsWide(-1);
return -1;
}
/*
@@ -7144,7 +7144,7 @@ Tcl_Tell(
if (chanPtr->typePtr->seekProc == NULL) {
Tcl_SetErrno(EINVAL);
return Tcl_LongAsWide(-1);
return -1;
}
/*
@@ -7161,10 +7161,10 @@ Tcl_Tell(
* wideSeekProc if that is available and non-NULL...
*/
curPos = ChanSeek(chanPtr, Tcl_LongAsWide(0), SEEK_CUR, &result);
if (curPos == Tcl_LongAsWide(-1)) {
curPos = ChanSeek(chanPtr, 0, SEEK_CUR, &result);
if (curPos == -1) {
Tcl_SetErrno(result);
return Tcl_LongAsWide(-1);
return -1;
}
if (inputBuffered != 0) {
+2 -2
View File
@@ -559,7 +559,7 @@ Tcl_SeekObjCmd(
TclChannelPreserve(chan);
result = Tcl_Seek(chan, offset, mode);
if (result == Tcl_LongAsWide(-1)) {
if (result == -1) {
/*
* TIP #219.
* Capture error messages put by the driver into the bypass area and
@@ -1913,7 +1913,7 @@ ChanTruncateObjCmd(
*/
length = Tcl_Tell(chan);
if (length == Tcl_WideAsLong(-1)) {
if (length == -1) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"could not determine current location in \"%s\": %s",
TclGetString(objv[1]), Tcl_PosixError(interp)));
+6 -7
View File
@@ -910,7 +910,7 @@ TransformWideSeekProc(
Tcl_ChannelWideSeekProc(parentType);
ClientData parentData = Tcl_GetChannelInstanceData(parent);
if ((offset == Tcl_LongAsWide(0)) && (mode == SEEK_CUR)) {
if ((offset == 0) && (mode == SEEK_CUR)) {
/*
* This is no seek but a request to tell the caller the current
* location. Simply pass the request down.
@@ -920,8 +920,7 @@ TransformWideSeekProc(
return parentWideSeekProc(parentData, offset, mode, errorCodePtr);
}
return Tcl_LongAsWide(parentSeekProc(parentData, 0, mode,
errorCodePtr));
return parentSeekProc(parentData, 0, mode, errorCodePtr);
}
/*
@@ -961,13 +960,13 @@ TransformWideSeekProc(
* to go out of the representable range.
*/
if (offset<Tcl_LongAsWide(LONG_MIN) || offset>Tcl_LongAsWide(LONG_MAX)) {
if (offset<LONG_MIN || offset>LONG_MAX) {
*errorCodePtr = EOVERFLOW;
return Tcl_LongAsWide(-1);
return -1;
}
return Tcl_LongAsWide(parentSeekProc(parentData, Tcl_WideAsLong(offset),
mode, errorCodePtr));
return parentSeekProc(parentData, offset,
mode, errorCodePtr);
}
/*
+27 -27
View File
@@ -39,7 +39,7 @@ static int ReflectOutput(ClientData clientData, const char *buf,
int toWrite, int *errorCodePtr);
static void ReflectWatch(ClientData clientData, int mask);
static int ReflectBlock(ClientData clientData, int mode);
#ifdef TCL_THREADS
#if TCL_THREADS
static void ReflectThread(ClientData clientData, int action);
static int ReflectEventRun(Tcl_Event *ev, int flags);
static int ReflectEventDelete(Tcl_Event *ev, ClientData cd);
@@ -76,7 +76,7 @@ static const Tcl_ChannelType tclRChannelType = {
NULL, /* Flush channel. Not used by core. NULL'able */
NULL, /* Handle events. NULL'able */
ReflectSeekWide, /* Move access point (64 bit). NULL'able */
#ifdef TCL_THREADS
#if TCL_THREADS
ReflectThread, /* thread action, tracking owner */
#else
NULL, /* thread action */
@@ -97,7 +97,7 @@ typedef struct {
* interpreter/thread containing its Tcl
* command is gone.
*/
#ifdef TCL_THREADS
#if TCL_THREADS
Tcl_ThreadId thread; /* Thread the 'interp' belongs to. == Handler thread */
Tcl_ThreadId owner; /* Thread owning the structure. == Channel thread */
#endif
@@ -201,7 +201,7 @@ typedef enum {
#define NEGIMPL(a,b)
#define HAS(x,f) (x & FLAG(f))
#ifdef TCL_THREADS
#if TCL_THREADS
/*
* Thread specific types and structures.
*
@@ -451,7 +451,7 @@ static const char *msg_read_toomuch = "{read delivered more than requested}";
static const char *msg_write_toomuch = "{write wrote more than requested}";
static const char *msg_write_nothing = "{write wrote nothing}";
static const char *msg_seek_beforestart = "{Tried to seek before origin}";
#ifdef TCL_THREADS
#if TCL_THREADS
static const char *msg_send_originlost = "{Channel thread lost}";
#endif /* TCL_THREADS */
static const char *msg_send_dstlost = "{Owner lost}";
@@ -706,7 +706,7 @@ TclChanCreateObjCmd(
Tcl_Panic("TclChanCreateObjCmd: duplicate channel names");
}
Tcl_SetHashValue(hPtr, chan);
#ifdef TCL_THREADS
#if TCL_THREADS
rcmPtr = GetThreadReflectedChannelMap();
hPtr = Tcl_CreateHashEntry(&rcmPtr->map, chanPtr->state->channelName,
&isNew);
@@ -750,7 +750,7 @@ TclChanCreateObjCmd(
*----------------------------------------------------------------------
*/
#ifdef TCL_THREADS
#if TCL_THREADS
typedef struct {
Tcl_Event header;
ReflectedChannel *rcPtr;
@@ -917,11 +917,11 @@ TclChanPostEventObjCmd(
* We have the channel and the events to post.
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rcPtr->owner == rcPtr->thread) {
#endif
Tcl_NotifyChannel(chan, events);
#ifdef TCL_THREADS
#if TCL_THREADS
} else {
ReflectEvent *ev = ckalloc(sizeof(ReflectEvent));
@@ -1137,7 +1137,7 @@ ReflectClose(
* if lost?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rcPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -1169,7 +1169,7 @@ ReflectClose(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rcPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -1216,7 +1216,7 @@ ReflectClose(
Tcl_DeleteHashEntry(hPtr);
}
}
#ifdef TCL_THREADS
#if TCL_THREADS
rcmPtr = GetThreadReflectedChannelMap();
hPtr = Tcl_FindHashEntry(&rcmPtr->map,
Tcl_GetChannelName(rcPtr->chan));
@@ -1267,7 +1267,7 @@ ReflectInput(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rcPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -1373,7 +1373,7 @@ ReflectOutput(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rcPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -1502,7 +1502,7 @@ ReflectSeekWide(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rcPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -1544,7 +1544,7 @@ ReflectSeekWide(
goto invalid;
}
if (newLoc < Tcl_LongAsWide(0)) {
if (newLoc < 0) {
SetChannelErrorStr(rcPtr->chan, msg_seek_beforestart);
goto invalid;
}
@@ -1576,7 +1576,7 @@ ReflectSeek(
* routine.
*/
return (int) ReflectSeekWide(clientData, Tcl_LongAsWide(offset), seekMode,
return ReflectSeekWide(clientData, offset, seekMode,
errorCodePtr);
}
@@ -1625,7 +1625,7 @@ ReflectWatch(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rcPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -1683,7 +1683,7 @@ ReflectBlock(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rcPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -1719,7 +1719,7 @@ ReflectBlock(
return errorNum;
}
#ifdef TCL_THREADS
#if TCL_THREADS
/*
*----------------------------------------------------------------------
*
@@ -1789,7 +1789,7 @@ ReflectSetOption(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rcPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -1868,7 +1868,7 @@ ReflectGetOption(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rcPtr->thread != Tcl_GetCurrentThread()) {
int opcode;
ForwardParam p;
@@ -2131,7 +2131,7 @@ NewReflectedChannel(
rcPtr->chan = NULL;
rcPtr->interp = interp;
rcPtr->dead = 0;
#ifdef TCL_THREADS
#if TCL_THREADS
rcPtr->thread = Tcl_GetCurrentThread();
#endif
rcPtr->mode = mode;
@@ -2506,7 +2506,7 @@ DeleteReflectedChannelMap(
Tcl_HashEntry *hPtr; /* Search variable. */
ReflectedChannel *rcPtr;
Tcl_Channel chan;
#ifdef TCL_THREADS
#if TCL_THREADS
ForwardingResult *resultPtr;
ForwardingEvent *evPtr;
ForwardParam *paramPtr;
@@ -2536,7 +2536,7 @@ DeleteReflectedChannelMap(
Tcl_DeleteHashTable(&rcmPtr->map);
ckfree(&rcmPtr->map);
#ifdef TCL_THREADS
#if TCL_THREADS
/*
* The origin interpreter for one or more reflected channels is gone.
*/
@@ -2622,7 +2622,7 @@ DeleteReflectedChannelMap(
#endif
}
#ifdef TCL_THREADS
#if TCL_THREADS
/*
*----------------------------------------------------------------------
*
@@ -3079,7 +3079,7 @@ ForwardProc(
Tcl_WideInt newLoc;
if (Tcl_GetWideIntFromObj(interp, resObj, &newLoc) == TCL_OK) {
if (newLoc < Tcl_LongAsWide(0)) {
if (newLoc < 0) {
ForwardSetStaticError(paramPtr, msg_seek_beforestart);
paramPtr->seek.offset = -1;
} else {
+27 -28
View File
@@ -127,7 +127,7 @@ typedef struct {
* in the argv, see below. The separate field
* gives us direct access, needed when working
* with the reflection maps. */
#ifdef TCL_THREADS
#if TCL_THREADS
Tcl_ThreadId thread; /* Thread the 'interp' belongs to. */
#endif
@@ -220,7 +220,7 @@ typedef enum {
#define NEGIMPL(a,b)
#define HAS(x,f) (x & FLAG(f))
#ifdef TCL_THREADS
#if TCL_THREADS
/*
* Thread specific types and structures.
*
@@ -438,7 +438,7 @@ static void DeleteReflectedTransformMap(ClientData clientData,
static const char *msg_read_unsup = "{read not supported by Tcl driver}";
static const char *msg_write_unsup = "{write not supported by Tcl driver}";
#ifdef TCL_THREADS
#if TCL_THREADS
static const char *msg_send_originlost = "{Channel thread lost}";
static const char *msg_send_dstlost = "{Owner lost}";
#endif /* TCL_THREADS */
@@ -699,7 +699,7 @@ TclChanPushObjCmd(
Tcl_Panic("TclChanPushObjCmd: duplicate transformation handle");
}
Tcl_SetHashValue(hPtr, rtPtr);
#ifdef TCL_THREADS
#if TCL_THREADS
rtmPtr = GetThreadReflectedTransformMap();
hPtr = Tcl_CreateHashEntry(&rtmPtr->map, TclGetString(rtId), &isNew);
Tcl_SetHashValue(hPtr, rtPtr);
@@ -911,7 +911,7 @@ ReflectClose(
* if lost?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rtPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -938,7 +938,7 @@ ReflectClose(
if (HAS(rtPtr->methods, METH_DRAIN) && !rtPtr->readIsDrained) {
if (!TransformDrain(rtPtr, &errorCode)) {
#ifdef TCL_THREADS
#if TCL_THREADS
if (rtPtr->thread != Tcl_GetCurrentThread()) {
Tcl_EventuallyFree(rtPtr,
(Tcl_FreeProc *) FreeReflectedTransform);
@@ -952,7 +952,7 @@ ReflectClose(
if (HAS(rtPtr->methods, METH_FLUSH)) {
if (!TransformFlush(rtPtr, &errorCode, FLUSH_WRITE)) {
#ifdef TCL_THREADS
#if TCL_THREADS
if (rtPtr->thread != Tcl_GetCurrentThread()) {
Tcl_EventuallyFree(rtPtr,
(Tcl_FreeProc *) FreeReflectedTransform);
@@ -968,7 +968,7 @@ ReflectClose(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rtPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -1025,7 +1025,7 @@ ReflectClose(
* under a channel by deleting the owning thread.
*/
#ifdef TCL_THREADS
#if TCL_THREADS
rtmPtr = GetThreadReflectedTransformMap();
hPtr = Tcl_FindHashEntry(&rtmPtr->map, TclGetString(rtPtr->handle));
if (hPtr) {
@@ -1340,7 +1340,7 @@ ReflectSeekWide(
if (seekProc == NULL) {
Tcl_SetErrno(EINVAL);
return Tcl_LongAsWide(-1);
return -1;
}
/*
@@ -1390,16 +1390,15 @@ ReflectSeekWide(
parent->typePtr->wideSeekProc != NULL) {
curPos = parent->typePtr->wideSeekProc(parent->instanceData, offset,
seekMode, errorCodePtr);
} else if (offset < Tcl_LongAsWide(LONG_MIN) ||
offset > Tcl_LongAsWide(LONG_MAX)) {
} else if (offset < LONG_MIN || offset > LONG_MAX) {
*errorCodePtr = EOVERFLOW;
curPos = Tcl_LongAsWide(-1);
curPos = -1;
} else {
curPos = Tcl_LongAsWide(parent->typePtr->seekProc(
parent->instanceData, Tcl_WideAsLong(offset), seekMode,
errorCodePtr));
curPos = parent->typePtr->seekProc(
parent->instanceData, offset, seekMode,
errorCodePtr);
}
if (curPos == Tcl_LongAsWide(-1)) {
if (curPos == -1) {
Tcl_SetErrno(*errorCodePtr);
}
@@ -1422,7 +1421,7 @@ ReflectSeek(
* routine.
*/
return (int) ReflectSeekWide(clientData, Tcl_LongAsWide(offset), seekMode,
return ReflectSeekWide(clientData, offset, seekMode,
errorCodePtr);
}
@@ -1767,7 +1766,7 @@ NewReflectedTransform(
rtPtr->chan = NULL;
rtPtr->methods = 0;
#ifdef TCL_THREADS
#if TCL_THREADS
rtPtr->thread = Tcl_GetCurrentThread();
#endif
rtPtr->parent = parentChan;
@@ -2152,7 +2151,7 @@ DeleteReflectedTransformMap(
Tcl_HashSearch hSearch; /* Search variable. */
Tcl_HashEntry *hPtr; /* Search variable. */
ReflectedTransform *rtPtr;
#ifdef TCL_THREADS
#if TCL_THREADS
ForwardingResult *resultPtr;
ForwardingEvent *evPtr;
ForwardParam *paramPtr;
@@ -2182,7 +2181,7 @@ DeleteReflectedTransformMap(
Tcl_DeleteHashTable(&rtmPtr->map);
ckfree(&rtmPtr->map);
#ifdef TCL_THREADS
#if TCL_THREADS
/*
* The origin interpreter for one or more reflected channels is gone.
*/
@@ -2254,7 +2253,7 @@ DeleteReflectedTransformMap(
#endif /* TCL_THREADS */
}
#ifdef TCL_THREADS
#if TCL_THREADS
/*
*----------------------------------------------------------------------
*
@@ -3088,7 +3087,7 @@ TransformRead(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rtPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -3144,7 +3143,7 @@ TransformWrite(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rtPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -3210,7 +3209,7 @@ TransformDrain(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rtPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -3260,7 +3259,7 @@ TransformFlush(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rtPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -3315,7 +3314,7 @@ TransformClear(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rtPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
@@ -3347,7 +3346,7 @@ TransformLimit(
* Are we in the correct thread?
*/
#ifdef TCL_THREADS
#if TCL_THREADS
if (rtPtr->thread != Tcl_GetCurrentThread()) {
ForwardParam p;
+1 -1
View File
@@ -11,7 +11,7 @@
#include "tclInt.h"
#if defined(_WIN32) && defined(UNICODE)
#if defined(_WIN32)
/*
* On Windows, we need to do proper Unicode->UTF-8 conversion.
*/
+55 -45
View File
@@ -139,7 +139,6 @@ Tcl_FSRenameFileProc TclpObjRenameFile;
Tcl_FSCreateDirectoryProc TclpObjCreateDirectory;
Tcl_FSCopyDirectoryProc TclpObjCopyDirectory;
Tcl_FSRemoveDirectoryProc TclpObjRemoveDirectory;
Tcl_FSUnloadFileProc TclpUnloadFile;
Tcl_FSLinkProc TclpObjLink;
Tcl_FSListVolumesProc TclpObjListVolumes;
@@ -276,8 +275,8 @@ Tcl_Stat(
Tcl_WideInt tmp1, tmp2, tmp3 = 0;
# define OUT_OF_RANGE(x) \
(((Tcl_WideInt)(x)) < Tcl_LongAsWide(LONG_MIN) || \
((Tcl_WideInt)(x)) > Tcl_LongAsWide(LONG_MAX))
(((Tcl_WideInt)(x)) < LONG_MIN || \
((Tcl_WideInt)(x)) > LONG_MAX)
# define OUT_OF_URANGE(x) \
(((Tcl_WideUInt)(x)) > ((Tcl_WideUInt)ULONG_MAX))
@@ -1391,31 +1390,62 @@ TclFSNormalizeToUniquePath(
{
FilesystemRecord *fsRecPtr, *firstFsRecPtr;
/*
* Call each of the "normalise path" functions in succession. This is a
* special case, in which if we have a native filesystem handler, we call
* it first. This is because the root of Tcl's filesystem is always a
* native filesystem (i.e., '/' on unix is native).
*/
int i;
int isVfsPath = 0;
char *path;
/*
* Paths starting with a UNC prefix whose final character is a colon
* are reserved for VFS use. These names can not conflict with real
* UNC paths per https://msdn.microsoft.com/en-us/library/gg465305.aspx
* and rfc3986's definition of reg-name.
*
* We check these first to avoid useless calls to the native filesystem's
* normalizePathProc.
*/
path = Tcl_GetStringFromObj(pathPtr, &i);
if ( (i >= 3) && ( (path[0] == '/' && path[1] == '/')
|| (path[0] == '\\' && path[1] == '\\') ) ) {
for ( i = 2; ; i++) {
if (path[i] == '\0') break;
if (path[i] == path[0]) break;
}
--i;
if (path[i] == ':') isVfsPath = 1;
}
/*
* Call each of the "normalise path" functions in succession.
*/
firstFsRecPtr = FsGetFirstFilesystem();
Claim();
for (fsRecPtr=firstFsRecPtr; fsRecPtr!=NULL; fsRecPtr=fsRecPtr->nextPtr) {
if (fsRecPtr->fsPtr != &tclNativeFilesystem) {
continue;
}
if (!isVfsPath) {
/*
* TODO: Assume that we always find the native file system; it should
* always be there...
* If we have a native filesystem handler, we call it first. This is
* because the root of Tcl's filesystem is always a native filesystem
* (i.e., '/' on unix is native).
*/
if (fsRecPtr->fsPtr->normalizePathProc != NULL) {
startAt = fsRecPtr->fsPtr->normalizePathProc(interp, pathPtr,
startAt);
for (fsRecPtr=firstFsRecPtr; fsRecPtr!=NULL; fsRecPtr=fsRecPtr->nextPtr) {
if (fsRecPtr->fsPtr != &tclNativeFilesystem) {
continue;
}
/*
* TODO: Assume that we always find the native file system; it should
* always be there...
*/
if (fsRecPtr->fsPtr->normalizePathProc != NULL) {
startAt = fsRecPtr->fsPtr->normalizePathProc(interp, pathPtr,
startAt);
}
break;
}
break;
}
for (fsRecPtr=firstFsRecPtr; fsRecPtr!=NULL; fsRecPtr=fsRecPtr->nextPtr) {
@@ -3154,8 +3184,8 @@ Tcl_FSLoadFile(
* present and set to true (any integer > 0) then the unlink is skipped.
*/
int
TclSkipUnlink(
static int
skipUnlink(
Tcl_Obj *shlibFile)
{
/*
@@ -3197,8 +3227,8 @@ TclSkipUnlink(
#ifndef AUFS_SUPER_MAGIC
#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
#endif /* AUFS_SUPER_MAGIC */
if ((statfs(Tcl_GetString (shlibFile), &fs) == 0) &&
(fs.f_type == AUFS_SUPER_MAGIC)) {
if ((statfs(Tcl_GetString(shlibFile), &fs) == 0)
&& (fs.f_type == AUFS_SUPER_MAGIC)) {
return 1;
}
}
@@ -3413,7 +3443,7 @@ Tcl_LoadFile(
* avoids any worries about leaving the copy laying around on exit.
*/
if (!TclSkipUnlink(copyToPtr) &&
if (!skipUnlink(copyToPtr) &&
(Tcl_FSDeleteFile(copyToPtr) == TCL_OK)) {
Tcl_DecrRefCount(copyToPtr);
@@ -3682,30 +3712,10 @@ Tcl_FSUnloadFile(
}
return TCL_ERROR;
}
TclpUnloadFile(handle);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclpUnloadFile --
*
* Unloads a library given its handle
*
* This function was once filesystem-specific, but has been made portable by
* having TclpDlopen return a structure that includes procedure pointers.
*
*----------------------------------------------------------------------
*/
void
TclpUnloadFile(
Tcl_LoadHandle handle)
{
if (handle->unloadFileProcPtr != NULL) {
handle->unloadFileProcPtr(handle);
}
return TCL_OK;
}
/*
+2 -2
View File
@@ -1075,7 +1075,7 @@ declare 9 win {
}
# new for 8.4.20+/8.5.12+ Cygwin only
declare 10 win {
Tcl_DirEntry *TclpReaddir(DIR *dir)
Tcl_DirEntry *TclpReaddir(TclDIR *dir)
}
# Removed in 8.3.1 (for Win32s only):
#declare 10 win {
@@ -1212,7 +1212,7 @@ declare 9 unix {
# Added in 8.4:
declare 10 unix {
Tcl_DirEntry *TclpReaddir(DIR *dir)
Tcl_DirEntry *TclpReaddir(TclDIR *dir)
}
# Slots 11 and 12 are forwarders for functions that were promoted to
# generic Stubs
+110 -39
View File
@@ -38,6 +38,23 @@
#define AVOID_HACKS_FOR_ITCL 1
/*
* Used to tag functions that are only to be visible within the module being
* built and not outside it (where this is supported by the linker).
* Also used in the platform-specific *Port.h files.
*/
#ifndef MODULE_SCOPE
# ifdef __cplusplus
# define MODULE_SCOPE extern "C"
# else
# define MODULE_SCOPE extern
# endif
#endif
/*
* Common include files needed by most of the Tcl source files are included
* here, so that system-dependent personalizations for the include files only
@@ -94,19 +111,6 @@ typedef int ptrdiff_t;
# endif
#endif
/*
* Used to tag functions that are only to be visible within the module being
* built and not outside it (where this is supported by the linker).
*/
#ifndef MODULE_SCOPE
# ifdef __cplusplus
# define MODULE_SCOPE extern "C"
# else
# define MODULE_SCOPE extern
# endif
#endif
/*
* Macros used to cast between pointers and integers (e.g. when storing an int
* in ClientData), on 64-bit architectures they avoid gcc warning about "cast
@@ -136,6 +140,26 @@ typedef int ptrdiff_t;
# define vsnprintf _vsnprintf
#endif
#if !defined(TCL_THREADS)
# define TCL_THREADS 1
#endif
#if !TCL_THREADS
# undef TCL_DECLARE_MUTEX
# define TCL_DECLARE_MUTEX(name)
# undef Tcl_MutexLock
# define Tcl_MutexLock(mutexPtr)
# undef Tcl_MutexUnlock
# define Tcl_MutexUnlock(mutexPtr)
# undef Tcl_MutexFinalize
# define Tcl_MutexFinalize(mutexPtr)
# undef Tcl_ConditionNotify
# define Tcl_ConditionNotify(condPtr)
# undef Tcl_ConditionWait
# define Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
# undef Tcl_ConditionFinalize
# define Tcl_ConditionFinalize(condPtr)
#endif
/*
* The following procedures allow namespaces to be customized to support
* special name resolution rules for commands/variables.
@@ -1146,6 +1170,10 @@ typedef struct CallFrame {
* field contains an Object reference that has
* been confirmed to refer to a class. Part of
* TIP#257. */
#define FRAME_IS_PRIVATE_DEFINE 0x10
/* Marks this frame as being used for private
* declarations with [oo::define]. Usually
* OR'd with FRAME_IS_OO_DEFINE. TIP#500. */
/*
* TIP #280
@@ -2760,6 +2788,10 @@ MODULE_SCOPE long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS];
MODULE_SCOPE char tclEmptyString;
enum CheckEmptyStringResult {
TCL_EMPTYSTRING_UNKNOWN = -1, TCL_EMPTYSTRING_NO, TCL_EMPTYSTRING_YES
};
/*
*----------------------------------------------------------------
* Procedures shared among Tcl modules but not used by the outside world,
@@ -2900,6 +2932,7 @@ MODULE_SCOPE int TclCheckArrayTraces(Tcl_Interp *interp, Var *varPtr,
Var *arrayPtr, Tcl_Obj *name, int index);
MODULE_SCOPE int TclCheckBadOctal(Tcl_Interp *interp,
const char *value);
MODULE_SCOPE int TclCheckEmptyString(Tcl_Obj *objPtr);
MODULE_SCOPE int TclChanCaughtErrorBypass(Tcl_Interp *interp,
Tcl_Channel chan);
MODULE_SCOPE Tcl_ObjCmdProc TclChannelNamesCmd;
@@ -2915,19 +2948,13 @@ MODULE_SCOPE void TclContinuationsCopy(Tcl_Obj *objPtr,
Tcl_Obj *originObjPtr);
MODULE_SCOPE int TclConvertElement(const char *src, int length,
char *dst, int flags);
MODULE_SCOPE Tcl_Command TclCreateObjCommandInNs (
Tcl_Interp *interp,
const char *cmdName,
Tcl_Namespace *nsPtr,
Tcl_ObjCmdProc *proc,
ClientData clientData,
MODULE_SCOPE Tcl_Command TclCreateObjCommandInNs(Tcl_Interp *interp,
const char *cmdName, Tcl_Namespace *nsPtr,
Tcl_ObjCmdProc *proc, ClientData clientData,
Tcl_CmdDeleteProc *deleteProc);
MODULE_SCOPE Tcl_Command TclCreateEnsembleInNs(
Tcl_Interp *interp,
const char *name,
Tcl_Namespace *nameNamespacePtr,
Tcl_Namespace *ensembleNamespacePtr,
int flags);
MODULE_SCOPE Tcl_Command TclCreateEnsembleInNs(Tcl_Interp *interp,
const char *name, Tcl_Namespace *nameNamespacePtr,
Tcl_Namespace *ensembleNamespacePtr, int flags);
MODULE_SCOPE void TclDeleteNamespaceVars(Namespace *nsPtr);
MODULE_SCOPE int TclFindDictElement(Tcl_Interp *interp,
const char *dict, int dictLength,
@@ -2954,9 +2981,9 @@ MODULE_SCOPE char * TclDStringAppendObj(Tcl_DString *dsPtr,
MODULE_SCOPE char * TclDStringAppendDString(Tcl_DString *dsPtr,
Tcl_DString *toAppendPtr);
MODULE_SCOPE Tcl_Obj * TclDStringToObj(Tcl_DString *dsPtr);
MODULE_SCOPE Tcl_Obj *const * TclFetchEnsembleRoot(Tcl_Interp *interp,
MODULE_SCOPE Tcl_Obj *const *TclFetchEnsembleRoot(Tcl_Interp *interp,
Tcl_Obj *const *objv, int objc, int *objcPtr);
MODULE_SCOPE Tcl_Namespace * TclEnsureNamespace(Tcl_Interp *interp,
MODULE_SCOPE Tcl_Namespace *TclEnsureNamespace(Tcl_Interp *interp,
Tcl_Namespace *namespacePtr);
MODULE_SCOPE void TclFinalizeAllocSubsystem(void);
MODULE_SCOPE void TclFinalizeAsync(void);
@@ -2984,15 +3011,11 @@ MODULE_SCOPE double TclFloor(const mp_int *a);
MODULE_SCOPE void TclFormatNaN(double value, char *buffer);
MODULE_SCOPE int TclFSFileAttrIndex(Tcl_Obj *pathPtr,
const char *attributeName, int *indexPtr);
MODULE_SCOPE Tcl_Command TclNRCreateCommandInNs (
Tcl_Interp *interp,
const char *cmdName,
Tcl_Namespace *nsPtr,
Tcl_ObjCmdProc *proc,
Tcl_ObjCmdProc *nreProc,
MODULE_SCOPE Tcl_Command TclNRCreateCommandInNs(Tcl_Interp *interp,
const char *cmdName, Tcl_Namespace *nsPtr,
Tcl_ObjCmdProc *proc, Tcl_ObjCmdProc *nreProc,
ClientData clientData,
Tcl_CmdDeleteProc *deleteProc);
MODULE_SCOPE int TclNREvalFile(Tcl_Interp *interp, Tcl_Obj *pathPtr,
const char *encodingName);
MODULE_SCOPE void TclFSUnloadTempFile(Tcl_LoadHandle loadHandle);
@@ -3018,6 +3041,8 @@ MODULE_SCOPE char * TclGetStringStorage(Tcl_Obj *objPtr,
MODULE_SCOPE int TclGetLoadedPackagesEx(Tcl_Interp *interp,
const char *targetName,
const char *packageName);
MODULE_SCOPE int TclGetWideBitsFromObj(Tcl_Interp *, Tcl_Obj *,
Tcl_WideInt *);
MODULE_SCOPE int TclGlob(Tcl_Interp *interp, char *pattern,
Tcl_Obj *unquotedPrefix, int globFlags,
Tcl_GlobTypeData *types);
@@ -3173,7 +3198,8 @@ MODULE_SCOPE void TclSetBgErrorHandler(Tcl_Interp *interp,
Tcl_Obj *cmdPrefix);
MODULE_SCOPE void TclSetBignumIntRep(Tcl_Obj *objPtr,
mp_int *bignumValue);
MODULE_SCOPE int TclSetBooleanFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
MODULE_SCOPE int TclSetBooleanFromAny(Tcl_Interp *interp,
Tcl_Obj *objPtr);
MODULE_SCOPE void TclSetCmdNameObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
Command *cmdPtr);
MODULE_SCOPE void TclSetDuplicateObj(Tcl_Obj *dupPtr, Tcl_Obj *objPtr);
@@ -3185,6 +3211,12 @@ MODULE_SCOPE void TclSpellFix(Tcl_Interp *interp,
Tcl_Obj *bad, Tcl_Obj *fix);
MODULE_SCOPE void * TclStackRealloc(Tcl_Interp *interp, void *ptr,
int numBytes);
typedef int (*memCmpFn_t)(const void*, const void*, size_t);
MODULE_SCOPE int TclStringCmp(Tcl_Obj *value1Ptr, Tcl_Obj *value2Ptr,
int checkEq, int nocase, int reqlength);
MODULE_SCOPE int TclStringCmpOpts(Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[], int *nocase,
int *reqlength);
MODULE_SCOPE int TclStringMatch(const char *str, int strLen,
const char *pattern, int ptnLen, int flags);
MODULE_SCOPE int TclStringMatchObj(Tcl_Obj *stringObj,
@@ -3206,6 +3238,10 @@ MODULE_SCOPE int TclTrimLeft(const char *bytes, int numBytes,
const char *trim, int numTrim);
MODULE_SCOPE int TclTrimRight(const char *bytes, int numBytes,
const char *trim, int numTrim);
MODULE_SCOPE const char*TclGetCommandTypeName(Tcl_Command command);
MODULE_SCOPE void TclRegisterCommandTypeName(
Tcl_ObjCmdProc *implementationProc,
const char *nameStr);
MODULE_SCOPE int TclUtfCmp(const char *cs, const char *ct);
MODULE_SCOPE int TclUtfCasecmp(const char *cs, const char *ct);
MODULE_SCOPE int TclUtfCount(int ch);
@@ -3229,12 +3265,20 @@ MODULE_SCOPE Tcl_WideInt TclpGetWideClicks(void);
MODULE_SCOPE double TclpWideClicksToNanoseconds(Tcl_WideInt clicks);
#endif
MODULE_SCOPE int TclZlibInit(Tcl_Interp *interp);
MODULE_SCOPE int TclZipfsInit(Tcl_Interp *interp);
MODULE_SCOPE int TclZipfsMount(Tcl_Interp *interp, const char *zipname,
const char *mntpt, const char *passwd);
MODULE_SCOPE int TclZipfsUnmount(Tcl_Interp *interp, const char *zipname);
MODULE_SCOPE void * TclpThreadCreateKey(void);
MODULE_SCOPE void TclpThreadDeleteKey(void *keyPtr);
MODULE_SCOPE void TclpThreadSetMasterTSD(void *tsdKeyPtr, void *ptr);
MODULE_SCOPE void * TclpThreadGetMasterTSD(void *tsdKeyPtr);
MODULE_SCOPE void TclErrorStackResetIf(Tcl_Interp *interp,
const char *msg, int length);
/* Tip 430 */
MODULE_SCOPE int TclZipfs_Init(Tcl_Interp *interp);
MODULE_SCOPE int TclZipfs_SafeInit(Tcl_Interp *interp);
MODULE_SCOPE void TclErrorStackResetIf(Tcl_Interp *interp, const char *msg, int length);
/*
*----------------------------------------------------------------
@@ -4073,6 +4117,19 @@ MODULE_SCOPE TCL_HASH_TYPE TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr);
MODULE_SCOPE int TclFullFinalizationRequested(void);
/*
* Just for the purposes of command-type registration.
*/
MODULE_SCOPE Tcl_ObjCmdProc TclEnsembleImplementationCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclAliasObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclLocalAliasObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclSlaveObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclInvokeImportedCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOPublicObjectCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOPrivateObjectCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOMyClassObjCmd;
/*
* TIP #462.
*/
@@ -4087,7 +4144,7 @@ typedef enum TclProcessWaitStatus {
TCL_PROCESS_EXITED = 1, /* Process has exited. */
TCL_PROCESS_SIGNALED = 2, /* Child killed because of a signal. */
TCL_PROCESS_STOPPED = 3, /* Child suspended because of a signal. */
TCL_PROCESS_UNKNOWN_STATUS = 4
TCL_PROCESS_UNKNOWN_STATUS = 4
/* Child wait status didn't make sense. */
} TclProcessWaitStatus;
@@ -4097,6 +4154,13 @@ MODULE_SCOPE TclProcessWaitStatus TclProcessWait(Tcl_Pid pid, int options,
int *codePtr, Tcl_Obj **msgObjPtr,
Tcl_Obj **errorObjPtr);
/*
* TIP #508: [array default]
*/
MODULE_SCOPE void TclInitArrayVar(Var *arrayPtr);
MODULE_SCOPE Tcl_Obj * TclGetArrayDefault(Var *arrayPtr);
/*
* Utility routines for encoding index values as integers. Used by both
* some of the command compilers and by [lsort] and [lsearch].
@@ -4198,6 +4262,10 @@ typedef const char *TclDTraceStr;
} \
}
#if TCL_THREADS && !defined(USE_THREAD_ALLOC)
# define USE_THREAD_ALLOC 1
#endif
#if defined(PURIFY)
/*
@@ -4215,7 +4283,7 @@ typedef const char *TclDTraceStr;
#undef USE_THREAD_ALLOC
#undef USE_TCLALLOC
#elif defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
#elif TCL_THREADS && defined(USE_THREAD_ALLOC)
/*
* The TCL_THREADS mode is like the regular mode but allocates Tcl_Obj's from
@@ -4280,7 +4348,7 @@ MODULE_SCOPE void TclpFreeAllocCache(void *);
# define USE_TCLALLOC 0
#endif
#ifdef TCL_THREADS
#if TCL_THREADS
/* declared in tclObj.c */
MODULE_SCOPE Tcl_Mutex tclObjMutex;
#endif
@@ -4540,6 +4608,9 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file,
*/
MODULE_SCOPE int TclIsPureByteArray(Tcl_Obj *objPtr);
#define TclIsPureDict(objPtr) \
(((objPtr)->bytes==NULL) && ((objPtr)->typePtr==&tclDictType))
/*
*----------------------------------------------------------------
+6 -11
View File
@@ -13,11 +13,6 @@
#ifndef _TCLINTPLATDECLS
#define _TCLINTPLATDECLS
#ifdef _WIN32
# define Tcl_DirEntry void
# define DIR void
#endif
#undef TCL_STORAGE_CLASS
#ifdef BUILD_tcl
# define TCL_STORAGE_CLASS DLLEXPORT
@@ -72,7 +67,7 @@ EXTERN int TclUnixWaitForFile(int fd, int mask, int timeout);
/* 9 */
EXTERN TclFile TclpCreateTempFile(const char *contents);
/* 10 */
EXTERN Tcl_DirEntry * TclpReaddir(DIR *dir);
EXTERN Tcl_DirEntry * TclpReaddir(TclDIR *dir);
/* 11 */
EXTERN struct tm * TclpLocaltime_unix(const time_t *clock);
/* 12 */
@@ -129,7 +124,7 @@ EXTERN int TclpGetPid(Tcl_Pid pid);
/* 9 */
EXTERN int TclWinGetPlatformId(void);
/* 10 */
EXTERN Tcl_DirEntry * TclpReaddir(DIR *dir);
EXTERN Tcl_DirEntry * TclpReaddir(TclDIR *dir);
/* 11 */
EXTERN void TclGetAndDetachPids(Tcl_Interp *interp,
Tcl_Channel chan);
@@ -206,7 +201,7 @@ EXTERN int TclUnixWaitForFile(int fd, int mask, int timeout);
/* 9 */
EXTERN TclFile TclpCreateTempFile(const char *contents);
/* 10 */
EXTERN Tcl_DirEntry * TclpReaddir(DIR *dir);
EXTERN Tcl_DirEntry * TclpReaddir(TclDIR *dir);
/* 11 */
EXTERN struct tm * TclpLocaltime_unix(const time_t *clock);
/* 12 */
@@ -269,7 +264,7 @@ typedef struct TclIntPlatStubs {
TclFile (*tclpOpenFile) (const char *fname, int mode); /* 7 */
int (*tclUnixWaitForFile) (int fd, int mask, int timeout); /* 8 */
TclFile (*tclpCreateTempFile) (const char *contents); /* 9 */
Tcl_DirEntry * (*tclpReaddir) (DIR *dir); /* 10 */
Tcl_DirEntry * (*tclpReaddir) (TclDIR *dir); /* 10 */
struct tm * (*tclpLocaltime_unix) (const time_t *clock); /* 11 */
struct tm * (*tclpGmtime_unix) (const time_t *clock); /* 12 */
char * (*tclpInetNtoa) (struct in_addr addr); /* 13 */
@@ -302,7 +297,7 @@ typedef struct TclIntPlatStubs {
int (*tclWinSetSockOpt) (SOCKET s, int level, int optname, const char *optval, int optlen); /* 7 */
int (*tclpGetPid) (Tcl_Pid pid); /* 8 */
int (*tclWinGetPlatformId) (void); /* 9 */
Tcl_DirEntry * (*tclpReaddir) (DIR *dir); /* 10 */
Tcl_DirEntry * (*tclpReaddir) (TclDIR *dir); /* 10 */
void (*tclGetAndDetachPids) (Tcl_Interp *interp, Tcl_Channel chan); /* 11 */
int (*tclpCloseFile) (TclFile file); /* 12 */
Tcl_Channel (*tclpCreateCommandChannel) (TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr); /* 13 */
@@ -335,7 +330,7 @@ typedef struct TclIntPlatStubs {
TclFile (*tclpOpenFile) (const char *fname, int mode); /* 7 */
int (*tclUnixWaitForFile) (int fd, int mask, int timeout); /* 8 */
TclFile (*tclpCreateTempFile) (const char *contents); /* 9 */
Tcl_DirEntry * (*tclpReaddir) (DIR *dir); /* 10 */
Tcl_DirEntry * (*tclpReaddir) (TclDIR *dir); /* 10 */
struct tm * (*tclpLocaltime_unix) (const time_t *clock); /* 11 */
struct tm * (*tclpGmtime_unix) (const time_t *clock); /* 12 */
char * (*tclpInetNtoa) (struct in_addr addr); /* 13 */
+90 -20
View File
@@ -222,9 +222,6 @@ static int AliasDelete(Tcl_Interp *interp,
static int AliasDescribe(Tcl_Interp *interp,
Tcl_Interp *slaveInterp, Tcl_Obj *objPtr);
static int AliasList(Tcl_Interp *interp, Tcl_Interp *slaveInterp);
static int AliasObjCmd(ClientData dummy,
Tcl_Interp *currentInterp, int objc,
Tcl_Obj *const objv[]);
static int AliasNRCmd(ClientData dummy,
Tcl_Interp *currentInterp, int objc,
Tcl_Obj *const objv[]);
@@ -257,8 +254,6 @@ static int SlaveInvokeHidden(Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static int SlaveMarkTrusted(Tcl_Interp *interp,
Tcl_Interp *slaveInterp);
static int SlaveObjCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static void SlaveObjCmdDeleteProc(ClientData clientData);
static int SlaveRecursionLimit(Tcl_Interp *interp,
Tcl_Interp *slaveInterp, int objc,
@@ -402,6 +397,7 @@ Tcl_Init(
" set scripts {{set tcl_library}}\n"
" } else {\n"
" set scripts {}\n"
" lappend scripts {zipfs tcl_library}\n"
" if {[info exists env(TCL_LIBRARY)] && ($env(TCL_LIBRARY) ne {})} {\n"
" lappend scripts {set env(TCL_LIBRARY)}\n"
" lappend scripts {\n"
@@ -1418,7 +1414,8 @@ TclPreventAliasLoop(
* create or rename the command.
*/
if (cmdPtr->objProc != AliasObjCmd) {
if (cmdPtr->objProc != TclAliasObjCmd
&& cmdPtr->objProc != TclLocalAliasObjCmd) {
return TCL_OK;
}
@@ -1473,7 +1470,8 @@ TclPreventAliasLoop(
* Otherwise we do not have a loop.
*/
if (aliasCmdPtr->objProc != AliasObjCmd) {
if (aliasCmdPtr->objProc != TclAliasObjCmd
&& aliasCmdPtr->objProc != TclLocalAliasObjCmd) {
return TCL_OK;
}
nextAliasPtr = aliasCmdPtr->objClientData;
@@ -1539,12 +1537,12 @@ AliasCreate(
if (slaveInterp == masterInterp) {
aliasPtr->slaveCmd = Tcl_NRCreateCommand(slaveInterp,
TclGetString(namePtr), AliasObjCmd, AliasNRCmd, aliasPtr,
AliasObjCmdDeleteProc);
TclGetString(namePtr), TclLocalAliasObjCmd, AliasNRCmd,
aliasPtr, AliasObjCmdDeleteProc);
} else {
aliasPtr->slaveCmd = Tcl_CreateObjCommand(slaveInterp,
TclGetString(namePtr), AliasObjCmd, aliasPtr,
AliasObjCmdDeleteProc);
aliasPtr->slaveCmd = Tcl_CreateObjCommand(slaveInterp,
TclGetString(namePtr), TclAliasObjCmd, aliasPtr,
AliasObjCmdDeleteProc);
}
if (TclPreventAliasLoop(interp, slaveInterp,
@@ -1780,7 +1778,7 @@ AliasList(
/*
*----------------------------------------------------------------------
*
* AliasObjCmd --
* TclAliasObjCmd, TclLocalAliasObjCmd --
*
* This is the function that services invocations of aliases in a slave
* interpreter. One such command exists for each alias. When invoked,
@@ -1788,6 +1786,11 @@ AliasList(
* master interpreter as designated by the Alias record associated with
* this command.
*
* TclLocalAliasObjCmd is a stripped down version used when the source
* and target interpreters of the alias are the same. That lets a number
* of safety precautions be avoided: the state is much more precisely
* known.
*
* Results:
* A standard Tcl result.
*
@@ -1847,8 +1850,8 @@ AliasNRCmd(
return Tcl_NREvalObj(interp, listPtr, flags);
}
static int
AliasObjCmd(
int
TclAliasObjCmd(
ClientData clientData, /* Alias record. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
@@ -1937,6 +1940,73 @@ AliasObjCmd(
return result;
#undef ALIAS_CMDV_PREALLOC
}
int
TclLocalAliasObjCmd(
ClientData clientData, /* Alias record. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument vector. */
{
#define ALIAS_CMDV_PREALLOC 10
Alias *aliasPtr = clientData;
int result, prefc, cmdc, i;
Tcl_Obj **prefv, **cmdv;
Tcl_Obj *cmdArr[ALIAS_CMDV_PREALLOC];
Interp *iPtr = (Interp *) interp;
int isRootEnsemble;
/*
* Append the arguments to the command prefix and invoke the command in
* the global namespace.
*/
prefc = aliasPtr->objc;
prefv = &aliasPtr->objPtr;
cmdc = prefc + objc - 1;
if (cmdc <= ALIAS_CMDV_PREALLOC) {
cmdv = cmdArr;
} else {
cmdv = TclStackAlloc(interp, cmdc * sizeof(Tcl_Obj *));
}
memcpy(cmdv, prefv, (size_t) (prefc * sizeof(Tcl_Obj *)));
memcpy(cmdv+prefc, objv+1, (size_t) ((objc-1) * sizeof(Tcl_Obj *)));
for (i=0; i<cmdc; i++) {
Tcl_IncrRefCount(cmdv[i]);
}
/*
* Use the ensemble rewriting machinery to ensure correct error messages:
* only the source command should show, not the full target prefix.
*/
isRootEnsemble = TclInitRewriteEnsemble((Tcl_Interp *)iPtr, 1, prefc, objv);
/*
* Execute the target command in the target interpreter.
*/
result = Tcl_EvalObjv(interp, cmdc, cmdv, TCL_EVAL_INVOKE);
/*
* Clean up the ensemble rewrite info if we set it in the first place.
*/
if (isRootEnsemble) {
TclResetRewriteEnsemble((Tcl_Interp *)iPtr, 1);
}
for (i=0; i<cmdc; i++) {
Tcl_DecrRefCount(cmdv[i]);
}
if (cmdv != cmdArr) {
TclStackFree(interp, cmdv);
}
return result;
#undef ALIAS_CMDV_PREALLOC
}
/*
*----------------------------------------------------------------------
@@ -2376,7 +2446,7 @@ SlaveCreate(
slavePtr->slaveEntryPtr = hPtr;
slavePtr->slaveInterp = slaveInterp;
slavePtr->interpCmd = Tcl_NRCreateCommand(masterInterp, path,
SlaveObjCmd, NRSlaveCmd, slaveInterp, SlaveObjCmdDeleteProc);
TclSlaveObjCmd, NRSlaveCmd, slaveInterp, SlaveObjCmdDeleteProc);
Tcl_InitHashTable(&slavePtr->aliasTable, TCL_STRING_KEYS);
Tcl_SetHashValue(hPtr, slavePtr);
Tcl_SetVar2(slaveInterp, "tcl_interactive", NULL, "0", TCL_GLOBAL_ONLY);
@@ -2444,7 +2514,7 @@ SlaveCreate(
/*
*----------------------------------------------------------------------
*
* SlaveObjCmd --
* TclSlaveObjCmd --
*
* Command to manipulate an interpreter, e.g. to send commands to it to
* be evaluated. One such command exists for each slave interpreter.
@@ -2458,8 +2528,8 @@ SlaveCreate(
*----------------------------------------------------------------------
*/
static int
SlaveObjCmd(
int
TclSlaveObjCmd(
ClientData clientData, /* Slave interpreter. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
@@ -2491,7 +2561,7 @@ NRSlaveCmd(
};
if (slaveInterp == NULL) {
Tcl_Panic("SlaveObjCmd: interpreter has been deleted");
Tcl_Panic("TclSlaveObjCmd: interpreter has been deleted");
}
if (objc < 2) {
+4 -6
View File
@@ -89,8 +89,6 @@ static char * EstablishErrorInfoTraces(ClientData clientData,
static void FreeNsNameInternalRep(Tcl_Obj *objPtr);
static int GetNamespaceFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, Tcl_Namespace **nsPtrPtr);
static int InvokeImportedCmd(ClientData clientData,
Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
static int InvokeImportedNRCmd(ClientData clientData,
Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]);
static int NamespaceChildrenCmd(ClientData dummy,
@@ -1766,7 +1764,7 @@ DoImport(
dataPtr = ckalloc(sizeof(ImportedCmdData));
importedCmd = Tcl_NRCreateCommand(interp, Tcl_DStringValue(&ds),
InvokeImportedCmd, InvokeImportedNRCmd, dataPtr,
TclInvokeImportedCmd, InvokeImportedNRCmd, dataPtr,
DeleteImportedCmd);
dataPtr->realCmdPtr = cmdPtr;
dataPtr->selfPtr = (Command *) importedCmd;
@@ -1987,7 +1985,7 @@ TclGetOriginalCommand(
/*
*----------------------------------------------------------------------
*
* InvokeImportedCmd --
* TclInvokeImportedCmd --
*
* Invoked by Tcl whenever the user calls an imported command that was
* created by Tcl_Import. Finds the "real" command (in another
@@ -2018,8 +2016,8 @@ InvokeImportedNRCmd(
return TclNREvalObjv(interp, objc, objv, TCL_EVAL_NOERR, realCmdPtr);
}
static int
InvokeImportedCmd(
int
TclInvokeImportedCmd(
ClientData clientData, /* Points to the imported command's
* ImportedCmdData structure. */
Tcl_Interp *interp, /* Current interpreter. */
+145 -100
View File
@@ -31,6 +31,7 @@ static const struct {
{"export", TclOODefineExportObjCmd, 0},
{"forward", TclOODefineForwardObjCmd, 0},
{"method", TclOODefineMethodObjCmd, 0},
{"private", TclOODefinePrivateObjCmd, 0},
{"renamemethod", TclOODefineRenameMethodObjCmd, 0},
{"self", TclOODefineSelfObjCmd, 0},
{"unexport", TclOODefineUnexportObjCmd, 0},
@@ -41,6 +42,7 @@ static const struct {
{"export", TclOODefineExportObjCmd, 1},
{"forward", TclOODefineForwardObjCmd, 1},
{"method", TclOODefineMethodObjCmd, 1},
{"private", TclOODefinePrivateObjCmd, 1},
{"renamemethod", TclOODefineRenameMethodObjCmd, 1},
{"self", TclOODefineObjSelfObjCmd, 0},
{"unexport", TclOODefineUnexportObjCmd, 1},
@@ -88,18 +90,16 @@ static inline void RemoveClass(Class **list, int num, int idx);
static inline void RemoveObject(Object **list, int num, int idx);
static inline void SquelchCachedName(Object *oPtr);
static int PublicObjectCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const *objv);
static int PublicNRObjectCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const *objv);
static int PrivateObjectCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const *objv);
static int PrivateNRObjectCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const *objv);
static int MyClassNRObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const *objv);
static void MyClassDeleted(ClientData clientData);
/*
* Methods in the oo::object and oo::class classes. First, we define a helper
@@ -150,65 +150,10 @@ static const char *initScript =
/* " tcloo.tcl OO_LIBRARY oo::library;"; */
/*
* The scripted part of the definitions of slots.
* The scripted part of the definitions of TclOO.
*/
static const char *slotScript =
"::oo::define ::oo::Slot {\n"
" method Get {} {error unimplemented}\n"
" method Set list {error unimplemented}\n"
" method -set args {\n"
" uplevel 1 [list [namespace which my] Set $args]\n"
" }\n"
" method -append args {\n"
" uplevel 1 [list [namespace which my] Set [list"
" {*}[uplevel 1 [list [namespace which my] Get]] {*}$args]]\n"
" }\n"
" method -clear {} {uplevel 1 [list [namespace which my] Set {}]}\n"
" forward --default-operation my -append\n"
" method unknown {args} {\n"
" set def --default-operation\n"
" if {[llength $args] == 0} {\n"
" return [uplevel 1 [list [namespace which my] $def]]\n"
" } elseif {![string match -* [lindex $args 0]]} {\n"
" return [uplevel 1 [list [namespace which my] $def {*}$args]]\n"
" }\n"
" next {*}$args\n"
" }\n"
" export -set -append -clear\n"
" unexport unknown destroy\n"
"}\n"
"::oo::objdefine ::oo::define::superclass forward --default-operation my -set\n"
"::oo::objdefine ::oo::define::mixin forward --default-operation my -set\n"
"::oo::objdefine ::oo::objdefine::mixin forward --default-operation my -set\n";
/*
* The body of the <cloned> method of oo::object.
*/
static const char *clonedBody =
"foreach p [info procs [info object namespace $originObject]::*] {"
" set args [info args $p];"
" set idx -1;"
" foreach a $args {"
" lset args [incr idx] "
" [if {[info default $p $a d]} {list $a $d} {list $a}]"
" };"
" set b [info body $p];"
" set p [namespace tail $p];"
" proc $p $args $b;"
"};"
"foreach v [info vars [info object namespace $originObject]::*] {"
" upvar 0 $v vOrigin;"
" namespace upvar [namespace current] [namespace tail $v] vNew;"
" if {[info exists vOrigin]} {"
" if {[array exists vOrigin]} {"
" array set vNew [array get vOrigin];"
" } else {"
" set vNew $vOrigin;"
" }"
" }"
"}";
#include "tclOOScript.h"
/*
* The actual definition of the variable holding the TclOO stub table.
@@ -358,7 +303,7 @@ InitFoundation(
ThreadLocalData *tsdPtr =
Tcl_GetThreadData(&tsdKey, sizeof(ThreadLocalData));
Foundation *fPtr = ckalloc(sizeof(Foundation));
Tcl_Obj *namePtr, *argsPtr, *bodyPtr;
Tcl_Obj *namePtr;
Tcl_DString buffer;
Command *cmdPtr;
int i;
@@ -437,18 +382,6 @@ InitFoundation(
TclOONewBasicMethod(interp, fPtr->classCls, &clsMethods[i]);
}
/*
* Create the default <cloned> method implementation, used when 'oo::copy'
* is called to finish the copying of one object to another.
*/
TclNewLiteralStringObj(argsPtr, "originObject");
Tcl_IncrRefCount(argsPtr);
bodyPtr = Tcl_NewStringObj(clonedBody, -1);
TclOONewProcMethod(interp, fPtr->objectCls, 0, fPtr->clonedName, argsPtr,
bodyPtr, NULL);
TclDecrRefCount(argsPtr);
/*
* Finish setting up the class of classes by marking the 'new' method as
* private; classes, unlike general objects, must have explicit names. We
@@ -489,7 +422,12 @@ InitFoundation(
if (TclOODefineSlots(fPtr) != TCL_OK) {
return TCL_ERROR;
}
return Tcl_EvalEx(interp, slotScript, -1, 0);
/*
* Evaluate the remaining definitions, which are a compiled-in Tcl script.
*/
return Tcl_EvalEx(interp, tclOOSetupScript, -1, 0);
}
/*
@@ -774,10 +712,9 @@ AllocObject(
if (nsPtr->parentPtr != NULL) {
nsPtr = nsPtr->parentPtr;
}
}
oPtr->command = TclCreateObjCommandInNs(interp, nameStr,
(Tcl_Namespace *)nsPtr, PublicObjectCmd, oPtr, NULL);
(Tcl_Namespace *)nsPtr, TclOOPublicObjectCmd, oPtr, NULL);
/*
* Add the NRE command and trace directly. While this breaks a number of
@@ -794,7 +731,10 @@ AllocObject(
tracePtr->refCount = 1;
oPtr->myCommand = TclNRCreateCommandInNs(interp, "my", oPtr->namespacePtr,
PrivateObjectCmd, PrivateNRObjectCmd, oPtr, MyDeleted);
TclOOPrivateObjectCmd, PrivateNRObjectCmd, oPtr, MyDeleted);
oPtr->myclassCommand = TclNRCreateCommandInNs(interp, "myclass",
oPtr->namespacePtr, TclOOMyClassObjCmd, MyClassNRObjCmd, oPtr,
MyClassDeleted);
return oPtr;
}
@@ -822,12 +762,12 @@ SquelchCachedName(
/*
* ----------------------------------------------------------------------
*
* MyDeleted --
* MyDeleted, MyClassDeleted --
*
* This callback is triggered when the object's [my] command is deleted
* by any mechanism. It just marks the object as not having a [my]
* command, and so prevents cleanup of that when the object itself is
* deleted.
* These callbacks are triggered when the object's [my] or [myclass]
* commands are deleted by any mechanism. They just mark the object as
* not having a [my] command or [myclass] command, and so prevent cleanup
* of those commands when the object itself is deleted.
*
* ----------------------------------------------------------------------
*/
@@ -841,6 +781,14 @@ MyDeleted(
oPtr->myCommand = NULL;
}
static void
MyClassDeleted(
ClientData clientData)
{
Object *oPtr = clientData;
oPtr->myclassCommand = NULL;
}
/*
* ----------------------------------------------------------------------
@@ -993,6 +941,7 @@ ReleaseClassContents(
Method *mPtr;
Foundation *fPtr = oPtr->fPtr;
Tcl_Obj *variableObj;
PrivateVariableMapping *privateVariable;
/*
* Sanity check!
@@ -1099,6 +1048,14 @@ ReleaseClassContents(
ckfree(clsPtr->variables.list);
}
FOREACH_STRUCT(privateVariable, clsPtr->privateVariables) {
TclDecrRefCount(privateVariable->variableObj);
TclDecrRefCount(privateVariable->fullNameObj);
}
if (i) {
ckfree(clsPtr->privateVariables.list);
}
if (IsRootClass(oPtr) && !Deleted(fPtr->objectCls->thisPtr)) {
Tcl_DeleteCommandFromToken(interp, fPtr->objectCls->thisPtr->command);
}
@@ -1128,6 +1085,7 @@ ObjectNamespaceDeleted(
Class *mixinPtr;
Method *mPtr;
Tcl_Obj *filterObj, *variableObj;
PrivateVariableMapping *privateVariable;
Tcl_Interp *interp = oPtr->fPtr->interp;
int i;
@@ -1162,7 +1120,7 @@ ObjectNamespaceDeleted(
if (!Tcl_InterpDeleted(interp) && !(oPtr->flags & DESTRUCTOR_CALLED)) {
CallContext *contextPtr =
TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL);
TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL, NULL, NULL);
int result;
Tcl_InterpState state;
@@ -1203,6 +1161,9 @@ ObjectNamespaceDeleted(
Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->command);
}
if (oPtr->myclassCommand) {
Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->myclassCommand);
}
if (oPtr->myCommand) {
Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->myCommand);
}
@@ -1248,6 +1209,14 @@ ObjectNamespaceDeleted(
ckfree(oPtr->variables.list);
}
FOREACH_STRUCT(privateVariable, oPtr->privateVariables) {
TclDecrRefCount(privateVariable->variableObj);
TclDecrRefCount(privateVariable->fullNameObj);
}
if (i) {
ckfree(oPtr->privateVariables.list);
}
if (oPtr->chainCache) {
TclOODeleteChainCache(oPtr->chainCache);
}
@@ -1631,7 +1600,7 @@ Tcl_NewObjectInstance(
if (objc >= 0) {
CallContext *contextPtr =
TclOOGetCallContext(oPtr, NULL, CONSTRUCTOR, NULL);
TclOOGetCallContext(oPtr, NULL, CONSTRUCTOR, NULL, NULL, NULL);
if (contextPtr != NULL) {
int isRoot, result;
@@ -1704,7 +1673,7 @@ TclNRNewObjectInstance(
*objectPtr = (Tcl_Object) oPtr;
return TCL_OK;
}
contextPtr = TclOOGetCallContext(oPtr, NULL, CONSTRUCTOR, NULL);
contextPtr = TclOOGetCallContext(oPtr, NULL, CONSTRUCTOR, NULL, NULL, NULL);
if (contextPtr == NULL) {
*objectPtr = (Tcl_Object) oPtr;
return TCL_OK;
@@ -1884,6 +1853,7 @@ Tcl_CopyObjectInstance(
Class *mixinPtr;
CallContext *contextPtr;
Tcl_Obj *keyPtr, *filterObj, *variableObj, *args[3];
PrivateVariableMapping *privateVariable;
int i, result;
/*
@@ -1953,7 +1923,7 @@ Tcl_CopyObjectInstance(
}
/*
* Copy the object's variable resolution list to the new object.
* Copy the object's variable resolution lists to the new object.
*/
DUPLICATE(o2Ptr->variables, oPtr->variables, Tcl_Obj *);
@@ -1961,6 +1931,13 @@ Tcl_CopyObjectInstance(
Tcl_IncrRefCount(variableObj);
}
DUPLICATE(o2Ptr->privateVariables, oPtr->privateVariables,
PrivateVariableMapping);
FOREACH_STRUCT(privateVariable, o2Ptr->privateVariables) {
Tcl_IncrRefCount(privateVariable->variableObj);
Tcl_IncrRefCount(privateVariable->fullNameObj);
}
/*
* Copy the object's flags to the new object, clearing those that must be
* kept object-local. The duplicate is never deleted at this point, nor is
@@ -2049,7 +2026,7 @@ Tcl_CopyObjectInstance(
}
/*
* Copy the source class's variable resolution list.
* Copy the source class's variable resolution lists.
*/
DUPLICATE(cls2Ptr->variables, clsPtr->variables, Tcl_Obj *);
@@ -2057,6 +2034,13 @@ Tcl_CopyObjectInstance(
Tcl_IncrRefCount(variableObj);
}
DUPLICATE(cls2Ptr->privateVariables, clsPtr->privateVariables,
PrivateVariableMapping);
FOREACH_STRUCT(privateVariable, cls2Ptr->privateVariables) {
Tcl_IncrRefCount(privateVariable->variableObj);
Tcl_IncrRefCount(privateVariable->fullNameObj);
}
/*
* Duplicate the source class's mixins (which cannot be circular
* references to the duplicate).
@@ -2129,7 +2113,8 @@ Tcl_CopyObjectInstance(
}
TclResetRewriteEnsemble(interp, 1);
contextPtr = TclOOGetCallContext(o2Ptr, oPtr->fPtr->clonedName, 0, NULL);
contextPtr = TclOOGetCallContext(o2Ptr, oPtr->fPtr->clonedName, 0, NULL,
NULL, NULL);
if (contextPtr) {
args[0] = TclOOObjectName(interp, o2Ptr);
args[1] = oPtr->fPtr->clonedName;
@@ -2417,7 +2402,7 @@ Tcl_ObjectSetMetadata(
/*
* ----------------------------------------------------------------------
*
* PublicObjectCmd, PrivateObjectCmd, TclOOInvokeObject --
* TclOOPublicObjectCmd, TclOOPrivateObjectCmd, TclOOInvokeObject --
*
* Main entry point for object invocations. The Public* and Private*
* wrapper functions (implementations of both object instance commands
@@ -2427,8 +2412,8 @@ Tcl_ObjectSetMetadata(
* ----------------------------------------------------------------------
*/
static int
PublicObjectCmd(
int
TclOOPublicObjectCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -2448,8 +2433,8 @@ PublicNRObjectCmd(
NULL);
}
static int
PrivateObjectCmd(
int
TclOOPrivateObjectCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -2499,6 +2484,43 @@ TclOOInvokeObject(
}
}
/*
* ----------------------------------------------------------------------
*
* TclOOMyClassObjCmd, MyClassNRObjCmd --
*
* Special trap door to allow an object to delegate simply to its class.
*
* ----------------------------------------------------------------------
*/
int
TclOOMyClassObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
return Tcl_NRCallObjProc(interp, MyClassNRObjCmd, clientData, objc, objv);
}
static int
MyClassNRObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = clientData;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "methodName ?arg ...?");
return TCL_ERROR;
}
return TclOOObjectCmdCore(oPtr->selfCls->thisPtr, interp, objc, objv, 0,
NULL);
}
/*
* ----------------------------------------------------------------------
*
@@ -2526,6 +2548,9 @@ TclOOObjectCmdCore(
{
CallContext *contextPtr;
Tcl_Obj *methodNamePtr;
CallFrame *framePtr = ((Interp *) interp)->varFramePtr;
Object *callerObjPtr = NULL;
Class *callerClsPtr = NULL;
int result;
/*
@@ -2539,6 +2564,24 @@ TclOOObjectCmdCore(
goto noMapping;
}
/*
* Determine if we're in a context that can see the extra, private methods
* in this class.
*/
if (framePtr->isProcCallFrame & FRAME_IS_METHOD) {
CallContext *callerContextPtr = framePtr->clientData;
Method *callerMethodPtr =
callerContextPtr->callPtr->chain[callerContextPtr->index].mPtr;
if (callerMethodPtr->declaringObjectPtr) {
callerObjPtr = callerMethodPtr->declaringObjectPtr;
}
if (callerMethodPtr->declaringClassPtr) {
callerClsPtr = callerMethodPtr->declaringClassPtr;
}
}
/*
* Give plugged in code a chance to remap the method name.
*/
@@ -2566,7 +2609,8 @@ TclOOObjectCmdCore(
Tcl_IncrRefCount(mappedMethodName);
contextPtr = TclOOGetCallContext(oPtr, mappedMethodName,
flags | (oPtr->flags & FILTER_HANDLING), methodNamePtr);
flags | (oPtr->flags & FILTER_HANDLING), callerObjPtr,
callerClsPtr, methodNamePtr);
TclDecrRefCount(mappedMethodName);
if (contextPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
@@ -2583,7 +2627,8 @@ TclOOObjectCmdCore(
noMapping:
contextPtr = TclOOGetCallContext(oPtr, methodNamePtr,
flags | (oPtr->flags & FILTER_HANDLING), NULL);
flags | (oPtr->flags & FILTER_HANDLING), callerObjPtr,
callerClsPtr, NULL);
if (contextPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"impossible to invoke method \"%s\": no defined method or"
@@ -2833,9 +2878,9 @@ Tcl_GetObjectFromObj(
if (cmdPtr == NULL) {
goto notAnObject;
}
if (cmdPtr->objProc != PublicObjectCmd) {
if (cmdPtr->objProc != TclOOPublicObjectCmd) {
cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
if (cmdPtr == NULL || cmdPtr->objProc != PublicObjectCmd) {
if (cmdPtr == NULL || cmdPtr->objProc != TclOOPublicObjectCmd) {
goto notAnObject;
}
}
+5 -2
View File
@@ -58,12 +58,12 @@ declare 10 {
}
declare 11 {
Tcl_Method Tcl_NewInstanceMethod(Tcl_Interp *interp, Tcl_Object object,
Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr,
Tcl_Obj *nameObj, int flags, const Tcl_MethodType *typePtr,
ClientData clientData)
}
declare 12 {
Tcl_Method Tcl_NewMethod(Tcl_Interp *interp, Tcl_Class cls,
Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr,
Tcl_Obj *nameObj, int flags, const Tcl_MethodType *typePtr,
ClientData clientData)
}
declare 13 {
@@ -126,6 +126,9 @@ declare 27 {
declare 28 {
Tcl_Obj *Tcl_GetObjectName(Tcl_Interp *interp, Tcl_Object object)
}
declare 29 {
int Tcl_MethodIsPrivate(Tcl_Method method)
}
######################################################################
# Private API, exposed to support advanced OO systems that plug in on top of
+9
View File
@@ -99,6 +99,15 @@ typedef struct {
*/
#define TCL_OO_METHOD_VERSION_CURRENT 1
/*
* Visibility constants for the flags parameter to Tcl_NewMethod and
* Tcl_NewInstanceMethod.
*/
#define TCL_OO_METHOD_PUBLIC 1
#define TCL_OO_METHOD_UNEXPORTED 0
#define TCL_OO_METHOD_PRIVATE 0x20
/*
* The type of some object (or class) metadata. This describes how to delete
+113 -19
View File
@@ -83,7 +83,7 @@ TclOO_Class_Constructor(
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
Tcl_Obj **invoke;
Tcl_Obj **invoke, *nameObj;
if (objc-1 > Tcl_ObjectContextSkippedArgs(context)) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
@@ -93,6 +93,17 @@ TclOO_Class_Constructor(
return TCL_OK;
}
/*
* Make the class definition delegate. This is special; it doesn't reenter
* here (and the class definition delegate doesn't run any constructors).
*/
nameObj = Tcl_NewStringObj(oPtr->namespacePtr->fullName, -1);
Tcl_AppendToObj(nameObj, ":: oo ::delegate", -1);
Tcl_NewObjectInstance(interp, (Tcl_Class) oPtr->fPtr->classCls,
TclGetString(nameObj), NULL, -1, NULL, -1);
Tcl_DecrRefCount(nameObj);
/*
* Delegate to [oo::define] to do the work.
*/
@@ -111,7 +122,7 @@ TclOO_Class_Constructor(
Tcl_IncrRefCount(invoke[1]);
Tcl_IncrRefCount(invoke[2]);
TclNRAddCallback(interp, DecrRefsPostClassConstructor,
invoke, NULL, NULL, NULL);
invoke, oPtr, NULL, NULL);
/*
* Tricky point: do not want the extra reported level in the Tcl stack
@@ -128,12 +139,27 @@ DecrRefsPostClassConstructor(
int result)
{
Tcl_Obj **invoke = data[0];
Object *oPtr = data[1];
Tcl_InterpState saved;
int code;
TclDecrRefCount(invoke[0]);
TclDecrRefCount(invoke[1]);
TclDecrRefCount(invoke[2]);
invoke[0] = Tcl_NewStringObj("::oo::MixinClassDelegates", -1);
invoke[1] = TclOOObjectName(interp, oPtr);
Tcl_IncrRefCount(invoke[0]);
Tcl_IncrRefCount(invoke[1]);
saved = Tcl_SaveInterpState(interp, result);
code = Tcl_EvalObjv(interp, 2, invoke, 0);
TclDecrRefCount(invoke[0]);
TclDecrRefCount(invoke[1]);
ckfree(invoke);
return result;
if (code != TCL_OK) {
Tcl_DiscardInterpState(saved);
return code;
}
return Tcl_RestoreInterpState(interp, saved);
}
/*
@@ -347,7 +373,8 @@ TclOO_Object_Destroy(
}
if (!(oPtr->flags & DESTRUCTOR_CALLED)) {
oPtr->flags |= DESTRUCTOR_CALLED;
contextPtr = TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL);
contextPtr = TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL, NULL,
NULL);
if (contextPtr != NULL) {
contextPtr->callPtr->flags |= DESTRUCTOR;
contextPtr->skip = 0;
@@ -499,9 +526,12 @@ TclOO_Object_Unknown(
Tcl_Obj *const *objv) /* The actual arguments. */
{
CallContext *contextPtr = (CallContext *) context;
Object *callerObj = NULL;
Class *callerCls = NULL;
Object *oPtr = contextPtr->oPtr;
const char **methodNames;
int numMethodNames, i, skip = Tcl_ObjectContextSkippedArgs(context);
CallFrame *framePtr = ((Interp *) interp)->varFramePtr;
Tcl_Obj *errorMsg;
/*
@@ -515,11 +545,32 @@ TclOO_Object_Unknown(
return TCL_ERROR;
}
/*
* Determine if the calling context should know about extra private
* methods, and if so, which.
*/
if (framePtr->isProcCallFrame & FRAME_IS_METHOD) {
CallContext *callerContext = framePtr->clientData;
Method *mPtr = callerContext->callPtr->chain[
callerContext->index].mPtr;
if (mPtr->declaringObjectPtr) {
if (oPtr == mPtr->declaringObjectPtr) {
callerObj = mPtr->declaringObjectPtr;
}
} else {
if (TclOOIsReachable(mPtr->declaringClassPtr, oPtr->selfCls)) {
callerCls = mPtr->declaringClassPtr;
}
}
}
/*
* Get the list of methods that we want to know about.
*/
numMethodNames = TclOOGetSortedMethodList(oPtr,
numMethodNames = TclOOGetSortedMethodList(oPtr, callerObj, callerCls,
contextPtr->callPtr->flags & PUBLIC_METHOD, &methodNames);
/*
@@ -684,6 +735,7 @@ TclOO_Object_VarName(
{
Var *varPtr, *aryVar;
Tcl_Obj *varNamePtr, *argPtr;
CallFrame *framePtr = ((Interp *) interp)->varFramePtr;
const char *arg;
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
@@ -709,6 +761,58 @@ TclOO_Object_VarName(
Tcl_Namespace *namespacePtr =
Tcl_GetObjectNamespace(Tcl_ObjectContextObject(context));
/*
* Private method handling. [TIP 500]
*
* If we're in a context that can see some private methods of an
* object, we may need to precede a variable name with its prefix.
* This is a little tricky as we need to check through the inheritance
* hierarchy when the method was declared by a class to see if the
* current object is an instance of that class.
*/
if (framePtr->isProcCallFrame & FRAME_IS_METHOD) {
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
CallContext *callerContext = framePtr->clientData;
Method *mPtr = callerContext->callPtr->chain[
callerContext->index].mPtr;
PrivateVariableMapping *pvPtr;
int i;
if (mPtr->declaringObjectPtr == oPtr) {
FOREACH_STRUCT(pvPtr, oPtr->privateVariables) {
if (!strcmp(Tcl_GetString(pvPtr->variableObj),
Tcl_GetString(argPtr))) {
argPtr = pvPtr->fullNameObj;
break;
}
}
} else if (mPtr->declaringClassPtr &&
mPtr->declaringClassPtr->privateVariables.num) {
Class *clsPtr = mPtr->declaringClassPtr;
int isInstance = TclOOIsReachable(clsPtr, oPtr->selfCls);
Class *mixinCls;
if (!isInstance) {
FOREACH(mixinCls, oPtr->mixins) {
if (TclOOIsReachable(clsPtr, mixinCls)) {
isInstance = 1;
break;
}
}
}
if (isInstance) {
FOREACH_STRUCT(pvPtr, clsPtr->privateVariables) {
if (!strcmp(Tcl_GetString(pvPtr->variableObj),
Tcl_GetString(argPtr))) {
argPtr = pvPtr->fullNameObj;
break;
}
}
}
}
}
varNamePtr = Tcl_NewStringObj(namespacePtr->fullName, -1);
Tcl_AppendToObj(varNamePtr, "::", 2);
Tcl_AppendObjToObj(varNamePtr, argPtr);
@@ -729,26 +833,16 @@ TclOO_Object_VarName(
varNamePtr = Tcl_NewObj();
if (aryVar != NULL) {
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
Tcl_GetVariableFullName(interp, (Tcl_Var) aryVar, varNamePtr);
/*
* WARNING! This code pokes inside the implementation of hash tables!
*/
hPtr = Tcl_FirstHashEntry((Tcl_HashTable *) aryVar->value.tablePtr,
&search);
while (hPtr != NULL) {
if (varPtr == Tcl_GetHashValue(hPtr)) {
Tcl_AppendToObj(varNamePtr, "(", -1);
Tcl_AppendObjToObj(varNamePtr, hPtr->key.objPtr);
Tcl_AppendToObj(varNamePtr, ")", -1);
break;
}
hPtr = Tcl_NextHashEntry(&search);
}
Tcl_AppendToObj(varNamePtr, "(", -1);
Tcl_AppendObjToObj(varNamePtr, ((VarInHash *)
varPtr)->entry.key.objPtr);
Tcl_AppendToObj(varNamePtr, ")", -1);
} else {
Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, varNamePtr);
}
+470 -212
View File
File diff suppressed because it is too large Load Diff
+9 -4
View File
@@ -59,11 +59,11 @@ TCLAPI Tcl_Obj * Tcl_MethodName(Tcl_Method method);
/* 11 */
TCLAPI Tcl_Method Tcl_NewInstanceMethod(Tcl_Interp *interp,
Tcl_Object object, Tcl_Obj *nameObj,
int isPublic, const Tcl_MethodType *typePtr,
int flags, const Tcl_MethodType *typePtr,
ClientData clientData);
/* 12 */
TCLAPI Tcl_Method Tcl_NewMethod(Tcl_Interp *interp, Tcl_Class cls,
Tcl_Obj *nameObj, int isPublic,
Tcl_Obj *nameObj, int flags,
const Tcl_MethodType *typePtr,
ClientData clientData);
/* 13 */
@@ -116,6 +116,8 @@ TCLAPI void Tcl_ClassSetDestructor(Tcl_Interp *interp,
/* 28 */
TCLAPI Tcl_Obj * Tcl_GetObjectName(Tcl_Interp *interp,
Tcl_Object object);
/* 29 */
TCLAPI int Tcl_MethodIsPrivate(Tcl_Method method);
typedef struct {
const struct TclOOIntStubs *tclOOIntStubs;
@@ -136,8 +138,8 @@ typedef struct TclOOStubs {
int (*tcl_MethodIsPublic) (Tcl_Method method); /* 8 */
int (*tcl_MethodIsType) (Tcl_Method method, const Tcl_MethodType *typePtr, ClientData *clientDataPtr); /* 9 */
Tcl_Obj * (*tcl_MethodName) (Tcl_Method method); /* 10 */
Tcl_Method (*tcl_NewInstanceMethod) (Tcl_Interp *interp, Tcl_Object object, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, ClientData clientData); /* 11 */
Tcl_Method (*tcl_NewMethod) (Tcl_Interp *interp, Tcl_Class cls, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, ClientData clientData); /* 12 */
Tcl_Method (*tcl_NewInstanceMethod) (Tcl_Interp *interp, Tcl_Object object, Tcl_Obj *nameObj, int flags, const Tcl_MethodType *typePtr, ClientData clientData); /* 11 */
Tcl_Method (*tcl_NewMethod) (Tcl_Interp *interp, Tcl_Class cls, Tcl_Obj *nameObj, int flags, const Tcl_MethodType *typePtr, ClientData clientData); /* 12 */
Tcl_Object (*tcl_NewObjectInstance) (Tcl_Interp *interp, Tcl_Class cls, const char *nameStr, const char *nsNameStr, int objc, Tcl_Obj *const *objv, int skip); /* 13 */
int (*tcl_ObjectDeleted) (Tcl_Object object); /* 14 */
int (*tcl_ObjectContextIsFiltering) (Tcl_ObjectContext context); /* 15 */
@@ -154,6 +156,7 @@ typedef struct TclOOStubs {
void (*tcl_ClassSetConstructor) (Tcl_Interp *interp, Tcl_Class clazz, Tcl_Method method); /* 26 */
void (*tcl_ClassSetDestructor) (Tcl_Interp *interp, Tcl_Class clazz, Tcl_Method method); /* 27 */
Tcl_Obj * (*tcl_GetObjectName) (Tcl_Interp *interp, Tcl_Object object); /* 28 */
int (*tcl_MethodIsPrivate) (Tcl_Method method); /* 29 */
} TclOOStubs;
extern const TclOOStubs *tclOOStubsPtr;
@@ -226,6 +229,8 @@ extern const TclOOStubs *tclOOStubsPtr;
(tclOOStubsPtr->tcl_ClassSetDestructor) /* 27 */
#define Tcl_GetObjectName \
(tclOOStubsPtr->tcl_GetObjectName) /* 28 */
#define Tcl_MethodIsPrivate \
(tclOOStubsPtr->tcl_MethodIsPrivate) /* 29 */
#endif /* defined(USE_TCLOO_STUBS) */
+359 -173
View File
@@ -16,6 +16,12 @@
#include "tclInt.h"
#include "tclOOInt.h"
/*
* The actual value used to mark private declaration frames.
*/
#define PRIVATE_FRAME (FRAME_IS_OO_DEFINE | FRAME_IS_PRIVATE_DEFINE)
/*
* The maximum length of fully-qualified object name to use in an errorinfo
* message. Longer than this will be curtailed.
@@ -31,14 +37,17 @@ struct DeclaredSlot {
const char *name;
const Tcl_MethodType getterType;
const Tcl_MethodType setterType;
const Tcl_MethodType resolverType;
};
#define SLOT(name,getter,setter) \
#define SLOT(name,getter,setter,resolver) \
{"::oo::" name, \
{TCL_OO_METHOD_VERSION_CURRENT, "core method: " name " Getter", \
getter, NULL, NULL}, \
{TCL_OO_METHOD_VERSION_CURRENT, "core method: " name " Setter", \
setter, NULL, NULL}}
setter, NULL, NULL}, \
{TCL_OO_METHOD_VERSION_CURRENT, "core method: " name " Resolver", \
resolver, NULL, NULL}}
/*
* Forward declarations.
@@ -103,21 +112,53 @@ static int ObjVarsGet(ClientData clientData,
static int ObjVarsSet(ClientData clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ResolveClass(ClientData clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
/*
* Now define the slots used in declarations.
*/
static const struct DeclaredSlot slots[] = {
SLOT("define::filter", ClassFilterGet, ClassFilterSet),
SLOT("define::mixin", ClassMixinGet, ClassMixinSet),
SLOT("define::superclass", ClassSuperGet, ClassSuperSet),
SLOT("define::variable", ClassVarsGet, ClassVarsSet),
SLOT("objdefine::filter", ObjFilterGet, ObjFilterSet),
SLOT("objdefine::mixin", ObjMixinGet, ObjMixinSet),
SLOT("objdefine::variable", ObjVarsGet, ObjVarsSet),
{NULL, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}
SLOT("define::filter", ClassFilterGet, ClassFilterSet, NULL),
SLOT("define::mixin", ClassMixinGet, ClassMixinSet, ResolveClass),
SLOT("define::superclass", ClassSuperGet, ClassSuperSet, ResolveClass),
SLOT("define::variable", ClassVarsGet, ClassVarsSet, NULL),
SLOT("objdefine::filter", ObjFilterGet, ObjFilterSet, NULL),
SLOT("objdefine::mixin", ObjMixinGet, ObjMixinSet, ResolveClass),
SLOT("objdefine::variable", ObjVarsGet, ObjVarsSet, NULL),
{NULL, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}
};
/*
* How to build the in-namespace name of a private variable. This is a pattern
* used with Tcl_ObjPrintf().
*/
#define PRIVATE_VARIABLE_PATTERN "%d : %s"
/*
* ----------------------------------------------------------------------
*
* IsPrivateDefine --
*
* Extracts whether the current context is handling private definitions.
*
* ----------------------------------------------------------------------
*/
static inline int
IsPrivateDefine(
Tcl_Interp *interp)
{
Interp *iPtr = (Interp *) interp;
if (!iPtr->varFramePtr) {
return 0;
}
return iPtr->varFramePtr->isProcCallFrame == PRIVATE_FRAME;
}
/*
* ----------------------------------------------------------------------
@@ -416,6 +457,123 @@ TclOOClassSetMixins(
BumpGlobalEpoch(interp, classPtr);
}
/*
* ----------------------------------------------------------------------
*
* InstallStandardVariableMapping, InstallPrivateVariableMapping --
*
* Helpers for installing standard and private variable maps.
*
* ----------------------------------------------------------------------
*/
static inline void
InstallStandardVariableMapping(
VariableNameList *vnlPtr,
int varc,
Tcl_Obj *const *varv)
{
Tcl_Obj *variableObj;
int i, n, created;
Tcl_HashTable uniqueTable;
for (i=0 ; i<varc ; i++) {
Tcl_IncrRefCount(varv[i]);
}
FOREACH(variableObj, *vnlPtr) {
Tcl_DecrRefCount(variableObj);
}
if (i != varc) {
if (varc == 0) {
ckfree(vnlPtr->list);
} else if (i) {
vnlPtr->list = ckrealloc(vnlPtr->list, sizeof(Tcl_Obj *) * varc);
} else {
vnlPtr->list = ckalloc(sizeof(Tcl_Obj *) * varc);
}
}
vnlPtr->num = 0;
if (varc > 0) {
Tcl_InitObjHashTable(&uniqueTable);
for (i=n=0 ; i<varc ; i++) {
Tcl_CreateHashEntry(&uniqueTable, varv[i], &created);
if (created) {
vnlPtr->list[n++] = varv[i];
} else {
Tcl_DecrRefCount(varv[i]);
}
}
vnlPtr->num = n;
/*
* Shouldn't be necessary, but maintain num/list invariant.
*/
if (n != varc) {
vnlPtr->list = ckrealloc(vnlPtr->list, sizeof(Tcl_Obj *) * n);
}
Tcl_DeleteHashTable(&uniqueTable);
}
}
static inline void
InstallPrivateVariableMapping(
PrivateVariableList *pvlPtr,
int varc,
Tcl_Obj *const *varv,
int creationEpoch)
{
PrivateVariableMapping *privatePtr;
int i, n, created;
Tcl_HashTable uniqueTable;
for (i=0 ; i<varc ; i++) {
Tcl_IncrRefCount(varv[i]);
}
FOREACH_STRUCT(privatePtr, *pvlPtr) {
Tcl_DecrRefCount(privatePtr->variableObj);
Tcl_DecrRefCount(privatePtr->fullNameObj);
}
if (i != varc) {
if (varc == 0) {
ckfree(pvlPtr->list);
} else if (i) {
pvlPtr->list = ckrealloc(pvlPtr->list,
sizeof(PrivateVariableMapping) * varc);
} else {
pvlPtr->list = ckalloc(sizeof(PrivateVariableMapping) * varc);
}
}
pvlPtr->num = 0;
if (varc > 0) {
Tcl_InitObjHashTable(&uniqueTable);
for (i=n=0 ; i<varc ; i++) {
Tcl_CreateHashEntry(&uniqueTable, varv[i], &created);
if (created) {
privatePtr = &(pvlPtr->list[n++]);
privatePtr->variableObj = varv[i];
privatePtr->fullNameObj = Tcl_ObjPrintf(
PRIVATE_VARIABLE_PATTERN,
creationEpoch, Tcl_GetString(varv[i]));
Tcl_IncrRefCount(privatePtr->fullNameObj);
} else {
Tcl_DecrRefCount(varv[i]);
}
}
pvlPtr->num = n;
/*
* Shouldn't be necessary, but maintain num/list invariant.
*/
if (n != varc) {
pvlPtr->list = ckrealloc(pvlPtr->list,
sizeof(PrivateVariableMapping) * n);
}
Tcl_DeleteHashTable(&uniqueTable);
}
}
/*
* ----------------------------------------------------------------------
*
@@ -708,7 +866,8 @@ TclOOGetDefineCmdContext(
Tcl_Object object;
if ((iPtr->varFramePtr == NULL)
|| (iPtr->varFramePtr->isProcCallFrame != FRAME_IS_OO_DEFINE)) {
|| (iPtr->varFramePtr->isProcCallFrame != FRAME_IS_OO_DEFINE
&& iPtr->varFramePtr->isProcCallFrame != PRIVATE_FRAME)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"this command may only be called from within the context of"
" an ::oo::define or ::oo::objdefine command", -1));
@@ -749,7 +908,8 @@ GetClassInOuterContext(
Object *oPtr;
CallFrame *savedFramePtr = iPtr->varFramePtr;
while (iPtr->varFramePtr->isProcCallFrame == FRAME_IS_OO_DEFINE) {
while (iPtr->varFramePtr->isProcCallFrame == FRAME_IS_OO_DEFINE
|| iPtr->varFramePtr->isProcCallFrame == PRIVATE_FRAME) {
if (iPtr->varFramePtr->callerVarPtr == NULL) {
Tcl_Panic("getting outer context when already in global context");
}
@@ -1038,7 +1198,7 @@ TclOODefineSelfObjCmd(
{
Foundation *fPtr = TclOOGetFoundation(interp);
Object *oPtr;
int result;
int result, private;
oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
@@ -1050,6 +1210,8 @@ TclOODefineSelfObjCmd(
return TCL_OK;
}
private = IsPrivateDefine(interp);
/*
* Make the oo::objdefine namespace the current namespace and evaluate the
* command(s).
@@ -1058,6 +1220,9 @@ TclOODefineSelfObjCmd(
if (InitDefineContext(interp, fPtr->objdefNs, oPtr, objc,objv) != TCL_OK){
return TCL_ERROR;
}
if (private) {
((Interp *) interp)->varFramePtr->isProcCallFrame = PRIVATE_FRAME;
}
AddRef(oPtr);
if (objc == 2) {
@@ -1065,7 +1230,7 @@ TclOODefineSelfObjCmd(
Tcl_IncrRefCount(objNameObj);
result = TclEvalObjEx(interp, objv[1], 0,
((Interp *)interp)->cmdFramePtr, 2);
((Interp *)interp)->cmdFramePtr, 1);
if (result == TCL_ERROR) {
GenerateErrorInfo(interp, oPtr, objNameObj, "class object");
}
@@ -1117,6 +1282,79 @@ TclOODefineObjSelfObjCmd(
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* TclOODefinePrivateObjCmd --
*
* Implementation of the "private" subcommand of the "oo::define"
* and "oo::objdefine" commands.
*
* ----------------------------------------------------------------------
*/
int
TclOODefinePrivateObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
int isInstancePrivate = (clientData != NULL);
/* Just so that we can generate the correct
* error message depending on the context of
* usage of this function. */
Interp *iPtr = (Interp *) interp;
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
int saved; /* The saved flag. We restore it on exit so
* that [private private ...] doesn't make
* things go weird. */
int result;
if (oPtr == NULL) {
return TCL_ERROR;
}
if (objc == 1) {
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(IsPrivateDefine(interp)));
return TCL_OK;
}
/*
* Change the frame type flag while evaluating the body.
*/
saved = iPtr->varFramePtr->isProcCallFrame;
iPtr->varFramePtr->isProcCallFrame = PRIVATE_FRAME;
/*
* Evaluate the body; standard pattern.
*/
AddRef(oPtr);
if (objc == 2) {
Tcl_Obj *objNameObj = TclOOObjectName(interp, oPtr);
Tcl_IncrRefCount(objNameObj);
result = TclEvalObjEx(interp, objv[1], 0, iPtr->cmdFramePtr, 1);
if (result == TCL_ERROR) {
GenerateErrorInfo(interp, oPtr, objNameObj,
isInstancePrivate ? "object" : "class");
}
TclDecrRefCount(objNameObj);
} else {
result = MagicDefinitionInvoke(interp, TclGetCurrentNamespace(interp),
1, objc, objv);
}
TclOODecrRefCount(oPtr);
/*
* Restore the frame type flag to what it was previously.
*/
iPtr->varFramePtr->isProcCallFrame = saved;
return result;
}
/*
* ----------------------------------------------------------------------
*
@@ -1460,8 +1698,9 @@ TclOODefineExportObjCmd(
} else {
mPtr = Tcl_GetHashValue(hPtr);
}
if (isNew || !(mPtr->flags & PUBLIC_METHOD)) {
if (isNew || !(mPtr->flags & (PUBLIC_METHOD | PRIVATE_METHOD))) {
mPtr->flags |= PUBLIC_METHOD;
mPtr->flags &= ~TRUE_PRIVATE_METHOD;
changed = 1;
}
}
@@ -1521,6 +1760,9 @@ TclOODefineForwardObjCmd(
}
isPublic = Tcl_StringMatch(TclGetString(objv[1]), "[a-z]*")
? PUBLIC_METHOD : 0;
if (IsPrivateDefine(interp)) {
isPublic = TRUE_PRIVATE_METHOD;
}
/*
* Create the method structure.
@@ -1580,6 +1822,9 @@ TclOODefineMethodObjCmd(
}
isPublic = Tcl_StringMatch(TclGetString(objv[1]), "[a-z]*")
? PUBLIC_METHOD : 0;
if (IsPrivateDefine(interp)) {
isPublic = TRUE_PRIVATE_METHOD;
}
/*
* Create the method by using the right back-end API.
@@ -1599,70 +1844,6 @@ TclOODefineMethodObjCmd(
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* TclOODefineMixinObjCmd --
*
* Implementation of the "mixin" subcommand of the "oo::define" and
* "oo::objdefine" commands.
*
* ----------------------------------------------------------------------
*/
int
TclOODefineMixinObjCmd(
ClientData clientData,
Tcl_Interp *interp,
const int objc,
Tcl_Obj *const *objv)
{
int isInstanceMixin = (clientData != NULL);
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Class **mixins;
int i;
if (oPtr == NULL) {
return TCL_ERROR;
}
if (!isInstanceMixin && !oPtr->classPtr) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"attempt to misuse API", -1));
Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
return TCL_ERROR;
}
mixins = TclStackAlloc(interp, sizeof(Class *) * (objc-1));
for (i=1 ; i<objc ; i++) {
Class *clsPtr = GetClassInOuterContext(interp, objv[i],
"may only mix in classes");
if (clsPtr == NULL) {
goto freeAndError;
}
if (!isInstanceMixin && TclOOIsReachable(oPtr->classPtr, clsPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"may not mix a class into itself", -1));
Tcl_SetErrorCode(interp, "TCL", "OO", "SELF_MIXIN", NULL);
goto freeAndError;
}
mixins[i-1] = clsPtr;
}
if (isInstanceMixin) {
TclOOObjectSetMixins(oPtr, objc-1, mixins);
} else {
TclOOClassSetMixins(interp, oPtr->classPtr, objc-1, mixins);
}
TclStackFree(interp, mixins);
return TCL_OK;
freeAndError:
TclStackFree(interp, mixins);
return TCL_ERROR;
}
/*
* ----------------------------------------------------------------------
*
@@ -1795,8 +1976,8 @@ TclOODefineUnexportObjCmd(
} else {
mPtr = Tcl_GetHashValue(hPtr);
}
if (isNew || mPtr->flags & PUBLIC_METHOD) {
mPtr->flags &= ~PUBLIC_METHOD;
if (isNew || mPtr->flags & (PUBLIC_METHOD | TRUE_PRIVATE_METHOD)) {
mPtr->flags &= ~(PUBLIC_METHOD | TRUE_PRIVATE_METHOD);
changed = 1;
}
}
@@ -1888,6 +2069,7 @@ TclOODefineSlots(
const struct DeclaredSlot *slotInfoPtr;
Tcl_Obj *getName = Tcl_NewStringObj("Get", -1);
Tcl_Obj *setName = Tcl_NewStringObj("Set", -1);
Tcl_Obj *resolveName = Tcl_NewStringObj("Resolve", -1);
Class *slotCls;
slotCls = ((Object *) Tcl_NewObjectInstance(fPtr->interp, (Tcl_Class)
@@ -1897,9 +2079,10 @@ TclOODefineSlots(
}
Tcl_IncrRefCount(getName);
Tcl_IncrRefCount(setName);
Tcl_IncrRefCount(resolveName);
for (slotInfoPtr = slots ; slotInfoPtr->name ; slotInfoPtr++) {
Tcl_Object slotObject = Tcl_NewObjectInstance(fPtr->interp,
(Tcl_Class) slotCls, slotInfoPtr->name, NULL,-1,NULL,0);
(Tcl_Class) slotCls, slotInfoPtr->name, NULL, -1, NULL, 0);
if (slotObject == NULL) {
continue;
@@ -1908,9 +2091,14 @@ TclOODefineSlots(
&slotInfoPtr->getterType, NULL);
Tcl_NewInstanceMethod(fPtr->interp, slotObject, setName, 0,
&slotInfoPtr->setterType, NULL);
if (slotInfoPtr->resolverType.callProc) {
Tcl_NewInstanceMethod(fPtr->interp, slotObject, resolveName, 0,
&slotInfoPtr->resolverType, NULL);
}
}
Tcl_DecrRefCount(getName);
Tcl_DecrRefCount(setName);
Tcl_DecrRefCount(resolveName);
return TCL_OK;
}
@@ -2288,7 +2476,7 @@ ClassVarsGet(
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Tcl_Obj *resultObj, *variableObj;
Tcl_Obj *resultObj;
int i;
if (Tcl_ObjectContextSkippedArgs(context) != objc) {
@@ -2306,8 +2494,18 @@ ClassVarsGet(
}
resultObj = Tcl_NewObj();
FOREACH(variableObj, oPtr->classPtr->variables) {
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
if (IsPrivateDefine(interp)) {
PrivateVariableMapping *privatePtr;
FOREACH_STRUCT(privatePtr, oPtr->classPtr->privateVariables) {
Tcl_ListObjAppendElement(NULL, resultObj, privatePtr->variableObj);
}
} else {
Tcl_Obj *variableObj;
FOREACH(variableObj, oPtr->classPtr->variables) {
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
}
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
@@ -2323,7 +2521,7 @@ ClassVarsSet(
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
int varc;
Tcl_Obj **varv, *variableObj;
Tcl_Obj **varv;
int i;
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
@@ -2364,49 +2562,11 @@ ClassVarsSet(
}
}
for (i=0 ; i<varc ; i++) {
Tcl_IncrRefCount(varv[i]);
}
FOREACH(variableObj, oPtr->classPtr->variables) {
Tcl_DecrRefCount(variableObj);
}
if (i != varc) {
if (varc == 0) {
ckfree(oPtr->classPtr->variables.list);
} else if (i) {
oPtr->classPtr->variables.list = (Tcl_Obj **)
ckrealloc((char *) oPtr->classPtr->variables.list,
sizeof(Tcl_Obj *) * varc);
} else {
oPtr->classPtr->variables.list = (Tcl_Obj **)
ckalloc(sizeof(Tcl_Obj *) * varc);
}
}
oPtr->classPtr->variables.num = 0;
if (varc > 0) {
int created, n;
Tcl_HashTable uniqueTable;
Tcl_InitObjHashTable(&uniqueTable);
for (i=n=0 ; i<varc ; i++) {
Tcl_CreateHashEntry(&uniqueTable, varv[i], &created);
if (created) {
oPtr->classPtr->variables.list[n++] = varv[i];
} else {
Tcl_DecrRefCount(varv[i]);
}
}
oPtr->classPtr->variables.num = n;
/*
* Shouldn't be necessary, but maintain num/list invariant.
*/
oPtr->classPtr->variables.list = (Tcl_Obj **)
ckrealloc((char *) oPtr->classPtr->variables.list,
sizeof(Tcl_Obj *) * n);
Tcl_DeleteHashTable(&uniqueTable);
if (IsPrivateDefine(interp)) {
InstallPrivateVariableMapping(&oPtr->classPtr->privateVariables,
varc, varv, oPtr->classPtr->thisPtr->creationEpoch);
} else {
InstallStandardVariableMapping(&oPtr->classPtr->variables, varc, varv);
}
return TCL_OK;
}
@@ -2585,7 +2745,7 @@ ObjVarsGet(
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Tcl_Obj *resultObj, *variableObj;
Tcl_Obj *resultObj;
int i;
if (Tcl_ObjectContextSkippedArgs(context) != objc) {
@@ -2597,8 +2757,18 @@ ObjVarsGet(
}
resultObj = Tcl_NewObj();
FOREACH(variableObj, oPtr->variables) {
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
if (IsPrivateDefine(interp)) {
PrivateVariableMapping *privatePtr;
FOREACH_STRUCT(privatePtr, oPtr->privateVariables) {
Tcl_ListObjAppendElement(NULL, resultObj, privatePtr->variableObj);
}
} else {
Tcl_Obj *variableObj;
FOREACH(variableObj, oPtr->variables) {
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
}
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
@@ -2614,7 +2784,7 @@ ObjVarsSet(
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
int varc, i;
Tcl_Obj **varv, *variableObj;
Tcl_Obj **varv;
if (Tcl_ObjectContextSkippedArgs(context)+1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
@@ -2647,50 +2817,66 @@ ObjVarsSet(
return TCL_ERROR;
}
}
for (i=0 ; i<varc ; i++) {
Tcl_IncrRefCount(varv[i]);
if (IsPrivateDefine(interp)) {
InstallPrivateVariableMapping(&oPtr->privateVariables, varc, varv,
oPtr->creationEpoch);
} else {
InstallStandardVariableMapping(&oPtr->variables, varc, varv);
}
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* ResolveClass --
*
* Implementation of the "Resolve" support method for some slots (those
* that are slots around a list of classes). This resolves possible class
* names to their fully-qualified names if possible.
*
* ----------------------------------------------------------------------
*/
static int
ResolveClass(
ClientData clientData,
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
int idx = Tcl_ObjectContextSkippedArgs(context);
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Class *clsPtr;
/*
* Check if were called wrongly. The definition context isn't used...
* except that GetClassInOuterContext() assumes that it is there.
*/
if (oPtr == NULL) {
return TCL_ERROR;
} else if (objc != idx + 1) {
Tcl_WrongNumArgs(interp, idx, objv, "slotElement");
return TCL_ERROR;
}
FOREACH(variableObj, oPtr->variables) {
Tcl_DecrRefCount(variableObj);
}
if (i != varc) {
if (varc == 0) {
ckfree(oPtr->variables.list);
} else if (i) {
oPtr->variables.list = (Tcl_Obj **)
ckrealloc((char *) oPtr->variables.list,
sizeof(Tcl_Obj *) * varc);
} else {
oPtr->variables.list = (Tcl_Obj **)
ckalloc(sizeof(Tcl_Obj *) * varc);
}
}
oPtr->variables.num = 0;
if (varc > 0) {
int created, n;
Tcl_HashTable uniqueTable;
/*
* Resolve the class if possible. If not, remove any resolution error and
* return what we've got anyway as the failure might not be fatal overall.
*/
Tcl_InitObjHashTable(&uniqueTable);
for (i=n=0 ; i<varc ; i++) {
Tcl_CreateHashEntry(&uniqueTable, varv[i], &created);
if (created) {
oPtr->variables.list[n++] = varv[i];
} else {
Tcl_DecrRefCount(varv[i]);
}
}
oPtr->variables.num = n;
/*
* Shouldn't be necessary, but maintain num/list invariant.
*/
oPtr->variables.list = (Tcl_Obj **)
ckrealloc((char *) oPtr->variables.list,
sizeof(Tcl_Obj *) * n);
Tcl_DeleteHashTable(&uniqueTable);
clsPtr = GetClassInOuterContext(interp, objv[idx],
"USER SHOULD NOT SEE THIS MESSAGE");
if (clsPtr == NULL) {
Tcl_ResetResult(interp);
Tcl_SetObjResult(interp, objv[idx]);
} else {
Tcl_SetObjResult(interp, TclOOObjectName(interp, clsPtr->thisPtr));
}
return TCL_OK;
}
+165 -27
View File
@@ -22,6 +22,7 @@ static Tcl_ObjCmdProc InfoObjectClassCmd;
static Tcl_ObjCmdProc InfoObjectDefnCmd;
static Tcl_ObjCmdProc InfoObjectFiltersCmd;
static Tcl_ObjCmdProc InfoObjectForwardCmd;
static Tcl_ObjCmdProc InfoObjectIdCmd;
static Tcl_ObjCmdProc InfoObjectIsACmd;
static Tcl_ObjCmdProc InfoObjectMethodsCmd;
static Tcl_ObjCmdProc InfoObjectMethodTypeCmd;
@@ -50,6 +51,7 @@ static Tcl_ObjCmdProc InfoClassVariablesCmd;
static const EnsembleImplMap infoObjectCmds[] = {
{"call", InfoObjectCallCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"class", InfoObjectClassCmd, TclCompileInfoObjectClassCmd, NULL, NULL, 0},
{"creationid", InfoObjectIdCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"definition", InfoObjectDefnCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"filters", InfoObjectFiltersCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"forward", InfoObjectForwardCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
@@ -58,7 +60,7 @@ static const EnsembleImplMap infoObjectCmds[] = {
{"methodtype", InfoObjectMethodTypeCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"mixins", InfoObjectMixinsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"namespace", InfoObjectNsCmd, TclCompileInfoObjectNamespaceCmd, NULL, NULL, 0},
{"variables", InfoObjectVariablesCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"variables", InfoObjectVariablesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"vars", InfoObjectVarsCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
@@ -80,7 +82,7 @@ static const EnsembleImplMap infoClassCmds[] = {
{"mixins", InfoClassMixinsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"subclasses", InfoClassSubsCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"superclasses", InfoClassSupersCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"variables", InfoClassVariablesCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"variables", InfoClassVariablesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
@@ -517,15 +519,22 @@ InfoObjectMethodsCmd(
Tcl_Obj *const objv[])
{
Object *oPtr;
int flag = PUBLIC_METHOD, recurse = 0;
int flag = PUBLIC_METHOD, recurse = 0, scope = -1;
FOREACH_HASH_DECLS;
Tcl_Obj *namePtr, *resultObj;
Method *mPtr;
static const char *const options[] = {
"-all", "-localprivate", "-private", NULL
"-all", "-localprivate", "-private", "-scope", NULL
};
enum Options {
OPT_ALL, OPT_LOCALPRIVATE, OPT_PRIVATE
OPT_ALL, OPT_LOCALPRIVATE, OPT_PRIVATE, OPT_SCOPE
};
static const char *const scopes[] = {
"private", "public", "unexported"
};
enum Scopes {
SCOPE_PRIVATE, SCOPE_PUBLIC, SCOPE_UNEXPORTED,
SCOPE_LOCALPRIVATE
};
if (objc < 2) {
@@ -554,14 +563,45 @@ InfoObjectMethodsCmd(
case OPT_PRIVATE:
flag = 0;
break;
case OPT_SCOPE:
if (++i >= objc) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"missing option for -scope"));
Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING",
NULL);
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[i], scopes, "scope", 0,
&scope) != TCL_OK) {
return TCL_ERROR;
}
break;
}
}
}
if (scope != -1) {
recurse = 0;
switch (scope) {
case SCOPE_PRIVATE:
flag = TRUE_PRIVATE_METHOD;
break;
case SCOPE_PUBLIC:
flag = PUBLIC_METHOD;
break;
case SCOPE_LOCALPRIVATE:
flag = PRIVATE_METHOD;
break;
case SCOPE_UNEXPORTED:
flag = 0;
break;
}
}
resultObj = Tcl_NewObj();
if (recurse) {
const char **names;
int i, numNames = TclOOGetSortedMethodList(oPtr, flag, &names);
int i, numNames = TclOOGetSortedMethodList(oPtr, NULL, NULL, flag,
&names);
for (i=0 ; i<numNames ; i++) {
Tcl_ListObjAppendElement(NULL, resultObj,
@@ -572,7 +612,7 @@ InfoObjectMethodsCmd(
}
} else if (oPtr->methodsPtr) {
FOREACH_HASH(namePtr, mPtr, oPtr->methodsPtr) {
if (mPtr->typePtr != NULL && (mPtr->flags & flag) == flag) {
if (mPtr->typePtr && (mPtr->flags & SCOPE_FLAGS) == flag) {
Tcl_ListObjAppendElement(NULL, resultObj, namePtr);
}
}
@@ -681,6 +721,38 @@ InfoObjectMixinsCmd(
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* InfoObjectIdCmd --
*
* Implements [info object creationid $objName]
*
* ----------------------------------------------------------------------
*/
static int
InfoObjectIdCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "objName");
return TCL_ERROR;
}
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
if (oPtr == NULL) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(oPtr->creationEpoch));
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
@@ -719,7 +791,7 @@ InfoObjectNsCmd(
*
* InfoObjectVariablesCmd --
*
* Implements [info object variables $objName]
* Implements [info object variables $objName ?-private?]
*
* ----------------------------------------------------------------------
*/
@@ -732,21 +804,37 @@ InfoObjectVariablesCmd(
Tcl_Obj *const objv[])
{
Object *oPtr;
Tcl_Obj *variableObj, *resultObj;
int i;
Tcl_Obj *resultObj;
int i, private = 0;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "objName");
if (objc != 2 && objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "objName ?-private?");
return TCL_ERROR;
}
if (objc == 3) {
if (strcmp("-private", Tcl_GetString(objv[2])) != 0) {
return TCL_ERROR;
}
private = 1;
}
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
if (oPtr == NULL) {
return TCL_ERROR;
}
resultObj = Tcl_NewObj();
FOREACH(variableObj, oPtr->variables) {
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
if (private) {
PrivateVariableMapping *privatePtr;
FOREACH_STRUCT(privatePtr, oPtr->privateVariables) {
Tcl_ListObjAppendElement(NULL, resultObj, privatePtr->variableObj);
}
} else {
Tcl_Obj *variableObj;
FOREACH(variableObj, oPtr->variables) {
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
}
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
@@ -1128,7 +1216,7 @@ InfoClassInstancesCmd(
*
* InfoClassMethodsCmd --
*
* Implements [info class methods $clsName ?-private?]
* Implements [info class methods $clsName ?options...?]
*
* ----------------------------------------------------------------------
*/
@@ -1140,15 +1228,21 @@ InfoClassMethodsCmd(
int objc,
Tcl_Obj *const objv[])
{
int flag = PUBLIC_METHOD, recurse = 0;
int flag = PUBLIC_METHOD, recurse = 0, scope = -1;
Tcl_Obj *namePtr, *resultObj;
Method *mPtr;
Class *clsPtr;
static const char *const options[] = {
"-all", "-localprivate", "-private", NULL
"-all", "-localprivate", "-private", "-scope", NULL
};
enum Options {
OPT_ALL, OPT_LOCALPRIVATE, OPT_PRIVATE
OPT_ALL, OPT_LOCALPRIVATE, OPT_PRIVATE, OPT_SCOPE
};
static const char *const scopes[] = {
"private", "public", "unexported"
};
enum Scopes {
SCOPE_PRIVATE, SCOPE_PUBLIC, SCOPE_UNEXPORTED
};
if (objc < 2) {
@@ -1177,9 +1271,36 @@ InfoClassMethodsCmd(
case OPT_PRIVATE:
flag = 0;
break;
case OPT_SCOPE:
if (++i >= objc) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"missing option for -scope"));
Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING",
NULL);
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[i], scopes, "scope", 0,
&scope) != TCL_OK) {
return TCL_ERROR;
}
break;
}
}
}
if (scope != -1) {
recurse = 0;
switch (scope) {
case SCOPE_PRIVATE:
flag = TRUE_PRIVATE_METHOD;
break;
case SCOPE_PUBLIC:
flag = PUBLIC_METHOD;
break;
case SCOPE_UNEXPORTED:
flag = 0;
break;
}
}
resultObj = Tcl_NewObj();
if (recurse) {
@@ -1197,7 +1318,7 @@ InfoClassMethodsCmd(
FOREACH_HASH_DECLS;
FOREACH_HASH(namePtr, mPtr, &clsPtr->classMethods) {
if (mPtr->typePtr != NULL && (mPtr->flags & flag) == flag) {
if (mPtr->typePtr && (mPtr->flags & SCOPE_FLAGS) == flag) {
Tcl_ListObjAppendElement(NULL, resultObj, namePtr);
}
}
@@ -1399,7 +1520,7 @@ InfoClassSupersCmd(
*
* InfoClassVariablesCmd --
*
* Implements [info class variables $clsName]
* Implements [info class variables $clsName ?-private?]
*
* ----------------------------------------------------------------------
*/
@@ -1412,21 +1533,37 @@ InfoClassVariablesCmd(
Tcl_Obj *const objv[])
{
Class *clsPtr;
Tcl_Obj *variableObj, *resultObj;
int i;
Tcl_Obj *resultObj;
int i, private = 0;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "className");
if (objc != 2 && objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "className ?-private?");
return TCL_ERROR;
}
if (objc == 3) {
if (strcmp("-private", Tcl_GetString(objv[2])) != 0) {
return TCL_ERROR;
}
private = 1;
}
clsPtr = GetClassFromObj(interp, objv[1]);
if (clsPtr == NULL) {
return TCL_ERROR;
}
resultObj = Tcl_NewObj();
FOREACH(variableObj, clsPtr->variables) {
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
if (private) {
PrivateVariableMapping *privatePtr;
FOREACH_STRUCT(privatePtr, clsPtr->privateVariables) {
Tcl_ListObjAppendElement(NULL, resultObj, privatePtr->variableObj);
}
} else {
Tcl_Obj *variableObj;
FOREACH(variableObj, clsPtr->variables) {
Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
}
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
@@ -1465,7 +1602,8 @@ InfoObjectCallCmd(
* Get the call context and render its call chain.
*/
contextPtr = TclOOGetCallContext(oPtr, objv[2], PUBLIC_METHOD, NULL);
contextPtr = TclOOGetCallContext(oPtr, objv[2], PUBLIC_METHOD, NULL, NULL,
NULL);
if (contextPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"cannot construct any call chain", -1));
+57 -5
View File
@@ -124,6 +124,18 @@ typedef struct ForwardMethod {
* non-empty list. */
} ForwardMethod;
/*
* Structure used in private variable mappings. Describes the mapping of a
* single variable from the user's local name to the system's storage name.
* [TIP #500]
*/
typedef struct {
Tcl_Obj *variableObj; /* Name used within methods. This is the part
* that is properly under user control. */
Tcl_Obj *fullNameObj; /* Name used at the instance namespace level. */
} PrivateVariableMapping;
/*
* Helper definitions that declare a "list" array. The two varieties are
* either optimized for simplicity (in the case that the whole array is
@@ -141,6 +153,13 @@ typedef struct ForwardMethod {
#define LIST_DYNAMIC(listType_t) \
struct { int num, size; listType_t *list; }
/*
* These types are needed in function arguments.
*/
typedef LIST_STATIC(Tcl_Obj *) VariableNameList;
typedef LIST_STATIC(PrivateVariableMapping) PrivateVariableList;
/*
* Now, the definition of what an object actually is.
*/
@@ -186,7 +205,12 @@ typedef struct Object {
Tcl_ObjectMapMethodNameProc *mapMethodNameProc;
/* Function to allow remapping of method
* names. For itcl-ng. */
LIST_STATIC(Tcl_Obj *) variables;
VariableNameList variables;
PrivateVariableList privateVariables;
/* Configurations for the variable resolver
* used inside methods. */
Tcl_Command myclassCommand; /* Reference to this object's class dispatcher
* command. */
} Object;
#define OBJECT_DELETED 1 /* Flag to say that an object has been
@@ -214,6 +238,10 @@ typedef struct Object {
* other spots). */
#define FORCE_UNKNOWN 0x10000 /* States that we are *really* looking up the
* unknown method handler at that point. */
#define HAS_PRIVATE_METHODS 0x20000
/* Object/class has (or had) private methods,
* and so shouldn't be cached so
* aggressively. */
/*
* And the definition of a class. Note that every class also has an associated
@@ -268,7 +296,10 @@ typedef struct Class {
* object doesn't override with its own mixins
* (and filters and method implementations for
* when getting method chains). */
LIST_STATIC(Tcl_Obj *) variables;
VariableNameList variables;
PrivateVariableList privateVariables;
/* Configurations for the variable resolver
* used inside methods. */
} Class;
/*
@@ -370,10 +401,15 @@ typedef struct CallContext {
#define PUBLIC_METHOD 0x01 /* This is a public (exported) method. */
#define PRIVATE_METHOD 0x02 /* This is a private (class's direct instances
* only) method. */
* only) method. Supports itcl. */
#define OO_UNKNOWN_METHOD 0x04 /* This is an unknown method. */
#define CONSTRUCTOR 0x08 /* This is a constructor. */
#define DESTRUCTOR 0x10 /* This is a destructor. */
#define TRUE_PRIVATE_METHOD 0x20
/* This is a private method only accessible
* from other methods defined on this class
* or instance. [TIP #500] */
#define SCOPE_FLAGS (PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD)
/*
* Structure containing definition information about basic class methods.
@@ -431,6 +467,9 @@ MODULE_SCOPE int TclOODefineSelfObjCmd(ClientData clientData,
MODULE_SCOPE int TclOODefineObjSelfObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const *objv);
MODULE_SCOPE int TclOODefinePrivateObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const *objv);
MODULE_SCOPE int TclOOUnknownDefinition(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const *objv);
@@ -504,6 +543,7 @@ MODULE_SCOPE void TclOODeleteContext(CallContext *contextPtr);
MODULE_SCOPE void TclOODelMethodRef(Method *method);
MODULE_SCOPE CallContext *TclOOGetCallContext(Object *oPtr,
Tcl_Obj *methodNameObj, int flags,
Object *contextObjPtr, Class *contextClsPtr,
Tcl_Obj *cacheInThisObj);
MODULE_SCOPE CallChain *TclOOGetStereotypeCallChain(Class *clsPtr,
Tcl_Obj *methodNameObj, int flags);
@@ -513,7 +553,8 @@ MODULE_SCOPE Proc * TclOOGetProcFromMethod(Method *mPtr);
MODULE_SCOPE Tcl_Obj * TclOOGetMethodBody(Method *mPtr);
MODULE_SCOPE int TclOOGetSortedClassMethodList(Class *clsPtr,
int flags, const char ***stringsPtr);
MODULE_SCOPE int TclOOGetSortedMethodList(Object *oPtr, int flags,
MODULE_SCOPE int TclOOGetSortedMethodList(Object *oPtr,
Object *contextObj, Class *contextCls, int flags,
const char ***stringsPtr);
MODULE_SCOPE int TclOOInit(Tcl_Interp *interp);
MODULE_SCOPE void TclOOInitInfo(Tcl_Interp *interp);
@@ -558,13 +599,24 @@ MODULE_SCOPE void TclOOSetupVariableResolver(Tcl_Namespace *nsPtr);
#define FOREACH(var,ary) \
for(i=0 ; i<(ary).num; i++) if ((ary).list[i] == NULL) { \
continue; \
} else if (var = (ary).list[i], 1)
} else if (var = (ary).list[i], 1)
/*
* A variation where the array is an array of structs. There's no issue with
* possible NULLs; every element of the array will be iterated over and the
* varable set to a pointer to each of those elements in turn.
* REQUIRES DECLARATION: int i;
*/
#define FOREACH_STRUCT(var,ary) \
for(i=0 ; var=&((ary).list[i]), i<(ary).num; i++)
/*
* Convenience macros for iterating through hash tables. FOREACH_HASH_DECLS
* sets up the declarations needed for the main macro, FOREACH_HASH, which
* does the actual iteration. FOREACH_HASH_VALUE is a restricted version that
* only iterates over values.
* REQUIRES DECLARATION: FOREACH_HASH_DECLS;
*/
#define FOREACH_HASH_DECLS \
+36 -3
View File
@@ -186,7 +186,11 @@ Tcl_NewInstanceMethod(
mPtr->declaringObjectPtr = oPtr;
mPtr->declaringClassPtr = NULL;
if (flags) {
mPtr->flags |= flags & (PUBLIC_METHOD | PRIVATE_METHOD);
mPtr->flags |= flags &
(PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD);
if (flags & TRUE_PRIVATE_METHOD) {
oPtr->flags |= HAS_PRIVATE_METHODS;
}
}
oPtr->epoch++;
return (Tcl_Method) mPtr;
@@ -250,7 +254,11 @@ Tcl_NewMethod(
mPtr->declaringObjectPtr = NULL;
mPtr->declaringClassPtr = clsPtr;
if (flags) {
mPtr->flags |= flags & (PUBLIC_METHOD | PRIVATE_METHOD);
mPtr->flags |= flags &
(PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD);
if (flags & TRUE_PRIVATE_METHOD) {
clsPtr->flags |= HAS_PRIVATE_METHODS;
}
}
return (Tcl_Method) mPtr;
@@ -928,7 +936,7 @@ PushMethodCallFrame(
* variables used in methods. The compiled variable resolver is more
* important, but both are needed as it is possible to have a variable
* that is only referred to in ways that aren't compilable and we can't
* force LVT presence. [TIP #320]
* force LVT presence. [TIP #320, #500]
*
* ----------------------------------------------------------------------
*/
@@ -986,6 +994,7 @@ ProcedureMethodCompiledVarConnect(
CallFrame *framePtr = iPtr->varFramePtr;
CallContext *contextPtr;
Tcl_Obj *variableObj;
PrivateVariableMapping *privateVar;
Tcl_HashEntry *hPtr;
int i, isNew, cacheIt, varLen, len;
const char *match, *varName;
@@ -1019,6 +1028,15 @@ ProcedureMethodCompiledVarConnect(
varName = TclGetStringFromObj(infoPtr->variableObj, &varLen);
if (contextPtr->callPtr->chain[contextPtr->index]
.mPtr->declaringClassPtr != NULL) {
FOREACH_STRUCT(privateVar, contextPtr->callPtr->chain[contextPtr->index]
.mPtr->declaringClassPtr->privateVariables) {
match = TclGetStringFromObj(privateVar->variableObj, &len);
if ((len == varLen) && !memcmp(match, varName, len)) {
variableObj = privateVar->fullNameObj;
cacheIt = 0;
goto gotMatch;
}
}
FOREACH(variableObj, contextPtr->callPtr->chain[contextPtr->index]
.mPtr->declaringClassPtr->variables) {
match = TclGetStringFromObj(variableObj, &len);
@@ -1028,6 +1046,14 @@ ProcedureMethodCompiledVarConnect(
}
}
} else {
FOREACH_STRUCT(privateVar, contextPtr->oPtr->privateVariables) {
match = TclGetStringFromObj(privateVar->variableObj, &len);
if ((len == varLen) && !memcmp(match, varName, len)) {
variableObj = privateVar->fullNameObj;
cacheIt = 1;
goto gotMatch;
}
}
FOREACH(variableObj, contextPtr->oPtr->variables) {
match = TclGetStringFromObj(variableObj, &len);
if ((len == varLen) && !memcmp(match, varName, len)) {
@@ -1673,6 +1699,13 @@ Tcl_MethodIsPublic(
{
return (((Method *)method)->flags & PUBLIC_METHOD) ? 1 : 0;
}
int
Tcl_MethodIsPrivate(
Tcl_Method method)
{
return (((Method *)method)->flags & TRUE_PRIVATE_METHOD) ? 1 : 0;
}
/*
* Extended method construction for itcl-ng.
+263
View File
@@ -0,0 +1,263 @@
/*
* tclOOScript.h --
*
* This file contains support scripts for TclOO. They are defined here so
* that the code can be definitely run even in safe interpreters; TclOO's
* core setup is safe.
*
* Copyright (c) 2012-2018 Donal K. Fellows
* Copyright (c) 2013 Andreas Kupries
* Copyright (c) 2017 Gerald Lester
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#ifndef TCL_OO_SCRIPT_H
#define TCL_OO_SCRIPT_H
/*
* The scripted part of the definitions of TclOO.
*
* Compiled from generic/tclOOScript.tcl by tools/makeHeader.tcl, which
* contains the commented version of everything; *this* file is automatically
* generated.
*/
static const char *tclOOSetupScript =
/* !BEGIN!: Do not edit below this line. */
"::namespace eval ::oo {\n"
"\t::namespace path {}\n"
"\tnamespace eval Helpers {\n"
"\t\t::namespace path {}\n"
"\t\tproc callback {method args} {\n"
"\t\t\tlist [uplevel 1 {::namespace which my}] $method {*}$args\n"
"\t\t}\n"
"\t\tnamespace export callback\n"
"\t\tnamespace eval tmp {namespace import ::oo::Helpers::callback}\n"
"\t\tnamespace export -clear\n"
"\t\trename tmp::callback mymethod\n"
"\t\tnamespace delete tmp\n"
"\t\tproc classvariable {name args} {\n"
"\t\t\tset ns [info object namespace [uplevel 1 {self class}]]\n"
"\t\t\tforeach v [list $name {*}$args] {\n"
"\t\t\t\tif {[string match *(*) $v]} {\n"
"\t\t\t\t\tset reason \"can\'t create a scalar variable that looks like an array element\"\n"
"\t\t\t\t\treturn -code error -errorcode {TCL UPVAR LOCAL_ELEMENT} \\\n"
"\t\t\t\t\t\t[format {bad variable name \"%s\": %s} $v $reason]\n"
"\t\t\t\t}\n"
"\t\t\t\tif {[string match *::* $v]} {\n"
"\t\t\t\t\tset reason \"can\'t create a local variable with a namespace separator in it\"\n"
"\t\t\t\t\treturn -code error -errorcode {TCL UPVAR INVERTED} \\\n"
"\t\t\t\t\t\t[format {bad variable name \"%s\": %s} $v $reason]\n"
"\t\t\t\t}\n"
"\t\t\t\tlappend vs $v $v\n"
"\t\t\t}\n"
"\t\t\ttailcall namespace upvar $ns {*}$vs\n"
"\t\t}\n"
"\t\tproc link {args} {\n"
"\t\t\tset ns [uplevel 1 {::namespace current}]\n"
"\t\t\tforeach link $args {\n"
"\t\t\t\tif {[llength $link] == 2} {\n"
"\t\t\t\t\tlassign $link src dst\n"
"\t\t\t\t} elseif {[llength $link] == 1} {\n"
"\t\t\t\t\tlassign $link src\n"
"\t\t\t\t\tset dst $src\n"
"\t\t\t\t} else {\n"
"\t\t\t\t\treturn -code error -errorcode {TCLOO CMDLINK FORMAT} \\\n"
"\t\t\t\t\t\t\"bad link description; must only have one or two elements\"\n"
"\t\t\t\t}\n"
"\t\t\t\tif {![string match ::* $src]} {\n"
"\t\t\t\t\tset src [string cat $ns :: $src]\n"
"\t\t\t\t}\n"
"\t\t\t\tinterp alias {} $src {} ${ns}::my $dst\n"
"\t\t\t\ttrace add command ${ns}::my delete [list \\\n"
"\t\t\t\t\t::oo::UnlinkLinkedCommand $src]\n"
"\t\t\t}\n"
"\t\t\treturn\n"
"\t\t}\n"
"\t}\n"
"\tproc UnlinkLinkedCommand {cmd args} {\n"
"\t\tif {[namespace which $cmd] ne {}} {\n"
"\t\t\trename $cmd {}\n"
"\t\t}\n"
"\t}\n"
"\tproc DelegateName {class} {\n"
"\t\tstring cat [info object namespace $class] {:: oo ::delegate}\n"
"\t}\n"
"\tproc MixinClassDelegates {class} {\n"
"\t\tif {![info object isa class $class]} {\n"
"\t\t\treturn\n"
"\t\t}\n"
"\t\tset delegate [DelegateName $class]\n"
"\t\tif {![info object isa class $delegate]} {\n"
"\t\t\treturn\n"
"\t\t}\n"
"\t\tforeach c [info class superclass $class] {\n"
"\t\t\tset d [DelegateName $c]\n"
"\t\t\tif {![info object isa class $d]} {\n"
"\t\t\t\tcontinue\n"
"\t\t\t}\n"
"\t\t\tdefine $delegate superclass -append $d\n"
"\t\t}\n"
"\t\tobjdefine $class mixin -append $delegate\n"
"\t}\n"
"\tproc UpdateClassDelegatesAfterClone {originObject targetObject} {\n"
"\t\tset originDelegate [DelegateName $originObject]\n"
"\t\tset targetDelegate [DelegateName $targetObject]\n"
"\t\tif {\n"
"\t\t\t[info object isa class $originDelegate]\n"
"\t\t\t&& ![info object isa class $targetDelegate]\n"
"\t\t} then {\n"
"\t\t\tcopy $originDelegate $targetDelegate\n"
"\t\t\tobjdefine $targetObject mixin -set \\\n"
"\t\t\t\t{*}[lmap c [info object mixin $targetObject] {\n"
"\t\t\t\t\tif {$c eq $originDelegate} {set targetDelegate} {set c}\n"
"\t\t\t\t}]\n"
"\t\t}\n"
"\t}\n"
"\tproc define::classmethod {name {args {}} {body {}}} {\n"
"\t\t::set argc [::llength [::info level 0]]\n"
"\t\t::if {$argc == 3} {\n"
"\t\t\t::return -code error -errorcode {TCL WRONGARGS} [::format \\\n"
"\t\t\t\t{wrong # args: should be \"%s name \?args body\?\"} \\\n"
"\t\t\t\t[::lindex [::info level 0] 0]]\n"
"\t\t}\n"
"\t\t::set cls [::uplevel 1 self]\n"
"\t\t::if {$argc == 4} {\n"
"\t\t\t::oo::define [::oo::DelegateName $cls] method $name $args $body\n"
"\t\t}\n"
"\t\t::tailcall forward $name myclass $name\n"
"\t}\n"
"\tproc define::initialise {body} {\n"
"\t\t::set clsns [::info object namespace [::uplevel 1 self]]\n"
"\t\t::tailcall apply [::list {} $body $clsns]\n"
"\t}\n"
"\tnamespace eval define {\n"
"\t\t::namespace export initialise\n"
"\t\t::namespace eval tmp {::namespace import ::oo::define::initialise}\n"
"\t\t::namespace export -clear\n"
"\t\t::rename tmp::initialise initialize\n"
"\t\t::namespace delete tmp\n"
"\t}\n"
"\tdefine Slot {\n"
"\t\tmethod Get {} {\n"
"\t\t\treturn -code error -errorcode {TCLOO ABSTRACT_SLOT} \"unimplemented\"\n"
"\t\t}\n"
"\t\tmethod Set list {\n"
"\t\t\treturn -code error -errorcode {TCLOO ABSTRACT_SLOT} \"unimplemented\"\n"
"\t\t}\n"
"\t\tmethod Resolve list {\n"
"\t\t\treturn $list\n"
"\t\t}\n"
"\t\tmethod -set args {\n"
"\t\t\tset my [namespace which my]\n"
"\t\t\tset args [lmap a $args {uplevel 1 [list $my Resolve $a]}]\n"
"\t\t\ttailcall my Set $args\n"
"\t\t}\n"
"\t\tmethod -append args {\n"
"\t\t\tset my [namespace which my]\n"
"\t\t\tset args [lmap a $args {uplevel 1 [list $my Resolve $a]}]\n"
"\t\t\tset current [uplevel 1 [list $my Get]]\n"
"\t\t\ttailcall my Set [list {*}$current {*}$args]\n"
"\t\t}\n"
"\t\tmethod -clear {} {tailcall my Set {}}\n"
"\t\tmethod -prepend args {\n"
"\t\t\tset my [namespace which my]\n"
"\t\t\tset args [lmap a $args {uplevel 1 [list $my Resolve $a]}]\n"
"\t\t\tset current [uplevel 1 [list $my Get]]\n"
"\t\t\ttailcall my Set [list {*}$args {*}$current]\n"
"\t\t}\n"
"\t\tmethod -remove args {\n"
"\t\t\tset my [namespace which my]\n"
"\t\t\tset args [lmap a $args {uplevel 1 [list $my Resolve $a]}]\n"
"\t\t\tset current [uplevel 1 [list $my Get]]\n"
"\t\t\ttailcall my Set [lmap val $current {\n"
"\t\t\t\tif {$val in $args} continue else {set val}\n"
"\t\t\t}]\n"
"\t\t}\n"
"\t\tforward --default-operation my -append\n"
"\t\tmethod unknown {args} {\n"
"\t\t\tset def --default-operation\n"
"\t\t\tif {[llength $args] == 0} {\n"
"\t\t\t\ttailcall my $def\n"
"\t\t\t} elseif {![string match -* [lindex $args 0]]} {\n"
"\t\t\t\ttailcall my $def {*}$args\n"
"\t\t\t}\n"
"\t\t\tnext {*}$args\n"
"\t\t}\n"
"\t\texport -set -append -clear -prepend -remove\n"
"\t\tunexport unknown destroy\n"
"\t}\n"
"\tobjdefine define::superclass forward --default-operation my -set\n"
"\tobjdefine define::mixin forward --default-operation my -set\n"
"\tobjdefine objdefine::mixin forward --default-operation my -set\n"
"\tdefine object method <cloned> {originObject} {\n"
"\t\tforeach p [info procs [info object namespace $originObject]::*] {\n"
"\t\t\tset args [info args $p]\n"
"\t\t\tset idx -1\n"
"\t\t\tforeach a $args {\n"
"\t\t\t\tif {[info default $p $a d]} {\n"
"\t\t\t\t\tlset args [incr idx] [list $a $d]\n"
"\t\t\t\t} else {\n"
"\t\t\t\t\tlset args [incr idx] [list $a]\n"
"\t\t\t\t}\n"
"\t\t\t}\n"
"\t\t\tset b [info body $p]\n"
"\t\t\tset p [namespace tail $p]\n"
"\t\t\tproc $p $args $b\n"
"\t\t}\n"
"\t\tforeach v [info vars [info object namespace $originObject]::*] {\n"
"\t\t\tupvar 0 $v vOrigin\n"
"\t\t\tnamespace upvar [namespace current] [namespace tail $v] vNew\n"
"\t\t\tif {[info exists vOrigin]} {\n"
"\t\t\t\tif {[array exists vOrigin]} {\n"
"\t\t\t\t\tarray set vNew [array get vOrigin]\n"
"\t\t\t\t} else {\n"
"\t\t\t\t\tset vNew $vOrigin\n"
"\t\t\t\t}\n"
"\t\t\t}\n"
"\t\t}\n"
"\t}\n"
"\tdefine class method <cloned> {originObject} {\n"
"\t\tnext $originObject\n"
"\t\t::oo::UpdateClassDelegatesAfterClone $originObject [self]\n"
"\t}\n"
"\tclass create singleton {\n"
"\t\tsuperclass class\n"
"\t\tvariable object\n"
"\t\tunexport create createWithNamespace\n"
"\t\tmethod new args {\n"
"\t\t\tif {![info exists object] || ![info object isa object $object]} {\n"
"\t\t\t\tset object [next {*}$args]\n"
"\t\t\t\t::oo::objdefine $object {\n"
"\t\t\t\t\tmethod destroy {} {\n"
"\t\t\t\t\t\t::return -code error -errorcode {TCLOO SINGLETON} \\\n"
"\t\t\t\t\t\t\t\"may not destroy a singleton object\"\n"
"\t\t\t\t\t}\n"
"\t\t\t\t\tmethod <cloned> {originObject} {\n"
"\t\t\t\t\t\t::return -code error -errorcode {TCLOO SINGLETON} \\\n"
"\t\t\t\t\t\t\t\"may not clone a singleton object\"\n"
"\t\t\t\t\t}\n"
"\t\t\t\t}\n"
"\t\t\t}\n"
"\t\t\treturn $object\n"
"\t\t}\n"
"\t}\n"
"\tclass create abstract {\n"
"\t\tsuperclass class\n"
"\t\tunexport create createWithNamespace new\n"
"\t}\n"
"}\n"
/* !END!: Do not edit above this line. */
;
#endif /* TCL_OO_SCRIPT_H */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
+456
View File
@@ -0,0 +1,456 @@
# tclOOScript.h --
#
# This file contains support scripts for TclOO. They are defined here so
# that the code can be definitely run even in safe interpreters; TclOO's
# core setup is safe.
#
# Copyright (c) 2012-2018 Donal K. Fellows
# Copyright (c) 2013 Andreas Kupries
# Copyright (c) 2017 Gerald Lester
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
::namespace eval ::oo {
::namespace path {}
#
# Commands that are made available to objects by default.
#
namespace eval Helpers {
::namespace path {}
# ------------------------------------------------------------------
#
# callback, mymethod --
#
# Create a script prefix that calls a method on the current
# object. Same operation, two names.
#
# ------------------------------------------------------------------
proc callback {method args} {
list [uplevel 1 {::namespace which my}] $method {*}$args
}
# Make the [callback] command appear as [mymethod] too.
namespace export callback
namespace eval tmp {namespace import ::oo::Helpers::callback}
namespace export -clear
rename tmp::callback mymethod
namespace delete tmp
# ------------------------------------------------------------------
#
# classvariable --
#
# Link to a variable in the class of the current object.
#
# ------------------------------------------------------------------
proc classvariable {name args} {
# Get a reference to the class's namespace
set ns [info object namespace [uplevel 1 {self class}]]
# Double up the list of variable names
foreach v [list $name {*}$args] {
if {[string match *(*) $v]} {
set reason "can't create a scalar variable that looks like an array element"
return -code error -errorcode {TCL UPVAR LOCAL_ELEMENT} \
[format {bad variable name "%s": %s} $v $reason]
}
if {[string match *::* $v]} {
set reason "can't create a local variable with a namespace separator in it"
return -code error -errorcode {TCL UPVAR INVERTED} \
[format {bad variable name "%s": %s} $v $reason]
}
lappend vs $v $v
}
# Lastly, link the caller's local variables to the class's variables
tailcall namespace upvar $ns {*}$vs
}
# ------------------------------------------------------------------
#
# link --
#
# Make a command that invokes a method on the current object.
# The name of the command and the name of the method match by
# default.
#
# ------------------------------------------------------------------
proc link {args} {
set ns [uplevel 1 {::namespace current}]
foreach link $args {
if {[llength $link] == 2} {
lassign $link src dst
} elseif {[llength $link] == 1} {
lassign $link src
set dst $src
} else {
return -code error -errorcode {TCLOO CMDLINK FORMAT} \
"bad link description; must only have one or two elements"
}
if {![string match ::* $src]} {
set src [string cat $ns :: $src]
}
interp alias {} $src {} ${ns}::my $dst
trace add command ${ns}::my delete [list \
::oo::UnlinkLinkedCommand $src]
}
return
}
}
# ----------------------------------------------------------------------
#
# UnlinkLinkedCommand --
#
# Callback used to remove linked command when the underlying mechanism
# that supports it is deleted.
#
# ----------------------------------------------------------------------
proc UnlinkLinkedCommand {cmd args} {
if {[namespace which $cmd] ne {}} {
rename $cmd {}
}
}
# ----------------------------------------------------------------------
#
# DelegateName --
#
# Utility that gets the name of the class delegate for a class. It's
# trivial, but makes working with them much easier as delegate names are
# intentionally hard to create by accident.
#
# ----------------------------------------------------------------------
proc DelegateName {class} {
string cat [info object namespace $class] {:: oo ::delegate}
}
# ----------------------------------------------------------------------
#
# MixinClassDelegates --
#
# Support code called *after* [oo::define] inside the constructor of a
# class that patches in the appropriate class delegates.
#
# ----------------------------------------------------------------------
proc MixinClassDelegates {class} {
if {![info object isa class $class]} {
return
}
set delegate [DelegateName $class]
if {![info object isa class $delegate]} {
return
}
foreach c [info class superclass $class] {
set d [DelegateName $c]
if {![info object isa class $d]} {
continue
}
define $delegate superclass -append $d
}
objdefine $class mixin -append $delegate
}
# ----------------------------------------------------------------------
#
# UpdateClassDelegatesAfterClone --
#
# Support code that is like [MixinClassDelegates] except for when a
# class is cloned.
#
# ----------------------------------------------------------------------
proc UpdateClassDelegatesAfterClone {originObject targetObject} {
# Rebuild the class inheritance delegation class
set originDelegate [DelegateName $originObject]
set targetDelegate [DelegateName $targetObject]
if {
[info object isa class $originDelegate]
&& ![info object isa class $targetDelegate]
} then {
copy $originDelegate $targetDelegate
objdefine $targetObject mixin -set \
{*}[lmap c [info object mixin $targetObject] {
if {$c eq $originDelegate} {set targetDelegate} {set c}
}]
}
}
# ----------------------------------------------------------------------
#
# oo::define::classmethod --
#
# Defines a class method. See define(n) for details.
#
# Note that the ::oo::define namespace is semi-public and a bit weird
# anyway, so we don't regard the namespace path as being under control:
# fully qualified names are used for everything.
#
# ----------------------------------------------------------------------
proc define::classmethod {name {args {}} {body {}}} {
# Create the method on the class if the caller gave arguments and body
::set argc [::llength [::info level 0]]
::if {$argc == 3} {
::return -code error -errorcode {TCL WRONGARGS} [::format \
{wrong # args: should be "%s name ?args body?"} \
[::lindex [::info level 0] 0]]
}
::set cls [::uplevel 1 self]
::if {$argc == 4} {
::oo::define [::oo::DelegateName $cls] method $name $args $body
}
# Make the connection by forwarding
::tailcall forward $name myclass $name
}
# ----------------------------------------------------------------------
#
# oo::define::initialise, oo::define::initialize --
#
# Do specific initialisation for a class. See define(n) for details.
#
# Note that the ::oo::define namespace is semi-public and a bit weird
# anyway, so we don't regard the namespace path as being under control:
# fully qualified names are used for everything.
#
# ----------------------------------------------------------------------
proc define::initialise {body} {
::set clsns [::info object namespace [::uplevel 1 self]]
::tailcall apply [::list {} $body $clsns]
}
# Make the [initialise] definition appear as [initialize] too
namespace eval define {
::namespace export initialise
::namespace eval tmp {::namespace import ::oo::define::initialise}
::namespace export -clear
::rename tmp::initialise initialize
::namespace delete tmp
}
# ----------------------------------------------------------------------
#
# Slot --
#
# The class of slot operations, which are basically lists at the low
# level of TclOO; this provides a more consistent interface to them.
#
# ----------------------------------------------------------------------
define Slot {
# ------------------------------------------------------------------
#
# Slot Get --
#
# Basic slot getter. Retrieves the contents of the slot.
# Particular slots must provide concrete non-erroring
# implementation.
#
# ------------------------------------------------------------------
method Get {} {
return -code error -errorcode {TCLOO ABSTRACT_SLOT} "unimplemented"
}
# ------------------------------------------------------------------
#
# Slot Set --
#
# Basic slot setter. Sets the contents of the slot. Particular
# slots must provide concrete non-erroring implementation.
#
# ------------------------------------------------------------------
method Set list {
return -code error -errorcode {TCLOO ABSTRACT_SLOT} "unimplemented"
}
# ------------------------------------------------------------------
#
# Slot Resolve --
#
# Helper that lets a slot convert a list of arguments of a
# particular type to their canonical forms. Defaults to doing
# nothing (suitable for simple strings).
#
# ------------------------------------------------------------------
method Resolve list {
return $list
}
# ------------------------------------------------------------------
#
# Slot -set, -append, -clear, --default-operation --
#
# Standard public slot operations. If a slot can't figure out
# what method to call directly, it uses --default-operation.
#
# ------------------------------------------------------------------
method -set args {
set my [namespace which my]
set args [lmap a $args {uplevel 1 [list $my Resolve $a]}]
tailcall my Set $args
}
method -append args {
set my [namespace which my]
set args [lmap a $args {uplevel 1 [list $my Resolve $a]}]
set current [uplevel 1 [list $my Get]]
tailcall my Set [list {*}$current {*}$args]
}
method -clear {} {tailcall my Set {}}
method -prepend args {
set my [namespace which my]
set args [lmap a $args {uplevel 1 [list $my Resolve $a]}]
set current [uplevel 1 [list $my Get]]
tailcall my Set [list {*}$args {*}$current]
}
method -remove args {
set my [namespace which my]
set args [lmap a $args {uplevel 1 [list $my Resolve $a]}]
set current [uplevel 1 [list $my Get]]
tailcall my Set [lmap val $current {
if {$val in $args} continue else {set val}
}]
}
# Default handling
forward --default-operation my -append
method unknown {args} {
set def --default-operation
if {[llength $args] == 0} {
tailcall my $def
} elseif {![string match -* [lindex $args 0]]} {
tailcall my $def {*}$args
}
next {*}$args
}
# Set up what is exported and what isn't
export -set -append -clear -prepend -remove
unexport unknown destroy
}
# Set the default operation differently for these slots
objdefine define::superclass forward --default-operation my -set
objdefine define::mixin forward --default-operation my -set
objdefine objdefine::mixin forward --default-operation my -set
# ----------------------------------------------------------------------
#
# oo::object <cloned> --
#
# Handler for cloning objects that clones basic bits (only!) of the
# object's namespace. Non-procedures, traces, sub-namespaces, etc. need
# more complex (and class-specific) handling.
#
# ----------------------------------------------------------------------
define object method <cloned> {originObject} {
# Copy over the procedures from the original namespace
foreach p [info procs [info object namespace $originObject]::*] {
set args [info args $p]
set idx -1
foreach a $args {
if {[info default $p $a d]} {
lset args [incr idx] [list $a $d]
} else {
lset args [incr idx] [list $a]
}
}
set b [info body $p]
set p [namespace tail $p]
proc $p $args $b
}
# Copy over the variables from the original namespace
foreach v [info vars [info object namespace $originObject]::*] {
upvar 0 $v vOrigin
namespace upvar [namespace current] [namespace tail $v] vNew
if {[info exists vOrigin]} {
if {[array exists vOrigin]} {
array set vNew [array get vOrigin]
} else {
set vNew $vOrigin
}
}
}
# General commands, sub-namespaces and advancd variable config (traces,
# etc) are *not* copied over. Classes that want that should do it
# themselves.
}
# ----------------------------------------------------------------------
#
# oo::class <cloned> --
#
# Handler for cloning classes, which fixes up the delegates.
#
# ----------------------------------------------------------------------
define class method <cloned> {originObject} {
next $originObject
# Rebuild the class inheritance delegation class
::oo::UpdateClassDelegatesAfterClone $originObject [self]
}
# ----------------------------------------------------------------------
#
# oo::singleton --
#
# A metaclass that is used to make classes that only permit one instance
# of them to exist. See singleton(n).
#
# ----------------------------------------------------------------------
class create singleton {
superclass class
variable object
unexport create createWithNamespace
method new args {
if {![info exists object] || ![info object isa object $object]} {
set object [next {*}$args]
::oo::objdefine $object {
method destroy {} {
::return -code error -errorcode {TCLOO SINGLETON} \
"may not destroy a singleton object"
}
method <cloned> {originObject} {
::return -code error -errorcode {TCLOO SINGLETON} \
"may not clone a singleton object"
}
}
}
return $object
}
}
# ----------------------------------------------------------------------
#
# oo::abstract --
#
# A metaclass that is used to make classes that can't be directly
# instantiated. See abstract(n).
#
# ----------------------------------------------------------------------
class create abstract {
superclass class
unexport create createWithNamespace new
}
}
# Local Variables:
# mode: tcl
# c-basic-offset: 4
# fill-column: 78
# End:
+1
View File
@@ -73,6 +73,7 @@ const TclOOStubs tclOOStubs = {
Tcl_ClassSetConstructor, /* 26 */
Tcl_ClassSetDestructor, /* 27 */
Tcl_GetObjectName, /* 28 */
Tcl_MethodIsPrivate, /* 29 */
};
/* !END!: Do not edit above this line. */
+127 -40
View File
@@ -37,7 +37,7 @@ Tcl_Obj *tclFreeObjList = NULL;
* TclNewObj macro, however, so must be visible.
*/
#ifdef TCL_THREADS
#if TCL_THREADS
MODULE_SCOPE Tcl_Mutex tclObjMutex;
Tcl_Mutex tclObjMutex;
#endif
@@ -50,7 +50,7 @@ Tcl_Mutex tclObjMutex;
char tclEmptyString = '\0';
#if defined(TCL_MEM_DEBUG) && defined(TCL_THREADS)
#if TCL_THREADS && defined(TCL_MEM_DEBUG)
/*
* Structure for tracking the source file and line number where a given
* Tcl_Obj was allocated. We also track the pointer to the Tcl_Obj itself,
@@ -87,7 +87,7 @@ typedef struct {
* tclCompile.h for the definition of this
* structure, and for references to all
* related places in the core. */
#if defined(TCL_MEM_DEBUG) && defined(TCL_THREADS)
#if TCL_THREADS && defined(TCL_MEM_DEBUG)
Tcl_HashTable *objThreadMap;/* Thread local table that is used to check
* that a Tcl_Obj was not allocated by some
* other thread. */
@@ -156,7 +156,7 @@ typedef struct PendingObjData {
/*
* Macro to set up the local reference to the deletion context.
*/
#ifndef TCL_THREADS
#if !TCL_THREADS
static PendingObjData pendingObjData;
#define ObjInitDeletionContext(contextPtr) \
PendingObjData *const contextPtr = &pendingObjData
@@ -452,7 +452,7 @@ TclInitObjSubsystem(void)
void
TclFinalizeThreadObjects(void)
{
#if defined(TCL_MEM_DEBUG) && defined(TCL_THREADS)
#if TCL_THREADS && defined(TCL_MEM_DEBUG)
Tcl_HashEntry *hPtr;
Tcl_HashSearch hSearch;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -1009,7 +1009,7 @@ void
TclDbDumpActiveObjects(
FILE *outFile)
{
#if defined(TCL_MEM_DEBUG) && defined(TCL_THREADS)
#if TCL_THREADS && defined(TCL_MEM_DEBUG)
Tcl_HashSearch hSearch;
Tcl_HashEntry *hPtr;
Tcl_HashTable *tablePtr;
@@ -1069,7 +1069,7 @@ TclDbInitNewObj(
objPtr->length = 0;
objPtr->typePtr = NULL;
#ifdef TCL_THREADS
#if TCL_THREADS
/*
* Add entry to a thread local map used to check if a Tcl_Obj was
* allocated by the currently executing thread.
@@ -1305,7 +1305,7 @@ TclFreeObj(
ObjInitDeletionContext(context);
# ifdef TCL_THREADS
#if TCL_THREADS
/*
* Check to make sure that the Tcl_Obj was allocated by the current
* thread. Don't do this check when shutting down since thread local
@@ -1632,32 +1632,30 @@ Tcl_GetString(
register Tcl_Obj *objPtr) /* Object whose string rep byte pointer should
* be returned. */
{
if (objPtr->bytes != NULL) {
return objPtr->bytes;
}
/*
* Note we do not check for objPtr->typePtr == NULL. An invariant of
* a properly maintained Tcl_Obj is that at least one of objPtr->bytes
* and objPtr->typePtr must not be NULL. If broken extensions fail to
* maintain that invariant, we can crash here.
*/
if (objPtr->typePtr->updateStringProc == NULL) {
if (objPtr->bytes == NULL) {
/*
* Those Tcl_ObjTypes which choose not to define an updateStringProc
* must be written in such a way that (objPtr->bytes) never becomes
* NULL. This panic was added in Tcl 8.1.
* Note we do not check for objPtr->typePtr == NULL. An invariant
* of a properly maintained Tcl_Obj is that at least one of
* objPtr->bytes and objPtr->typePtr must not be NULL. If broken
* extensions fail to maintain that invariant, we can crash here.
*/
Tcl_Panic("UpdateStringProc should not be invoked for type %s",
objPtr->typePtr->name);
}
objPtr->typePtr->updateStringProc(objPtr);
if (objPtr->bytes == NULL || objPtr->length < 0
|| objPtr->bytes[objPtr->length] != '\0') {
Tcl_Panic("UpdateStringProc for type '%s' "
"failed to create a valid string rep", objPtr->typePtr->name);
if (objPtr->typePtr->updateStringProc == NULL) {
/*
* Those Tcl_ObjTypes which choose not to define an
* updateStringProc must be written in such a way that
* (objPtr->bytes) never becomes NULL.
*/
Tcl_Panic("UpdateStringProc should not be invoked for type %s",
objPtr->typePtr->name);
}
objPtr->typePtr->updateStringProc(objPtr);
if (objPtr->bytes == NULL || objPtr->length < 0
|| objPtr->bytes[objPtr->length] != '\0') {
Tcl_Panic("UpdateStringProc for type '%s' "
"failed to create a valid string rep",
objPtr->typePtr->name);
}
}
return objPtr->bytes;
}
@@ -1693,8 +1691,31 @@ Tcl_GetStringFromObj(
* rep's byte array length should * be stored.
* If NULL, no length is stored. */
{
(void) TclGetString(objPtr);
if (objPtr->bytes == NULL) {
/*
* Note we do not check for objPtr->typePtr == NULL. An invariant
* of a properly maintained Tcl_Obj is that at least one of
* objPtr->bytes and objPtr->typePtr must not be NULL. If broken
* extensions fail to maintain that invariant, we can crash here.
*/
if (objPtr->typePtr->updateStringProc == NULL) {
/*
* Those Tcl_ObjTypes which choose not to define an
* updateStringProc must be written in such a way that
* (objPtr->bytes) never becomes NULL.
*/
Tcl_Panic("UpdateStringProc should not be invoked for type %s",
objPtr->typePtr->name);
}
objPtr->typePtr->updateStringProc(objPtr);
if (objPtr->bytes == NULL || objPtr->length < 0
|| objPtr->bytes[objPtr->length] != '\0') {
Tcl_Panic("UpdateStringProc for type '%s' "
"failed to create a valid string rep",
objPtr->typePtr->name);
}
}
if (lengthPtr != NULL) {
*lengthPtr = objPtr->length;
}
@@ -2786,7 +2807,7 @@ Tcl_GetLongFromObj(
if (w >= -(Tcl_WideInt)(ULONG_MAX)
&& w <= (Tcl_WideInt)(ULONG_MAX)) {
*longPtr = Tcl_WideAsLong(w);
*longPtr = (long) w;
return TCL_OK;
}
goto tooLarge;
@@ -2812,10 +2833,9 @@ Tcl_GetLongFromObj(
mp_int big;
UNPACK_BIGNUM(objPtr, big);
if ((size_t) big.used <= (CHAR_BIT * sizeof(long) + DIGIT_BIT - 1)
if ((size_t) big.used <= (CHAR_BIT * sizeof(unsigned long) + DIGIT_BIT - 1)
/ DIGIT_BIT) {
unsigned long value = 0, numBytes = sizeof(long);
long scratch;
unsigned long scratch, value = 0, numBytes = sizeof(unsigned long);
unsigned char *bytes = (unsigned char *) &scratch;
if (mp_to_unsigned_bin_n(&big, bytes, &numBytes) == MP_OKAY) {
@@ -3083,6 +3103,73 @@ Tcl_GetWideIntFromObj(
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* TclGetWideBitsFromObj --
*
* Attempt to return a wide integer from the Tcl object "objPtr". If the
* object is not already a int, double or bignum, an attempt will be made
* to convert it to one of these. Out-of-range values don't result in an
* error, but only the least significant 64 bits will be returned.
*
* Results:
* The return value is a standard Tcl object result. If an error occurs
* during conversion, an error message is left in the interpreter's
* result unless "interp" is NULL.
*
* Side effects:
* If the object is not already an int, double or bignum object, the
* conversion will free any old internal representation.
*
*----------------------------------------------------------------------
*/
int
TclGetWideBitsFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* Object from which to get a wide int. */
Tcl_WideInt *wideIntPtr) /* Place to store resulting wide integer. */
{
do {
if (objPtr->typePtr == &tclIntType) {
*wideIntPtr = objPtr->internalRep.wideValue;
return TCL_OK;
}
if (objPtr->typePtr == &tclDoubleType) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected integer but got \"%s\"",
TclGetString(objPtr)));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
}
return TCL_ERROR;
}
if (objPtr->typePtr == &tclBignumType) {
mp_int big;
Tcl_WideUInt value = 0, scratch;
unsigned long numBytes = sizeof(Tcl_WideInt);
unsigned char *bytes = (unsigned char *) &scratch;
Tcl_GetBignumFromObj(NULL, objPtr, &big);
mp_mod_2d(&big, (int) (CHAR_BIT * sizeof(Tcl_WideInt)), &big);
mp_to_unsigned_bin_n(&big, bytes, &numBytes);
while (numBytes-- > 0) {
value = (value << CHAR_BIT) | *bytes++;
}
if (big.sign) {
value = -value;
}
*wideIntPtr = (Tcl_WideInt) value;
mp_clear(&big);
return TCL_OK;
}
} while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
TCL_PARSE_INTEGER_ONLY)==TCL_OK);
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
@@ -3449,7 +3536,7 @@ Tcl_SetBignumObj(
while (numBytes-- > 0) {
value = (value << CHAR_BIT) | *bytes++;
}
if (value > (((~(Tcl_WideUInt)0) >> 1) + bignumValue->sign)) {
if (value > ((Tcl_WideUInt)WIDE_MAX + bignumValue->sign)) {
goto tooLargeForWide;
}
if (bignumValue->sign) {
@@ -3598,7 +3685,7 @@ Tcl_DbIncrRefCount(
Tcl_Panic("incrementing refCount of previously disposed object");
}
# ifdef TCL_THREADS
#if TCL_THREADS
/*
* Check to make sure that the Tcl_Obj was allocated by the current
* thread. Don't do this check when shutting down since thread local
@@ -3661,7 +3748,7 @@ Tcl_DbDecrRefCount(
Tcl_Panic("decrementing refCount of previously disposed object");
}
# ifdef TCL_THREADS
#if TCL_THREADS
/*
* Check to make sure that the Tcl_Obj was allocated by the current
* thread. Don't do this check when shutting down since thread local
@@ -3726,7 +3813,7 @@ Tcl_DbIsShared(
Tcl_Panic("checking whether previously disposed object is shared");
}
# ifdef TCL_THREADS
#if TCL_THREADS
/*
* Check to make sure that the Tcl_Obj was allocated by the current
* thread. Don't do this check when shutting down since thread local
+3 -2
View File
@@ -23,8 +23,8 @@
* procedure.
*/
#if defined(__CYGWIN__)
static TCL_NORETURN Tcl_PanicProc *panicProc = tclWinDebugPanic;
#if defined(__CYGWIN__) || (defined(_WIN32) && (defined(TCL_NO_DEPRECATED) || TCL_MAJOR_VERSION > 8))
static TCL_NORETURN1 Tcl_PanicProc *panicProc = tclWinDebugPanic;
#else
static TCL_NORETURN1 Tcl_PanicProc *panicProc = NULL;
#endif
@@ -45,6 +45,7 @@ static TCL_NORETURN1 Tcl_PanicProc *panicProc = NULL;
*----------------------------------------------------------------------
*/
#undef Tcl_SetPanicProc
void
Tcl_SetPanicProc(
TCL_NORETURN1 Tcl_PanicProc *proc)
+6 -1
View File
@@ -979,7 +979,12 @@ TclParseBackslash(
if (readPtr != NULL) {
*readPtr = count;
}
return Tcl_UniCharToUtf(result, dst);
count = Tcl_UniCharToUtf(result, dst);
if (!count) {
/* Special case for handling upper surrogates. */
count = Tcl_UniCharToUtf(-1, dst);
}
return count;
}
/*
+1 -1
View File
@@ -577,7 +577,7 @@ SelectPackage(ClientData data[], Tcl_Interp *interp, int result) {
PkgAvail *availPtr, *bestPtr, *bestStablePtr;
char *availVersion, *bestVersion, *bestStableVersion;
/* Internal rep. of versions */
int availStable, satisfies;
int availStable, satisfies;
Require *reqPtr = data[0];
int reqc = PTR2INT(data[1]);
Tcl_Obj **const reqv = data[2];
+3 -1
View File
@@ -40,7 +40,7 @@
* configuration information.
*/
#ifdef TCL_THREADS
#if TCL_THREADS
# define CFG_THREADED "1"
#else
# define CFG_THREADED "0"
@@ -105,6 +105,8 @@ static Tcl_Config const cfg[] = {
{"scriptdir,runtime", CFG_RUNTIME_SCRDIR},
{"includedir,runtime", CFG_RUNTIME_INCDIR},
{"docdir,runtime", CFG_RUNTIME_DOCDIR},
{"dllfile,runtime", CFG_RUNTIME_DLLFILE},
{"zipfile,runtime", CFG_RUNTIME_ZIPFILE},
/* Installation paths to various stuff */
+3 -15
View File
@@ -24,20 +24,8 @@
#endif
#include "tcl.h"
#if !defined(LLONG_MIN)
# ifdef TCL_WIDE_INT_IS_LONG
# define LLONG_MIN LONG_MIN
# else
# ifdef LLONG_BIT
# define LLONG_MIN ((Tcl_WideInt)(Tcl_LongAsWide(1)<<(LLONG_BIT-1)))
# else
/* Assume we're on a system with a 64-bit 'long long' type */
# define LLONG_MIN ((Tcl_WideInt)(Tcl_LongAsWide(1)<<63))
# endif
# endif
/* Assume that if LLONG_MIN is undefined, then so is LLONG_MAX */
# define LLONG_MAX (~LLONG_MIN)
#endif
#define UWIDE_MAX ((Tcl_WideUInt)-1)
#define WIDE_MAX ((Tcl_WideInt)(UWIDE_MAX >> 1))
#define WIDE_MIN ((Tcl_WideInt)((Tcl_WideUInt)WIDE_MAX+1))
#endif /* _TCLPORT */
+53 -79
View File
@@ -505,10 +505,11 @@ TclCreateProc(
goto procError;
}
nameLength = Tcl_NumUtfChars(Tcl_GetString(fieldValues[0]), fieldValues[0]->length);
argname = Tcl_GetStringFromObj(fieldValues[0], &plen);
nameLength = Tcl_NumUtfChars(argname, plen);
if (fieldCount == 2) {
valueLength = Tcl_NumUtfChars(Tcl_GetString(fieldValues[1]),
fieldValues[1]->length);
const char * value = TclGetString(fieldValues[1]);
valueLength = Tcl_NumUtfChars(value, fieldValues[1]->length);
} else {
valueLength = 0;
}
@@ -517,7 +518,6 @@ TclCreateProc(
* Check that the formal parameter name is a scalar.
*/
argname = Tcl_GetStringFromObj(fieldValues[0], &plen);
argnamei = argname;
argnamelast = argname[plen-1];
while (plen--) {
@@ -611,7 +611,7 @@ TclCreateProc(
procPtr->lastLocalPtr = localPtr;
}
localPtr->nextPtr = NULL;
localPtr->nameLength = Tcl_NumUtfChars(argname, fieldValues[0]->length);
localPtr->nameLength = nameLength;
localPtr->frameIndex = i;
localPtr->flags = VAR_ARGUMENT;
localPtr->resolveInfo = NULL;
@@ -688,51 +688,15 @@ TclGetFrame(
CallFrame **framePtrPtr) /* Store pointer to frame here (or NULL if
* global frame indicated). */
{
register Interp *iPtr = (Interp *) interp;
int curLevel, level, result;
CallFrame *framePtr;
int result;
Tcl_Obj obj;
/*
* Parse string to figure out which level number to go to.
*/
result = 1;
curLevel = iPtr->varFramePtr->level;
if (*name== '#') {
if (Tcl_GetInt(interp, name+1, &level) != TCL_OK || level < 0) {
goto levelError;
}
} else if (isdigit(UCHAR(*name))) { /* INTL: digit */
if (Tcl_GetInt(interp, name, &level) != TCL_OK) {
goto levelError;
}
level = curLevel - level;
} else {
level = curLevel - 1;
result = 0;
}
/*
* Figure out which frame to use, and return it to the caller.
*/
for (framePtr = iPtr->varFramePtr; framePtr != NULL;
framePtr = framePtr->callerVarPtr) {
if (framePtr->level == level) {
break;
}
}
if (framePtr == NULL) {
goto levelError;
}
*framePtrPtr = framePtr;
return result;
levelError:
Tcl_SetObjResult(interp, Tcl_ObjPrintf("bad level \"%s\"", name));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "STACKLEVEL", NULL);
return -1;
obj.bytes = (char *) name;
obj.length = strlen(name);
obj.typePtr = NULL;
result = TclObjGetFrame(interp, &obj, framePtrPtr);
TclFreeIntRep(&obj);
return result;
}
/*
@@ -770,6 +734,7 @@ TclObjGetFrame(
register Interp *iPtr = (Interp *) interp;
int curLevel, level, result;
const char *name = NULL;
Tcl_WideInt w;
/*
* Parse object to figure out which level number to go to.
@@ -785,25 +750,33 @@ TclObjGetFrame(
if (objPtr == NULL) {
/* Do nothing */
} else if (TCL_OK == Tcl_GetIntFromObj(NULL, objPtr, &level)
&& (level >= 0)) {
level = curLevel - level;
result = 1;
} else if (TCL_OK == Tcl_GetIntFromObj(NULL, objPtr, &level)) {
Tcl_GetWideIntFromObj(NULL, objPtr, &w);
if (w < 0 || w > INT_MAX || curLevel > w + INT_MAX) {
result = -1;
} else {
level = curLevel - level;
result = 1;
}
} else if (objPtr->typePtr == &levelReferenceType) {
level = (int) objPtr->internalRep.wideValue;
result = 1;
} else {
name = TclGetString(objPtr);
if (name[0] == '#') {
if (TCL_OK == Tcl_GetInt(NULL, name+1, &level) && level >= 0) {
TclFreeIntRep(objPtr);
objPtr->typePtr = &levelReferenceType;
objPtr->internalRep.wideValue = level;
result = 1;
if (TCL_OK == Tcl_GetInt(NULL, name+1, &level)) {
if (level < 0 || (level > 0 && name[1] == '-')) {
result = -1;
} else {
TclFreeIntRep(objPtr);
objPtr->typePtr = &levelReferenceType;
objPtr->internalRep.wideValue = level;
result = 1;
}
} else {
result = -1;
}
} else if (isdigit(UCHAR(name[0]))) { /* INTL: digit */
} else if (TclGetWideBitsFromObj(interp, objPtr, &w) == TCL_OK) {
/*
* If this were an integer, we'd have succeeded already.
* Docs say we have to treat this as a 'bad level' error.
@@ -814,7 +787,6 @@ TclObjGetFrame(
if (result == 0) {
level = curLevel - 1;
name = "1";
}
if (result != -1) {
if (level >= 0) {
@@ -827,11 +799,11 @@ TclObjGetFrame(
}
}
}
if (name == NULL) {
name = TclGetString(objPtr);
}
}
if (name == NULL) {
name = TclGetString(objPtr);
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf("bad level \"%s\"", name));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "LEVEL", name, NULL);
return -1;
@@ -1035,7 +1007,6 @@ ProcWrongNumArgs(
{
CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
register Proc *procPtr = framePtr->procPtr;
register Var *defPtr;
int localCt = procPtr->numCompiledLocals, numArgs, i;
Tcl_Obj **desiredObjs;
const char *final = NULL;
@@ -1059,23 +1030,26 @@ ProcWrongNumArgs(
}
Tcl_IncrRefCount(desiredObjs[0]);
defPtr = (Var *) (&framePtr->localCachePtr->varName0 + localCt);
for (i=1 ; i<=numArgs ; i++, defPtr++) {
Tcl_Obj *argObj;
Tcl_Obj *namePtr = localName(framePtr, i-1);
if (localCt > 0) {
register Var *defPtr = (Var *) (&framePtr->localCachePtr->varName0 + localCt);
if (defPtr->value.objPtr != NULL) {
TclNewObj(argObj);
Tcl_AppendStringsToObj(argObj, "?", TclGetString(namePtr), "?", NULL);
} else if (defPtr->flags & VAR_IS_ARGS) {
numArgs--;
final = "?arg ...?";
break;
} else {
argObj = namePtr;
Tcl_IncrRefCount(namePtr);
for (i=1 ; i<=numArgs ; i++, defPtr++) {
Tcl_Obj *argObj;
Tcl_Obj *namePtr = localName(framePtr, i-1);
if (defPtr->value.objPtr != NULL) {
TclNewObj(argObj);
Tcl_AppendStringsToObj(argObj, "?", TclGetString(namePtr), "?", NULL);
} else if (defPtr->flags & VAR_IS_ARGS) {
numArgs--;
final = "?arg ...?";
break;
} else {
argObj = namePtr;
Tcl_IncrRefCount(namePtr);
}
desiredObjs[i] = argObj;
}
desiredObjs[i] = argObj;
}
Tcl_ResetResult(interp);
+35 -35
View File
@@ -1,7 +1,7 @@
/*
* tclProcess.c --
*
* This file implements the "tcl::process" ensemble for subprocess
* This file implements the "tcl::process" ensemble for subprocess
* management as defined by TIP #462.
*
* Copyright (c) 2017 Frederic Bonnet.
@@ -13,14 +13,14 @@
#include "tclInt.h"
/*
* Autopurge flag. Process-global because of the way Tcl manages child
* Autopurge flag. Process-global because of the way Tcl manages child
* processes (see tclPipe.c).
*/
static int autopurge = 1; /* Autopurge flag. */
/*
* Hash tables that keeps track of all child process statuses. Keys are the
* Hash tables that keeps track of all child process statuses. Keys are the
* child process ids and resolved pids, values are (ProcessInfo *).
*/
@@ -29,7 +29,7 @@ typedef struct ProcessInfo {
int resolvedPid; /* Resolved process id. */
int purge; /* Purge eventualy. */
TclProcessWaitStatus status;/* Process status. */
int code; /* Error code, exit status or signal
int code; /* Error code, exit status or signal
number. */
Tcl_Obj *msg; /* Error message. */
Tcl_Obj *error; /* Error code. */
@@ -47,7 +47,7 @@ static void InitProcessInfo(ProcessInfo *info, Tcl_Pid pid,
int resolvedPid);
static void FreeProcessInfo(ProcessInfo *info);
static int RefreshProcessInfo(ProcessInfo *info, int options);
static TclProcessWaitStatus WaitProcessStatus(Tcl_Pid pid, int resolvedPid,
static TclProcessWaitStatus WaitProcessStatus(Tcl_Pid pid, int resolvedPid,
int options, int *codePtr, Tcl_Obj **msgPtr,
Tcl_Obj **errorObjPtr);
static Tcl_Obj * BuildProcessStatusObj(ProcessInfo *info);
@@ -160,7 +160,7 @@ RefreshProcessInfo(
* Refresh & store status.
*/
info->status = WaitProcessStatus(info->pid, info->resolvedPid,
info->status = WaitProcessStatus(info->pid, info->resolvedPid,
options, &info->code, &info->msg, &info->error);
if (info->msg) Tcl_IncrRefCount(info->msg);
if (info->error) Tcl_IncrRefCount(info->error);
@@ -214,7 +214,7 @@ WaitProcessStatus(
/*
* No change.
*/
return TCL_PROCESS_UNCHANGED;
}
@@ -370,7 +370,7 @@ BuildProcessStatusObj(
/*
* Normal exit, return TCL_OK.
*/
return Tcl_NewIntObj(TCL_OK);
}
@@ -388,7 +388,7 @@ BuildProcessStatusObj(
*
* ProcessListObjCmd --
*
* This function implements the 'tcl::process list' Tcl command.
* This function implements the 'tcl::process list' Tcl command.
* Refer to the user documentation for details on what it does.
*
* Results:
@@ -423,10 +423,10 @@ ProcessListObjCmd(
list = Tcl_NewListObj(0, NULL);
Tcl_MutexLock(&infoTablesMutex);
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
entry != NULL; entry = Tcl_NextHashEntry(&search)) {
info = (ProcessInfo *) Tcl_GetHashValue(entry);
Tcl_ListObjAppendElement(interp, list,
Tcl_ListObjAppendElement(interp, list,
Tcl_NewIntObj(info->resolvedPid));
}
Tcl_MutexUnlock(&infoTablesMutex);
@@ -438,7 +438,7 @@ ProcessListObjCmd(
*
* ProcessStatusObjCmd --
*
* This function implements the 'tcl::process status' Tcl command.
* This function implements the 'tcl::process status' Tcl command.
* Refer to the user documentation for details on what it does.
*
* Results:
@@ -504,7 +504,7 @@ ProcessStatusObjCmd(
dict = Tcl_NewDictObj();
Tcl_MutexLock(&infoTablesMutex);
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
entry != NULL; entry = Tcl_NextHashEntry(&search)) {
info = (ProcessInfo *) Tcl_GetHashValue(entry);
RefreshProcessInfo(info, options);
@@ -513,7 +513,7 @@ ProcessStatusObjCmd(
/*
* Purge entry.
*/
Tcl_DeleteHashEntry(entry);
entry = Tcl_FindHashEntry(&infoTablePerPid, info->pid);
Tcl_DeleteHashEntry(entry);
@@ -523,7 +523,7 @@ ProcessStatusObjCmd(
* Add to result.
*/
Tcl_DictObjPut(interp, dict, Tcl_NewIntObj(info->resolvedPid),
Tcl_DictObjPut(interp, dict, Tcl_NewIntObj(info->resolvedPid),
BuildProcessStatusObj(info));
}
}
@@ -532,7 +532,7 @@ ProcessStatusObjCmd(
/*
* Only return statuses of provided processes.
*/
result = Tcl_ListObjGetElements(interp, objv[1], &numPids, &pidObjs);
if (result != TCL_OK) {
return result;
@@ -552,10 +552,10 @@ ProcessStatusObjCmd(
/*
* Skip unknown process.
*/
continue;
}
info = (ProcessInfo *) Tcl_GetHashValue(entry);
RefreshProcessInfo(info, options);
@@ -563,7 +563,7 @@ ProcessStatusObjCmd(
/*
* Purge entry.
*/
Tcl_DeleteHashEntry(entry);
entry = Tcl_FindHashEntry(&infoTablePerPid, info->pid);
Tcl_DeleteHashEntry(entry);
@@ -573,7 +573,7 @@ ProcessStatusObjCmd(
* Add to result.
*/
Tcl_DictObjPut(interp, dict, Tcl_NewIntObj(info->resolvedPid),
Tcl_DictObjPut(interp, dict, Tcl_NewIntObj(info->resolvedPid),
BuildProcessStatusObj(info));
}
}
@@ -587,7 +587,7 @@ ProcessStatusObjCmd(
*
* ProcessPurgeObjCmd --
*
* This function implements the 'tcl::process purge' Tcl command.
* This function implements the 'tcl::process purge' Tcl command.
* Refer to the user documentation for details on what it does.
*
* Results:
@@ -632,7 +632,7 @@ ProcessPurgeObjCmd(
*/
Tcl_MutexLock(&infoTablesMutex);
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
for (entry = Tcl_FirstHashEntry(&infoTablePerResolvedPid, &search);
entry != NULL; entry = Tcl_NextHashEntry(&search)) {
info = (ProcessInfo *) Tcl_GetHashValue(entry);
if (info->purge) {
@@ -647,7 +647,7 @@ ProcessPurgeObjCmd(
/*
* Purge only provided processes.
*/
result = Tcl_ListObjGetElements(interp, objv[1], &numPids, &pidObjs);
if (result != TCL_OK) {
return result;
@@ -665,7 +665,7 @@ ProcessPurgeObjCmd(
/*
* Skip unknown process.
*/
continue;
}
@@ -687,7 +687,7 @@ ProcessPurgeObjCmd(
*
* ProcessAutopurgeObjCmd --
*
* This function implements the 'tcl::process autopurge' Tcl command.
* This function implements the 'tcl::process autopurge' Tcl command.
* Refer to the user documentation for details on what it does.
*
* Results:
@@ -715,7 +715,7 @@ ProcessAutopurgeObjCmd(
/*
* Set given value.
*/
int flag;
int result = Tcl_GetBooleanFromObj(interp, objv[1], &flag);
if (result != TCL_OK) {
@@ -725,8 +725,8 @@ ProcessAutopurgeObjCmd(
autopurge = !!flag;
}
/*
* Return current value.
/*
* Return current value.
*/
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(autopurge));
@@ -821,9 +821,9 @@ TclProcessCreated(
/*
* Pid was reused, free old info and reuse structure.
*/
info = (ProcessInfo *) Tcl_GetHashValue(entry);
entry2 = Tcl_FindHashEntry(&infoTablePerResolvedPid,
entry2 = Tcl_FindHashEntry(&infoTablePerResolvedPid,
INT2PTR(resolvedPid));
if (entry2) Tcl_DeleteHashEntry(entry2);
FreeProcessInfo(info);
@@ -893,8 +893,8 @@ TclProcessWait(
/*
* Unknown process, just call WaitProcessStatus and return.
*/
result = WaitProcessStatus(pid, TclpGetPid(pid), options, codePtr,
result = WaitProcessStatus(pid, TclpGetPid(pid), options, codePtr,
msgObjPtr, errorObjPtr);
if (msgObjPtr && *msgObjPtr) Tcl_IncrRefCount(*msgObjPtr);
if (errorObjPtr && *errorObjPtr) Tcl_IncrRefCount(*errorObjPtr);
@@ -909,7 +909,7 @@ TclProcessWait(
* so report no change.
*/
Tcl_MutexUnlock(&infoTablesMutex);
return TCL_PROCESS_UNCHANGED;
}
@@ -919,7 +919,7 @@ TclProcessWait(
* No change, stop there.
*/
Tcl_MutexUnlock(&infoTablesMutex);
return TCL_PROCESS_UNCHANGED;
}
@@ -940,7 +940,7 @@ TclProcessWait(
*/
Tcl_DeleteHashEntry(entry);
entry = Tcl_FindHashEntry(&infoTablePerResolvedPid,
entry = Tcl_FindHashEntry(&infoTablePerResolvedPid,
INT2PTR(info->resolvedPid));
Tcl_DeleteHashEntry(entry);
FreeProcessInfo(info);
+2 -2
View File
@@ -926,9 +926,9 @@ Tcl_ScanObjCmd(
}
if (flags & SCAN_LONGER) {
if (Tcl_GetWideIntFromObj(NULL, objPtr, &wideValue) != TCL_OK) {
wideValue = LLONG_MAX;
wideValue = WIDE_MAX;
if (TclGetString(objPtr)[0] == '-') {
wideValue = LLONG_MIN;
wideValue = WIDE_MIN;
}
}
if ((flags & SCAN_UNSIGNED) && (wideValue < 0)) {
+2 -2
View File
@@ -4543,7 +4543,7 @@ Tcl_InitBignumFromDouble(
return TCL_ERROR;
}
fract = frexp(d,&expt);
fract = frexp(d, &expt);
if (expt <= 0) {
mp_init(b);
mp_zero(b);
@@ -4883,7 +4883,7 @@ Pow10TimesFrExp(
* Multiply by 10**exponent.
*/
retval = frexp(retval * pow10vals[exponent&0xf], &j);
retval = frexp(retval * pow10vals[exponent & 0xf], &j);
expt += j;
for (i=4; i<9; ++i) {
if (exponent & (1<<i)) {
+377 -114
View File
@@ -455,6 +455,48 @@ Tcl_GetCharLength(
return numChars;
}
/*
*----------------------------------------------------------------------
*
* TclCheckEmptyString --
*
* Determine whether the string value of an object is or would be the
* empty string, without generating a string representation.
*
* Results:
* Returns 1 if empty, 0 if not, and -1 if unknown.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclCheckEmptyString(
Tcl_Obj *objPtr)
{
int length = -1;
if (objPtr->bytes == &tclEmptyString) {
return TCL_EMPTYSTRING_YES;
}
if (TclListObjIsCanonical(objPtr)) {
Tcl_ListObjLength(NULL, objPtr, &length);
return length == 0;
}
if (TclIsPureDict(objPtr)) {
Tcl_DictObjSize(NULL, objPtr, &length);
return length == 0;
}
if (objPtr->bytes == NULL) {
return TCL_EMPTYSTRING_UNKNOWN;
}
return objPtr->length == 0;
}
/*
*----------------------------------------------------------------------
*
@@ -525,20 +567,22 @@ Tcl_GetUniChar(
if (index >= stringPtr->numChars) {
return -1;
}
ch = stringPtr->unicode[index];
ch = stringPtr->unicode[index];
#if TCL_UTF_MAX <= 4
/* See: bug [11ae2be95dac9417] */
if ((ch&0xF800) == 0xD800) {
if (ch&0x400) {
if ((index > 0) && ((stringPtr->unicode[index-1]&0xFC00) == 0xD800)) {
ch = -1; /* low surrogate preceded by high surrogate */
}
} else if ((++index < stringPtr->numChars)
&& ((stringPtr->unicode[index]&0xFC00) == 0xDC00)) {
/* high surrogate followed by low surrogate */
ch = (((ch & 0x3FF) << 10) | (stringPtr->unicode[index] & 0x3FF)) + 0x10000;
/* See: bug [11ae2be95dac9417] */
if ((ch & 0xF800) == 0xD800) {
if (ch & 0x400) {
if ((index > 0)
&& ((stringPtr->unicode[index-1] & 0xFC00) == 0xD800)) {
ch = -1; /* low surrogate preceded by high surrogate */
}
} else if ((++index < stringPtr->numChars)
&& ((stringPtr->unicode[index] & 0xFC00) == 0xDC00)) {
/* high surrogate followed by low surrogate */
ch = (((ch & 0x3FF) << 10) |
(stringPtr->unicode[index] & 0x3FF)) + 0x10000;
}
}
#endif
return ch;
}
@@ -562,6 +606,8 @@ Tcl_GetUniChar(
*----------------------------------------------------------------------
*/
#ifndef TCL_NO_DEPRECATED
#undef Tcl_GetUnicode
Tcl_UniChar *
Tcl_GetUnicode(
Tcl_Obj *objPtr) /* The object to find the unicode string
@@ -569,6 +615,7 @@ Tcl_GetUnicode(
{
return Tcl_GetUnicodeFromObj(objPtr, NULL);
}
#endif /* TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------
@@ -644,7 +691,8 @@ Tcl_GetRange(
if (first < 0) {
first = 0;
}
}
/*
* Optimize the case where we're really dealing with a bytearray object
* we don't need to convert to a string to perform the substring operation.
@@ -652,13 +700,14 @@ Tcl_GetRange(
if (TclIsPureByteArray(objPtr)) {
unsigned char *bytes = Tcl_GetByteArrayFromObj(objPtr, &length);
if (last >= length) {
last = length - 1;
}
if (last < first) {
return Tcl_NewObj();
}
return Tcl_NewByteArrayObj(bytes+first, last-first+1);
return Tcl_NewByteArrayObj(bytes + first, last - first + 1);
}
/*
@@ -697,24 +746,25 @@ Tcl_GetRange(
FillUnicodeRep(objPtr);
stringPtr = GET_STRING(objPtr);
}
if (last > stringPtr->numChars) {
last = stringPtr->numChars;
}
if (last < first) {
return Tcl_NewObj();
}
if (last > stringPtr->numChars) {
last = stringPtr->numChars;
}
if (last < first) {
return Tcl_NewObj();
}
#if TCL_UTF_MAX <= 4
/* See: bug [11ae2be95dac9417] */
if ((first>0) && ((stringPtr->unicode[first]&0xFC00) == 0xDC00)
&& ((stringPtr->unicode[first-1]&0xFC00) == 0xD800)) {
++first;
}
if ((last+1<stringPtr->numChars) && ((stringPtr->unicode[last+1]&0xFC00) == 0xDC00)
&& ((stringPtr->unicode[last]&0xFC00) == 0xD800)) {
++last;
}
/* See: bug [11ae2be95dac9417] */
if ((first > 0) && ((stringPtr->unicode[first] & 0xFC00) == 0xDC00)
&& ((stringPtr->unicode[first-1] & 0xFC00) == 0xD800)) {
++first;
}
if ((last + 1 < stringPtr->numChars)
&& ((stringPtr->unicode[last+1] & 0xFC00) == 0xDC00)
&& ((stringPtr->unicode[last] & 0xFC00) == 0xD800)) {
++last;
}
#endif
return Tcl_NewUnicodeObj(stringPtr->unicode + first, last-first+1);
return Tcl_NewUnicodeObj(stringPtr->unicode + first, last - first + 1);
}
/*
@@ -1272,45 +1322,51 @@ Tcl_AppendObjToObj(
/*
* Handle append of one bytearray object to another as a special case.
* Note that we only do this when the objects are pure so that the
* bytearray faithfully represent the true value; Otherwise
* appending the byte arrays together could lose information;
* bytearray faithfully represent the true value; Otherwise appending the
* byte arrays together could lose information;
*/
if ((TclIsPureByteArray(objPtr) || objPtr->bytes == &tclEmptyString)
&& TclIsPureByteArray(appendObjPtr)) {
/*
* You might expect the code here to be
*
* bytes = Tcl_GetByteArrayFromObj(appendObjPtr, &length);
* TclAppendBytesToByteArray(objPtr, bytes, length);
*
* and essentially all of the time that would be fine. However,
* it would run into trouble in the case where objPtr and
* appendObjPtr point to the same thing. That may never be a
* good idea. It seems to violate Copy On Write, and we don't
* have any tests for the situation, since making any Tcl commands
* that call Tcl_AppendObjToObj() do that appears impossible
* (They honor Copy On Write!). For the sake of extensions that
* go off into that realm, though, here's a more complex approach
* that can handle all the cases.
* and essentially all of the time that would be fine. However, it
* would run into trouble in the case where objPtr and appendObjPtr
* point to the same thing. That may never be a good idea. It seems to
* violate Copy On Write, and we don't have any tests for the
* situation, since making any Tcl commands that call
* Tcl_AppendObjToObj() do that appears impossible (They honor Copy On
* Write!). For the sake of extensions that go off into that realm,
* though, here's a more complex approach that can handle all the
* cases.
*
* First, get the lengths.
*/
/* Get lengths */
int lengthSrc;
(void) Tcl_GetByteArrayFromObj(objPtr, &length);
(void) Tcl_GetByteArrayFromObj(appendObjPtr, &lengthSrc);
/* Grow buffer enough for the append */
/*
* Grow buffer enough for the append.
*/
TclAppendBytesToByteArray(objPtr, NULL, lengthSrc);
/* Reset objPtr back to the original value */
/*
* Reset objPtr back to the original value.
*/
Tcl_SetByteArrayLength(objPtr, length);
/*
* Now do the append knowing that buffer growth cannot cause
* any trouble.
* Now do the append knowing that buffer growth cannot cause any
* trouble.
*/
TclAppendBytesToByteArray(objPtr,
@@ -1358,6 +1414,7 @@ Tcl_AppendObjToObj(
numChars = stringPtr->numChars;
if ((numChars >= 0) && (appendObjPtr->typePtr == &tclStringType)) {
String *appendStringPtr = GET_STRING(appendObjPtr);
appendNumChars = appendStringPtr->numChars;
}
@@ -1847,6 +1904,11 @@ Tcl_AppendFormatToObj(
width = 0;
if (isdigit(UCHAR(ch))) {
width = strtoul(format, &end, 10);
if (width < 0) {
msg = overflow;
errCode = "OVERFLOW";
goto errorMsg;
}
format = end;
step = TclUtfToUniChar(format, &ch);
} else if (ch == '*') {
@@ -1943,7 +2005,8 @@ Tcl_AppendFormatToObj(
format += step;
step = TclUtfToUniChar(format, &ch);
}
} else if ((ch == 't') || (ch == 'z') || (ch == 'q') || (ch == 'j') || (ch == 'L')) {
} else if ((ch == 't') || (ch == 'z') || (ch == 'q') || (ch == 'j')
|| (ch == 'L')) {
format += step;
step = TclUtfToUniChar(format, &ch);
useBig = 1;
@@ -1985,6 +2048,10 @@ Tcl_AppendFormatToObj(
goto error;
}
length = Tcl_UniCharToUtf(code, buf);
if (!length) {
/* Special case for handling upper surrogates. */
length = Tcl_UniCharToUtf(-1, buf);
}
segment = Tcl_NewStringObj(buf, length);
Tcl_IncrRefCount(segment);
allocSegment = 1;
@@ -2030,35 +2097,17 @@ Tcl_AppendFormatToObj(
}
#ifndef TCL_WIDE_INT_IS_LONG
} else if (useWide) {
if (TclGetWideIntFromObj(NULL, segment, &w) != TCL_OK) {
Tcl_Obj *objPtr;
if (Tcl_GetBignumFromObj(interp,segment,&big) != TCL_OK) {
goto error;
}
mp_mod_2d(&big, (int) CHAR_BIT*sizeof(Tcl_WideInt), &big);
objPtr = Tcl_NewBignumObj(&big);
Tcl_IncrRefCount(objPtr);
TclGetWideIntFromObj(NULL, objPtr, &w);
Tcl_DecrRefCount(objPtr);
if (TclGetWideBitsFromObj(interp, segment, &w) != TCL_OK) {
goto error;
}
isNegative = (w < (Tcl_WideInt) 0);
if (w == (Tcl_WideInt) 0) gotHash = 0;
#endif
} else if (TclGetLongFromObj(NULL, segment, &l) != TCL_OK) {
if (TclGetWideIntFromObj(NULL, segment, &w) != TCL_OK) {
Tcl_Obj *objPtr;
if (Tcl_GetBignumFromObj(interp,segment,&big) != TCL_OK) {
goto error;
}
mp_mod_2d(&big, (int) CHAR_BIT * sizeof(long), &big);
objPtr = Tcl_NewBignumObj(&big);
Tcl_IncrRefCount(objPtr);
TclGetLongFromObj(NULL, objPtr, &l);
Tcl_DecrRefCount(objPtr);
if (TclGetWideBitsFromObj(interp, segment, &w) != TCL_OK) {
goto error;
} else {
l = Tcl_WideAsLong(w);
l = (long) w;
}
if (useShort) {
s = (short) l;
@@ -2468,7 +2517,7 @@ Tcl_AppendFormatToObj(
/*
*---------------------------------------------------------------------------
*
* Tcl_Format--
* Tcl_Format --
*
* Results:
* A refcount zero Tcl_Obj.
@@ -2859,7 +2908,10 @@ TclStringRepeat(
Tcl_GetByteArrayFromObj(objResultPtr, NULL),
(count - done) * length);
} else if (unichar) {
/* Efficiently produce a pure Tcl_UniChar array result */
/*
* Efficiently produce a pure Tcl_UniChar array result.
*/
if (!inPlace || Tcl_IsShared(objPtr)) {
objResultPtr = Tcl_NewUnicodeObj(Tcl_GetUnicode(objPtr), length);
} else {
@@ -2885,7 +2937,10 @@ TclStringRepeat(
Tcl_AppendUnicodeToObj(objResultPtr, Tcl_GetUnicode(objResultPtr),
(count - done) * length);
} else {
/* Efficiently concatenate string reps */
/*
* Efficiently concatenate string reps.
*/
if (!inPlace || Tcl_IsShared(objPtr)) {
objResultPtr = Tcl_NewStringObj(Tcl_GetString(objPtr), length);
} else {
@@ -2969,9 +3024,10 @@ TclStringCat(
/* Value has a string rep. */
if (objPtr->length) {
/*
* Non-empty string rep. Not a pure bytearray, so we
* won't create a pure bytearray
* Non-empty string rep. Not a pure bytearray, so we won't
* create a pure bytearray.
*/
binary = 0;
if ((objPtr->typePtr) && (objPtr->typePtr != &tclStringType)) {
/* Prevent shimmer of non-string types. */
@@ -2992,15 +3048,25 @@ TclStringCat(
} while (--oc && (binary || allowUniChar));
if (binary) {
/* Result will be pure byte array. Pre-size it */
ov = objv; oc = objc;
/*
* Result will be pure byte array. Pre-size it
*/
int numBytes;
ov = objv;
oc = objc;
do {
Tcl_Obj *objPtr = *ov++;
if (objPtr->bytes == NULL) {
int numBytes;
/*
* Every argument is either a bytearray with a ("pure")
* value we know we can safely use, or it is an empty string.
* We don't need to count bytes for the empty strings.
*/
if (TclIsPureByteArray(objPtr)) {
Tcl_GetByteArrayFromObj(objPtr, &numBytes); /* PANIC? */
if (numBytes) {
last = objc - oc;
if (length == 0) {
@@ -3013,8 +3079,12 @@ TclStringCat(
}
} while (--oc);
} else if (allowUniChar && requestUniChar) {
/* Result will be pure Tcl_UniChar array. Pre-size it. */
ov = objv; oc = objc;
/*
* Result will be pure Tcl_UniChar array. Pre-size it.
*/
ov = objv;
oc = objc;
do {
Tcl_Obj *objPtr = *ov++;
@@ -3059,9 +3129,9 @@ TclStringCat(
} while (--oc && (length == 0) && (pendingPtr == NULL));
/*
* Either we found a possibly non-empty value, and we
* remember this index as the first and last such value so
* far seen, or (oc == 0) and all values are known empty,
* Either we found a possibly non-empty value, and we remember
* this index as the first and last such value so far seen,
* or (oc == 0) and all values are known empty,
* so first = last = objc - 1 signals the right quick return.
*/
@@ -3073,10 +3143,9 @@ TclStringCat(
/* assert ( pendingPtr != NULL ) */
/*
* There's a pending value followed by more values.
* Loop over remaining values generating strings until
* a non-empty value is found, or the pending value gets
* its string generated.
* There's a pending value followed by more values. Loop over
* remaining values generating strings until a non-empty value
* is found, or the pending value gets its string generated.
*/
do {
@@ -3132,10 +3201,10 @@ TclStringCat(
unsigned char *dst;
/*
* Broken interface! Byte array value routines offer no way
* to handle failure to allocate enough space. Following
* stanza may panic.
* Broken interface! Byte array value routines offer no way to handle
* failure to allocate enough space. Following stanza may panic.
*/
if (inPlace && !Tcl_IsShared(*objv)) {
int start;
@@ -3149,7 +3218,13 @@ TclStringCat(
while (objc--) {
Tcl_Obj *objPtr = *objv++;
if (objPtr->bytes == NULL) {
/*
* Every argument is either a bytearray with a ("pure")
* value we know we can safely use, or it is an empty string.
* We don't need to copy bytes from the empty strings.
*/
if (TclIsPureByteArray(objPtr)) {
int more;
unsigned char *src = Tcl_GetByteArrayFromObj(objPtr, &more);
memcpy(dst, src, (size_t) more);
@@ -3250,6 +3325,7 @@ TclStringCat(
if ((objPtr->bytes == NULL) || (objPtr->length)) {
int more;
char *src = Tcl_GetStringFromObj(objPtr, &more);
memcpy(dst, src, (size_t) more);
dst += more;
}
@@ -3268,6 +3344,187 @@ TclStringCat(
return NULL;
}
/*
*---------------------------------------------------------------------------
*
* TclStringCmp --
* Compare two Tcl_Obj values as strings.
*
* Results:
* Like memcmp, return -1, 0, or 1.
*
* Side effects:
* String representations may be generated. Internal representation may
* be changed.
*
*---------------------------------------------------------------------------
*/
int TclStringCmp(
Tcl_Obj *value1Ptr,
Tcl_Obj *value2Ptr,
int checkEq, /* comparison is only for equality */
int nocase, /* comparison is not case sensitive */
int reqlength) /* requested length */
{
char *s1, *s2;
int empty, length, match, s1len, s2len;
memCmpFn_t memCmpFn;
if ((reqlength == 0) || (value1Ptr == value2Ptr)) {
/*
* Always match at 0 chars of if it is the same obj.
*/
match = 0;
} else {
if (!nocase && TclIsPureByteArray(value1Ptr)
&& TclIsPureByteArray(value2Ptr)) {
/*
* Use binary versions of comparisons since that won't cause undue
* type conversions and it is much faster. Only do this if we're
* case-sensitive (which is all that really makes sense with byte
* arrays anyway, and we have no memcasecmp() for some reason... :^)
*/
s1 = (char *) Tcl_GetByteArrayFromObj(value1Ptr, &s1len);
s2 = (char *) Tcl_GetByteArrayFromObj(value2Ptr, &s2len);
memCmpFn = memcmp;
} else if ((value1Ptr->typePtr == &tclStringType)
&& (value2Ptr->typePtr == &tclStringType)) {
/*
* Do a unicode-specific comparison if both of the args are of
* String type. If the char length == byte length, we can do a
* memcmp. In benchmark testing this proved the most efficient
* check between the unicode and string comparison operations.
*/
if (nocase) {
s1 = (char *) Tcl_GetUnicodeFromObj(value1Ptr, &s1len);
s2 = (char *) Tcl_GetUnicodeFromObj(value2Ptr, &s2len);
memCmpFn = (memCmpFn_t)Tcl_UniCharNcasecmp;
} else {
s1len = Tcl_GetCharLength(value1Ptr);
s2len = Tcl_GetCharLength(value2Ptr);
if ((s1len == value1Ptr->length)
&& (value1Ptr->bytes != NULL)
&& (s2len == value2Ptr->length)
&& (value2Ptr->bytes != NULL)) {
s1 = value1Ptr->bytes;
s2 = value2Ptr->bytes;
memCmpFn = memcmp;
} else {
s1 = (char *) Tcl_GetUnicode(value1Ptr);
s2 = (char *) Tcl_GetUnicode(value2Ptr);
if (
#ifdef WORDS_BIGENDIAN
1
#else
checkEq
#endif
) {
memCmpFn = memcmp;
s1len *= sizeof(Tcl_UniChar);
s2len *= sizeof(Tcl_UniChar);
} else {
memCmpFn = (memCmpFn_t) Tcl_UniCharNcmp;
}
}
}
} else {
if ((empty = TclCheckEmptyString(value1Ptr)) > 0) {
switch (TclCheckEmptyString(value2Ptr)) {
case -1:
s1 = 0;
s1len = 0;
s2 = TclGetStringFromObj(value2Ptr, &s2len);
break;
case 0:
match = -1;
goto matchdone;
case 1:
default: /* avoid warn: `s2` may be used uninitialized */
match = 0;
goto matchdone;
}
} else if (TclCheckEmptyString(value2Ptr) > 0) {
switch (empty) {
case -1:
s2 = 0;
s2len = 0;
s1 = TclGetStringFromObj(value1Ptr, &s1len);
break;
case 0:
match = 1;
goto matchdone;
case 1:
default: /* avoid warn: `s1` may be used uninitialized */
match = 0;
goto matchdone;
}
} else {
s1 = TclGetStringFromObj(value1Ptr, &s1len);
s2 = TclGetStringFromObj(value2Ptr, &s2len);
}
if (!nocase && checkEq) {
/*
* When we have equal-length we can check only for
* (in)equality. We can use memcmp in all (n)eq cases because
* we don't need to worry about lexical LE/BE variance.
*/
memCmpFn = memcmp;
} else {
/*
* As a catch-all we will work with UTF-8. We cannot use
* memcmp() as that is unsafe with any string containing NUL
* (\xC0\x80 in Tcl's utf rep). We can use the more efficient
* TclpUtfNcmp2 if we are case-sensitive and no specific
* length was requested.
*/
if ((reqlength < 0) && !nocase) {
memCmpFn = (memCmpFn_t) TclpUtfNcmp2;
} else {
s1len = Tcl_NumUtfChars(s1, s1len);
s2len = Tcl_NumUtfChars(s2, s2len);
memCmpFn = (memCmpFn_t)
(nocase ? Tcl_UtfNcasecmp : Tcl_UtfNcmp);
}
}
}
length = (s1len < s2len) ? s1len : s2len;
if (reqlength > 0 && reqlength < length) {
length = reqlength;
} else if (reqlength < 0) {
/*
* The requested length is negative, so we ignore it by setting it
* to length + 1 so we correct the match var.
*/
reqlength = length + 1;
}
if (checkEq && (s1len != s2len)) {
match = 1; /* This will be reversed below. */
} else {
/*
* The comparison function should compare up to the minimum byte
* length only.
*/
match = memCmpFn(s1, s2, (size_t) length);
}
if ((match == 0) && (reqlength > length)) {
match = s1len - s2len;
}
match = (match > 0) ? 1 : (match < 0) ? -1 : 0;
}
matchdone:
return match;
}
/*
*---------------------------------------------------------------------------
*
@@ -3298,7 +3555,7 @@ TclStringFirst(
start = 0;
}
if (ln == 0) {
/* We don't find empty substrings. Bizarre!
/* We don't find empty substrings. Bizarre!
* Whenever this routine is turned into a proper substring
* finder, change to `return start` after limits imposed. */
return -1;
@@ -3462,18 +3719,20 @@ static void
ReverseBytes(
unsigned char *to, /* Copy bytes into here... */
unsigned char *from, /* ...from here... */
int count) /* Until this many are copied, */
int count) /* Until this many are copied, */
/* reversing as you go. */
{
unsigned char *src = from + count;
if (to == from) {
/* Reversing in place */
while (--src > to) {
unsigned char c = *src;
*src = *to;
*to++ = c;
}
} else {
} else {
while (--src >= from) {
*to++ = *src;
}
@@ -3522,7 +3781,10 @@ TclStringReverse(
*to++ = *src;
}
} else {
/* Reversing in place */
/*
* Reversing in place.
*/
while (--src > from) {
ch = *src;
*src = *from;
@@ -3546,20 +3808,22 @@ TclStringReverse(
/*
* Either numChars == -1 and we don't know how many chars are
* represented by objPtr->bytes and we need Pass 1 just in case,
* or numChars >= 0 and we know we have fewer chars than bytes,
* so we know there's a multibyte character needing Pass 1.
* or numChars >= 0 and we know we have fewer chars than bytes, so
* we know there's a multibyte character needing Pass 1.
*
* Pass 1. Reverse the bytes of each multi-byte character.
*/
int charCount = 0;
int bytesLeft = numBytes;
while (bytesLeft) {
/*
* NOTE: We know that the from buffer is NUL-terminated.
* It's part of the contract for objPtr->bytes values.
* Thus, we can skip calling Tcl_UtfCharComplete() here.
* NOTE: We know that the from buffer is NUL-terminated. It's
* part of the contract for objPtr->bytes values. Thus, we can
* skip calling Tcl_UtfCharComplete() here.
*/
int bytesInChar = TclUtfToUniChar(from, &ch);
ReverseBytes((unsigned char *)to, (unsigned char *)from,
@@ -3589,19 +3853,18 @@ TclStringReverse(
*
* The result is a concatenation of a prefix from objPtr, characters
* 0 through first-1, the insertPtr string value, and a suffix from
* objPtr, characters from first + count to the end. The effect is
* as if the inner substring of characters first through first+count-1
* are removed and replaced with insertPtr.
* If insertPtr is NULL, it is treated as an empty string.
* When passed the flag TCL_STRING_IN_PLACE, this routine will try
* to do the work within objPtr, so long as no sharing forbids it.
* Without that request, or as needed, a new Tcl value will be allocated
* to be the result.
* objPtr, characters from first + count to the end. The effect is as if
* the inner substring of characters first through first+count-1 are
* removed and replaced with insertPtr. If insertPtr is NULL, it is
* treated as an empty string. When passed the flag TCL_STRING_IN_PLACE,
* this routine will try to do the work within objPtr, so long as no
* sharing forbids it. Without that request, or as needed, a new Tcl
* value will be allocated to be the result.
*
* Results:
* A Tcl value that is the result of the substring replacement.
* May return NULL in case of an error. When NULL is returned and
* interp is non-NULL, error information is left in interp
* A Tcl value that is the result of the substring replacement. May
* return NULL in case of an error. When NULL is returned and interp is
* non-NULL, error information is left in interp
*
*---------------------------------------------------------------------------
*/
@@ -3689,7 +3952,7 @@ TclStringReplace(
result = Tcl_NewByteArrayObj(NULL, numBytes - count + newBytes);
/* PANIC? */
Tcl_SetByteArrayLength(result, 0);
TclAppendBytesToByteArray(result, bytes, first);
TclAppendBytesToByteArray(result, bytes, first);
TclAppendBytesToByteArray(result, iBytes, newBytes);
TclAppendBytesToByteArray(result, bytes + first + count,
numBytes - count - first);
@@ -3711,7 +3974,7 @@ TclStringReplace(
Tcl_UniChar *ustring = Tcl_GetUnicodeFromObj(objPtr, &numChars);
/* TODO: Is there an in-place option worth pursuing here? */
result = Tcl_NewUnicodeObj(ustring, first);
if (insertPtr) {
Tcl_AppendObjToObj(result, insertPtr);
+48 -13
View File
@@ -34,12 +34,14 @@
#undef Tcl_DbNewLongObj
#undef Tcl_NewObj
#undef Tcl_NewStringObj
#undef Tcl_GetUnicode
#undef Tcl_DumpActiveMemory
#undef Tcl_ValidateAllMemory
#undef Tcl_FindHashEntry
#undef Tcl_CreateHashEntry
#undef Tcl_Panic
#undef Tcl_FindExecutable
#undef Tcl_SetPanicProc
#undef TclpGetPid
#undef TclSockMinimumBuffers
#undef Tcl_SetIntObj
@@ -223,17 +225,31 @@ Tcl_WinUtfToTChar(
int len,
Tcl_DString *dsPtr)
{
WCHAR *wp;
WCHAR *wp, *p;
int size = MultiByteToWideChar(CP_UTF8, 0, string, len, 0, 0);
Tcl_DStringInit(dsPtr);
Tcl_DStringSetLength(dsPtr, 2*size+2);
wp = (WCHAR *)Tcl_DStringValue(dsPtr);
p = wp = (WCHAR *)Tcl_DStringValue(dsPtr);
MultiByteToWideChar(CP_UTF8, 0, string, len, wp, size+1);
if (len == -1) --size; /* account for 0-byte at string end */
/* It turns out that MultiByteToWideChar() cannot handle the 'modified'
* UTF-8 as used by Tcl. Every sequence of 0xC0 followed by 0x80 will
* be translated to two 0xfffd characters. This results in a test-failure
* of the registry-6.20 test-case. The simplest solution is to search for
* those two 0xfffd characters and replace them by a \u0000 character. */
while (p < wp + size - 1) {
if (p[0] == 0xfffd && p[1] == 0xfffd) {
memmove(p+1, p+2, sizeof(WCHAR) * (p - wp + size - 2));
p[0] = '\0';
++p; --size;
}
++p;
}
Tcl_DStringSetLength(dsPtr, 2*size);
wp[size] = 0;
return (char *)wp;
return (char *) wp;
}
char *
@@ -243,17 +259,27 @@ Tcl_WinTCharToUtf(
Tcl_DString *dsPtr)
{
char *p;
int size;
int size, i = 0;
if (len > 0) {
len /= 2;
}
size = WideCharToMultiByte(CP_UTF8, 0, string, len, 0, 0, NULL, NULL);
Tcl_DStringInit(dsPtr);
Tcl_DStringSetLength(dsPtr, size+1);
Tcl_DStringSetLength(dsPtr, size+8); /* Add some spare, in case of NULL-bytes */
p = (char *)Tcl_DStringValue(dsPtr);
WideCharToMultiByte(CP_UTF8, 0, string, len, p, size, NULL, NULL);
if (len == -1) --size; /* account for 0-byte at string end */
while (i < size) {
if (!p[i]) {
/* Output contains '\0'-byte, but Tcl expect two-bytes: C0 80 */
memmove(p+i+2, p+i+1, size-i-1);
memcpy(p + i++, "\xC0\x80", 2);
Tcl_DStringSetLength(dsPtr, ++size + 1);
p = (char *)Tcl_DStringValue(dsPtr);
}
++i;
}
Tcl_DStringSetLength(dsPtr, size);
p[size] = 0;
return p;
@@ -401,6 +427,7 @@ static int uniCharNcasecmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsig
# define TclpGmtime 0
# define TclpLocaltime_unix 0
# define TclpGmtime_unix 0
# define Tcl_GetUnicode 0
#else /* TCL_NO_DEPRECATED */
# define Tcl_SeekOld seekOld
# define Tcl_TellOld tellOld
@@ -428,20 +455,14 @@ seekOld(
int offset, /* Offset to seek to. */
int mode) /* Relative to which location to seek? */
{
Tcl_WideInt wOffset, wResult;
wOffset = Tcl_LongAsWide((long) offset);
wResult = Tcl_Seek(chan, wOffset, mode);
return (int) Tcl_WideAsLong(wResult);
return Tcl_Seek(chan, offset, mode);
}
static int
tellOld(
Tcl_Channel chan) /* The channel to return pos for. */
{
Tcl_WideInt wResult = Tcl_Tell(chan);
return (int) Tcl_WideAsLong(wResult);
return Tcl_Tell(chan);
}
#endif /* !TCL_NO_DEPRECATED */
@@ -454,6 +475,15 @@ tellOld(
MODULE_SCOPE const TclStubs tclStubs;
MODULE_SCOPE const TclTomMathStubs tclTomMathStubs;
#ifdef __GNUC__
/*
* The rest of this file shouldn't warn about deprecated functions; they're
* there because we intend them to be so and know that this file is OK to
* touch those fields.
*/
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
/* !BEGIN!: Do not edit below this line. */
static const TclIntStubs tclIntStubs = {
@@ -910,6 +940,7 @@ const TclTomMathStubs tclTomMathStubs = {
TclBN_mp_get_long_long, /* 69 */
TclBN_mp_set_long, /* 70 */
TclBN_mp_get_long, /* 71 */
TclBN_mp_get_int, /* 72 */
};
static const TclStubHooks tclStubHooks = {
@@ -1577,6 +1608,10 @@ const TclStubs tclStubs = {
Tcl_FSUnloadFile, /* 629 */
Tcl_ZlibStreamSetCompressionDictionary, /* 630 */
Tcl_OpenTcpServerEx, /* 631 */
TclZipfs_Mount, /* 632 */
TclZipfs_Unmount, /* 633 */
TclZipfs_TclLibrary, /* 634 */
TclZipfs_Mount_Buffer, /* 635 */
};
/* !END!: Do not edit above this line. */
+28 -6
View File
@@ -161,7 +161,7 @@ static TestChannel *firstDetached;
static int AsyncHandlerProc(ClientData clientData,
Tcl_Interp *interp, int code);
#ifdef TCL_THREADS
#if TCL_THREADS
static Tcl_ThreadCreateType AsyncThreadProc(ClientData);
#endif
static void CleanupTestSetassocdataTests(
@@ -293,6 +293,8 @@ static int TestgetassocdataCmd(ClientData dummy,
Tcl_Interp *interp, int argc, const char **argv);
static int TestgetintCmd(ClientData dummy,
Tcl_Interp *interp, int argc, const char **argv);
static int TestlongsizeCmd(ClientData dummy,
Tcl_Interp *interp, int argc, const char **argv);
static int TestgetplatformCmd(ClientData dummy,
Tcl_Interp *interp, int argc, const char **argv);
static int TestgetvarfullnameCmd(
@@ -645,6 +647,8 @@ Tcltest_Init(
NULL, NULL);
Tcl_CreateCommand(interp, "testgetint", TestgetintCmd,
NULL, NULL);
Tcl_CreateCommand(interp, "testlongsize", TestlongsizeCmd,
NULL, NULL);
Tcl_CreateCommand(interp, "testgetplatform", TestgetplatformCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testgetvarfullname",
@@ -722,7 +726,7 @@ Tcltest_Init(
if (Procbodytest_Init(interp) != TCL_OK) {
return TCL_ERROR;
}
#ifdef TCL_THREADS
#if TCL_THREADS
if (TclThread_Init(interp) != TCL_OK) {
return TCL_ERROR;
}
@@ -902,7 +906,7 @@ TestasyncCmd(
Tcl_SetObjResult(interp, Tcl_NewStringObj(argv[3], -1));
Tcl_MutexUnlock(&asyncTestMutex);
return code;
#ifdef TCL_THREADS
#if TCL_THREADS
} else if (strcmp(argv[1], "marklater") == 0) {
if (argc != 3) {
goto wrongNumArgs;
@@ -999,7 +1003,7 @@ AsyncHandlerProc(
*----------------------------------------------------------------------
*/
#ifdef TCL_THREADS
#if TCL_THREADS
static Tcl_ThreadCreateType
AsyncThreadProc(
ClientData clientData) /* Parameter is the id of a
@@ -2828,7 +2832,7 @@ TestlinkCmd(
static int intVar = 43;
static int boolVar = 4;
static double realVar = 1.23;
static Tcl_WideInt wideVar = Tcl_LongAsWide(79);
static Tcl_WideInt wideVar = 79;
static char *stringVar = NULL;
static char charVar = '@';
static unsigned char ucharVar = 130;
@@ -2838,7 +2842,7 @@ TestlinkCmd(
static long longVar = 123456789L;
static unsigned long ulongVar = 3456789012UL;
static float floatVar = 4.5;
static Tcl_WideUInt uwideVar = (Tcl_WideUInt) Tcl_LongAsWide(123);
static Tcl_WideUInt uwideVar = 123;
static int created = 0;
char buffer[2*TCL_DOUBLE_SPACE];
int writable, flag;
@@ -6936,6 +6940,24 @@ TestgetintCmd(
}
}
/*
* Used for determining sizeof(long) at script level.
*/
static int
TestlongsizeCmd(
ClientData dummy,
Tcl_Interp *interp,
int argc,
const char **argv)
{
if (argc != 1) {
Tcl_AppendResult(interp, "wrong # args", NULL);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)sizeof(long)));
return TCL_OK;
}
static int
NREUnwind_callback(
ClientData data[],
+10 -25
View File
@@ -40,21 +40,6 @@ static void ForgetSyncObject(void *objPtr, SyncObjRecord *recPtr);
static void RememberSyncObject(void *objPtr,
SyncObjRecord *recPtr);
/*
* Several functions are #defined to nothing in tcl.h if TCL_THREADS is not
* specified. Here we undo that so the functions are defined in the stubs
* table.
*/
#ifndef TCL_THREADS
#undef Tcl_MutexLock
#undef Tcl_MutexUnlock
#undef Tcl_MutexFinalize
#undef Tcl_ConditionNotify
#undef Tcl_ConditionWait
#undef Tcl_ConditionFinalize
#endif
/*
*----------------------------------------------------------------------
*
@@ -79,7 +64,7 @@ Tcl_GetThreadData(
int size) /* Size of storage block */
{
void *result;
#ifdef TCL_THREADS
#if TCL_THREADS
/*
* Initialize the key for this thread.
*/
@@ -126,7 +111,7 @@ TclThreadDataKeyGet(
Tcl_ThreadDataKey *keyPtr) /* Identifier for the data chunk. */
{
#ifdef TCL_THREADS
#if TCL_THREADS
return TclThreadStorageKeyGet(keyPtr);
#else /* TCL_THREADS */
return *keyPtr;
@@ -269,11 +254,12 @@ TclRememberMutex(
*----------------------------------------------------------------------
*/
#undef Tcl_MutexFinalize
void
Tcl_MutexFinalize(
Tcl_Mutex *mutexPtr)
{
#ifdef TCL_THREADS
#if TCL_THREADS
TclpFinalizeMutex(mutexPtr);
#endif
TclpMasterLock();
@@ -322,11 +308,12 @@ TclRememberCondition(
*----------------------------------------------------------------------
*/
#undef Tcl_ConditionFinalize
void
Tcl_ConditionFinalize(
Tcl_Condition *condPtr)
{
#ifdef TCL_THREADS
#if TCL_THREADS
TclpFinalizeCondition(condPtr);
#endif
TclpMasterLock();
@@ -356,7 +343,7 @@ void
TclFinalizeThreadData(int quick)
{
TclFinalizeThreadDataThread();
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
if (!quick) {
/*
* Quick exit principle makes it useless to terminate allocators
@@ -389,7 +376,7 @@ TclFinalizeSynchronization(void)
int i;
void *blockPtr;
Tcl_ThreadDataKey *keyPtr;
#ifdef TCL_THREADS
#if TCL_THREADS
Tcl_Mutex *mutexPtr;
Tcl_Condition *condPtr;
@@ -413,7 +400,7 @@ TclFinalizeSynchronization(void)
keyRecord.max = 0;
keyRecord.num = 0;
#ifdef TCL_THREADS
#if TCL_THREADS
/*
* Call thread storage master cleanup.
*/
@@ -473,12 +460,10 @@ Tcl_ExitThread(
int status)
{
Tcl_FinalizeThread();
#ifdef TCL_THREADS
TclpThreadExit(status);
#endif
}
#ifndef TCL_THREADS
#if !TCL_THREADS
/*
*----------------------------------------------------------------------
+1 -1
View File
@@ -13,7 +13,7 @@
*/
#include "tclInt.h"
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
/*
* If range checking is enabled, an additional byte will be allocated to store

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